This is an automated email from the ASF dual-hosted git repository.

jhorvath pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git

commit 1b19e802045a5eabd4dec1851c1b3ea9f88ff28e
Author: Ondřej Douda <ondrej.do...@oracle.com>
AuthorDate: Mon Jun 5 11:30:43 2023 +0200

    Database connection PropertiesView.
---
 java/java.lsp.server/licenseinfo.xml               |   1 +
 java/java.lsp.server/vscode/.vscode/tasks.json     |   4 +-
 java/java.lsp.server/vscode/esbuild.js             |  52 ++
 java/java.lsp.server/vscode/package-lock.json      | 764 +++++++++++++++++++++
 java/java.lsp.server/vscode/package.json           |  24 +-
 java/java.lsp.server/vscode/src/extension.ts       | 264 +++----
 .../vscode/src/propertiesView/controlTypes.ts      |  69 ++
 .../src/propertiesView/propertiesHtmlBuilder.ts    | 106 +++
 .../vscode/src/propertiesView/propertiesView.ts    | 174 +++++
 .../vscode/src/propertiesView/script.ts            |  86 +++
 java/java.lsp.server/vscode/src/typesUtil.ts       |  42 ++
 java/java.lsp.server/vscode/tsconfig.json          |   3 +-
 nbbuild/licenses/MIT-sindre-sorhus                 |   9 +
 .../netbeans/prepare/bundles/PrepareBundles.java   |   2 +
 14 files changed, 1462 insertions(+), 138 deletions(-)

diff --git a/java/java.lsp.server/licenseinfo.xml 
b/java/java.lsp.server/licenseinfo.xml
index 05cb44d7e7..fc390b64bb 100644
--- a/java/java.lsp.server/licenseinfo.xml
+++ b/java/java.lsp.server/licenseinfo.xml
@@ -24,6 +24,7 @@
         <file>vscode/package-lock.json</file>
         <file>vscode/package.json</file>
         <file>vscode/tsconfig.json</file>
+        <file>vscode/esbuild.js</file>
         <file>vscode/schemas/package.schema.json</file>
         <license ref="Apache-2.0" />
         <comment type="COMMENT_UNSUPPORTED" />
diff --git a/java/java.lsp.server/vscode/.vscode/tasks.json 
b/java/java.lsp.server/vscode/.vscode/tasks.json
index 3b17e53b62..e2e2358082 100644
--- a/java/java.lsp.server/vscode/.vscode/tasks.json
+++ b/java/java.lsp.server/vscode/.vscode/tasks.json
@@ -5,7 +5,7 @@
        "tasks": [
                {
                        "type": "npm",
-                       "script": "watch",
+                       "script": "compile",
                        "problemMatcher": "$tsc-watch",
                        "isBackground": true,
                        "presentation": {
@@ -17,4 +17,4 @@
                        }
                }
        ]
-}
+}
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/esbuild.js 
b/java/java.lsp.server/vscode/esbuild.js
new file mode 100644
index 0000000000..5023fa6ecc
--- /dev/null
+++ b/java/java.lsp.server/vscode/esbuild.js
@@ -0,0 +1,52 @@
+const { build } = require("esbuild");
+
+const baseConfig = {
+  bundle: true,
+  minify: process.env.NODE_ENV === "production",
+  sourcemap: process.env.NODE_ENV !== "production",
+};
+
+const scriptConfig = {
+  ...baseConfig,
+  target: "es2020",
+  format: "esm",
+  entryPoints: ["./src/propertiesView/script.ts"],
+  outfile: "./out/script.js",
+};
+
+const watchConfig = {
+    watch: {
+      onRebuild(error, result) {
+        console.log("[watch] build started");
+        if (error) {
+          error.errors.forEach(error =>
+            console.error(`> 
${error.location.file}:${error.location.line}:${error.location.column}: error: 
${error.text}`)
+          );
+        } else {
+          console.log("[watch] build finished");
+        }
+      },
+    },
+  };
+  
+  (async () => {
+    const args = process.argv.slice(2);
+    try {
+      if (args.includes("--watch")) {
+        // Build and watch source code
+        console.log("[watch] build started");
+        await build({
+          ...scriptConfig,
+          ...watchConfig,
+        });
+        console.log("[watch] build finished");
+      } else {
+        // Build source code
+        await build(scriptConfig);
+        console.log("build complete");
+      }
+    } catch (err) {
+      process.stderr.write(err.stderr);
+      process.exit(1);
+    }
+  })();
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/package-lock.json 
b/java/java.lsp.server/vscode/package-lock.json
index dbda8651ce..81118c27ff 100644
--- a/java/java.lsp.server/vscode/package-lock.json
+++ b/java/java.lsp.server/vscode/package-lock.json
@@ -10,6 +10,7 @@
                        "license": "Apache 2.0",
                        "dependencies": {
                                "@vscode/debugadapter": "1.55.1",
+                               "@vscode/webview-ui-toolkit": "^1.2.2",
                                "jsonc-parser": "3.0.0",
                                "vscode-languageclient": "8.0.1"
                        },
@@ -19,7 +20,9 @@
                                "@types/node": "^13.11.0",
                                "@types/ps-node": "^0.1.0",
                                "@types/vscode": "^1.76.0",
+                               "@types/vscode-webview": "^1.57.1",
                                "@vscode/codicons": "0.0.29",
+                               "esbuild": "^0.16.17",
                                "glob": "^7.1.6",
                                "mocha": "^9.1.2",
                                "ps-node": "^0.1.6",
@@ -30,6 +33,394 @@
                                "vscode": "^1.76.0"
                        }
                },
