From 20f64f3cf3d875a0650e2d2a4a69dc410b10d191 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 4 Dec 2024 17:27:19 +0100 Subject: [PATCH 01/11] fix: can not select files on the connection form VSCODE-658 --- package-lock.json | 227 +++++++++--------- package.json | 2 +- .../extension-app-message-constants.ts | 11 +- src/views/webview-app/overview-page.tsx | 11 + src/views/webview-app/use-connection-form.ts | 22 ++ src/views/webviewController.ts | 5 + webpack.config.js | 6 +- 7 files changed, 165 insertions(+), 119 deletions(-) diff --git a/package-lock.json b/package-lock.json index dba1496a3..6d62261c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", "@mongodb-js/compass-components": "^1.30.1", - "@mongodb-js/connection-form": "^1.42.0", + "@mongodb-js/connection-form": "^1.45.1", "@mongodb-js/connection-info": "^0.9.1", "@mongodb-js/mongodb-constants": "^0.10.3", "@mongosh/browser-runtime-electron": "^2.3.3", @@ -1747,9 +1747,9 @@ } }, "node_modules/@codemirror/autocomplete": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.1.tgz", - "integrity": "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==", + "version": "6.18.3", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.3.tgz", + "integrity": "sha512-1dNIOmiM0z4BIBwxmxEfA1yoxh1MF/6KPBbh20a5vphGV0ictKlgQsbJs6D6SkR6iJpGbpwRsa6PFMNlg9T9pQ==", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -1764,9 +1764,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.0.tgz", - "integrity": "sha512-+cduIZ2KbesDhbykV02K25A5xIVrquSPz4UxxYBemRlAT2aW8dhwUgLDwej7q/RJUHKk4nALYcR1puecDvbdqw==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.1.tgz", + "integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", @@ -1798,9 +1798,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.3.tgz", - "integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==", + "version": "6.10.6", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.6.tgz", + "integrity": "sha512-KrsbdCnxEztLVbB5PycWXFxas4EOyk/fPAfruSOnDDppevQgid2XZ+KbJ9u+fDikP/e7MW7HPBTvTb8JlZK9vA==", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -1811,12 +1811,12 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz", - "integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.4.tgz", + "integrity": "sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==", "dependencies": { "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", + "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, @@ -1826,9 +1826,9 @@ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" }, "node_modules/@codemirror/view": { - "version": "6.34.1", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz", - "integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==", + "version": "6.35.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.35.0.tgz", + "integrity": "sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw==", "dependencies": { "@codemirror/state": "^6.4.0", "style-mod": "^4.1.0", @@ -2828,18 +2828,18 @@ } }, "node_modules/@leafygreen-ui/hooks": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-8.1.3.tgz", - "integrity": "sha512-UAHii7T+g8h8sSzogqUgIid64bbKPHGihAAoBpNzbNsjqFllYVC0FpF59jQeL6tCYd32C2KatWOvhYheBf1hsA==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-8.2.1.tgz", + "integrity": "sha512-yozp+WfMo1aNzQJG4WOa4eoxEEMK3T7Q7D2AObRWEPR+jPeeocsBKSHoAkUsfJ/8AklQ+LIWM1SvtUm4iuLXtQ==", "dependencies": { "@leafygreen-ui/lib": "^13.3.0", "lodash": "^4.17.21" } }, "node_modules/@leafygreen-ui/icon": { - "version": "12.5.4", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-12.5.4.tgz", - "integrity": "sha512-RsoIN4hfBtJDGuR5ClElCYvpX5+YqjB381EJDZQGC12iQGhhJwCuD4p4NW4O+jWXpt7KGISDKg0Ieao5R/vmpw==", + "version": "12.8.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-12.8.0.tgz", + "integrity": "sha512-LDYSFtdn+dX3/hyBJJw722grz98To+X9Nw/97F6MUk+D9eNdufzPFYQCd8iDsgUbfeSVJ/uw1PVr20QEJ7Xtcw==", "dependencies": { "@leafygreen-ui/emotion": "^4.0.8", "lodash": "^4.17.21" @@ -2945,9 +2945,9 @@ } }, "node_modules/@leafygreen-ui/lib": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-13.6.0.tgz", - "integrity": "sha512-4TglZhImmJ5G13nEoBsNkwBEDZLS0Qo4b3hfPnJsXQ0+BYguxExevan6S7i7hQ4iwvZekCVKGd/yrp0UonrOHQ==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-13.8.0.tgz", + "integrity": "sha512-WHbs0ZKzMR/UU0XmlI7+PKDzayuynTXrEQ2GwL5WpPjRElxlajkDyjkzmxXkQLIKce+T+q8ucIVlRVInDG+Qlg==", "dependencies": { "@storybook/csf": "^0.1.0", "lodash": "^4.17.21", @@ -3284,9 +3284,9 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/@leafygreen-ui/table": { - "version": "12.6.4", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/table/-/table-12.6.4.tgz", - "integrity": "sha512-bXnYUrn+SWdLcaUIjfr3CwLilpdjpLJrW8GY/co4SOqlA57/ih8pi1dei3ltmsjtCxOkupU0jZeMUoF45JNikg==", + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/table/-/table-12.7.0.tgz", + "integrity": "sha512-zsenGdk7yXu7aFELSDlGa1yjv4Q6C4KfL4o8MEqAZYXlZqzsB6z/QiZRJfVjti4vIYWVENC2GwDSLRAAUDGuuQ==", "dependencies": { "@leafygreen-ui/checkbox": "^13.1.0", "@leafygreen-ui/emotion": "^4.0.8", @@ -3296,8 +3296,9 @@ "@leafygreen-ui/lib": "^13.6.0", "@leafygreen-ui/palette": "^4.0.9", "@leafygreen-ui/polymorphic": "^2.0.0", - "@leafygreen-ui/tokens": "^2.9.0", + "@leafygreen-ui/tokens": "^2.11.0", "@leafygreen-ui/typography": "^19.2.0", + "@lg-tools/test-harnesses": "^0.1.2", "@tanstack/react-table": "^8.13.2", "lodash": "^4.17.21", "polished": "^4.2.2", @@ -3310,13 +3311,13 @@ } }, "node_modules/@leafygreen-ui/table/node_modules/@leafygreen-ui/checkbox": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/checkbox/-/checkbox-13.1.0.tgz", - "integrity": "sha512-Cu+Jqunde+yTYqdUvRe/o2gBZE/WI8nyhvS+Ozy2PB1KMN95PCQ/oCU1oMI3n5/gQTbFEXi4ia54eln0TRgh7w==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/checkbox/-/checkbox-13.1.2.tgz", + "integrity": "sha512-rdn55oDiywyk/t3wKnJKbzDn6CUtCCSm4PQF6t4svZWVaHvNzDgTDjHy5D1s8MYpFQbqhsWbJhf17tpRrzY/Mw==", "dependencies": { "@leafygreen-ui/a11y": "^1.4.13", "@leafygreen-ui/emotion": "^4.0.8", - "@leafygreen-ui/hooks": "^8.1.3", + "@leafygreen-ui/hooks": "^8.1.4", "@leafygreen-ui/lib": "^13.4.0", "@leafygreen-ui/palette": "^4.0.10", "@leafygreen-ui/tokens": "^2.5.2", @@ -3329,22 +3330,22 @@ } }, "node_modules/@leafygreen-ui/table/node_modules/@leafygreen-ui/polymorphic": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/polymorphic/-/polymorphic-2.0.1.tgz", - "integrity": "sha512-rzNoS0Q50NI6e+qkc0ytLwnCbiBEfDdLTta2WBPT7noi1yshCcPDlM7+g2R6gTRdTNVUSOLVNyt4VeLZOERc6g==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/polymorphic/-/polymorphic-2.0.2.tgz", + "integrity": "sha512-OjP+hPG/cwADShcGa1SZdm51G2wVpbNqpU0B3GonEAvGLcAvG4LDMXa7BWo3GDliNkPtVMS86w0eZzEDmLfKmQ==", "dependencies": { "@leafygreen-ui/lib": "^13.6.0", "lodash": "^4.17.21" } }, "node_modules/@leafygreen-ui/table/node_modules/@leafygreen-ui/typography": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-19.2.0.tgz", - "integrity": "sha512-57O0eplpV3nYQMVtSYuOGafPhGC26ShPDTK46HF9I9xCgLRul4YHFM3jwXQEvdWcZO5JSMHzx5iH7ec2+pHBrA==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-19.3.0.tgz", + "integrity": "sha512-pgTRcc4usW/S9nDDzkf5Ac/JPEybhWtOnDpmrp99mAJHM6tH48Pd1HjRNHWjn6bnh0nXWjwANXX1ZEe+8ggCNg==", "dependencies": { "@leafygreen-ui/emotion": "^4.0.8", - "@leafygreen-ui/icon": "^12.5.4", - "@leafygreen-ui/lib": "^13.6.0", + "@leafygreen-ui/icon": "^12.6.0", + "@leafygreen-ui/lib": "^13.6.1", "@leafygreen-ui/palette": "^4.0.10", "@leafygreen-ui/polymorphic": "^2.0.0", "@leafygreen-ui/tokens": "^2.9.0" @@ -3471,12 +3472,13 @@ } }, "node_modules/@leafygreen-ui/tokens": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-2.9.0.tgz", - "integrity": "sha512-Ogn250aFFHylmkKZAtdyS6qhA3JiHra+Zx8tMK500kkWTo8lwh7bSiK6nVwKWzkkeReEr8Iq41a08RjaRaf4HQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-2.11.0.tgz", + "integrity": "sha512-/0G+UaDpLBLLtEP1mjGjiDnqReHufUTUkteqNUsyTOz1bpfejoo1anu3f6dZDqNlxoKhHZEEngQ+HvP1l1RJVw==", "dependencies": { - "@leafygreen-ui/lib": "^13.6.0", - "@leafygreen-ui/palette": "^4.0.9" + "@leafygreen-ui/lib": "^13.7.0", + "@leafygreen-ui/palette": "^4.0.9", + "polished": "^4.2.2" } }, "node_modules/@leafygreen-ui/tooltip": { @@ -3559,9 +3561,9 @@ } }, "node_modules/@lezer/javascript": { - "version": "1.4.19", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.19.tgz", - "integrity": "sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==", + "version": "1.4.20", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.20.tgz", + "integrity": "sha512-Qhl3x+hVPnZkylv+BS//zx77KR4GLxM4PiL02r/D1Zoa4WLQI1A0cHuOr6k0FOTTSCPNNfeNANax0I5DWcXBYw==", "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.1.3", @@ -3656,9 +3658,9 @@ } }, "node_modules/@mongodb-js/compass-components": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/compass-components/-/compass-components-1.30.1.tgz", - "integrity": "sha512-XTlQsmKagGmb2oQifkzsw7ssmYBgqm9/vKXgGKgGKTdC4Jr6k3INm+lvRp3gU54ejNfaPgV269MQWATVMGwF4w==", + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/compass-components/-/compass-components-1.32.1.tgz", + "integrity": "sha512-fP1zdixe3zTjtxAYSj4N44K0LKlz6Keqiyn1uqiPu/XXGqWYuztdmAKmwS1Ud4w0o9Q3mXOaVG7tOgeBvowgVA==", "dependencies": { "@dnd-kit/core": "^6.0.7", "@dnd-kit/sortable": "^7.0.2", @@ -3693,7 +3695,7 @@ "@leafygreen-ui/search-input": "^2.1.5", "@leafygreen-ui/segmented-control": "^8.2.10", "@leafygreen-ui/select": "^11.2.2", - "@leafygreen-ui/table": "^12.6.1", + "@leafygreen-ui/table": "^12.7.0", "@leafygreen-ui/tabs": "^11.1.13", "@leafygreen-ui/text-area": "^8.1.2", "@leafygreen-ui/text-input": "^12.1.26", @@ -3705,10 +3707,11 @@ "@react-aria/interactions": "^3.9.1", "@react-aria/utils": "^3.13.1", "@react-aria/visually-hidden": "^3.3.1", + "@tanstack/table-core": "^8.14.0", "bson": "^6.8.0", "focus-trap-react": "^9.0.2", - "hadron-document": "^8.6.4", - "hadron-type-checker": "^7.2.3", + "hadron-document": "^8.6.6", + "hadron-type-checker": "^7.2.4", "is-electron-renderer": "^2.0.1", "lodash": "^4.17.21", "polished": "^4.2.2", @@ -3721,9 +3724,9 @@ } }, "node_modules/@mongodb-js/compass-editor": { - "version": "0.31.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/compass-editor/-/compass-editor-0.31.1.tgz", - "integrity": "sha512-BNsgrOpJG/m1s4IKJD2HclfHR/5SJOfxay77HTrSdZR8kqlN43k9jzomVKv3LaZ4NFNHVFqpPoxyVDcswOAc/g==", + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/compass-editor/-/compass-editor-0.34.1.tgz", + "integrity": "sha512-0AclLRvldtJ48bn0soFKFw1YRDQhL43Wbom5DfbJ9xn075UITkX8fvKntkpQMYHb/gl7tDGbs2XMIZiApxLo2Q==", "dependencies": { "@codemirror/autocomplete": "^6.17.0", "@codemirror/commands": "^6.1.2", @@ -3734,7 +3737,7 @@ "@codemirror/state": "^6.1.4", "@codemirror/view": "^6.7.1", "@lezer/highlight": "^1.2.0", - "@mongodb-js/compass-components": "^1.30.1", + "@mongodb-js/compass-components": "^1.32.1", "@mongodb-js/mongodb-constants": "^0.10.0", "mongodb-query-parser": "^4.2.3", "polished": "^4.2.2", @@ -3743,54 +3746,54 @@ } }, "node_modules/@mongodb-js/compass-logging": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/compass-logging/-/compass-logging-1.4.8.tgz", - "integrity": "sha512-+mCyiKM24u6k+380/Gr59DksbW/1ago0g3BGZqR8KVFG4WVQ1UQWyan28xI81ofOuF9/Sz3qGmpG5T7lMxJOcQ==", + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@mongodb-js/compass-logging/-/compass-logging-1.4.12.tgz", + "integrity": "sha512-XVUdc/76R3yUI4vxnE1GadyuJA7+TKLT8yfynmi77wcGd1/0g0uX2yrJtGja1UsqPRVejz5mrVTjHw22yyxPYw==", "dependencies": { "debug": "^4.3.4", - "hadron-app-registry": "^9.2.7", - "hadron-ipc": "^3.2.23", + "hadron-app-registry": "^9.2.8", + "hadron-ipc": "^3.2.27", "is-electron-renderer": "^2.0.1", "mongodb-log-writer": "^1.4.2", "react": "^17.0.2" } }, "node_modules/@mongodb-js/compass-utils": { - "version": "0.6.12", - "resolved": "https://registry.npmjs.org/@mongodb-js/compass-utils/-/compass-utils-0.6.12.tgz", - "integrity": "sha512-TIeNeta2aGmkIWlzqKwkPfXUMFAxpCG9ml68wYRrKHXvWmnnCot0/lJZdXyD9PQ3U41DnF6BfmguTeo3A/Us6Q==", + "version": "0.6.16", + "resolved": "https://registry.npmjs.org/@mongodb-js/compass-utils/-/compass-utils-0.6.16.tgz", + "integrity": "sha512-BjR5Tw2AXtAf3GdZWiYmsXXjB1kWJ2Y5U7k0yLAsA8tPueaPeJAmSTc9OZM8eHCmcWrQZOSoIfW5ZNUkVoaTaw==", "dependencies": { "@electron/remote": "^2.1.2", - "electron": "^30.5.1" + "electron": "^32.2.5" } }, "node_modules/@mongodb-js/connection-form": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/connection-form/-/connection-form-1.42.0.tgz", - "integrity": "sha512-kGJRzVvYIeDHYjUEAXSEWz0ycxd3uFY+i+6ol3EA0MSY7Qd+1T8wMT78rB8EDoqDtpSUke4yBhEMlrcDHz7WLQ==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/connection-form/-/connection-form-1.45.1.tgz", + "integrity": "sha512-7b2BOAJFiVRRcDmzMvdmIYqgWqJuFTcdcaaLhc6oTugwfYt1Dy3/EXKp2A2R4TuU9ZX0gim8pTpHVzbH1saGfg==", "dependencies": { - "@mongodb-js/compass-components": "^1.30.1", - "@mongodb-js/compass-editor": "^0.31.1", - "@mongodb-js/connection-info": "^0.9.1", + "@mongodb-js/compass-components": "^1.32.1", + "@mongodb-js/compass-editor": "^0.34.1", + "@mongodb-js/connection-info": "^0.9.5", "@mongodb-js/shell-bson-parser": "^1.1.2", "lodash": "^4.17.21", "mongodb": "^6.9.0", "mongodb-build-info": "^1.7.2", "mongodb-connection-string-url": "^3.0.1", - "mongodb-data-service": "^22.23.5", + "mongodb-data-service": "^22.23.9", "mongodb-query-parser": "^4.2.3", "react": "^17.0.2" } }, "node_modules/@mongodb-js/connection-info": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/connection-info/-/connection-info-0.9.1.tgz", - "integrity": "sha512-DrM7v/QP+8LUrYNwS8zF4a6FFXW4wI/7KSjkO6nis9ivA/n5uQwpr6JkRP5wMe5j1m1AzsEcb3sVK9ZrEvVo+w==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@mongodb-js/connection-info/-/connection-info-0.9.5.tgz", + "integrity": "sha512-CeNjUmt8hEIoBmzEnLoNhjQjBqAaP9W/nNurxGNpbvkE/8Pw+GUR5OkiXDN/7f2mWm+g1P/RTIlWyK1wsqyRyQ==", "dependencies": { "lodash": "^4.17.21", "mongodb": "^6.9.0", "mongodb-connection-string-url": "^3.0.1", - "mongodb-data-service": "^22.23.5" + "mongodb-data-service": "^22.23.9" } }, "node_modules/@mongodb-js/devtools-proxy-support": { @@ -5279,11 +5282,11 @@ } }, "node_modules/@tanstack/react-table": { - "version": "8.17.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.17.3.tgz", - "integrity": "sha512-5gwg5SvPD3lNAXPuJJz1fOCEZYk9/GeBFH3w/hCgnfyszOIzwkwgp5I7Q4MJtn0WECp84b5STQUDdmvGi8m3nA==", + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", "dependencies": { - "@tanstack/table-core": "8.17.3" + "@tanstack/table-core": "8.20.5" }, "engines": { "node": ">=12" @@ -5298,9 +5301,9 @@ } }, "node_modules/@tanstack/table-core": { - "version": "8.17.3", - "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.17.3.tgz", - "integrity": "sha512-mPBodDGVL+fl6d90wUREepHa/7lhsghg2A3vFpakEhrhtbIlgNAZiMr7ccTgak5qbHqF14Fwy+W1yFWQt+WmYQ==", + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", "engines": { "node": ">=12" }, @@ -9553,9 +9556,9 @@ } }, "node_modules/electron": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-30.5.1.tgz", - "integrity": "sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw==", + "version": "32.2.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-32.2.6.tgz", + "integrity": "sha512-aGG1MLvWCf+ECUFBCmaCF52F8312OPAJfph2D0FSsFmlbfnJuNevZCbty2lFzsiIMtU7/QRo6d0ksbgR4s7y3w==", "hasInstallScript": true, "dependencies": { "@electron/get": "^2.0.0", @@ -9575,9 +9578,9 @@ "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==" }, "node_modules/electron/node_modules/@types/node": { - "version": "20.16.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz", - "integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==", + "version": "20.17.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.9.tgz", + "integrity": "sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw==", "dependencies": { "undici-types": "~6.19.2" } @@ -12019,9 +12022,9 @@ } }, "node_modules/hadron-app-registry": { - "version": "9.2.7", - "resolved": "https://registry.npmjs.org/hadron-app-registry/-/hadron-app-registry-9.2.7.tgz", - "integrity": "sha512-j9gzTlzyuRxis1ywcoDRyOUJtDRktc/ZFXjbxtxTQMuDnSJYtshbzF1D7N38fvs61gDQNQ20egRTDg9oPAhQCA==", + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/hadron-app-registry/-/hadron-app-registry-9.2.8.tgz", + "integrity": "sha512-amnO2cicQ1VLrw8N122fv/fBsFHDG0Uy36FFwegpc6/FvIroS1JvRuOy/i9fN8h3NrwdIKbGilVhdU5W/xU96Q==", "dependencies": { "eventemitter3": "^4.0.0", "react": "^17.0.2", @@ -12074,30 +12077,30 @@ } }, "node_modules/hadron-document": { - "version": "8.6.4", - "resolved": "https://registry.npmjs.org/hadron-document/-/hadron-document-8.6.4.tgz", - "integrity": "sha512-BJdtCE34krvjlUOx+OeNNNSlf29vrnB0V2RuodfXhBB/Sast7wOb9Ig5NjCCHlfzKiGmw+5MIilqIit2Titewg==", + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/hadron-document/-/hadron-document-8.6.6.tgz", + "integrity": "sha512-RXkcQYQC5qoxf0ohNX4Hp19bVVb57IGWF+WUGquTxLL2T5Lq80oYk/79xkrzJJNnnyXLxUWyGcF2/e2QSMI6zA==", "dependencies": { "bson": "^6.8.0", "eventemitter3": "^4.0.0", - "hadron-type-checker": "^7.2.3", + "hadron-type-checker": "^7.2.4", "lodash": "^4.17.21" } }, "node_modules/hadron-ipc": { - "version": "3.2.23", - "resolved": "https://registry.npmjs.org/hadron-ipc/-/hadron-ipc-3.2.23.tgz", - "integrity": "sha512-KQLfJFVxPJtMrF378V/M8hZimrgUT8wM6//3WGF8Lx1+G5r3CV07QNyxkb9NbEii0FA9Xn3A9Yyg/mDBXNP2iQ==", + "version": "3.2.27", + "resolved": "https://registry.npmjs.org/hadron-ipc/-/hadron-ipc-3.2.27.tgz", + "integrity": "sha512-ZnVbuoXJ9zLfy+abmLwdnEU23VQ0ZcIzlLUovEKW9d5uMtE8j7q+t3/igdxacPFPywBbR4alhOUml4NgVr0cxA==", "dependencies": { "debug": "^4.3.4", - "electron": "^30.5.1", + "electron": "^32.2.5", "is-electron-renderer": "^2.0.1" } }, "node_modules/hadron-type-checker": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/hadron-type-checker/-/hadron-type-checker-7.2.3.tgz", - "integrity": "sha512-IeqnXS2r3874S8ZByEKwXrQDFdHmYpkEB1G40zIU0toW/UrIrLhD4HokNWVhTWck5GSvlEMEAG924sBQdRlnRQ==", + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/hadron-type-checker/-/hadron-type-checker-7.2.4.tgz", + "integrity": "sha512-I6mht/w0/HLIu/AE4na8WYDrjyo9tvVC7j+NMs+8icW/P8xSP4WgDk9KyvgfgBhMOtEMY2kQI5AuKKCncsdF+A==", "dependencies": { "bson": "^6.8.0", "lodash": "^4.17.21" @@ -14877,12 +14880,12 @@ } }, "node_modules/mongodb-data-service": { - "version": "22.23.5", - "resolved": "https://registry.npmjs.org/mongodb-data-service/-/mongodb-data-service-22.23.5.tgz", - "integrity": "sha512-US4zCIkJ44pVMROine5mvykg374M60WQ4fu1K92+u/4vBP/Z5ZqlxIytBj1OH1x04S0yvyN/Y6BCVzug4EWAKw==", + "version": "22.23.9", + "resolved": "https://registry.npmjs.org/mongodb-data-service/-/mongodb-data-service-22.23.9.tgz", + "integrity": "sha512-aaKNTHWD+lOdrbFdH4zJK/9OlsSFaAxkAcy0fIbXOtbUy26ShX8018QfoRbwyqGbmJr0iDZd4Wd1Gpqc3bPaLw==", "dependencies": { - "@mongodb-js/compass-logging": "^1.4.8", - "@mongodb-js/compass-utils": "^0.6.12", + "@mongodb-js/compass-logging": "^1.4.12", + "@mongodb-js/compass-utils": "^0.6.16", "@mongodb-js/devtools-connect": "^3.3.1", "@mongodb-js/devtools-proxy-support": "^0.4.1", "bson": "^6.8.0", diff --git a/package.json b/package.json index 61d274e83..12abcac4c 100644 --- a/package.json +++ b/package.json @@ -1178,7 +1178,7 @@ "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", "@mongodb-js/compass-components": "^1.30.1", - "@mongodb-js/connection-form": "^1.42.0", + "@mongodb-js/connection-form": "^1.45.1", "@mongodb-js/connection-info": "^0.9.1", "@mongodb-js/mongodb-constants": "^0.10.3", "@mongosh/browser-runtime-electron": "^2.3.3", diff --git a/src/views/webview-app/extension-app-message-constants.ts b/src/views/webview-app/extension-app-message-constants.ts index 6407587b6..51a26ab51 100644 --- a/src/views/webview-app/extension-app-message-constants.ts +++ b/src/views/webview-app/extension-app-message-constants.ts @@ -1,4 +1,6 @@ import type { ConnectionOptions } from 'mongodb-data-service'; +import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components'; +import type { BaseWindow } from 'electron'; export enum CONNECTION_STATUS { LOADING = 'LOADING', // When the connection status has not yet been shared from the extension. @@ -19,6 +21,7 @@ export enum MESSAGE_TYPES { CANCEL_CONNECT = 'CANCEL_CONNECT', CONNECT_RESULT = 'CONNECT_RESULT', CONNECTION_FORM_OPENED = 'CONNECTION_FORM_OPENED', + ELECTRON_FILE_INPUT_BACKEND = 'ELECTRON_FILE_INPUT_BACKEND', CONNECTION_STATUS_MESSAGE = 'CONNECTION_STATUS_MESSAGE', OPEN_EDIT_CONNECTION = 'OPEN_EDIT_CONNECTION', EDIT_AND_CONNECT_CONNECTION = 'EDIT_AND_CONNECT_CONNECTION', @@ -85,6 +88,11 @@ export interface ConnectResultsMessage extends BasicWebviewMessage { connectionId: string; } +export interface ElectronFileInputBackendMessage extends BasicWebviewMessage { + command: MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND; + dialog: ElectronShowFileDialogProvider; +} + export interface GetConnectionStatusMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.GET_CONNECTION_STATUS; } @@ -129,4 +137,5 @@ export type MESSAGE_FROM_EXTENSION_TO_WEBVIEW = | ConnectResultsMessage | ConnectionStatusMessage | ThemeChangedMessage - | OpenEditConnectionMessage; + | OpenEditConnectionMessage + | ElectronFileInputBackendMessage; diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 1231e4b8f..3f01f83e9 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -4,6 +4,8 @@ import { css, resetGlobalCSS, spacing, + // FileInputBackendProvider, + // createElectronFileInputBackend, } from '@mongodb-js/compass-components'; import OverviewHeader from './overview-header'; @@ -39,6 +41,7 @@ const OverviewPage: React.FC = () => { handleCancelConnectClicked, handleSaveConnectionClicked, handleConnectClicked, + // dialog, } = useConnectionForm(); const handleResourcesPanelClose = useCallback( () => setShowResourcesPanel(false), @@ -55,12 +58,19 @@ const OverviewPage: React.FC = () => { resetGlobalCSS(); }, []); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const util = require('util'); + console.log('(globalThis as any).vscode----------------------'); + console.log(`${util.inspect((globalThis as any).vscode)}`); + console.log('----------------------'); + return (
{showResourcesPanel && ( )} {isConnectionFormOpen && ( + // { open={isConnectionFormOpen} connectionErrorMessage={connectionErrorMessage} /> + // )} diff --git a/src/views/webview-app/use-connection-form.ts b/src/views/webview-app/use-connection-form.ts index c0edd7989..3f4c2d65c 100644 --- a/src/views/webview-app/use-connection-form.ts +++ b/src/views/webview-app/use-connection-form.ts @@ -1,6 +1,8 @@ import { useEffect, useReducer } from 'react'; import { v4 as uuidv4 } from 'uuid'; import type { ConnectionOptions } from 'mongodb-data-service'; +import type { BaseWindow } from 'electron'; +import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components'; import { sendConnectToExtension, @@ -34,6 +36,7 @@ type State = { isConnectionFormOpen: boolean; isEditingConnection: boolean; connectionErrorMessage: string; + dialog: ElectronShowFileDialogProvider | null; }; export function getDefaultConnectionFormState(): State { @@ -43,6 +46,7 @@ export function getDefaultConnectionFormState(): State { isConnectionFormOpen: false, isEditingConnection: false, connectionErrorMessage: '', + dialog: null, }; } @@ -70,6 +74,10 @@ type Action = } | { type: 'attempt-connect'; + } + | { + type: 'electron-file-input-backend'; + dialog: ElectronShowFileDialogProvider; }; function connectionFormReducer(state: State, action: Action): State { @@ -95,6 +103,11 @@ function connectionFormReducer(state: State, action: Action): State { connectionErrorMessage: action.connectionMessage, isConnectionFormOpen: !action.connectionSuccess, }; + case 'electron-file-input-backend': + return { + ...state, + dialog: action.dialog, + }; case 'open-edit-connection': return { ...state, @@ -124,6 +137,7 @@ export default function useConnectionForm() { isConnectionFormOpen, isEditingConnection, connectionErrorMessage, + dialog, }, dispatch, ] = useReducer(connectionFormReducer, { @@ -142,6 +156,13 @@ export default function useConnectionForm() { connectionSuccess: message.connectionSuccess, connectionMessage: message.connectionMessage, }); + } else if ( + message.command === MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND + ) { + dispatch({ + type: 'electron-file-input-backend', + dialog: message.dialog, + }); } }; window.addEventListener('message', handleConnectResultResponse); @@ -177,6 +198,7 @@ export default function useConnectionForm() { isConnecting, initialConnectionInfo, connectionErrorMessage, + dialog, openConnectionForm: () => { dispatch({ type: 'open-connection-form', diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index fac9a83d6..4c347b2fc 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import path from 'path'; import crypto from 'crypto'; import type { ConnectionOptions } from 'mongodb-data-service'; +import { dialog } from 'electron'; import type ConnectionController from '../connectionController'; import { ConnectionTypes } from '../connectionController'; @@ -189,6 +190,10 @@ export default class WebviewController { // If the connection string input is open we want to close it // when the user opens the form. this._connectionController.closeConnectionStringInput(); + void panel.webview.postMessage({ + command: MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND, + dialog, + }); return; case MESSAGE_TYPES.GET_CONNECTION_STATUS: void panel.webview.postMessage({ diff --git a/webpack.config.js b/webpack.config.js index fd928938f..fe198b20b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -37,10 +37,6 @@ module.exports = (env, argv) => { // This alias can be removed once `mongodb-data-service` will not include `mongodb-connection-model` anymore. 'ampersand-sync': false, - // Removes `electron`: is an optional dependency of `oidc-plugin`, but also installed as dev-dep, - // webpack would bring it inside the bundle otherwise. - electron: false, - 'hadron-ipc': false, // We don't currently support kerberos in our extension. @@ -60,7 +56,7 @@ module.exports = (env, argv) => { // own keytar dependency. Here we are telling it to use vscode's keytar. keytar: 'keytar', - '@electron/remote': '@electron/remote', + electron: 'electron', // MongoDB node driver externals: snappy: 'snappy', From 7f9b635dbcfbc730389b602b937a8503d8c98280 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 17:58:18 +0100 Subject: [PATCH 02/11] feat: use vscode window dialog --- .../extension-app-message-constants.ts | 22 +++-- src/views/webview-app/overview-page.tsx | 98 +++++++++++++------ src/views/webview-app/use-connection-form.ts | 28 ++---- src/views/webview-app/vscode-api.ts | 7 ++ src/views/webviewController.ts | 13 ++- 5 files changed, 105 insertions(+), 63 deletions(-) diff --git a/src/views/webview-app/extension-app-message-constants.ts b/src/views/webview-app/extension-app-message-constants.ts index 51a26ab51..3b938007f 100644 --- a/src/views/webview-app/extension-app-message-constants.ts +++ b/src/views/webview-app/extension-app-message-constants.ts @@ -1,6 +1,4 @@ import type { ConnectionOptions } from 'mongodb-data-service'; -import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components'; -import type { BaseWindow } from 'electron'; export enum CONNECTION_STATUS { LOADING = 'LOADING', // When the connection status has not yet been shared from the extension. @@ -21,7 +19,8 @@ export enum MESSAGE_TYPES { CANCEL_CONNECT = 'CANCEL_CONNECT', CONNECT_RESULT = 'CONNECT_RESULT', CONNECTION_FORM_OPENED = 'CONNECTION_FORM_OPENED', - ELECTRON_FILE_INPUT_BACKEND = 'ELECTRON_FILE_INPUT_BACKEND', + OPEN_FILE_CHOOSER = 'OPEN_FILE_CHOOSER', + OPEN_FILE_CHOOSER_RESULT = 'OPEN_FILE_CHOOSER_RESULT', CONNECTION_STATUS_MESSAGE = 'CONNECTION_STATUS_MESSAGE', OPEN_EDIT_CONNECTION = 'OPEN_EDIT_CONNECTION', EDIT_AND_CONNECT_CONNECTION = 'EDIT_AND_CONNECT_CONNECTION', @@ -69,6 +68,11 @@ export interface EditAndConnectConnection extends BasicWebviewMessage { }; } +export interface OpenFileChooser extends BasicWebviewMessage { + command: MESSAGE_TYPES.OPEN_FILE_CHOOSER; + requestId: string; +} + export interface ConnectMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.CONNECT; connectionInfo: { @@ -88,9 +92,10 @@ export interface ConnectResultsMessage extends BasicWebviewMessage { connectionId: string; } -export interface ElectronFileInputBackendMessage extends BasicWebviewMessage { - command: MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND; - dialog: ElectronShowFileDialogProvider; +export interface OpenFileChooserResultMessage extends BasicWebviewMessage { + command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT; + files: any; + requestId: string; } export interface GetConnectionStatusMessage extends BasicWebviewMessage { @@ -131,11 +136,12 @@ export type MESSAGE_FROM_WEBVIEW_TO_EXTENSION = | OpenConnectionStringInputMessage | OpenTrustedLinkMessage | RenameConnectionMessage - | EditAndConnectConnection; + | EditAndConnectConnection + | OpenFileChooser; export type MESSAGE_FROM_EXTENSION_TO_WEBVIEW = | ConnectResultsMessage | ConnectionStatusMessage | ThemeChangedMessage | OpenEditConnectionMessage - | ElectronFileInputBackendMessage; + | OpenFileChooserResultMessage; diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 3f01f83e9..8e3372b4f 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -4,9 +4,10 @@ import { css, resetGlobalCSS, spacing, - // FileInputBackendProvider, - // createElectronFileInputBackend, + FileInputBackendProvider, + createElectronFileInputBackend, } from '@mongodb-js/compass-components'; +import type { Uri } from 'vscode'; import OverviewHeader from './overview-header'; import ConnectionStatus from './connection-status'; @@ -15,6 +16,8 @@ import AtlasCta from './atlas-cta'; import ResourcesPanel from './resources-panel/panel'; import { ConnectionForm } from './connection-form'; import useConnectionForm from './use-connection-form'; +import type { MESSAGE_FROM_EXTENSION_TO_WEBVIEW } from './extension-app-message-constants'; +import { MESSAGE_TYPES } from './extension-app-message-constants'; const pageStyles = css({ width: '90%', @@ -41,7 +44,7 @@ const OverviewPage: React.FC = () => { handleCancelConnectClicked, handleSaveConnectionClicked, handleConnectClicked, - // dialog, + handleOpenFileChooser, } = useConnectionForm(); const handleResourcesPanelClose = useCallback( () => setShowResourcesPanel(false), @@ -58,11 +61,45 @@ const OverviewPage: React.FC = () => { resetGlobalCSS(); }, []); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const util = require('util'); - console.log('(globalThis as any).vscode----------------------'); - console.log(`${util.inspect((globalThis as any).vscode)}`); - console.log('----------------------'); + function handleOpenFileChooserResult(): Promise { + const requestId = handleOpenFileChooser(); + return new Promise((resolve) => { + const messageHandler = (event) => { + const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + if ( + message.command === MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT && + message.requestId === requestId + ) { + window.removeEventListener('message', messageHandler); + resolve(message.files); + } + }; + window.addEventListener('message', messageHandler); + }); + } + + const dialogProvider = { + getCurrentWindow(): void {}, + dialog: { + showSaveDialog(): Promise<{ canceled: boolean; filePath?: string }> { + return handleOpenFileChooserResult().then( + (file?: Uri) => { + return { canceled: false, filePath: file?.path }; + } + ); + }, + showOpenDialog(): Promise<{ canceled: boolean; filePaths: string[] }> { + return handleOpenFileChooserResult().then( + (files?: Uri[]) => { + return { + canceled: false, + filePaths: files ? files?.map((file) => file.path) : [], + }; + } + ); + }, + }, + }; return (
@@ -70,26 +107,31 @@ const OverviewPage: React.FC = () => { )} {isConnectionFormOpen && ( - // - { - void handleSaveConnectionClicked({ - id, - connectionOptions, - }); - handleConnectClicked({ - id, - connectionOptions, - }); - }} - onCancelConnectClicked={handleCancelConnectClicked} - onClose={closeConnectionForm} - open={isConnectionFormOpen} - connectionErrorMessage={connectionErrorMessage} - /> - // + + { + void handleSaveConnectionClicked({ + id, + connectionOptions, + }); + handleConnectClicked({ + id, + connectionOptions, + }); + }} + onCancelConnectClicked={handleCancelConnectClicked} + onClose={closeConnectionForm} + open={isConnectionFormOpen} + connectionErrorMessage={connectionErrorMessage} + /> + )} diff --git a/src/views/webview-app/use-connection-form.ts b/src/views/webview-app/use-connection-form.ts index 3f4c2d65c..a2e33fa5a 100644 --- a/src/views/webview-app/use-connection-form.ts +++ b/src/views/webview-app/use-connection-form.ts @@ -1,14 +1,13 @@ import { useEffect, useReducer } from 'react'; import { v4 as uuidv4 } from 'uuid'; import type { ConnectionOptions } from 'mongodb-data-service'; -import type { BaseWindow } from 'electron'; -import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components'; import { sendConnectToExtension, sendCancelConnectToExtension, sendFormOpenedToExtension, sendEditConnectionToExtension, + sendOpenFileChooserToExtension, } from './vscode-api'; import { MESSAGE_TYPES } from './extension-app-message-constants'; import type { MESSAGE_FROM_EXTENSION_TO_WEBVIEW } from './extension-app-message-constants'; @@ -36,7 +35,6 @@ type State = { isConnectionFormOpen: boolean; isEditingConnection: boolean; connectionErrorMessage: string; - dialog: ElectronShowFileDialogProvider | null; }; export function getDefaultConnectionFormState(): State { @@ -46,7 +44,6 @@ export function getDefaultConnectionFormState(): State { isConnectionFormOpen: false, isEditingConnection: false, connectionErrorMessage: '', - dialog: null, }; } @@ -74,10 +71,6 @@ type Action = } | { type: 'attempt-connect'; - } - | { - type: 'electron-file-input-backend'; - dialog: ElectronShowFileDialogProvider; }; function connectionFormReducer(state: State, action: Action): State { @@ -103,11 +96,6 @@ function connectionFormReducer(state: State, action: Action): State { connectionErrorMessage: action.connectionMessage, isConnectionFormOpen: !action.connectionSuccess, }; - case 'electron-file-input-backend': - return { - ...state, - dialog: action.dialog, - }; case 'open-edit-connection': return { ...state, @@ -137,7 +125,6 @@ export default function useConnectionForm() { isConnectionFormOpen, isEditingConnection, connectionErrorMessage, - dialog, }, dispatch, ] = useReducer(connectionFormReducer, { @@ -156,13 +143,6 @@ export default function useConnectionForm() { connectionSuccess: message.connectionSuccess, connectionMessage: message.connectionMessage, }); - } else if ( - message.command === MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND - ) { - dispatch({ - type: 'electron-file-input-backend', - dialog: message.dialog, - }); } }; window.addEventListener('message', handleConnectResultResponse); @@ -198,7 +178,6 @@ export default function useConnectionForm() { isConnecting, initialConnectionInfo, connectionErrorMessage, - dialog, openConnectionForm: () => { dispatch({ type: 'open-connection-form', @@ -210,6 +189,11 @@ export default function useConnectionForm() { type: 'close-connection-form', }); }, + handleOpenFileChooser: () => { + const requestId = uuidv4(); + sendOpenFileChooserToExtension(requestId); + return requestId; + }, handleCancelConnectClicked: () => { sendCancelConnectToExtension(); }, diff --git a/src/views/webview-app/vscode-api.ts b/src/views/webview-app/vscode-api.ts index 90585bf9f..6d44994c2 100644 --- a/src/views/webview-app/vscode-api.ts +++ b/src/views/webview-app/vscode-api.ts @@ -29,6 +29,13 @@ export const sendConnectToExtension = ( }); }; +export const sendOpenFileChooserToExtension = (requestId: string) => { + vscode.postMessage({ + command: MESSAGE_TYPES.OPEN_FILE_CHOOSER, + requestId, + }); +}; + export const sendCancelConnectToExtension = () => { vscode.postMessage({ command: MESSAGE_TYPES.CANCEL_CONNECT, diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index 4c347b2fc..013b748fe 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -2,7 +2,6 @@ import * as vscode from 'vscode'; import path from 'path'; import crypto from 'crypto'; import type { ConnectionOptions } from 'mongodb-data-service'; -import { dialog } from 'electron'; import type ConnectionController from '../connectionController'; import { ConnectionTypes } from '../connectionController'; @@ -181,6 +180,14 @@ export default class WebviewController { }); this._telemetryService.track(TelemetryEventTypes.CONNECTION_EDITED); return; + case MESSAGE_TYPES.OPEN_FILE_CHOOSER: + const files = await vscode.window.showOpenDialog(); + void panel.webview.postMessage({ + command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT, + files, + requestId: message.requestId, + }); + return; case MESSAGE_TYPES.CREATE_NEW_PLAYGROUND: void vscode.commands.executeCommand( EXTENSION_COMMANDS.MDB_CREATE_PLAYGROUND_FROM_OVERVIEW_PAGE @@ -190,10 +197,6 @@ export default class WebviewController { // If the connection string input is open we want to close it // when the user opens the form. this._connectionController.closeConnectionStringInput(); - void panel.webview.postMessage({ - command: MESSAGE_TYPES.ELECTRON_FILE_INPUT_BACKEND, - dialog, - }); return; case MESSAGE_TYPES.GET_CONNECTION_STATUS: void panel.webview.postMessage({ From f684de262ae8ec386e1d009e4f90bac63b517833 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 18:13:49 +0100 Subject: [PATCH 03/11] docs: add comment --- src/views/webview-app/overview-page.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 8e3372b4f..edaaa4e7a 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -78,6 +78,11 @@ const OverviewPage: React.FC = () => { }); } + // Electron 32.0 removed support for the `path` property of the Web File object + // https://github.com/electron/electron/blob/83d704009687956fb4b69cb13ab03664d7950118/docs/breaking-changes.md%23removed-filepath + // To work around this, we use a custom dialog provider that returns the file path from the electron file input backend. + // The overview page uses webview APIs to send a message to the extension to open the file chooser dialog, + // and listens for the response to get the file path. const dialogProvider = { getCurrentWindow(): void {}, dialog: { From 6b392b09909d399ef68a1352d4163a2e79b4c8b4 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 18:18:48 +0100 Subject: [PATCH 04/11] docs: more context --- src/views/webview-app/overview-page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index edaaa4e7a..9d5ad3fa5 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -78,8 +78,9 @@ const OverviewPage: React.FC = () => { }); } - // Electron 32.0 removed support for the `path` property of the Web File object + // Electron 32.0 removed support for the `path` property of the Web File object in favor of the webUtils.getPathForFile method. // https://github.com/electron/electron/blob/83d704009687956fb4b69cb13ab03664d7950118/docs/breaking-changes.md%23removed-filepath + // We can not import `dialog` and `webUtils` from 'electron' in the sandboxed webview. // To work around this, we use a custom dialog provider that returns the file path from the electron file input backend. // The overview page uses webview APIs to send a message to the extension to open the file chooser dialog, // and listens for the response to get the file path. From 270a91a00f20bc9250e30a1b7dbf188a450921a4 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 18:24:35 +0100 Subject: [PATCH 05/11] docs: update comment --- src/views/webview-app/overview-page.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 9d5ad3fa5..074a416ed 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -81,9 +81,9 @@ const OverviewPage: React.FC = () => { // Electron 32.0 removed support for the `path` property of the Web File object in favor of the webUtils.getPathForFile method. // https://github.com/electron/electron/blob/83d704009687956fb4b69cb13ab03664d7950118/docs/breaking-changes.md%23removed-filepath // We can not import `dialog` and `webUtils` from 'electron' in the sandboxed webview. - // To work around this, we use a custom dialog provider that returns the file path from the electron file input backend. - // The overview page uses webview APIs to send a message to the extension to open the file chooser dialog, - // and listens for the response to get the file path. + // To work around this, we use a custom dialog provider that uses webview APIs + // to send a message to the extension process to open the electron file dialog + // and listen for the response to get the file path and send them to the electron file input backend. const dialogProvider = { getCurrentWindow(): void {}, dialog: { From ad6dc3fbeedc9c72d5beb5fdb5af713d82b31336 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 19:00:11 +0100 Subject: [PATCH 06/11] chore: bump connection dependencies --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d62261c3..ed0a02c75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,9 @@ "@babel/core": "^7.25.8", "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", - "@mongodb-js/compass-components": "^1.30.1", + "@mongodb-js/compass-components": "^1.32.1", "@mongodb-js/connection-form": "^1.45.1", - "@mongodb-js/connection-info": "^0.9.1", + "@mongodb-js/connection-info": "^0.9.5", "@mongodb-js/mongodb-constants": "^0.10.3", "@mongosh/browser-runtime-electron": "^2.3.3", "@mongosh/i18n": "^2.3.3", diff --git a/package.json b/package.json index 12abcac4c..df6a0b8cc 100644 --- a/package.json +++ b/package.json @@ -1177,9 +1177,9 @@ "@babel/core": "^7.25.8", "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", - "@mongodb-js/compass-components": "^1.30.1", + "@mongodb-js/compass-components": "^1.32.1", "@mongodb-js/connection-form": "^1.45.1", - "@mongodb-js/connection-info": "^0.9.1", + "@mongodb-js/connection-info": "^0.9.5", "@mongodb-js/mongodb-constants": "^0.10.3", "@mongosh/browser-runtime-electron": "^2.3.3", "@mongosh/i18n": "^2.3.3", From 5725f880bd4e709275d12efba2a43bed8d68a933 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 19:06:26 +0100 Subject: [PATCH 07/11] refactor: add type --- src/views/webview-app/extension-app-message-constants.ts | 3 ++- src/views/webview-app/overview-page.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/views/webview-app/extension-app-message-constants.ts b/src/views/webview-app/extension-app-message-constants.ts index 3b938007f..051c38c8d 100644 --- a/src/views/webview-app/extension-app-message-constants.ts +++ b/src/views/webview-app/extension-app-message-constants.ts @@ -1,4 +1,5 @@ import type { ConnectionOptions } from 'mongodb-data-service'; +import type { Uri } from 'vscode'; export enum CONNECTION_STATUS { LOADING = 'LOADING', // When the connection status has not yet been shared from the extension. @@ -94,7 +95,7 @@ export interface ConnectResultsMessage extends BasicWebviewMessage { export interface OpenFileChooserResultMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT; - files: any; + files: Uri | Uri[] | undefined; requestId: string; } diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 074a416ed..b5265caa9 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -71,7 +71,7 @@ const OverviewPage: React.FC = () => { message.requestId === requestId ) { window.removeEventListener('message', messageHandler); - resolve(message.files); + resolve(message.files as T); } }; window.addEventListener('message', messageHandler); From 3fa585a7d2b4ca973db9cc88dd050618b78926d8 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 5 Dec 2024 19:18:45 +0100 Subject: [PATCH 08/11] refractor: revert webpack config --- webpack.config.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webpack.config.js b/webpack.config.js index fe198b20b..fd928938f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -37,6 +37,10 @@ module.exports = (env, argv) => { // This alias can be removed once `mongodb-data-service` will not include `mongodb-connection-model` anymore. 'ampersand-sync': false, + // Removes `electron`: is an optional dependency of `oidc-plugin`, but also installed as dev-dep, + // webpack would bring it inside the bundle otherwise. + electron: false, + 'hadron-ipc': false, // We don't currently support kerberos in our extension. @@ -56,7 +60,7 @@ module.exports = (env, argv) => { // own keytar dependency. Here we are telling it to use vscode's keytar. keytar: 'keytar', - electron: 'electron', + '@electron/remote': '@electron/remote', // MongoDB node driver externals: snappy: 'snappy', From 4e7bf3eb685f24b06443c09c2df21b181606f6ff Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 6 Dec 2024 19:58:07 +0100 Subject: [PATCH 09/11] feat: address pr comments --- .../views/webview-app/overview-page.test.tsx | 4 +- .../suite/views/webviewController.test.ts | 2 +- .../extension-app-message-constants.ts | 22 ++++--- src/views/webview-app/overview-page.tsx | 50 +++++++------- src/views/webview-app/use-connection-form.ts | 21 ++++-- .../webview-app/use-connection-status.ts | 4 +- .../use-detect-vscode-dark-mode.tsx | 4 +- src/views/webview-app/vscode-api.ts | 13 ++-- src/views/webviewController.ts | 66 ++++++++++++++++--- 9 files changed, 130 insertions(+), 56 deletions(-) diff --git a/src/test/suite/views/webview-app/overview-page.test.tsx b/src/test/suite/views/webview-app/overview-page.test.tsx index 459e2d75b..650264a57 100644 --- a/src/test/suite/views/webview-app/overview-page.test.tsx +++ b/src/test/suite/views/webview-app/overview-page.test.tsx @@ -156,7 +156,7 @@ describe('OverviewPage test suite', function () { .getCalls() .filter( (call) => - call.args[0].command === MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION + call.args[0].command === MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT ); }; expect(getConnectMessages()).to.have.length(0); @@ -165,7 +165,7 @@ describe('OverviewPage test suite', function () { expect(connectMessages).to.have.length(1); expect(connectMessages[0].args[0]).to.deep.equal({ - command: 'EDIT_AND_CONNECT_CONNECTION', + command: 'EDIT_CONNECTION_AND_CONNECT', connectionInfo: { id: 'pear', connectionOptions: { diff --git a/src/test/suite/views/webviewController.test.ts b/src/test/suite/views/webviewController.test.ts index 675a484bf..e629c2d12 100644 --- a/src/test/suite/views/webviewController.test.ts +++ b/src/test/suite/views/webviewController.test.ts @@ -538,7 +538,7 @@ suite('Webview Test Suite', () => { // Mock a connection status request call. messageReceived({ - command: MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION, + command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT, connectionInfo: { id: 'pineapple', connectionOptions: { diff --git a/src/views/webview-app/extension-app-message-constants.ts b/src/views/webview-app/extension-app-message-constants.ts index 051c38c8d..d1a1c35ad 100644 --- a/src/views/webview-app/extension-app-message-constants.ts +++ b/src/views/webview-app/extension-app-message-constants.ts @@ -1,5 +1,6 @@ import type { ConnectionOptions } from 'mongodb-data-service'; import type { Uri } from 'vscode'; +import type { FileChooserOptions } from './use-connection-form'; export enum CONNECTION_STATUS { LOADING = 'LOADING', // When the connection status has not yet been shared from the extension. @@ -24,7 +25,7 @@ export enum MESSAGE_TYPES { OPEN_FILE_CHOOSER_RESULT = 'OPEN_FILE_CHOOSER_RESULT', CONNECTION_STATUS_MESSAGE = 'CONNECTION_STATUS_MESSAGE', OPEN_EDIT_CONNECTION = 'OPEN_EDIT_CONNECTION', - EDIT_AND_CONNECT_CONNECTION = 'EDIT_AND_CONNECT_CONNECTION', + EDIT_CONNECTION_AND_CONNECT = 'EDIT_CONNECTION_AND_CONNECT', EXTENSION_LINK_CLICKED = 'EXTENSION_LINK_CLICKED', CREATE_NEW_PLAYGROUND = 'CREATE_NEW_PLAYGROUND', GET_CONNECTION_STATUS = 'GET_CONNECTION_STATUS', @@ -61,16 +62,17 @@ export interface OpenEditConnectionMessage extends BasicWebviewMessage { }; } -export interface EditAndConnectConnection extends BasicWebviewMessage { - command: MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION; +export interface EditConnectionAndConnectMessage extends BasicWebviewMessage { + command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT; connectionInfo: { id: string; connectionOptions: ConnectionOptions; }; } -export interface OpenFileChooser extends BasicWebviewMessage { +export interface OpenFileChooserMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.OPEN_FILE_CHOOSER; + fileChooserOptions: FileChooserOptions; requestId: string; } @@ -95,7 +97,9 @@ export interface ConnectResultsMessage extends BasicWebviewMessage { export interface OpenFileChooserResultMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT; - files: Uri | Uri[] | undefined; + fileChooserResult: + | { canceled: false; filePaths?: Uri[] } + | { canceled: false; filePath?: Uri }; requestId: string; } @@ -127,7 +131,7 @@ export interface ThemeChangedMessage extends BasicWebviewMessage { darkMode: boolean; } -export type MESSAGE_FROM_WEBVIEW_TO_EXTENSION = +export type MessageFromWebviewToExtension = | ConnectMessage | CancelConnectMessage | ConnectionFormOpenedMessage @@ -137,10 +141,10 @@ export type MESSAGE_FROM_WEBVIEW_TO_EXTENSION = | OpenConnectionStringInputMessage | OpenTrustedLinkMessage | RenameConnectionMessage - | EditAndConnectConnection - | OpenFileChooser; + | EditConnectionAndConnectMessage + | OpenFileChooserMessage; -export type MESSAGE_FROM_EXTENSION_TO_WEBVIEW = +export type MessageFromExtensionToWebview = | ConnectResultsMessage | ConnectionStatusMessage | ThemeChangedMessage diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index b5265caa9..9cf11645a 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -6,8 +6,8 @@ import { spacing, FileInputBackendProvider, createElectronFileInputBackend, + type ElectronFileDialogOptions, } from '@mongodb-js/compass-components'; -import type { Uri } from 'vscode'; import OverviewHeader from './overview-header'; import ConnectionStatus from './connection-status'; @@ -15,8 +15,11 @@ import ConnectHelper from './connect-helper'; import AtlasCta from './atlas-cta'; import ResourcesPanel from './resources-panel/panel'; import { ConnectionForm } from './connection-form'; -import useConnectionForm from './use-connection-form'; -import type { MESSAGE_FROM_EXTENSION_TO_WEBVIEW } from './extension-app-message-constants'; +import useConnectionForm, { + FILE_CHOOSER_MODE, + type FileChooserOptions, +} from './use-connection-form'; +import type { MessageFromExtensionToWebview } from './extension-app-message-constants'; import { MESSAGE_TYPES } from './extension-app-message-constants'; const pageStyles = css({ @@ -61,17 +64,19 @@ const OverviewPage: React.FC = () => { resetGlobalCSS(); }, []); - function handleOpenFileChooserResult(): Promise { - const requestId = handleOpenFileChooser(); + function handleOpenFileChooserResult( + options: FileChooserOptions + ): Promise { + const requestId = handleOpenFileChooser(options); return new Promise((resolve) => { const messageHandler = (event) => { - const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + const message: MessageFromExtensionToWebview = event.data; if ( message.command === MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT && message.requestId === requestId ) { window.removeEventListener('message', messageHandler); - resolve(message.files as T); + resolve(message.fileChooserResult as T); } }; window.addEventListener('message', messageHandler); @@ -87,22 +92,23 @@ const OverviewPage: React.FC = () => { const dialogProvider = { getCurrentWindow(): void {}, dialog: { - showSaveDialog(): Promise<{ canceled: boolean; filePath?: string }> { - return handleOpenFileChooserResult().then( - (file?: Uri) => { - return { canceled: false, filePath: file?.path }; - } - ); + async showSaveDialog( + window: void, + electronFileDialogOptions: Partial + ): Promise<{ canceled: boolean; filePath?: string }> { + return handleOpenFileChooserResult({ + electronFileDialogOptions, + mode: FILE_CHOOSER_MODE.SAVE, + }); }, - showOpenDialog(): Promise<{ canceled: boolean; filePaths: string[] }> { - return handleOpenFileChooserResult().then( - (files?: Uri[]) => { - return { - canceled: false, - filePaths: files ? files?.map((file) => file.path) : [], - }; - } - ); + async showOpenDialog( + window: void, + electronFileDialogOptions: Partial + ): Promise<{ canceled: boolean; filePaths: string[] }> { + return handleOpenFileChooserResult({ + electronFileDialogOptions, + mode: FILE_CHOOSER_MODE.OPEN, + }); }, }, }; diff --git a/src/views/webview-app/use-connection-form.ts b/src/views/webview-app/use-connection-form.ts index a2e33fa5a..26972cbbf 100644 --- a/src/views/webview-app/use-connection-form.ts +++ b/src/views/webview-app/use-connection-form.ts @@ -10,7 +10,18 @@ import { sendOpenFileChooserToExtension, } from './vscode-api'; import { MESSAGE_TYPES } from './extension-app-message-constants'; -import type { MESSAGE_FROM_EXTENSION_TO_WEBVIEW } from './extension-app-message-constants'; +import type { MessageFromExtensionToWebview } from './extension-app-message-constants'; +import type { ElectronFileDialogOptions } from '@mongodb-js/compass-components'; + +export enum FILE_CHOOSER_MODE { + OPEN = 'open', + SAVE = 'save', +} + +export type FileChooserOptions = { + electronFileDialogOptions?: Partial; + mode: FILE_CHOOSER_MODE; +}; type ConnectionInfo = { id: string; @@ -133,7 +144,7 @@ export default function useConnectionForm() { useEffect(() => { const handleConnectResultResponse = (event) => { - const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + const message: MessageFromExtensionToWebview = event.data; if ( message.command === MESSAGE_TYPES.CONNECT_RESULT && message.connectionId === initialConnectionInfo.id @@ -153,7 +164,7 @@ export default function useConnectionForm() { useEffect(() => { const handleConnectResultResponse = (event) => { - const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + const message: MessageFromExtensionToWebview = event.data; if (message.command === MESSAGE_TYPES.OPEN_EDIT_CONNECTION) { dispatch({ type: 'open-edit-connection', @@ -189,9 +200,9 @@ export default function useConnectionForm() { type: 'close-connection-form', }); }, - handleOpenFileChooser: () => { + handleOpenFileChooser: (options: FileChooserOptions) => { const requestId = uuidv4(); - sendOpenFileChooserToExtension(requestId); + sendOpenFileChooserToExtension(options, requestId); return requestId; }, handleCancelConnectClicked: () => { diff --git a/src/views/webview-app/use-connection-status.ts b/src/views/webview-app/use-connection-status.ts index c570661bc..46d5b1739 100644 --- a/src/views/webview-app/use-connection-status.ts +++ b/src/views/webview-app/use-connection-status.ts @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { CONNECTION_STATUS, - type MESSAGE_FROM_EXTENSION_TO_WEBVIEW, + type MessageFromExtensionToWebview, MESSAGE_TYPES, } from './extension-app-message-constants'; import vscode from './vscode-api'; @@ -15,7 +15,7 @@ const useConnectionStatus = () => { const [connectionName, setConnectionName] = useState(''); useEffect(() => { const handleConnectionStatusResponse = (event) => { - const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + const message: MessageFromExtensionToWebview = event.data; if (message.command === MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE) { setConnectionStatus(message.connectionStatus); setConnectionName(message.activeConnectionName); diff --git a/src/views/webview-app/use-detect-vscode-dark-mode.tsx b/src/views/webview-app/use-detect-vscode-dark-mode.tsx index 1e62eedfc..e3d317787 100644 --- a/src/views/webview-app/use-detect-vscode-dark-mode.tsx +++ b/src/views/webview-app/use-detect-vscode-dark-mode.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { - type MESSAGE_FROM_EXTENSION_TO_WEBVIEW, + type MessageFromExtensionToWebview, MESSAGE_TYPES, } from './extension-app-message-constants'; @@ -11,7 +11,7 @@ export const useDetectVsCodeDarkMode = () => { ); useEffect(() => { const onThemeChanged = (event) => { - const message: MESSAGE_FROM_EXTENSION_TO_WEBVIEW = event.data; + const message: MessageFromExtensionToWebview = event.data; if (message.command === MESSAGE_TYPES.THEME_CHANGED) { setDarkModeDetected(message.darkMode); } diff --git a/src/views/webview-app/vscode-api.ts b/src/views/webview-app/vscode-api.ts index 6d44994c2..f4bf40e4d 100644 --- a/src/views/webview-app/vscode-api.ts +++ b/src/views/webview-app/vscode-api.ts @@ -1,11 +1,12 @@ import { MESSAGE_TYPES, - type MESSAGE_FROM_WEBVIEW_TO_EXTENSION, + type MessageFromWebviewToExtension, type ConnectMessage, } from './extension-app-message-constants'; +import type { FileChooserOptions } from './use-connection-form'; interface VSCodeApi { - postMessage: (message: MESSAGE_FROM_WEBVIEW_TO_EXTENSION) => void; + postMessage: (message: MessageFromWebviewToExtension) => void; } declare const acquireVsCodeApi: () => VSCodeApi; @@ -15,7 +16,7 @@ export const sendEditConnectionToExtension = ( connectionInfo: ConnectMessage['connectionInfo'] ) => { vscode.postMessage({ - command: MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION, + command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT, connectionInfo, }); }; @@ -29,9 +30,13 @@ export const sendConnectToExtension = ( }); }; -export const sendOpenFileChooserToExtension = (requestId: string) => { +export const sendOpenFileChooserToExtension = ( + fileChooserOptions: FileChooserOptions, + requestId: string +) => { vscode.postMessage({ command: MESSAGE_TYPES.OPEN_FILE_CHOOSER, + fileChooserOptions, requestId, }); }; diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index 013b748fe..cb6e0bf2b 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -7,7 +7,7 @@ import type ConnectionController from '../connectionController'; import { ConnectionTypes } from '../connectionController'; import { createLogger } from '../logging'; import EXTENSION_COMMANDS from '../commands'; -import type { MESSAGE_FROM_WEBVIEW_TO_EXTENSION } from './webview-app/extension-app-message-constants'; +import type { MessageFromWebviewToExtension } from './webview-app/extension-app-message-constants'; import { MESSAGE_TYPES, VSCODE_EXTENSION_OIDC_DEVICE_AUTH_ID, @@ -18,6 +18,7 @@ import type { StorageController } from '../storage'; import type TelemetryService from '../telemetry/telemetryService'; import { getFeatureFlagsScript } from '../featureFlags'; import { TelemetryEventTypes } from '../telemetry/telemetryService'; +import type { FileChooserOptions } from './webview-app/use-connection-form'; const log = createLogger('webview controller'); @@ -105,6 +106,54 @@ export default class WebviewController { this._themeChangedSubscription?.dispose(); } + handleWebviewOpenFileChooserAttempt = async ({ + panel, + fileChooserOptions, + requestId, + }: { + panel: vscode.WebviewPanel; + fileChooserOptions: FileChooserOptions; + requestId: string; + }): Promise => { + let files; + + try { + files = await vscode.window[ + fileChooserOptions.mode === 'open' ? 'showOpenDialog' : 'showSaveDialog' + ]({ + defaultUri: vscode.Uri.from({ + path: fileChooserOptions.electronFileDialogOptions?.defaultPath, + scheme: 'file', + }), + [`${fileChooserOptions.mode}Label`]: + fileChooserOptions.electronFileDialogOptions?.buttonLabel, + filters: fileChooserOptions.electronFileDialogOptions?.filters?.reduce( + (acc, filter) => { + acc[filter.name] = filter.extensions; + return acc; + }, + {} + ), + title: fileChooserOptions.electronFileDialogOptions?.title, + }); + } catch (error) { + void vscode.window.showErrorMessage( + `Unable to open file chooser dialog: ${error}` + ); + } + + void panel.webview.postMessage({ + command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT, + fileChooserResult: { + canceled: false, + ...(fileChooserOptions.mode === 'open' + ? { filePaths: files ? files?.map((file) => file.path) : [] } + : { filePath: files?.path }), + }, + requestId, + }); + }; + handleWebviewConnectAttempt = async ({ panel, connection, @@ -159,7 +208,7 @@ export default class WebviewController { // eslint-disable-next-line complexity handleWebviewMessage = async ( - message: MESSAGE_FROM_WEBVIEW_TO_EXTENSION, + message: MessageFromWebviewToExtension, panel: vscode.WebviewPanel ): Promise => { switch (message.command) { @@ -172,7 +221,7 @@ export default class WebviewController { case MESSAGE_TYPES.CANCEL_CONNECT: this._connectionController.cancelConnectionAttempt(); return; - case MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION: + case MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT: await this.handleWebviewConnectAttempt({ panel, connection: message.connectionInfo, @@ -181,10 +230,9 @@ export default class WebviewController { this._telemetryService.track(TelemetryEventTypes.CONNECTION_EDITED); return; case MESSAGE_TYPES.OPEN_FILE_CHOOSER: - const files = await vscode.window.showOpenDialog(); - void panel.webview.postMessage({ - command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT, - files, + await this.handleWebviewOpenFileChooserAttempt({ + panel, + fileChooserOptions: message.fileChooserOptions, requestId: message.requestId, }); return; @@ -239,7 +287,7 @@ export default class WebviewController { }; onReceivedWebviewMessage = async ( - message: MESSAGE_FROM_WEBVIEW_TO_EXTENSION, + message: MessageFromWebviewToExtension, panel: vscode.WebviewPanel ): Promise => { // Ensure handling message from the webview can't crash the extension. @@ -342,7 +390,7 @@ export default class WebviewController { // Handle messages from the webview. panel.webview.onDidReceiveMessage( - (message: MESSAGE_FROM_WEBVIEW_TO_EXTENSION) => + (message: MessageFromWebviewToExtension) => this.onReceivedWebviewMessage(message, panel), undefined, context.subscriptions From 34fb8a2c00e54d8b1b5046995210281c6117155d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 6 Dec 2024 20:14:52 +0100 Subject: [PATCH 10/11] fix: use proper type --- src/views/webview-app/extension-app-message-constants.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/views/webview-app/extension-app-message-constants.ts b/src/views/webview-app/extension-app-message-constants.ts index d1a1c35ad..80a197347 100644 --- a/src/views/webview-app/extension-app-message-constants.ts +++ b/src/views/webview-app/extension-app-message-constants.ts @@ -1,5 +1,4 @@ import type { ConnectionOptions } from 'mongodb-data-service'; -import type { Uri } from 'vscode'; import type { FileChooserOptions } from './use-connection-form'; export enum CONNECTION_STATUS { @@ -95,11 +94,13 @@ export interface ConnectResultsMessage extends BasicWebviewMessage { connectionId: string; } +export type FileChooserResult = + | { canceled: false; filePaths: string[] } + | { canceled: false; filePath?: string }; + export interface OpenFileChooserResultMessage extends BasicWebviewMessage { command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT; - fileChooserResult: - | { canceled: false; filePaths?: Uri[] } - | { canceled: false; filePath?: Uri }; + fileChooserResult: FileChooserResult; requestId: string; } From 36a86bb6ac526167f93bd23400a7a3a5de6f7035 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 9 Dec 2024 14:46:33 +0100 Subject: [PATCH 11/11] fix: use fsPath --- .../suite/views/webviewController.test.ts | 10 +-- src/views/webview-app/connection-form.tsx | 2 +- src/views/webview-app/overview-page.tsx | 23 ++++-- src/views/webview-app/use-connection-form.ts | 18 ++--- .../webview-app/use-connection-status.ts | 7 +- .../use-detect-vscode-dark-mode.tsx | 4 +- src/views/webview-app/vscode-api.ts | 23 +++--- src/views/webviewController.ts | 75 ++++++++++++------- 8 files changed, 96 insertions(+), 66 deletions(-) diff --git a/src/test/suite/views/webviewController.test.ts b/src/test/suite/views/webviewController.test.ts index e629c2d12..f0cb964dd 100644 --- a/src/test/suite/views/webviewController.test.ts +++ b/src/test/suite/views/webviewController.test.ts @@ -124,7 +124,7 @@ suite('Webview Test Suite', () => { const extensionPath = mdbTestExtension.extensionContextStub.extensionPath; const htmlString = getWebviewContent({ extensionPath, - telemetryUserId: 'MOCK_ANONYMOU_ID', + telemetryUserId: 'MOCK_ANONYMOUS_ID', webview: { asWebviewUri: (jsUri) => { return jsUri; @@ -133,7 +133,7 @@ suite('Webview Test Suite', () => { }); expect(htmlString).to.include( - ">window['VSCODE_EXTENSION_SEGMENT_ANONYMOUS_ID'] = 'MOCK_ANONYMOU_ID';" + ">window['VSCODE_EXTENSION_SEGMENT_ANONYMOUS_ID'] = 'MOCK_ANONYMOUS_ID';" ); }); @@ -143,7 +143,7 @@ suite('Webview Test Suite', () => { extensionPath, telemetryUserId: 'test', webview: { - asWebviewUri: (jsUri) => { + asWebviewUri: (jsUri: vscode.Uri) => { return jsUri; }, } as unknown as vscode.Webview, @@ -177,7 +177,7 @@ suite('Webview Test Suite', () => { extensionPath, telemetryUserId: 'test', webview: { - asWebviewUri: (jsUri) => { + asWebviewUri: (jsUri: vscode.Uri) => { return jsUri; }, } as unknown as vscode.Webview, @@ -368,7 +368,7 @@ suite('Webview Test Suite', () => { onDidReceiveMessage: (callback): void => { messageReceived = callback; }, - asWebviewUri: () => '', + asWebviewUri: (): string => '', }; const fakeVSCodeExecuteCommand = sandbox .stub(vscode.commands, 'executeCommand') diff --git a/src/views/webview-app/connection-form.tsx b/src/views/webview-app/connection-form.tsx index 638e1deb8..111979820 100644 --- a/src/views/webview-app/connection-form.tsx +++ b/src/views/webview-app/connection-form.tsx @@ -67,7 +67,7 @@ const ConnectionForm: React.FunctionComponent< // Warning: This property may be removed in future // modal releases. contentClassName={modalContentStyles} - setOpen={() => onClose()} + setOpen={(): void => onClose()} open={open} size="large" > diff --git a/src/views/webview-app/overview-page.tsx b/src/views/webview-app/overview-page.tsx index 9cf11645a..ea5bfe387 100644 --- a/src/views/webview-app/overview-page.tsx +++ b/src/views/webview-app/overview-page.tsx @@ -1,4 +1,5 @@ import React, { useCallback, useLayoutEffect, useState } from 'react'; +import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components'; import { HorizontalRule, css, @@ -8,6 +9,7 @@ import { createElectronFileInputBackend, type ElectronFileDialogOptions, } from '@mongodb-js/compass-components'; +import type { ConnectionOptions } from 'mongodb-data-service'; import OverviewHeader from './overview-header'; import ConnectionStatus from './connection-status'; @@ -69,8 +71,10 @@ const OverviewPage: React.FC = () => { ): Promise { const requestId = handleOpenFileChooser(options); return new Promise((resolve) => { - const messageHandler = (event) => { - const message: MessageFromExtensionToWebview = event.data; + const messageHandler = ( + event: MessageEvent + ): void => { + const message = event.data; if ( message.command === MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT && message.requestId === requestId @@ -89,7 +93,7 @@ const OverviewPage: React.FC = () => { // To work around this, we use a custom dialog provider that uses webview APIs // to send a message to the extension process to open the electron file dialog // and listen for the response to get the file path and send them to the electron file input backend. - const dialogProvider = { + const dialogProvider: ElectronShowFileDialogProvider = { getCurrentWindow(): void {}, dialog: { async showSaveDialog( @@ -128,11 +132,14 @@ const OverviewPage: React.FC = () => { { - void handleSaveConnectionClicked({ - id, - connectionOptions, - }); + onSaveAndConnectClicked={({ + id, + connectionOptions, + }: { + id: string; + connectionOptions: ConnectionOptions; + }): void => { + void handleSaveConnectionClicked(); handleConnectClicked({ id, connectionOptions, diff --git a/src/views/webview-app/use-connection-form.ts b/src/views/webview-app/use-connection-form.ts index 26972cbbf..e21f2723d 100644 --- a/src/views/webview-app/use-connection-form.ts +++ b/src/views/webview-app/use-connection-form.ts @@ -179,7 +179,7 @@ export default function useConnectionForm() { } }; window.addEventListener('message', handleConnectResultResponse); - return () => { + return (): void => { window.removeEventListener('message', handleConnectResultResponse); }; }, []); @@ -189,38 +189,34 @@ export default function useConnectionForm() { isConnecting, initialConnectionInfo, connectionErrorMessage, - openConnectionForm: () => { + openConnectionForm: (): void => { dispatch({ type: 'open-connection-form', }); sendFormOpenedToExtension(); }, - closeConnectionForm: () => { + closeConnectionForm: (): void => { dispatch({ type: 'close-connection-form', }); }, - handleOpenFileChooser: (options: FileChooserOptions) => { + handleOpenFileChooser: (options: FileChooserOptions): string => { const requestId = uuidv4(); sendOpenFileChooserToExtension(options, requestId); return requestId; }, - handleCancelConnectClicked: () => { + handleCancelConnectClicked: (): void => { sendCancelConnectToExtension(); }, // eslint-disable-next-line @typescript-eslint/no-unused-vars - handleSaveConnectionClicked: (connectionAttempt: { - id: string; - connectionOptions: ConnectionOptions; - }) => { + handleSaveConnectionClicked: (): Promise => { // no-op, this cannot be called as don't set the `showFavoriteActions` setting. - return Promise.resolve(); }, handleConnectClicked: (connectionAttempt: { id: string; connectionOptions: ConnectionOptions; - }) => { + }): void => { dispatch({ type: 'attempt-connect', }); diff --git a/src/views/webview-app/use-connection-status.ts b/src/views/webview-app/use-connection-status.ts index 46d5b1739..7c5944e2d 100644 --- a/src/views/webview-app/use-connection-status.ts +++ b/src/views/webview-app/use-connection-status.ts @@ -8,7 +8,10 @@ import vscode from './vscode-api'; const CONNECTION_STATUS_POLLING_FREQ_MS = 1000; -const useConnectionStatus = () => { +const useConnectionStatus = (): { + connectionStatus: CONNECTION_STATUS; + connectionName: string; +} => { const [connectionStatus, setConnectionStatus] = useState( CONNECTION_STATUS.LOADING ); @@ -23,7 +26,7 @@ const useConnectionStatus = () => { }; window.addEventListener('message', handleConnectionStatusResponse); - const requestConnectionStatus = () => + const requestConnectionStatus = (): void => vscode.postMessage({ command: MESSAGE_TYPES.GET_CONNECTION_STATUS, }); diff --git a/src/views/webview-app/use-detect-vscode-dark-mode.tsx b/src/views/webview-app/use-detect-vscode-dark-mode.tsx index e3d317787..640c231aa 100644 --- a/src/views/webview-app/use-detect-vscode-dark-mode.tsx +++ b/src/views/webview-app/use-detect-vscode-dark-mode.tsx @@ -4,7 +4,7 @@ import { MESSAGE_TYPES, } from './extension-app-message-constants'; -export const useDetectVsCodeDarkMode = () => { +export const useDetectVsCodeDarkMode = (): boolean => { const [darkModeDetected, setDarkModeDetected] = useState( globalThis.document.body.classList.contains('vscode-dark') || globalThis.document.body.classList.contains('vscode-high-contrast') @@ -17,7 +17,7 @@ export const useDetectVsCodeDarkMode = () => { } }; window.addEventListener('message', onThemeChanged); - return () => window.removeEventListener('message', onThemeChanged); + return (): void => window.removeEventListener('message', onThemeChanged); }, []); return darkModeDetected; diff --git a/src/views/webview-app/vscode-api.ts b/src/views/webview-app/vscode-api.ts index f4bf40e4d..29bb13102 100644 --- a/src/views/webview-app/vscode-api.ts +++ b/src/views/webview-app/vscode-api.ts @@ -14,7 +14,7 @@ const vscode = acquireVsCodeApi(); export const sendEditConnectionToExtension = ( connectionInfo: ConnectMessage['connectionInfo'] -) => { +): void => { vscode.postMessage({ command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT, connectionInfo, @@ -23,7 +23,7 @@ export const sendEditConnectionToExtension = ( export const sendConnectToExtension = ( connectionInfo: ConnectMessage['connectionInfo'] -) => { +): void => { vscode.postMessage({ command: MESSAGE_TYPES.CONNECT, connectionInfo, @@ -33,7 +33,7 @@ export const sendConnectToExtension = ( export const sendOpenFileChooserToExtension = ( fileChooserOptions: FileChooserOptions, requestId: string -) => { +): void => { vscode.postMessage({ command: MESSAGE_TYPES.OPEN_FILE_CHOOSER, fileChooserOptions, @@ -41,7 +41,7 @@ export const sendOpenFileChooserToExtension = ( }); }; -export const sendCancelConnectToExtension = () => { +export const sendCancelConnectToExtension = (): void => { vscode.postMessage({ command: MESSAGE_TYPES.CANCEL_CONNECT, }); @@ -49,31 +49,34 @@ export const sendCancelConnectToExtension = () => { // When the form is opened we want to close the connection string // input if it's open, so we message the extension. -export const sendFormOpenedToExtension = () => { +export const sendFormOpenedToExtension = (): void => { vscode.postMessage({ command: MESSAGE_TYPES.CONNECTION_FORM_OPENED, }); }; -export const renameActiveConnection = () => { +export const renameActiveConnection = (): void => { vscode.postMessage({ command: MESSAGE_TYPES.RENAME_ACTIVE_CONNECTION, }); }; -export const createNewPlayground = () => { +export const createNewPlayground = (): void => { vscode.postMessage({ command: MESSAGE_TYPES.CREATE_NEW_PLAYGROUND, }); }; -export const connectWithConnectionString = () => { +export const connectWithConnectionString = (): void => { vscode.postMessage({ command: MESSAGE_TYPES.OPEN_CONNECTION_STRING_INPUT, }); }; -export const trackExtensionLinkClicked = (screen: string, linkId: string) => { +export const trackExtensionLinkClicked = ( + screen: string, + linkId: string +): void => { vscode.postMessage({ command: MESSAGE_TYPES.EXTENSION_LINK_CLICKED, screen, @@ -81,7 +84,7 @@ export const trackExtensionLinkClicked = (screen: string, linkId: string) => { }); }; -export const openTrustedLink = (linkTo: string) => { +export const openTrustedLink = (linkTo: string): void => { vscode.postMessage({ command: MESSAGE_TYPES.OPEN_TRUSTED_LINK, linkTo, diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index cb6e0bf2b..fbf0c81cb 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -22,7 +22,7 @@ import type { FileChooserOptions } from './webview-app/use-connection-form'; const log = createLogger('webview controller'); -const getNonce = () => { +const getNonce = (): string => { return crypto.randomBytes(16).toString('base64'); }; @@ -115,27 +115,44 @@ export default class WebviewController { fileChooserOptions: FileChooserOptions; requestId: string; }): Promise => { - let files; + let files: vscode.Uri[] | vscode.Uri | undefined; try { - files = await vscode.window[ - fileChooserOptions.mode === 'open' ? 'showOpenDialog' : 'showSaveDialog' - ]({ - defaultUri: vscode.Uri.from({ - path: fileChooserOptions.electronFileDialogOptions?.defaultPath, - scheme: 'file', - }), - [`${fileChooserOptions.mode}Label`]: - fileChooserOptions.electronFileDialogOptions?.buttonLabel, - filters: fileChooserOptions.electronFileDialogOptions?.filters?.reduce( - (acc, filter) => { - acc[filter.name] = filter.extensions; - return acc; - }, - {} - ), - title: fileChooserOptions.electronFileDialogOptions?.title, - }); + if (fileChooserOptions.mode === 'open') { + files = await vscode.window.showOpenDialog({ + defaultUri: vscode.Uri.from({ + path: fileChooserOptions.electronFileDialogOptions?.defaultPath, + scheme: 'file', + }), + openLabel: fileChooserOptions.electronFileDialogOptions?.buttonLabel, + filters: + fileChooserOptions.electronFileDialogOptions?.filters?.reduce( + (acc, filter) => { + acc[filter.name] = filter.extensions; + return acc; + }, + {} + ), + title: fileChooserOptions.electronFileDialogOptions?.title, + }); + } else if (fileChooserOptions.mode === 'save') { + files = await vscode.window.showSaveDialog({ + defaultUri: vscode.Uri.from({ + path: fileChooserOptions.electronFileDialogOptions?.defaultPath, + scheme: 'file', + }), + saveLabel: fileChooserOptions.electronFileDialogOptions?.buttonLabel, + filters: + fileChooserOptions.electronFileDialogOptions?.filters?.reduce( + (acc, filter) => { + acc[filter.name] = filter.extensions; + return acc; + }, + {} + ), + title: fileChooserOptions.electronFileDialogOptions?.title, + }); + } } catch (error) { void vscode.window.showErrorMessage( `Unable to open file chooser dialog: ${error}` @@ -146,9 +163,13 @@ export default class WebviewController { command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT, fileChooserResult: { canceled: false, - ...(fileChooserOptions.mode === 'open' - ? { filePaths: files ? files?.map((file) => file.path) : [] } - : { filePath: files?.path }), + ...(Array.isArray(files) + ? { + filePaths: files + ? files?.map((file: vscode.Uri) => file.fsPath) + : [], + } + : { filePath: files?.fsPath }), }, requestId, }); @@ -165,7 +186,7 @@ export default class WebviewController { id: string; }; isEditingConnection?: boolean; - }) => { + }): Promise => { try { const { successfullyConnected, connectionErrorMessage } = isEditingConnection @@ -299,13 +320,13 @@ export default class WebviewController { } }; - onWebviewPanelClosed = (disposedPanel: vscode.WebviewPanel) => { + onWebviewPanelClosed = (disposedPanel: vscode.WebviewPanel): void => { this._activeWebviewPanels = this._activeWebviewPanels.filter( (panel) => panel !== disposedPanel ); }; - onThemeChanged = (theme: vscode.ColorTheme) => { + onThemeChanged = (theme: vscode.ColorTheme): void => { const darkModeDetected = theme.kind === vscode.ColorThemeKind.Dark || theme.kind === vscode.ColorThemeKind.HighContrast; @@ -334,7 +355,7 @@ export default class WebviewController { connectionOptions: ConnectionOptions; }; context: vscode.ExtensionContext; - }) => { + }): Promise => { const webviewPanel = this.openWebview(context); // Wait for the panel to open.