+               "node_modules/@esbuild/android-arm": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz";,
+                       "integrity": 
"sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==",
+                       "cpu": [
+                               "arm"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "android"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/android-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==",
+                       "cpu": [
+                               "arm64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "android"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/android-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "android"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/darwin-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==",
+                       "cpu": [
+                               "arm64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "darwin"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/darwin-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "darwin"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/freebsd-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==",
+                       "cpu": [
+                               "arm64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "freebsd"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/freebsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "freebsd"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-arm": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz";,
+                       "integrity": 
"sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==",
+                       "cpu": [
+                               "arm"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==",
+                       "cpu": [
+                               "arm64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-ia32": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz";,
+                       "integrity": 
"sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==",
+                       "cpu": [
+                               "ia32"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-loong64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz";,
+                       "integrity": 
"sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==",
+                       "cpu": [
+                               "loong64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-mips64el": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz";,
+                       "integrity": 
"sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==",
+                       "cpu": [
+                               "mips64el"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-ppc64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz";,
+                       "integrity": 
"sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==",
+                       "cpu": [
+                               "ppc64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-riscv64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz";,
+                       "integrity": 
"sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==",
+                       "cpu": [
+                               "riscv64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-s390x": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz";,
+                       "integrity": 
"sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==",
+                       "cpu": [
+                               "s390x"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/linux-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "linux"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/netbsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "netbsd"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/openbsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "openbsd"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/sunos-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "sunos"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/win32-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==",
+                       "cpu": [
+                               "arm64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "win32"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/win32-ia32": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz";,
+                       "integrity": 
"sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==",
+                       "cpu": [
+                               "ia32"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "win32"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@esbuild/win32-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==",
+                       "cpu": [
+                               "x64"
+                       ],
+                       "dev": true,
+                       "optional": true,
+                       "os": [
+                               "win32"
+                       ],
+                       "engines": {
+                               "node": ">=12"
+                       }
+               },
+               "node_modules/@microsoft/fast-element": {
+                       "version": "1.12.0",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.12.0.tgz";,
+                       "integrity": 
"sha512-gQutuDHPKNxUEcQ4pypZT4Wmrbapus+P9s3bR/SEOLsMbNqNoXigGImITygI5zhb+aA5rzflM6O8YWkmRbGkPA=="
+               },
+               "node_modules/@microsoft/fast-foundation": {
+                       "version": "2.49.0",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.49.0.tgz";,
+                       "integrity": 
"sha512-Wk4e4QXFVtT5hPwhMfHyGY30kixM0td8aDs7bAD6NM2z2SCBNvpTTWp+FCjx0I0lpUMlMenb6wsw7pMWQreRkQ==",
+                       "dependencies": {
+                               "@microsoft/fast-element": "^1.12.0",
+                               "@microsoft/fast-web-utilities": "^5.4.1",
+                               "tabbable": "^5.2.0",
+                               "tslib": "^1.13.0"
+                       }
+               },
+               "node_modules/@microsoft/fast-react-wrapper": {
+                       "version": "0.1.48",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz";,
+                       "integrity": 
"sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==",
+                       "dependencies": {
+                               "@microsoft/fast-element": "^1.9.0",
+                               "@microsoft/fast-foundation": "^2.41.1"
+                       },
+                       "peerDependencies": {
+                               "react": ">=16.9.0"
+                       }
+               },
+               "node_modules/@microsoft/fast-web-utilities": {
+                       "version": "5.4.1",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz";,
+                       "integrity": 
"sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==",
+                       "dependencies": {
+                               "exenv-es6": "^1.1.1"
+                       }
+               },
                "node_modules/@types/glob": {
                        "version": "7.1.3",
                        "dev": true,
@@ -65,6 +456,12 @@
                        "integrity": 
"sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==",
                        "dev": true
                },
+               "node_modules/@types/vscode-webview": {
+                       "version": "1.57.1",
+                       "resolved": 
"https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz";,
+                       "integrity": 
"sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ==",
+                       "dev": true
+               },
                "node_modules/@ungap/promise-all-settled": {
                        "version": "1.1.2",
                        "dev": true,
@@ -92,6 +489,19 @@
                        "resolved": 
"https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.55.1.tgz";,
                        "integrity": 
"sha512-tEOY1KxSACd77JFfoipYvLZdVdrTnXBiVgS7zKDmAQxxmVsKPERB6HOXDijoWi1wUjFx+K7plXCtweX+k5Fc/g=="
                },
+               "node_modules/@vscode/webview-ui-toolkit": {
+                       "version": "1.2.2",
+                       "resolved": 
"https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.2.tgz";,
+                       "integrity": 
"sha512-xIQoF4FC3Xh6d7KNKIoIezSiFWYFuf6gQMdDyKueKBFGeKwaHWEn+dY2g3makvvEsNMEDji/woEwvg9QSbuUsw==",
+                       "dependencies": {
+                               "@microsoft/fast-element": "^1.6.2",
+                               "@microsoft/fast-foundation": "^2.38.0",
+                               "@microsoft/fast-react-wrapper": "^0.1.18"
+                       },
+                       "peerDependencies": {
+                               "react": ">=16.9.0"
+                       }
+               },
                "node_modules/agent-base": {
                        "version": "4.3.0",
                        "dev": true,
@@ -337,6 +747,43 @@
                                "es6-promise": "^4.0.3"
                        }
                },
+               "node_modules/esbuild": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz";,
+                       "integrity": 
"sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==",
+                       "dev": true,
+                       "hasInstallScript": true,
+                       "bin": {
+                               "esbuild": "bin/esbuild"
+                       },
+                       "engines": {
+                               "node": ">=12"
+                       },
+                       "optionalDependencies": {
+                               "@esbuild/android-arm": "0.16.17",
+                               "@esbuild/android-arm64": "0.16.17",
+                               "@esbuild/android-x64": "0.16.17",
+                               "@esbuild/darwin-arm64": "0.16.17",
+                               "@esbuild/darwin-x64": "0.16.17",
+                               "@esbuild/freebsd-arm64": "0.16.17",
+                               "@esbuild/freebsd-x64": "0.16.17",
+                               "@esbuild/linux-arm": "0.16.17",
+                               "@esbuild/linux-arm64": "0.16.17",
+                               "@esbuild/linux-ia32": "0.16.17",
+                               "@esbuild/linux-loong64": "0.16.17",
+                               "@esbuild/linux-mips64el": "0.16.17",
+                               "@esbuild/linux-ppc64": "0.16.17",
+                               "@esbuild/linux-riscv64": "0.16.17",
+                               "@esbuild/linux-s390x": "0.16.17",
+                               "@esbuild/linux-x64": "0.16.17",
+                               "@esbuild/netbsd-x64": "0.16.17",
+                               "@esbuild/openbsd-x64": "0.16.17",
+                               "@esbuild/sunos-x64": "0.16.17",
+                               "@esbuild/win32-arm64": "0.16.17",
+                               "@esbuild/win32-ia32": "0.16.17",
+                               "@esbuild/win32-x64": "0.16.17"
+                       }
+               },
                "node_modules/escalade": {
                        "version": "3.1.1",
                        "dev": true,
@@ -356,6 +803,11 @@
                                "url": 
"https://github.com/sponsors/sindresorhus";
                        }
                },
+               "node_modules/exenv-es6": {
+                       "version": "1.1.1",
+                       "resolved": 
"https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz";,
+                       "integrity": 
"sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ=="
+               },
                "node_modules/fill-range": {
                        "version": "7.0.1",
                        "dev": true,
@@ -598,6 +1050,12 @@
                        "dev": true,
                        "license": "ISC"
                },
+               "node_modules/js-tokens": {
+                       "version": "4.0.0",
+                       "resolved": 
"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz";,
+                       "integrity": 
"sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+                       "peer": true
+               },
                "node_modules/js-yaml": {
                        "version": "4.1.0",
                        "dev": true,
@@ -642,6 +1100,18 @@
                                "url": 
"https://github.com/sponsors/sindresorhus";
                        }
                },
+               "node_modules/loose-envify": {
+                       "version": "1.4.0",
+                       "resolved": 
"https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz";,
+                       "integrity": 
"sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+                       "peer": true,
+                       "dependencies": {
+                               "js-tokens": "^3.0.0 || ^4.0.0"
+                       },
+                       "bin": {
+                               "loose-envify": "cli.js"
+                       }
+               },
                "node_modules/lru-cache": {
                        "version": "6.0.0",
                        "license": "ISC",
@@ -827,6 +1297,18 @@
                                "safe-buffer": "^5.1.0"
                        }
                },
+               "node_modules/react": {
+                       "version": "18.2.0",
+                       "resolved": 
"https://registry.npmjs.org/react/-/react-18.2.0.tgz";,
+                       "integrity": 
"sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+                       "peer": true,
+                       "dependencies": {
+                               "loose-envify": "^1.1.0"
+                       },
+                       "engines": {
+                               "node": ">=0.10.0"
+                       }
+               },
                "node_modules/readdirp": {
                        "version": "3.6.0",
                        "dev": true,
@@ -946,6 +1428,11 @@
                                "url": 
"https://github.com/chalk/supports-color?sponsor=1";
                        }
                },
+               "node_modules/tabbable": {
+                       "version": "5.3.3",
+                       "resolved": 
"https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz";,
+                       "integrity": 
"sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
+               },
                "node_modules/table-parser": {
                        "version": "0.1.3",
                        "dev": true,
@@ -965,6 +1452,11 @@
                                "node": ">=8.0"
                        }
                },
+               "node_modules/tslib": {
+                       "version": "1.14.1",
+                       "resolved": 
"https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz";,
+                       "integrity": 
"sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+               },
                "node_modules/typescript": {
                        "version": "4.6.4",
                        "resolved": 
"https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz";,
@@ -1130,6 +1622,193 @@
                }
        },
        "dependencies": {
+               "@esbuild/android-arm": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz";,
+                       "integrity": 
"sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/android-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/android-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/darwin-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/darwin-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/freebsd-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/freebsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-arm": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz";,
+                       "integrity": 
"sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-ia32": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz";,
+                       "integrity": 
"sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-loong64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz";,
+                       "integrity": 
"sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-mips64el": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz";,
+                       "integrity": 
"sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-ppc64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz";,
+                       "integrity": 
"sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-riscv64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz";,
+                       "integrity": 
"sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-s390x": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz";,
+                       "integrity": 
"sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/linux-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/netbsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/openbsd-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/sunos-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/win32-arm64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz";,
+                       "integrity": 
"sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/win32-ia32": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz";,
+                       "integrity": 
"sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@esbuild/win32-x64": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz";,
+                       "integrity": 
"sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==",
+                       "dev": true,
+                       "optional": true
+               },
+               "@microsoft/fast-element": {
+                       "version": "1.12.0",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.12.0.tgz";,
+                       "integrity": 
"sha512-gQutuDHPKNxUEcQ4pypZT4Wmrbapus+P9s3bR/SEOLsMbNqNoXigGImITygI5zhb+aA5rzflM6O8YWkmRbGkPA=="
+               },
+               "@microsoft/fast-foundation": {
+                       "version": "2.49.0",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.49.0.tgz";,
+                       "integrity": 
"sha512-Wk4e4QXFVtT5hPwhMfHyGY30kixM0td8aDs7bAD6NM2z2SCBNvpTTWp+FCjx0I0lpUMlMenb6wsw7pMWQreRkQ==",
+                       "requires": {
+                               "@microsoft/fast-element": "^1.12.0",
+                               "@microsoft/fast-web-utilities": "^5.4.1",
+                               "tabbable": "^5.2.0",
+                               "tslib": "^1.13.0"
+                       }
+               },
+               "@microsoft/fast-react-wrapper": {
+                       "version": "0.1.48",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz";,
+                       "integrity": 
"sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==",
+                       "requires": {
+                               "@microsoft/fast-element": "^1.9.0",
+                               "@microsoft/fast-foundation": "^2.41.1"
+                       }
+               },
+               "@microsoft/fast-web-utilities": {
+                       "version": "5.4.1",
+                       "resolved": 
"https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz";,
+                       "integrity": 
"sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==",
+                       "requires": {
+                               "exenv-es6": "^1.1.1"
+                       }
+               },
                "@types/glob": {
                        "version": "7.1.3",
                        "dev": true,
@@ -1160,6 +1839,12 @@
                        "integrity": 
"sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==",
                        "dev": true
                },
+               "@types/vscode-webview": {
+                       "version": "1.57.1",
+                       "resolved": 
"https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz";,
+                       "integrity": 
"sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ==",
+                       "dev": true
+               },
                "@ungap/promise-all-settled": {
                        "version": "1.1.2",
                        "dev": true
@@ -1183,6 +1868,16 @@
                        "resolved": 
"https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.55.1.tgz";,
                        "integrity": 
"sha512-tEOY1KxSACd77JFfoipYvLZdVdrTnXBiVgS7zKDmAQxxmVsKPERB6HOXDijoWi1wUjFx+K7plXCtweX+k5Fc/g=="
                },
+               "@vscode/webview-ui-toolkit": {
+                       "version": "1.2.2",
+                       "resolved": 
"https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.2.tgz";,
+                       "integrity": 
"sha512-xIQoF4FC3Xh6d7KNKIoIezSiFWYFuf6gQMdDyKueKBFGeKwaHWEn+dY2g3makvvEsNMEDji/woEwvg9QSbuUsw==",
+                       "requires": {
+                               "@microsoft/fast-element": "^1.6.2",
+                               "@microsoft/fast-foundation": "^2.38.0",
+                               "@microsoft/fast-react-wrapper": "^0.1.18"
+                       }
+               },
                "agent-base": {
                        "version": "4.3.0",
                        "dev": true,
@@ -1334,6 +2029,36 @@
                                "es6-promise": "^4.0.3"
                        }
                },
+               "esbuild": {
+                       "version": "0.16.17",
+                       "resolved": 
"https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz";,
+                       "integrity": 
"sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==",
+                       "dev": true,
+                       "requires": {
+                               "@esbuild/android-arm": "0.16.17",
+                               "@esbuild/android-arm64": "0.16.17",
+                               "@esbuild/android-x64": "0.16.17",
+                               "@esbuild/darwin-arm64": "0.16.17",
+                               "@esbuild/darwin-x64": "0.16.17",
+                               "@esbuild/freebsd-arm64": "0.16.17",
+                               "@esbuild/freebsd-x64": "0.16.17",
+                               "@esbuild/linux-arm": "0.16.17",
+                               "@esbuild/linux-arm64": "0.16.17",
+                               "@esbuild/linux-ia32": "0.16.17",
+                               "@esbuild/linux-loong64": "0.16.17",
+                               "@esbuild/linux-mips64el": "0.16.17",
+                               "@esbuild/linux-ppc64": "0.16.17",
+                               "@esbuild/linux-riscv64": "0.16.17",
+                               "@esbuild/linux-s390x": "0.16.17",
+                               "@esbuild/linux-x64": "0.16.17",
+                               "@esbuild/netbsd-x64": "0.16.17",
+                               "@esbuild/openbsd-x64": "0.16.17",
+                               "@esbuild/sunos-x64": "0.16.17",
+                               "@esbuild/win32-arm64": "0.16.17",
+                               "@esbuild/win32-ia32": "0.16.17",
+                               "@esbuild/win32-x64": "0.16.17"
+                       }
+               },
                "escalade": {
                        "version": "3.1.1",
                        "dev": true
@@ -1342,6 +2067,11 @@
                        "version": "4.0.0",
                        "dev": true
                },
+               "exenv-es6": {
+                       "version": "1.1.1",
+                       "resolved": 
"https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz";,
+                       "integrity": 
"sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ=="
+               },
                "fill-range": {
                        "version": "7.0.1",
                        "dev": true,
@@ -1493,6 +2223,12 @@
                        "version": "2.0.0",
                        "dev": true
                },
+               "js-tokens": {
+                       "version": "4.0.0",
+                       "resolved": 
"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz";,
+                       "integrity": 
"sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+                       "peer": true
+               },
                "js-yaml": {
                        "version": "4.1.0",
                        "dev": true,
@@ -1518,6 +2254,15 @@
                                "is-unicode-supported": "^0.1.0"
                        }
                },
+               "loose-envify": {
+                       "version": "1.4.0",
+                       "resolved": 
"https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz";,
+                       "integrity": 
"sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+                       "peer": true,
+                       "requires": {
+                               "js-tokens": "^3.0.0 || ^4.0.0"
+                       }
+               },
                "lru-cache": {
                        "version": "6.0.0",
                        "requires": {
@@ -1640,6 +2385,15 @@
                                "safe-buffer": "^5.1.0"
                        }
                },
+               "react": {
+                       "version": "18.2.0",
+                       "resolved": 
"https://registry.npmjs.org/react/-/react-18.2.0.tgz";,
+                       "integrity": 
"sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+                       "peer": true,
+                       "requires": {
+                               "loose-envify": "^1.1.0"
+                       }
+               },
                "readdirp": {
                        "version": "3.6.0",
                        "dev": true,
@@ -1702,6 +2456,11 @@
                                "has-flag": "^4.0.0"
                        }
                },
+               "tabbable": {
+                       "version": "5.3.3",
+                       "resolved": 
"https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz";,
+                       "integrity": 
"sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
+               },
                "table-parser": {
                        "version": "0.1.3",
                        "dev": true,
@@ -1716,6 +2475,11 @@
                                "is-number": "^7.0.0"
                        }
                },
+               "tslib": {
+                       "version": "1.14.1",
+                       "resolved": 
"https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz";,
+                       "integrity": 
"sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+               },
                "typescript": {
                        "version": "4.6.4",
                        "resolved": 
"https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz";,
diff --git a/java/java.lsp.server/vscode/package.json 
b/java/java.lsp.server/vscode/package.json
index 14d50031da..d7fef35353 100644
--- a/java/java.lsp.server/vscode/package.json
+++ b/java/java.lsp.server/vscode/package.json
@@ -445,6 +445,10 @@
                        }
                ],
                "commands": [
+                       {
+                               "command": "nbls.node.properties.edit",
+                               "title": "Properties"
+                       },
                        {
                                "command": "nbls.workspace.compile",
                                "title": "Compile Workspace",
@@ -661,6 +665,10 @@
                                        "command": "foundProjects.deleteEntry",
                                        "when": "false"
                                },
+                               {
+                                       "command": "nbls.node.properties.edit",
+                                       "when": "false"
+                               },
                                {
                                        "command": 
"nbls:Database:netbeans.db.explorer.action.Connect",
                                        "when": "false"
@@ -751,6 +759,11 @@
                                        "command": "foundProjects.deleteEntry",
                                        "when": "view == foundProjects && 
viewItem == node && config.netbeans.javaSupport.enabled"
                                },
+                               {
+                                       "command": "nbls.node.properties.edit",
+                                       "when": "viewItem =~ 
/class:org.netbeans.api.db.explorer.DatabaseConnection/",
+                                       "group": "db@9999"
+                               },
                                {
                                        "command": 
"nbls:Database:netbeans.db.explorer.action.Connect",
                                        "when": "viewItem =~ 
/class:org.netbeans.api.db.explorer.DatabaseConnection/ && viewItem =~ 
/is:disconnected/",
@@ -1025,20 +1038,22 @@
        },
        "scripts": {
                "vscode:prepublish": "npm run compile",
-               "compile": "tsc -p ./",
-               "watch": "tsc -watch -p ./",
+               "compile": "tsc -p ./; node ./esbuild.js",
+               "watch": "tsc -watch -p ./ | node ./esbuild.js --watch",
                "test": "node ./out/test/runTest.js",
                "nbcode": "node ./out/nbcode.js",
                "nbjavac": "node ./out/nbcode.js -J-Dnetbeans.close=true 
--modules --install .*nbjavac.*",
                "apisupport": "node ./out/nbcode.js -J-Dnetbeans.close=true 
--modules --install 
'(org.netbeans.libs.xerces|org.netbeans.modules.editor.structure|org.netbeans.modules.xml|org.netbeans.modules.xml.axi|org.netbeans.modules.xml.retriever|org.netbeans.modules.xml.schema.model|org.netbeans.modules.xml.tax|org.netbeans.modules.xml.text|org.netbeans.modules.ant.browsetask|.*apisupport.*|org.netbeans.modules.debugger.jpda.ant)'
 && node ./out/nbcode.js -J-Dnetbeans.close=true --modules --enable  [...]
        },
        "devDependencies": {
-               "@vscode/codicons": "0.0.29",
                "@types/glob": "^7.1.1",
                "@types/mocha": "^9.0.0",
                "@types/node": "^13.11.0",
                "@types/ps-node": "^0.1.0",
                "@types/vscode": "^1.76.0",
+               "@types/vscode-webview": "^1.57.1",
+               "@vscode/codicons": "0.0.29",
+               "esbuild": "^0.16.17",
                "glob": "^7.1.6",
                "mocha": "^9.1.2",
                "ps-node": "^0.1.6",
@@ -1046,8 +1061,9 @@
                "vscode-test": "^1.3.0"
        },
        "dependencies": {
-               "jsonc-parser": "3.0.0",
                "@vscode/debugadapter": "1.55.1",
+               "@vscode/webview-ui-toolkit": "^1.2.2",
+               "jsonc-parser": "3.0.0",
                "vscode-languageclient": "8.0.1"
        },
        "__metadata": {
diff --git a/java/java.lsp.server/vscode/src/extension.ts 
b/java/java.lsp.server/vscode/src/extension.ts
index ac65bff14f..b3bef4980b 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -21,10 +21,10 @@
 import { commands, window, workspace, ExtensionContext, ProgressLocation, 
TextEditorDecorationType } from 'vscode';
 
 import {
-       LanguageClient,
-       LanguageClientOptions,
-       ServerOptions,
-       StreamInfo
+    LanguageClient,
+    LanguageClientOptions,
+    ServerOptions,
+    StreamInfo
 } from 'vscode-languageclient/node';
 
 import {
@@ -45,10 +45,11 @@ import * as path from 'path';
 import { ChildProcess } from 'child_process';
 import * as vscode from 'vscode';
 import * as launcher from './nbcode';
-import {NbTestAdapter} from './testAdapter';
-import { asRanges, StatusMessageRequest, ShowStatusMessageParams, 
QuickPickRequest, InputBoxRequest, MutliStepInputRequest, 
TestProgressNotification, DebugConnector,
-         TextEditorDecorationCreateRequest, 
TextEditorDecorationSetNotification, TextEditorDecorationDisposeNotification, 
HtmlPageRequest, HtmlPageParams,
-         ExecInHtmlPageRequest, SetTextEditorDecorationParams, 
ProjectActionParams, UpdateConfigurationRequest, QuickPickStep, InputBoxStep
+import { NbTestAdapter } from './testAdapter';
+import {
+    asRanges, StatusMessageRequest, ShowStatusMessageParams, QuickPickRequest, 
InputBoxRequest, MutliStepInputRequest, TestProgressNotification, 
DebugConnector,
+    TextEditorDecorationCreateRequest, TextEditorDecorationSetNotification, 
TextEditorDecorationDisposeNotification, HtmlPageRequest, HtmlPageParams,
+    ExecInHtmlPageRequest, SetTextEditorDecorationParams, ProjectActionParams, 
UpdateConfigurationRequest, QuickPickStep, InputBoxStep
 } from './protocol';
 import * as launchConfigurations from './launchConfigurations';
 import { createTreeViewService, TreeViewService, TreeItemDecorator, 
Visualizer, CustomizableTreeDataProvider } from './explorer';
@@ -57,19 +58,20 @@ import { DBConfigurationProvider } from 
'./dbConfigurationProvider';
 import { TLSSocket } from 'tls';
 import { InputStep, MultiStepInput } from './utils';
 import { env } from 'process';
+import { PropertiesView } from './propertiesView/propertiesView';
 
 const API_VERSION : string = "1.0";
 const DATABASE: string = 'Database';
 let client: Promise<NbLanguageClient>;
 let testAdapter: NbTestAdapter | undefined;
-let nbProcess : ChildProcess | null = null;
+let nbProcess: ChildProcess | null = null;
 let debugPort: number = -1;
 let consoleLog: boolean = !!process.env['ENABLE_CONSOLE_LOG'];
 
 export class NbLanguageClient extends LanguageClient {
     private _treeViewService: TreeViewService;
 
-    constructor (id : string, name: string, s : ServerOptions, log : 
vscode.OutputChannel, c : LanguageClientOptions) {
+    constructor(id: string, name: string, s: ServerOptions, log: 
vscode.OutputChannel, c: LanguageClientOptions) {
         super(id, name, s, c);
         this._treeViewService = createTreeViewService(log, this);
     }
@@ -106,7 +108,7 @@ export function enableConsoleLog() {
     console.log("enableConsoleLog");
 }
 
-export function findClusters(myPath : string): string[] {
+export function findClusters(myPath: string): string[] {
     let clusters = [];
     for (let e of vscode.extensions.all) {
         if (e.extensionPath === myPath) {
@@ -133,8 +135,8 @@ export function findClusters(myPath : string): string[] {
 }
 
 // for tests only !
-export function awaitClient() : Promise<NbLanguageClient> {
-    const c : Promise<NbLanguageClient> = client;
+export function awaitClient(): Promise<NbLanguageClient> {
+    const c: Promise<NbLanguageClient> = client;
     if (c && !(c instanceof InitialPromise)) {
         return c;
     }
@@ -142,7 +144,7 @@ export function awaitClient() : Promise<NbLanguageClient> {
     if (!nbcode) {
         return Promise.reject(new Error("Extension not installed."));
     }
-    const t : Thenable<NbLanguageClient> = nbcode.activate().then(nc => {
+    const t: Thenable<NbLanguageClient> = nbcode.activate().then(nc => {
         if (client === undefined || client instanceof InitialPromise) {
             throw new Error("Client not available");
         } else {
@@ -152,9 +154,9 @@ export function awaitClient() : Promise<NbLanguageClient> {
     return Promise.resolve(t);
 }
 
-function findJDK(onChange: (path : string | null) => void): void {
-    let nowDark : boolean = isDarkColorTheme();
-    let nowJavaEnabled : boolean = isJavaSupportEnabled();
+function findJDK(onChange: (path: string | null) => void): void {
+    let nowDark: boolean = isDarkColorTheme();
+    let nowJavaEnabled: boolean = isJavaSupportEnabled();
     function find(): string | null {
         let nbJdk = workspace.getConfiguration('netbeans').get('jdkhome');
         if (nbJdk) {
@@ -182,7 +184,7 @@ function findJDK(onChange: (path : string | null) => void): 
void {
         if (timeout) {
             return;
         }
-        let interested : boolean = false;
+        let interested: boolean = false;
         if (params.affectsConfiguration('netbeans') || 
params.affectsConfiguration('java')) {
             interested = true;
         } else if (params.affectsConfiguration('workbench.colorTheme')) {
@@ -211,11 +213,11 @@ function findJDK(onChange: (path : string | null) => 
void): void {
 }
 
 interface VSNetBeansAPI {
-    version : string;
+    version: string;
     apiVersion: string;
 }
 
-function contextUri(ctx : any) : vscode.Uri | undefined {
+function contextUri(ctx: any): vscode.Uri | undefined {
     if (ctx?.fsPath) {
         return ctx as vscode.Uri;
     } else if (ctx?.resourceUri) {
@@ -242,14 +244,14 @@ function contextUri(ctx : any) : vscode.Uri | undefined {
  * @param args additional arguments
  * @returns Promise for the command's result
  */
-function wrapProjectActionWithProgress(action : string, configuration : string 
| undefined, title : string, log? : vscode.OutputChannel, showOutput? : 
boolean, ...args : any[]) : Thenable<unknown> {
+function wrapProjectActionWithProgress(action: string, configuration: string | 
undefined, title: string, log?: vscode.OutputChannel, showOutput?: boolean, 
...args: any[]): Thenable<unknown> {
     let items = [];
     let actionParams = {
-        action : action,
-        configuration : configuration,
+        action: action,
+        configuration: configuration,
     } as ProjectActionParams;
     for (let item of args) {
-        let u : vscode.Uri | undefined;
+        let u: vscode.Uri | undefined;
         if (item?.fsPath) {
             items.push((item.fsPath as vscode.Uri).toString());
         } else if (item?.resourceUri) {
@@ -261,10 +263,10 @@ function wrapProjectActionWithProgress(action : string, 
configuration : string |
     return wrapCommandWithProgress('java.project.run.action', title, log, 
showOutput, actionParams, ...items);
 }
 
-function wrapCommandWithProgress(lsCommand : string, title : string, log? : 
vscode.OutputChannel, showOutput? : boolean, ...args : any[]) : 
Thenable<unknown> {
+function wrapCommandWithProgress(lsCommand: string, title: string, log?: 
vscode.OutputChannel, showOutput?: boolean, ...args: any[]): Thenable<unknown> {
     return window.withProgress({ location: ProgressLocation.Window }, p => {
         return new Promise(async (resolve, reject) => {
-            let c : LanguageClient = await client;
+            let c: LanguageClient = await client;
             const commands = await vscode.commands.getCommands();
             if (commands.includes(lsCommand)) {
                 p.report({ message: title });
@@ -299,7 +301,7 @@ function wrapCommandWithProgress(lsCommand : string, title 
: string, log? : vsco
  * the initial one needs to be largely ignored in the launching/mgmt code, BUT 
should be available to normal commands / features.
  */
 class InitialPromise extends Promise<NbLanguageClient> {
-    constructor(f : (resolve: (value: NbLanguageClient | 
PromiseLike<NbLanguageClient>) => void, reject: (reason?: any) => void) => 
void) {
+    constructor(f: (resolve: (value: NbLanguageClient | 
PromiseLike<NbLanguageClient>) => void, reject: (reason?: any) => void) => 
void) {
         super(f);
     }
 }
@@ -308,7 +310,7 @@ class InitialPromise extends Promise<NbLanguageClient> {
  * Determines the outcome, if there's a conflict betwee RH Java and us: 
disable java, enable java, ask the user.
  * @returns false, if java should be disablde; true, if enabled. Undefined if 
no config is present, ask the user
  */
-function shouldEnableConflictingJavaSupport() : boolean | undefined {
+function shouldEnableConflictingJavaSupport(): boolean | undefined {
     // backwards compatibility; remove in NBLS 19
     if (vscode.extensions.getExtension('oracle-labs-graalvm.gcn')) {
         return false;
@@ -333,9 +335,8 @@ function shouldEnableConflictingJavaSupport() : boolean | 
undefined {
 
 export function activate(context: ExtensionContext): VSNetBeansAPI {
     let log = vscode.window.createOutputChannel("Apache NetBeans Language 
Server");
-
-    var clientResolve : (x : NbLanguageClient) => void;
-    var clientReject : (err : any) => void;
+    var clientResolve: (x: NbLanguageClient) => void;
+    var clientReject: (err: any) => void;
 
     // establish a waitable Promise, export the callbacks so they can be 
called after activation.
     client = new InitialPromise((resolve, reject) => {
@@ -347,7 +348,7 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
         let conf = workspace.getConfiguration();
         if (conf.get("netbeans.conflict.check")) {
             if (conf.get("netbeans.javaSupport.enabled")) {
-                const e : boolean | undefined = 
shouldEnableConflictingJavaSupport();
+                const e: boolean | undefined = 
shouldEnableConflictingJavaSupport();
                 if (!e && vscode.extensions.getExtension('redhat.java')) {
                     if (e === false) {
                         // do not ask, an extension wants us to disable on 
conflict
@@ -395,7 +396,7 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
     });
 
     //register debugger:
-    let debugTrackerFactory =new NetBeansDebugAdapterTrackerFactory();
+    let debugTrackerFactory = new NetBeansDebugAdapterTrackerFactory();
     
context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory('java+',
 debugTrackerFactory));
     let configInitialProvider = new NetBeansConfigurationInitialProvider();
     
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java+',
 configInitialProvider, vscode.DebugConfigurationProviderTriggerKind.Initial));
@@ -412,7 +413,7 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
 
     // initialize Run Configuration
     initializeRunConfiguration().then(initialized => {
-               if (initialized) {
+        if (initialized) {
             
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java+',
 new DBConfigurationProvider()));
                        
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java+',
 runConfigurationProvider));
                        
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java',
 runConfigurationProvider));
@@ -436,7 +437,7 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
                 let newFile = vscode.Uri.parse(res as string);
                 await vscode.window.showTextDocument(newFile, { preview: false 
});
             } else if (Array.isArray(res)) {
-                for(let r of res) {
+                for (let r of res) {
                     if (typeof r === 'string') {
                         let newFile = vscode.Uri.parse(r as string);
                         await vscode.window.showTextDocument(newFile, { 
preview: false });
@@ -523,7 +524,7 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
             await commands.executeCommand(selected.userData.command.command, 
...(selected.userData.command.arguments || []));
         }
     }));
-    const mergeWithLaunchConfig = (dconfig : vscode.DebugConfiguration) => {
+    const mergeWithLaunchConfig = (dconfig: vscode.DebugConfiguration) => {
         const folder = vscode.workspace.workspaceFolders?.[0];
         const uri = folder?.uri;
         if (uri) {
@@ -545,11 +546,11 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
         }
     }
 
-    const runDebug = async (noDebug: boolean, testRun: boolean, uri: any, 
methodName?: string, launchConfiguration?: string, project : boolean = false, ) 
=> {
+    const runDebug = async (noDebug: boolean, testRun: boolean, uri: any, 
methodName?: string, launchConfiguration?: string, project: boolean = false,) 
=> {
         const docUri = contextUri(uri);
         if (docUri) {
             const workspaceFolder = 
vscode.workspace.getWorkspaceFolder(docUri);
-            const debugConfig : vscode.DebugConfiguration = {
+            const debugConfig: vscode.DebugConfiguration = {
                 type: "java+",
                 name: "Java Single Debug",
                 request: "launch",
@@ -561,10 +562,10 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
                 debugConfig['projectFile'] = docUri.toString();
                 debugConfig['project'] = true;
             } else {
-                debugConfig['mainClass'] =  docUri.toString();
+                debugConfig['mainClass'] = docUri.toString();
             }
             mergeWithLaunchConfig(debugConfig);
-            const debugOptions : vscode.DebugSessionOptions = {
+            const debugOptions: vscode.DebugSessionOptions = {
                 noDebug: noDebug,
             }
             const ret = await vscode.debug.startDebugging(workspaceFolder, 
debugConfig, debugOptions);
@@ -622,39 +623,40 @@ export function activate(context: ExtensionContext): 
VSNetBeansAPI {
     
context.subscriptions.push(commands.registerCommand('nbls.startup.condition', 
async () => {
         return client;
     }));
+    
context.subscriptions.push(commands.registerCommand('nbls.node.properties.edit',
 async (node) => await PropertiesView.createOrShow(context, node)));
 
     launchConfigurations.updateLaunchConfig();
 
     // register completions:
     launchConfigurations.registerCompletion(context);
     return Object.freeze({
-        version : API_VERSION,
-        apiVersion : API_VERSION
+        version: API_VERSION,
+        apiVersion: API_VERSION
     });
 }
 
 /**
  * Pending maintenance (install) task, activations should be chained after it.
  */
-let maintenance : Promise<void> | null;
+let maintenance: Promise<void> | null;
 
 /**
  * Pending activation flag. Will be cleared when the process produces some 
message or fails.
  */
-let activationPending : boolean = false;
+let activationPending: boolean = false;
 
-function activateWithJDK(specifiedJDK: string | null, context: 
ExtensionContext, log : vscode.OutputChannel, notifyKill: boolean, 
-    clientResolve? : (x : NbLanguageClient) => void, clientReject? : (x : any) 
=> void): void {
+function activateWithJDK(specifiedJDK: string | null, context: 
ExtensionContext, log: vscode.OutputChannel, notifyKill: boolean,
+    clientResolve?: (x: NbLanguageClient) => void, clientReject?: (x: any) => 
void): void {
     if (activationPending) {
         // do not activate more than once in parallel.
         handleLog(log, "Server activation requested repeatedly, ignoring...");
         return;
     }
     let oldClient = client;
-    let setClient : [(c : NbLanguageClient) => void, (err : any) => void];
+    let setClient: [(c: NbLanguageClient) => void, (err: any) => void];
     client = new Promise<NbLanguageClient>((clientOK, clientErr) => {
         setClient = [
-            function (c : NbLanguageClient) {
+            function (c: NbLanguageClient) {
                 clientOK(c);
                 if (clientResolve) {
                     clientResolve(c);
@@ -668,7 +670,7 @@ function activateWithJDK(specifiedJDK: string | null, 
context: ExtensionContext,
         ]
         //setClient = [ clientOK, clientErr ];
     });
-    const a : Promise<void> | null = maintenance;
+    const a: Promise<void> | null = maintenance;
 
     commands.executeCommand('setContext', 'nbJavaLSReady', false);
     commands.executeCommand('setContext', 'dbAddConnectionPresent', true);
@@ -688,7 +690,7 @@ function activateWithJDK(specifiedJDK: string | null, 
context: ExtensionContext,
 }
 
 
-function killNbProcess(notifyKill : boolean, log : vscode.OutputChannel, 
specProcess?: ChildProcess) : Promise<void> {
+function killNbProcess(notifyKill: boolean, log: vscode.OutputChannel, 
specProcess?: ChildProcess): Promise<void> {
     const p = nbProcess;
     handleLog(log, "Request to kill LSP server.");
     if (p && (!specProcess || specProcess == p)) {
@@ -697,7 +699,7 @@ function killNbProcess(notifyKill : boolean, log : 
vscode.OutputChannel, specPro
         }
         return new Promise((resolve, reject) => {
             nbProcess = null;
-            p.on('close', function(code: number) {
+            p.on('close', function (code: number) {
                 handleLog(log, "LSP server closed: " + p.pid)
                 resolve();
             });
@@ -720,23 +722,23 @@ function killNbProcess(notifyKill : boolean, log : 
vscode.OutputChannel, specPro
  * Attempts to determine if the Workbench is using dark-style color theme, so 
that NBLS
  * starts with some dark L&F for icon resource selection.
  */
-function isDarkColorTheme() : boolean {
+function isDarkColorTheme(): boolean {
     const themeName = 
workspace.getConfiguration('workbench')?.get('colorTheme');
     if (!themeName) {
         return false;
     }
     for (const ext of vscode.extensions.all) {
-        const themeList : object[] =  ext.packageJSON?.contributes && 
ext.packageJSON?.contributes['themes'];
+        const themeList: object[] = ext.packageJSON?.contributes && 
ext.packageJSON?.contributes['themes'];
         if (!themeList) {
             continue;
         }
-        let t : any;
+        let t: any;
         for (t of themeList) {
             if (t.id !== themeName) {
                 continue;
             }
             const uiTheme = t.uiTheme;
-            if (typeof(uiTheme) == 'string') {
+            if (typeof (uiTheme) == 'string') {
                 if (uiTheme.includes('-dark') || uiTheme.includes('-black')) {
                     return true;
                 }
@@ -746,15 +748,15 @@ function isDarkColorTheme() : boolean {
     return false;
 }
 
-function isJavaSupportEnabled() : boolean {
+function isJavaSupportEnabled(): boolean {
     return workspace.getConfiguration('netbeans')?.get('javaSupport.enabled') 
as boolean;
 }
 
-function doActivateWithJDK(specifiedJDK: string | null, context: 
ExtensionContext, log : vscode.OutputChannel, notifyKill: boolean,
-    setClient : [(c : NbLanguageClient) => void, (err : any) => void]
+function doActivateWithJDK(specifiedJDK: string | null, context: 
ExtensionContext, log: vscode.OutputChannel, notifyKill: boolean,
+    setClient: [(c: NbLanguageClient) => void, (err: any) => void]
 ): void {
     maintenance = null;
-    let restartWithJDKLater : ((time: number, n: boolean) => void) = function 
restartLater(time: number, n : boolean) {
+    let restartWithJDKLater: ((time: number, n: boolean) => void) = function 
restartLater(time: number, n: boolean) {
         handleLog(log, `Restart of Apache Language Server requested in ${(time 
/ 1000)} s.`);
         setTimeout(() => {
             activateWithJDK(specifiedJDK, context, log, n);
@@ -762,7 +764,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
     };
 
     const netbeansConfig = workspace.getConfiguration('netbeans');
-    const beVerbose : boolean = netbeansConfig.get('verbose', false);
+    const beVerbose: boolean = netbeansConfig.get('verbose', false);
     let userdir = process.env['nbcode_userdir'] || 
netbeansConfig.get('userdir', 'local');
     switch (userdir) {
         case 'local':
@@ -770,19 +772,19 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
                 userdir = context.storagePath;
                 break;
             }
-            // fallthru
+        // fallthru
         case 'global':
             userdir = context.globalStoragePath;
             break;
         default:
-            // assume storage is path on disk
+        // assume storage is path on disk
     }
 
     let info = {
-        clusters : findClusters(context.extensionPath),
+        clusters: findClusters(context.extensionPath),
         extensionPath: context.extensionPath,
-        storagePath : userdir,
-        jdkHome : specifiedJDK,
+        storagePath: userdir,
+        jdkHome: specifiedJDK,
         verbose: beVerbose
     };
     let launchMsg = `Launching Apache NetBeans Language Server with 
${specifiedJDK ? specifiedJDK : 'default system JDK'} and userdir ${userdir}`;
@@ -790,7 +792,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
     vscode.window.setStatusBarMessage(launchMsg, 2000);
 
     let ideRunning = new Promise((resolve, reject) => {
-        let stdOut : string | null = '';
+        let stdOut: string | null = '';
         function logAndWaitForEnabled(text: string, isOut: boolean) {
             if (p == nbProcess) {
                 activationPending = false;
@@ -807,7 +809,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
                 stdOut = null;
             }
         }
-        let extras : string[] = ["--modules", "--list", 
"-J-XX:PerfMaxStringConstLength=10240"];
+        let extras: string[] = ["--modules", "--list", 
"-J-XX:PerfMaxStringConstLength=10240"];
         if (isDarkColorTheme()) {
             extras.push('--laf', 'com.formdev.flatlaf.FlatDarkLaf');
         }
@@ -819,14 +821,14 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
         let p = launcher.launch(info, ...extras);
         handleLog(log, "LSP server launching: " + p.pid);
         handleLog(log, "LSP server user directory: " + userdir);
-        p.stdout.on('data', function(d: any) {
+        p.stdout.on('data', function (d: any) {
             logAndWaitForEnabled(d.toString(), true);
         });
-        p.stderr.on('data', function(d: any) {
+        p.stderr.on('data', function (d: any) {
             logAndWaitForEnabled(d.toString(), false);
         });
         nbProcess = p;
-        p.on('close', function(code: number) {
+        p.on('close', function (code: number) {
             if (p == nbProcess) {
                 nbProcess = null;
             }
@@ -892,18 +894,18 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             });
         });
         const conf = workspace.getConfiguration();
-        let documentSelectors : DocumentSelector = [
-                { language: 'java' },
-                { language: 'yaml', pattern: '**/{application,bootstrap}*.yml' 
},
-                { language: 'properties', pattern: 
'**/{application,bootstrap}*.properties' },
-                { language: 'jackpot-hint' },
-                { language: 'xml', pattern: '**/pom.xml' },
-                { pattern: '**/build.gradle'}
+        let documentSelectors: DocumentSelector = [
+            { language: 'java' },
+            { language: 'yaml', pattern: '**/{application,bootstrap}*.yml' },
+            { language: 'properties', pattern: 
'**/{application,bootstrap}*.properties' },
+            { language: 'jackpot-hint' },
+            { language: 'xml', pattern: '**/pom.xml' },
+            { pattern: '**/build.gradle' }
         ];
         const enableJava = isJavaSupportEnabled();
-        const enableGroovy : boolean = 
conf.get("netbeans.groovySupport.enabled") as boolean;
+        const enableGroovy: boolean = 
conf.get("netbeans.groovySupport.enabled") as boolean;
         if (enableGroovy) {
-            documentSelectors.push({ language: 'groovy'});
+            documentSelectors.push({ language: 'groovy' });
         }
         // Options to control the language client
         let clientOptions: LanguageClientOptions = {
@@ -921,20 +923,20 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             outputChannel: log,
             revealOutputChannelOn: RevealOutputChannelOn.Never,
             progressOnInitialization: true,
-            initializationOptions : {
-                'nbcodeCapabilities' : {
-                    'statusBarMessageSupport' : true,
-                    'testResultsSupport' : true,
-                    'showHtmlPageSupport' : true,
-                    'wantsJavaSupport' : enableJava,
-                    'wantsGroovySupport' : enableGroovy
+            initializationOptions: {
+                'nbcodeCapabilities': {
+                    'statusBarMessageSupport': true,
+                    'testResultsSupport': true,
+                    'showHtmlPageSupport': true,
+                    'wantsJavaSupport': enableJava,
+                    'wantsGroovySupport': enableGroovy
                 }
             },
             errorHandler: {
-                error : function(error: Error, _message: Message, count: 
number): ErrorHandlerResult {
+                error: function (error: Error, _message: Message, count: 
number): ErrorHandlerResult {
                     return { action: ErrorAction.Continue, message: 
error.message };
                 },
-                closed : function(): CloseHandlerResult {
+                closed: function (): CloseHandlerResult {
                     handleLog(log, "Connection to Apache NetBeans Language 
Server closed.");
                     if (!activationPending) {
                         restartWithJDKLater(10000, false);
@@ -946,11 +948,11 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
 
 
         let c = new NbLanguageClient(
-                'java',
-                'NetBeans Java',
-                connection,
-                log,
-                clientOptions
+            'java',
+            'NetBeans Java',
+            connection,
+            log,
+            clientOptions
         );
         handleLog(log, 'Language Client: Starting');
         c.start().then(() => {
@@ -1060,7 +1062,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             handleLog(log, 'Language Client: Ready');
             setClient[0](c);
             commands.executeCommand('setContext', 'nbJavaLSReady', true);
-        
+
             if (enableJava) {
                 // create project explorer:
                 //c.findTreeViewService().createView('foundProjects', 
'Projects', { canSelectMany : false });
@@ -1069,7 +1071,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
 
             createDatabaseView(c);
             if (enableJava) {
-                c.findTreeViewService().createView('cloud.resources', 
undefined, { canSelectMany : false });
+                c.findTreeViewService().createView('cloud.resources', 
undefined, { canSelectMany: false });
             }
         }).catch(setClient[1]);
     }).catch((reason) => {
@@ -1079,11 +1081,11 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
     });
 
     class Decorator implements TreeItemDecorator<Visualizer> {
-        private provider : CustomizableTreeDataProvider<Visualizer>;
-        private setCommand : vscode.Disposable;
+        private provider: CustomizableTreeDataProvider<Visualizer>;
+        private setCommand: vscode.Disposable;
         private initialized: boolean = false;
 
-        constructor(provider : CustomizableTreeDataProvider<Visualizer>, 
client : NbLanguageClient) {
+        constructor(provider: CustomizableTreeDataProvider<Visualizer>, 
client: NbLanguageClient) {
             this.provider = provider;
             this.setCommand = 
vscode.commands.registerCommand('java.local.db.set.preferred.connection', (n) 
=> this.setPreferred(n));
         }
@@ -1095,7 +1097,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             return children;
         }
 
-        async decorateTreeItem(vis : Visualizer, item : vscode.TreeItem) : 
Promise<vscode.TreeItem> {
+        async decorateTreeItem(vis: Visualizer, item: vscode.TreeItem): 
Promise<vscode.TreeItem> {
             if (!(item.contextValue && 
item.contextValue.match(/class:org.netbeans.api.db.explorer.DatabaseConnection/)))
 {
                 return item;
             }
@@ -1119,22 +1121,22 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
         }
     }
 
-    function createDatabaseView(c : NbLanguageClient) {
-        let decoRegister : CustomizableTreeDataProvider<Visualizer>;
-        c.findTreeViewService().createView('database.connections', undefined , 
{
-            canSelectMany : true,
+    function createDatabaseView(c: NbLanguageClient) {
+        let decoRegister: CustomizableTreeDataProvider<Visualizer>;
+        c.findTreeViewService().createView('database.connections', undefined, {
+            canSelectMany: true,
 
-            providerInitializer : (customizable) =>
+            providerInitializer: (customizable) =>
                 customizable.addItemDecorator(new Decorator(customizable, c))
         });
 
     }
 
-    async function createProjectView(ctx : ExtensionContext, client : 
NbLanguageClient) {
-        const ts : TreeViewService = client.findTreeViewService();
-        let tv : vscode.TreeView<Visualizer> = await 
ts.createView('foundProjects', 'Projects', { canSelectMany : false });
+    async function createProjectView(ctx: ExtensionContext, client: 
NbLanguageClient) {
+        const ts: TreeViewService = client.findTreeViewService();
+        let tv: vscode.TreeView<Visualizer> = await 
ts.createView('foundProjects', 'Projects', { canSelectMany: false });
 
-        async function revealActiveEditor(ed? : vscode.TextEditor) {
+        async function revealActiveEditor(ed?: vscode.TextEditor) {
             const uri = window.activeTextEditor?.document?.uri;
             if (!uri || uri.scheme.toLowerCase() !== 'file') {
                 return;
@@ -1142,11 +1144,11 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             if (!tv.visible) {
                 return;
             }
-            let vis : Visualizer | undefined = await ts.findPath(tv, 
uri.toString());
+            let vis: Visualizer | undefined = await ts.findPath(tv, 
uri.toString());
             if (!vis) {
                 return;
             }
-            tv.reveal(vis, { select : true, focus : false, expand : false });
+            tv.reveal(vis, { select: true, focus: false, expand: false });
         }
 
         ctx.subscriptions.push(window.onDidChangeActiveTextEditor(ed => {
@@ -1165,7 +1167,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
 
     const webviews = new Map<string, vscode.Webview>();
 
-    async function showHtmlPage(params : HtmlPageParams): Promise<void> {
+    async function showHtmlPage(params: HtmlPageParams): Promise<void> {
         return new Promise(resolve => {
             let data = params.text;
             const match = /<title>(.*)<\/title>/i.exec(data);
@@ -1201,12 +1203,12 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
             });
             view.onDidDispose(() => {
                 resolve();
-                workspace.fs.delete(resourceDir, {recursive: true});
+                workspace.fs.delete(resourceDir, { recursive: true });
             });
         });
     }
 
-    async function execInHtmlPage(params : HtmlPageParams): Promise<boolean> {
+    async function execInHtmlPage(params: HtmlPageParams): Promise<boolean> {
         return new Promise(resolve => {
             const webview = webviews.get(params.id);
             if (webview) {
@@ -1221,8 +1223,8 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
         });
     }
 
-    function showStatusBarMessage(params : ShowStatusMessageParams) {
-        let decorated : string = params.message;
+    function showStatusBarMessage(params: ShowStatusMessageParams) {
+        let decorated: string = params.message;
         let defTimeout;
 
         switch (params.type) {
@@ -1248,22 +1250,22 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
         }
     }
 
-    function checkInstallNbJavac(msg : string) {
+    function checkInstallNbJavac(msg: string) {
         const NO_JAVA_SUPPORT = "Cannot initialize Java support";
         if (msg.startsWith(NO_JAVA_SUPPORT)) {
             const yes = "Install GPLv2+CPEx code";
             window.showErrorMessage("Additional Java Support is needed", 
yes).then(reply => {
                 if (yes === reply) {
                     vscode.window.setStatusBarMessage("Preparing Apache 
NetBeans Language Server for additional installation", 2000);
-                    restartWithJDKLater = function() {
+                    restartWithJDKLater = function () {
                         handleLog(log, "Ignoring request for restart of Apache 
NetBeans Language Server");
                     };
                     maintenance = new Promise((resolve, reject) => {
-                        const kill : Promise<void> = killNbProcess(false, log);
+                        const kill: Promise<void> = killNbProcess(false, log);
                         kill.then(() => {
                             let installProcess = launcher.launch(info, 
"-J-Dnetbeans.close=true", "--modules", "--install", ".*nbjavac.*");
                             handleLog(log, "Launching installation process: " 
+ installProcess.pid);
-                            let logData = function(d: any) {
+                            let logData = function (d: any) {
                                 handleLogNoNL(log, d.toString());
                             };
                             installProcess.stdout.on('data', logData);
@@ -1271,7 +1273,7 @@ function doActivateWithJDK(specifiedJDK: string | null, 
context: ExtensionContex
                             installProcess.addListener("error", reject);
                             // MUST wait on 'close', since stdout is inherited 
by children. The installProcess dies but
                             // the inherited stream will be closed by the last 
child dying.
-                            installProcess.on('close', function(code: number) {
+                            installProcess.on('close', function (code: number) 
{
                                 handleLog(log, "Installation completed: " + 
installProcess.pid);
                                 handleLog(log, "Additional Java Support 
installed with exit code " + code);
                                 // will be actually run after maintenance is 
resolve()d.
@@ -1340,15 +1342,15 @@ class NetBeansDebugAdapterDescriptionFactory implements 
vscode.DebugAdapterDescr
 class NetBeansConfigurationInitialProvider implements 
vscode.DebugConfigurationProvider {
 
     provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, 
token?: vscode.CancellationToken): 
vscode.ProviderResult<vscode.DebugConfiguration[]> {
-       return this.doProvideDebugConfigurations(folder, token);
+        return this.doProvideDebugConfigurations(folder, token);
     }
 
-    async doProvideDebugConfigurations(folder: vscode.WorkspaceFolder | 
undefined, _token?:  vscode.CancellationToken):  
Promise<vscode.DebugConfiguration[]> {
-        let c : LanguageClient = await client;
+    async doProvideDebugConfigurations(folder: vscode.WorkspaceFolder | 
undefined, _token?: vscode.CancellationToken): 
Promise<vscode.DebugConfiguration[]> {
+        let c: LanguageClient = await client;
         if (!folder) {
             return [];
         }
-        var u : vscode.Uri | undefined;
+        var u: vscode.Uri | undefined;
         if (folder && folder.uri) {
             u = folder.uri;
         } else {
@@ -1357,9 +1359,9 @@ class NetBeansConfigurationInitialProvider implements 
vscode.DebugConfigurationP
         let result : vscode.DebugConfiguration[] = [];
         const configNames : string[] | null | undefined = await 
vscode.commands.executeCommand('java.project.configurations', u?.toString());
         if (configNames) {
-            let first : boolean = true;
+            let first: boolean = true;
             for (let cn of configNames) {
-                let cname : string;
+                let cname: string;
 
                 if (first) {
                     // ignore the default config, comes first.
@@ -1368,7 +1370,7 @@ class NetBeansConfigurationInitialProvider implements 
vscode.DebugConfigurationP
                 } else {
                     cname = "Launch Java: " + cn;
                 }
-                const debugConfig : vscode.DebugConfiguration = {
+                const debugConfig: vscode.DebugConfiguration = {
                     name: cname,
                     type: "java+",
                     request: "launch",
@@ -1391,11 +1393,11 @@ class NetBeansConfigurationDynamicProvider implements 
vscode.DebugConfigurationP
     }
 
     provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, 
token?: vscode.CancellationToken): 
vscode.ProviderResult<vscode.DebugConfiguration[]> {
-       return this.doProvideDebugConfigurations(folder, this.context, 
this.commandValues, token);
+        return this.doProvideDebugConfigurations(folder, this.context, 
this.commandValues, token);
     }
 
-    async doProvideDebugConfigurations(folder: vscode.WorkspaceFolder | 
undefined, context: ExtensionContext, commandValues: Map<string, string>, 
_token?:  vscode.CancellationToken):  Promise<vscode.DebugConfiguration[]> {
-        let c : LanguageClient = await client;
+    async doProvideDebugConfigurations(folder: vscode.WorkspaceFolder | 
undefined, context: ExtensionContext, commandValues: Map<string, string>, 
_token?: vscode.CancellationToken): Promise<vscode.DebugConfiguration[]> {
+        let c: LanguageClient = await client;
         if (!folder) {
             return [];
         }
@@ -1403,7 +1405,7 @@ class NetBeansConfigurationDynamicProvider implements 
vscode.DebugConfigurationP
         const attachConnectors : DebugConnector[] | null | undefined = await 
vscode.commands.executeCommand('java.attachDebugger.configurations');
         if (attachConnectors) {
             for (let ac of attachConnectors) {
-                const debugConfig : vscode.DebugConfiguration = {
+                const debugConfig: vscode.DebugConfiguration = {
                     name: ac.name,
                     type: ac.type,
                     request: "attach",
diff --git a/java/java.lsp.server/vscode/src/propertiesView/controlTypes.ts 
b/java/java.lsp.server/vscode/src/propertiesView/controlTypes.ts
new file mode 100644
index 0000000000..aabe501b85
--- /dev/null
+++ b/java/java.lsp.server/vscode/src/propertiesView/controlTypes.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at 
https://oss.oracle.com/licenses/upl.
+ */
+import { EnumType, KeyOfArray, Typed } from "../typesUtil";
+
+export type ID = number;
+
+export const PropTypes: KeyOfArray<PropTypeMap> = [
+    "java.lang.String",
+    "java.lang.Boolean",
+    "java.util.Properties",
+    "unknown"
+];// unfortunate but necessary duplication
+export type PropTypeMap = {
+    "java.lang.String": string;
+    "java.lang.Boolean": boolean;
+    "java.util.Properties": Record<string, string>;
+    "unknown": unknown
+};
+export type Property<T extends keyof PropTypeMap = keyof PropTypeMap> = T 
extends T ? {
+    propPref: boolean;
+    propDispName: string;
+    propShortName: string;
+    propWrite: boolean;
+    propHidden: boolean;
+    propExpert: boolean;
+    propType: T;
+    propValue: PropTypeMap[T];
+    propName: string;
+} : never; // Distributive type
+export type Properties = {
+    propPref: boolean;
+    propDispName: string;
+    propShortName: string;
+    propHidden: boolean;
+    propExpert: boolean;
+    propName: string;
+    props: Property[];
+};
+
+export type MessageProp = {
+    name: string;
+    value: string | boolean | Record<string, string>;
+};
+
+export type Command = "Save" | "Cancel" | "Error" | "Info";
+export const CommandKey: EnumType<Command> = {
+    Save: "Save",
+    Error: "Error",
+    Info: "Info",
+    Cancel: "Cancel"
+};
+
+export type MessageCommon<T extends Command> = Typed<T>;
+export type InfoMessage = MessageCommon<typeof CommandKey.Info> & {
+    info: string;
+};
+export type ErrMessage = MessageCommon<typeof CommandKey.Error> & {
+    error: string;
+    stack?: string;
+};
+export type SaveMessage = MessageCommon<typeof CommandKey.Save> & {
+    properties: MessageProp[];
+};
+export type CancelMessage = MessageCommon<typeof CommandKey.Cancel>;
+export type Message = InfoMessage | ErrMessage | SaveMessage | CancelMessage;
\ No newline at end of file
diff --git 
a/java/java.lsp.server/vscode/src/propertiesView/propertiesHtmlBuilder.ts 
b/java/java.lsp.server/vscode/src/propertiesView/propertiesHtmlBuilder.ts
new file mode 100644
index 0000000000..e638d2432b
--- /dev/null
+++ b/java/java.lsp.server/vscode/src/propertiesView/propertiesHtmlBuilder.ts
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at 
https://oss.oracle.com/licenses/upl.
+ */
+import * as vscode from 'vscode';
+import { Properties, Property } from "./controlTypes";
+
+export function makeHtmlForProperties(name: string, nonce: string, scriptUri: 
vscode.Uri, properties: Properties): string {
+    return `<!DOCTYPE html>
+    <html lang="en">
+    
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="Content-Security-Policy" content="default-src 
'none'; script-src 'nonce-${nonce}';">
+        <title>${name}</title>
+    </head>
+    
+    <body>
+        <h1>${name} Properties</h1>
+        <vscode-divider></vscode-divider>
+        <table>
+            ${makePropertiesTable(properties)}
+            <tr>
+                <td colspan="2">
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2" align="right" style="text-align: right;">
+                    <vscode-button id="save" 
appearance="primary">Save</vscode-button>
+                    <vscode-button id="cancel" 
appearance="secondary">Cancel</vscode-button>
+                </td>
+            </tr>
+        </table>
+        <script type="module" nonce="${nonce}" src="${scriptUri}"></script>
+    </body>
+    
+    </html>`
+};
+
+function wrapToTable(name: string, content: string, separator: string = ":"): 
string {
+    return `<tr><td align="right"><b>${name}${separator}</b></td><td 
align="left">${content}</td></tr>`;
+}
+
+function makePropertiesTable(properties: Properties): string {
+    let html = "";
+    for (const prop of properties.props) {
+        html += makePropAccess(prop);
+    }
+    return html;
+}
+
+function makePropAccess(prop: Property): string {
+    let out: string;
+    switch (prop.propType) {
+        case 'java.lang.String':
+            out = makeStringAccess(prop);
+            break;
+        case 'java.lang.Boolean':
+            out = makeBoolAccess(prop);
+            break;
+        case 'java.util.Properties':
+            out = makePropertiesAccess(prop);
+            break;
+        default:
+            out = prop.propValue + "";
+            break;
+    }
+    return wrapToTable(prop.propDispName, out) + '\n';
+}
+
+function makeStringAccess(prop: Property<'java.lang.String'>) {
+    return `<vscode-text-field name="input" id="${prop.propName}" 
value="${encode(prop.propValue)}" ${prop.propWrite ? "" : 
"disabled"}></vscode-text-field>`;
+}
+
+function makeBoolAccess(prop: Property<'java.lang.Boolean'>) {
+    return `<vscode-checkbox name="input" id="${prop.propName}" 
${prop.propWrite ? "" : "disabled"} ${prop.propValue ? "checked" : 
""}></vscode-checkbox>`;
+}
+
+function makePropertiesAccess(prop: Property<'java.util.Properties'>) {
+    return `<details><summary><b>${prop.propDispName}</b></summary><table 
name="input" id="${prop.propName}">
+    ${makePropTable(prop)}
+    </table></details>`;
+}
+
+function makePropTable(prop: Property<'java.util.Properties'>) {
+    let out = "";
+    for (const key in prop.propValue) {
+        out += makePropRow(prop, key) + '\n';
+    }
+    return out;
+}
+
+function makePropRow(prop: Property<'java.util.Properties'>, key: string) {
+    return wrapToTable(asTextField(key, prop.propWrite, "name"), 
asTextField(prop.propValue[key], prop.propWrite, "value"), " = ");
+}
+
+function asTextField(value: string, enabled: boolean, name: string) {
+    return `<vscode-text-field class="${name}" value="${encode(value)}" 
${enabled ? "" : "disabled"}></vscode-text-field>`
+}
+
+function encode(value: string): string {
+    return value.replace(/\"/g, "&quot;");
+}
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/src/propertiesView/propertiesView.ts 
b/java/java.lsp.server/vscode/src/propertiesView/propertiesView.ts
new file mode 100644
index 0000000000..627b8ab32c
--- /dev/null
+++ b/java/java.lsp.server/vscode/src/propertiesView/propertiesView.ts
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at 
https://oss.oracle.com/licenses/upl.
+ */
+
+import * as vscode from 'vscode';
+import { CommandKey, ID, Message, MessageProp, Properties, Property, PropTypes 
} from './controlTypes';
+import { asClass, assertNever } from '../typesUtil';
+import { makeHtmlForProperties } from './propertiesHtmlBuilder';
+
+export class PropertiesView {
+       private static readonly COMMAND_GET_NODE_PROPERTIES = 
"java.node.properties.get";      // NOI18N
+       private static readonly COMMAND_SET_NODE_PROPERTIES = 
"java.node.properties.set";      // NOI18N
+
+       private static extensionUri: vscode.Uri;
+       private static scriptPath: vscode.Uri;
+       private static panels: Record<ID, PropertiesView> = {};
+
+       private readonly _panel: vscode.WebviewPanel;
+       private readonly id: ID;
+       private readonly name: string;
+       private readonly _disposables: vscode.Disposable[] = [];
+
+       private properties?: Properties;
+
+       public static async createOrShow(context: vscode.ExtensionContext, 
node: any) {
+               if (!node)
+                       return;
+               const id = node.id;
+               // If we already have a panel, show it.
+               const current = PropertiesView.panels[id];
+               try {
+                       if (current) {
+                               await current.load();
+                               current._panel.reveal();
+                               return;
+                       }
+                       if (!PropertiesView.extensionUri) {
+                               PropertiesView.extensionUri = 
context.extensionUri;
+                               PropertiesView.scriptPath = 
vscode.Uri.joinPath(context.extensionUri, 'out', 'script.js');
+                       } else if (PropertiesView.extensionUri !== 
context.extensionUri)
+                               throw new Error("Extension paths differ.");
+                       // Otherwise, create a new panel.
+                       PropertiesView.panels[id] = new PropertiesView(id, 
node.tooltip + " " + node.label);
+               } catch (e: unknown) {
+                       console.log(e);
+               }
+       }
+
+       private constructor(id: ID, name: string) {
+               this.id = id;
+               this.name = name;
+               this._panel = vscode.window.createWebviewPanel('Properties', 
'Properties', vscode.ViewColumn.One, {
+                       // Enable javascript in the webview
+                       enableScripts: true,
+               });
+
+               // Set the webview's html content
+               this.load().then(() =>
+                       this.setHtml()).catch((e) => {
+                               console.error(e);
+                               this.dispose();
+                       });
+
+               // Listen for when the panel is disposed
+               // This happens when the user closes the panel or when the 
panel is closed programatically
+               this._panel.onDidDispose(() => this.dispose(), null, 
this._disposables);
+
+               // Update the content based on view changes
+               this._panel.onDidChangeViewState(
+                       () => {
+                               if (this._panel.visible) {
+                                       try {
+                                               this.setHtml();
+                                       } catch (e: unknown) {
+                                               console.error(e);
+                                               this.dispose();
+                                       }
+                               }
+                       },
+                       null,
+                       this._disposables
+               );
+
+               // Handle messages from the webview
+               this._panel.webview.onDidReceiveMessage(
+                       message => {
+                               try {
+                                       this.processMessage(message);
+                               } catch (e: unknown) {
+                                       console.error(e);
+                                       this.dispose();
+                               }
+                       },
+                       undefined,
+                       this._disposables
+               );
+       }
+
+       private async load() {
+               const props = await this.get();
+               if (props.length === 0)
+                       throw new Error("No properties.");
+               this.properties = props[0] as Properties;
+       }
+
+       private async get() {
+               return asClass(Array, await 
vscode.commands.executeCommand(PropertiesView.COMMAND_GET_NODE_PROPERTIES, 
this.id));
+       }
+
+       private save(properties: MessageProp[]) {
+               for (const prop of properties)
+                       this.mergeProps(prop, this.properties?.props);
+               
vscode.commands.executeCommand(PropertiesView.COMMAND_SET_NODE_PROPERTIES, 
this.id, [this.properties]);
+       }
+
+       private mergeProps(prop: MessageProp, props?: Property[]): void {
+               const p = props?.find(p => p.propName === prop.name);
+               if (p && PropTypes.includes(p.propType))
+                       p.propValue = prop.value;
+       }
+
+       private processMessage(message: Message) {
+               switch (message._type) {
+                       case CommandKey.Save:
+                               this.save(message.properties);
+                       case CommandKey.Cancel:
+                               this.dispose();
+                               break;
+                       case CommandKey.Error:
+                               console.error(message.error);
+                               if (message.stack)
+                                       console.error(message.stack);
+                               this.dispose();
+                               break;
+                       case CommandKey.Info:
+                               console.log(message.info);
+                               break;
+                       default:
+                               assertNever(message, "Got unknown message: " + 
JSON.stringify(message));
+               }
+       }
+
+       private static getNonce() {
+               let text = "";
+               const possible = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+               for (let i = 0; i < 32; i++) {
+                       text += possible.charAt(Math.floor(Math.random() * 
possible.length));
+               }
+               return text;
+       }
+
+       private setHtml() {
+               if (!this.properties)
+                       throw new Error("No properties to show.");
+               const script = 
this._panel.webview.asWebviewUri(PropertiesView.scriptPath);
+               const html = makeHtmlForProperties(this.name, 
PropertiesView.getNonce(), script, this.properties);
+               this._panel.webview.html = html;
+       }
+
+       public dispose() {
+               delete PropertiesView.panels[this.id];
+               // Clean up our resources
+               this._panel.dispose();
+               while (this._disposables.length) {
+                       const x = this._disposables.pop();
+                       if (x) {
+                               x.dispose();
+                       }
+               }
+       }
+}
diff --git a/java/java.lsp.server/vscode/src/propertiesView/script.ts 
b/java/java.lsp.server/vscode/src/propertiesView/script.ts
new file mode 100644
index 0000000000..6fe32a10de
--- /dev/null
+++ b/java/java.lsp.server/vscode/src/propertiesView/script.ts
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at 
https://oss.oracle.com/licenses/upl.
+ */
+import { provideVSCodeDesignSystem, vsCodeButton, vsCodeTextField, 
vsCodeDivider, vsCodeCheckbox, Button, TextField, Checkbox } from 
"@vscode/webview-ui-toolkit";
+import { isError, asClass, isClass } from "../typesUtil";
+import { CommandKey, Message, MessageProp } from "./controlTypes";
+
+provideVSCodeDesignSystem().register(vsCodeButton(), vsCodeTextField(), 
vsCodeDivider(), vsCodeCheckbox());
+
+const vscode = acquireVsCodeApi();
+document.addEventListener("DOMContentLoaded", () => {
+    try {
+        asClass(Button, document.getElementById('save'), "Not save.")
+            .addEventListener('click', () => {
+                try {
+                    if (validate())
+                        sendMessage({ _type: CommandKey.Save, properties: 
getProperties() });
+                } catch (e: unknown) {
+                    handleError(e);
+                }
+            });
+        asClass(Button, document.getElementById('cancel'), "Not cancel.")
+            .addEventListener('click', () => {
+                sendMessage({ _type: CommandKey.Cancel });
+            });
+    } catch (e: unknown) {
+        handleError(e);
+    }
+});
+
+function handleError(error: unknown) {
+    if (isError(error))
+        sendMessage({ _type: CommandKey.Error, error: error.message, stack: 
error.stack });
+    else
+        sendMessage({ _type: CommandKey.Error, error: JSON.stringify(error) });
+}
+
+function sendMessage(message: Message) {
+    vscode.postMessage(message);
+}
+
+function getProperties(): MessageProp[] {
+    const out: MessageProp[] = [];
+    const elements = document.getElementsByName("input");
+    for (let i = 0; i < elements.length; ++i) {
+        const element = elements.item(i);
+        if (element)
+            out.push(getProperty(element));
+    }
+    return out;
+}
+
+function getProperty(element: HTMLElement): MessageProp {
+    if (isClass(TextField, element)) {
+        return makeProperty(element.value, element?.id);
+    } else if (isClass(Checkbox, element)) {
+        return makeProperty(element.checked, element?.id);
+    } else if (isClass(HTMLTableElement, element)) {
+        return makeProperty(parseProperties(element), element?.id);
+    }
+    return { name: element?.id || "", value: element?.nodeValue || "" };
+}
+
+function makeProperty(value: string | boolean | Record<string, string>, name?: 
string): MessageProp {
+    return { name: name || "NoID", value: value };
+}
+
+function parseProperties(table: HTMLTableElement): Record<string, string> {
+    const out: Record<string, string> = {};
+    for (let i = 0; i < table.rows.length; ++i) {
+        readProperty(out, table.rows.item(i)?.cells);
+    }
+    return out;
+}
+
+function readProperty(out: Record<string, string>, cells?: 
HTMLCollectionOf<HTMLTableCellElement> | null) {
+    out[asClass(TextField, 
cells?.item(0)?.getElementsByClassName("name").item(0)).value]
+        = asClass(TextField, 
cells?.item(1)?.getElementsByClassName("value").item(0)).value;
+}
+
+function validate(): boolean {
+    return true; // no validation needed ATM
+}
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/src/typesUtil.ts 
b/java/java.lsp.server/vscode/src/typesUtil.ts
new file mode 100644
index 0000000000..b79dbc1c48
--- /dev/null
+++ b/java/java.lsp.server/vscode/src/typesUtil.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at 
https://oss.oracle.com/licenses/upl.
+ */
+
+export type IsType<T> = (obj: unknown) => obj is T;
+
+function assertType<T>(obj: unknown, isTypeTest: IsType<T>, errorMessage?: 
string): asserts obj is T {
+    if (!isTypeTest(obj))
+        throw new Error(errorMessage || "Object isn't of expected type.");
+}
+
+export type Constructor<T> = new (...args: any) => T;
+
+export function isClass<T>(cls: Constructor<T>, obj: unknown): obj is T {
+    return obj instanceof cls;
+}
+export function isClassTest<T>(cls: Constructor<T>): ((obj: unknown) => obj is 
T) {
+    return (obj: unknown): obj is T => isClass(cls, obj);
+}
+export function asClass<T>(cls: Constructor<T>, obj: unknown, errorMessage?: 
string): T {
+    assertType(obj, isClassTest(cls), errorMessage);
+    return obj;
+}
+
+export function isError(obj: unknown): obj is Error {
+    return obj instanceof Error;
+}
+
+export function assertNever(_obj: never, errorMessage?: string): never {
+    throw new Error(errorMessage || "Shouldn't reach here.");
+}
+
+export type KeyOfArray<T> = TupleUnion<keyof T>;
+export type TupleUnion<U extends PropertyKey, R extends PropertyKey[] = []> = {
+    [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, 
S>, [...R, S]>;
+}[U];
+
+export type EnumType<T extends PropertyKey> = { readonly [P in T]: P };
+export type Typed<T extends PropertyKey> = { _type: T };
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/tsconfig.json 
b/java/java.lsp.server/vscode/tsconfig.json
index b65c745109..64351bb6a4 100644
--- a/java/java.lsp.server/vscode/tsconfig.json
+++ b/java/java.lsp.server/vscode/tsconfig.json
@@ -4,7 +4,8 @@
                "target": "es6",
                "outDir": "out",
                "lib": [
-                       "es6"
+                       "ES2020",
+                       "DOM"
                ],
                "sourceMap": true,
                "rootDir": "src",
diff --git a/nbbuild/licenses/MIT-sindre-sorhus 
b/nbbuild/licenses/MIT-sindre-sorhus
new file mode 100644
index 0000000000..fa7ceba3eb
--- /dev/null
+++ b/nbbuild/licenses/MIT-sindre-sorhus
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresor...@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.
diff --git 
a/nbbuild/misc/prepare-bundles/src/main/java/org/netbeans/prepare/bundles/PrepareBundles.java
 
b/nbbuild/misc/prepare-bundles/src/main/java/org/netbeans/prepare/bundles/PrepareBundles.java
index f8f0c21d63..5349a20e09 100644
--- 
a/nbbuild/misc/prepare-bundles/src/main/java/org/netbeans/prepare/bundles/PrepareBundles.java
+++ 
b/nbbuild/misc/prepare-bundles/src/main/java/org/netbeans/prepare/bundles/PrepareBundles.java
@@ -105,6 +105,8 @@ public class PrepareBundles {
                 if (".bin".equals(module.getFileName().toString())) continue;
                 if 
(".package-lock.json".equals(module.getFileName().toString())) continue;
                 if ("@types".equals(module.getFileName().toString())) continue;
+                if ("@esbuild".equals(module.getFileName().toString())) 
continue;
+                if ("@microsoft".equals(module.getFileName().toString())) 
continue;
                 if ("@vscode".equals(module.getFileName().toString())) {
                     try (DirectoryStream<Path> sds = 
Files.newDirectoryStream(module)) {
                         for (Path sModule : sds) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


Reply via email to