diff --git a/.vscode/launch.json b/.vscode/launch.json index 1bfe6c2..fecb366 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "${workspaceRoot}/client/out/**/*.js", "${workspaceRoot}/serverJS/out/**/*.js" ], - "preLaunchTask": "npm" + "preLaunchTask": "npm: watch" }, { "name": "Launch Tests", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0309598..0ccfeb8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -15,7 +15,7 @@ "label": "npm", "type": "shell", "command": "npm", - "args": ["run", "compile", "--loglevel", "silent"], //custom script "compile" as defined in package.json + "args": ["run", "watch"], //custom script "watch" as defined in package.json "presentation": { "echo": false, "reveal":"silent", @@ -25,7 +25,20 @@ }, "isBackground": true, // tsc compiler is started in watching mode "problemMatcher": ["$tsc-watch"] - } + }, + { + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + } ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bfee5..01d3dbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Add native token based authentication (#247) +- Refactor configuration entries (#247) +- Remove 3rd Party references and rename console setting (#247) +- Replace deprecated http library (#247) + ## [0.8.2] - 2021-03-19 - Dependency fixes (#239) diff --git a/client/package-lock.json b/client/package-lock.json index 5d81587..a80855d 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,9 +1,602 @@ { "name": "openhab-vscode-extension", "version": "0.8.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "openhab-vscode-extension", + "version": "0.8.0", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "ascii-table": "0.0.9", + "axios": "^0.21.1", + "copy-paste": "^1.3.0", + "lodash": "^4.17.20", + "request": "^2.88.2", + "request-promise-native": "^1.0.9", + "vscode-languageclient": "6.0.0-next.1" + }, + "devDependencies": { + "@types/axios": "^0.14.0", + "@types/vscode": "^1.14.0" + }, + "engines": { + "vscode": "^1.37.0" + } + }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dev": true, + "dependencies": { + "axios": "*" + } + }, + "node_modules/@types/vscode": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz", + "integrity": "sha512-Kt3bvWzAvvF/WH9YEcrCICDp0Z7aHhJGhLJ1BxeyNP6yRjonWqWnAIh35/pXAjswAnWOABrYlF7SwXR9+1nnLA==", + "dev": true + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/ascii-table": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ascii-table/-/ascii-table-0.0.9.tgz", + "integrity": "sha1-BqZgTWpV1L9BqaR9mHLXp42jHnM=" + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/copy-paste": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/copy-paste/-/copy-paste-1.3.0.tgz", + "integrity": "sha1-p+bEocKP3t8rCB5yuX3y75X0ce0=", + "dependencies": { + "iconv-lite": "^0.4.8" + }, + "optionalDependencies": { + "sync-exec": "~0.6.x" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "dependencies": { + "mime-db": "1.45.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sync-exec": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz", + "integrity": "sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=", + "optional": true + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "5.0.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz", + "integrity": "sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg==", + "engines": { + "node": ">=8.0.0 || >=10.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "6.0.0-next.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz", + "integrity": "sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg==", + "dependencies": { + "semver": "^6.3.0", + "vscode-languageserver-protocol": "^3.15.0-next.9" + }, + "engines": { + "vscode": "^1.38.0" + } + }, + "node_modules/vscode-languageclient/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.15.0-next.9", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz", + "integrity": "sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g==", + "dependencies": { + "vscode-jsonrpc": "^5.0.0-next.2", + "vscode-languageserver-types": "^3.15.0-next.5" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.15.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz", + "integrity": "sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw==" + } + }, "dependencies": { + "@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", + "dev": true, + "requires": { + "axios": "*" + } + }, "@types/vscode": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz", @@ -54,6 +647,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -131,6 +732,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", diff --git a/client/package.json b/client/package.json index 0549b0b..dee61d7 100644 --- a/client/package.json +++ b/client/package.json @@ -18,10 +18,9 @@ }, "dependencies": { "ascii-table": "0.0.9", + "axios": "^0.21.1", "copy-paste": "^1.3.0", "lodash": "^4.17.20", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "vscode-languageclient": "6.0.0-next.1" }, "devDependencies": { diff --git a/client/src/HoverProvider/HoverProvider.ts b/client/src/HoverProvider/HoverProvider.ts index 5980a72..4cea4fc 100644 --- a/client/src/HoverProvider/HoverProvider.ts +++ b/client/src/HoverProvider/HoverProvider.ts @@ -3,8 +3,10 @@ import { MarkdownString } from 'vscode' -import * as utils from '../Utils' -import * as request from 'request-promise-native' +import * as utils from '../Utils/Utils' +import axios, { AxiosRequestConfig } from 'axios' +import { ConfigManager } from '../Utils/ConfigManager' +import { OH_CONFIG_PARAMETERS } from '../Utils/types' /** * Handles hover actions in editor windows. @@ -92,10 +94,20 @@ export class HoverProvider { private getRestItemHover(hoveredText: string): Thenable { return new Promise((resolve, reject) => { console.log(`Requesting => ${utils.getHost()}/rest/items/${hoveredText} <= now`) + let config: AxiosRequestConfig = { + url: utils.getHost() + `/rest/items/${hoveredText}`, + headers: {} + } - request(`${utils.getHost()}/rest/items/${hoveredText}`) + if(ConfigManager.tokenAuthAvailable()){ + config.headers = { + 'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken) + } + } + + axios(config) .then((response) => { - let result = JSON.parse(response) + let result = response.data if (!result.error) { let resultText = new MarkdownString() @@ -146,13 +158,23 @@ export class HoverProvider { * @returns **true** when update was successful, **false** otherwise */ public updateItems() : Boolean { + let config: AxiosRequestConfig = { + url: utils.getHost() + '/rest/items', + headers: {} + } - request(`${utils.getHost()}/rest/items/`) + if(ConfigManager.tokenAuthAvailable()){ + config.headers = { + 'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken) + } + } + + axios(config) .then((response) => { // Clear prossible existing array this.knownItems = new Array() - let result = JSON.parse(response) + let result = response.data result.forEach(item => { this.knownItems.push(item.name) diff --git a/client/src/ItemsExplorer/ItemsCompletion.ts b/client/src/ItemsExplorer/ItemsCompletion.ts index abafa64..17f65e1 100644 --- a/client/src/ItemsExplorer/ItemsCompletion.ts +++ b/client/src/ItemsExplorer/ItemsCompletion.ts @@ -11,6 +11,8 @@ import { import { Item } from './Item' import { ItemsModel } from './ItemsModel' import * as _ from 'lodash' +import { ConfigManager } from '../Utils/ConfigManager' +import { OH_CONFIG_PARAMETERS } from '../Utils/types' /** * Produces a list of openHAB items completions @@ -30,9 +32,7 @@ export class ItemsCompletion implements CompletionItemProvider { public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable { return new Promise((resolve, reject) => { - let config = workspace.getConfiguration('openhab') - - if (config.useRestApi) { + if (ConfigManager.get(OH_CONFIG_PARAMETERS.useRestApi)) { this.model.completions.then(completions => { resolve(completions.map((item: Item) => { let completionItem = _.assign(new CompletionItem(item.name), { diff --git a/client/src/ItemsExplorer/ItemsModel.ts b/client/src/ItemsExplorer/ItemsModel.ts index 0fc8cee..0e24d28 100644 --- a/client/src/ItemsExplorer/ItemsModel.ts +++ b/client/src/ItemsExplorer/ItemsModel.ts @@ -5,10 +5,12 @@ import { workspace } from 'vscode' import { Item } from './Item' -import * as utils from '../Utils' +import * as utils from '../Utils/Utils' import * as _ from 'lodash' -import * as request from 'request-promise-native' +import axios, { AxiosRequestConfig } from 'axios' +import { ConfigManager } from '../Utils/ConfigManager' +import { OH_CONFIG_PARAMETERS } from '../Utils/types' /** * Collects Items in JSON format from REST API @@ -59,21 +61,26 @@ export class ItemsModel { * @param transform callback */ private sendRequest(uri: string, transform): Thenable { - let options = { - uri: uri || utils.getHost() + '/rest/items', - json: true, - encoding: 'utf8' + let config: AxiosRequestConfig = { + url: uri || utils.getHost() + '/rest/items', + headers: {} + } + + if(ConfigManager.tokenAuthAvailable()){ + config.headers = { + 'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken) + } } return new Promise((resolve, _reject) => { - request(options) - .then(function (response: Item[] | Item) { - resolve(transform(response)) - }.bind(this)) - .catch(err => { - utils.appendToOutput(`Could not reload items for Items Explorer`) - utils.handleRequestError(err).then(err => resolve([])) - }) + axios(config) + .then(function (response) { + resolve(transform(response.data as Item[] | Item)) + }.bind(this)) + .catch(err => { + utils.appendToOutput(`Could not reload items for Items Explorer`) + utils.handleRequestError(err).then(err => resolve([])) + }) }) } diff --git a/client/src/LanguageClient/LocalLanguageClientProvider.ts b/client/src/LanguageClient/LocalLanguageClientProvider.ts index 5cfe3b1..52a218c 100644 --- a/client/src/LanguageClient/LocalLanguageClientProvider.ts +++ b/client/src/LanguageClient/LocalLanguageClientProvider.ts @@ -7,7 +7,9 @@ import { LanguageClient, LanguageClientOptions, TransportKind, - ServerOptions + ServerOptions, + ErrorAction, + CloseAction } from 'vscode-languageclient' import * as path from 'path' @@ -46,10 +48,16 @@ export class LocalLanguageClientProvider { configurationSection: "openhab", fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), }, + // Disable the default error handler + errorHandler: { + error: () => ErrorAction.Continue, + closed: () => CloseAction.DoNotRestart + } } // Create the language client and start the client. const lc = new LanguageClient("openhabLanguageServer", "Openhab Language Server", serverOptions, clientOptions) return lc.start() } + } \ No newline at end of file diff --git a/client/src/LanguageClient/RemoteLanguageClientProvider.ts b/client/src/LanguageClient/RemoteLanguageClientProvider.ts index 0cd7e57..d58ab70 100644 --- a/client/src/LanguageClient/RemoteLanguageClientProvider.ts +++ b/client/src/LanguageClient/RemoteLanguageClientProvider.ts @@ -10,17 +10,21 @@ import { LanguageClient, LanguageClientOptions } from 'vscode-languageclient' +import { ConfigManager } from '../Utils/ConfigManager' +import { OH_CONFIG_PARAMETERS } from '../Utils/types' + +import * as utils from '../Utils/Utils' export class RemoteLanguageClientProvider { constructor() { } public connect(): Disposable { - let config = workspace.getConfiguration('openhab') - let host = config.host.includes('://') ? config.host.split('://')[1] : config.host + let hostConfig = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.host) as string + let host = hostConfig.includes('://') ? hostConfig.split('://')[1] : hostConfig let connectionInfo = { host: host, - port: config.remoteLspPort + port: ConfigManager.get(OH_CONFIG_PARAMETERS.languageserver.remotePort) as number } let extensions = [ @@ -49,7 +53,9 @@ export class RemoteLanguageClientProvider { synchronize: { configurationSection: "openhab", fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), - } + }, + outputChannelName: "openHAB Extension", + outputChannel: utils.getOutputChannel() } // Create the language client and start the client. diff --git a/client/src/ThingsExplorer/ItemsProvider.ts b/client/src/ThingsExplorer/ItemsProvider.ts index 1bcea14..cae715f 100644 --- a/client/src/ThingsExplorer/ItemsProvider.ts +++ b/client/src/ThingsExplorer/ItemsProvider.ts @@ -9,7 +9,7 @@ import * as AsciiTable from 'ascii-table' import { Thing } from './Thing' import { Channel } from './Channel' -import { humanize } from '../Utils' +import { humanize } from '../Utils/Utils' /** generate an Item name from a Thing label by using the configured casing */ function generateItemName(label: string) : string { diff --git a/client/src/ThingsExplorer/ThingsModel.ts b/client/src/ThingsExplorer/ThingsModel.ts index df91722..bbcaf27 100644 --- a/client/src/ThingsExplorer/ThingsModel.ts +++ b/client/src/ThingsExplorer/ThingsModel.ts @@ -1,15 +1,11 @@ -import { - commands, - Uri, - window, - workspace -} from 'vscode' import { Thing } from './Thing' import { Channel } from './Channel' -import * as utils from '../Utils' +import * as utils from '../Utils/Utils' import * as _ from 'lodash' -import * as request from 'request-promise-native' +import axios, { AxiosRequestConfig } from 'axios' +import { ConfigManager } from '../Utils/ConfigManager' +import { OH_CONFIG_PARAMETERS } from '../Utils/types' /** @@ -41,21 +37,26 @@ export class ThingsModel { } private sendRequest(uri: string, transform): Thenable { - let options = { - uri: uri || utils.getHost() + '/rest/things', - json: true, - encoding: 'utf8' + let config: AxiosRequestConfig = { + url: uri || utils.getHost() + '/rest/things', + headers: {} + } + + if(ConfigManager.tokenAuthAvailable()){ + config.headers = { + 'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken) + } } return new Promise((resolve, reject) => { - request(options) - .then(function (response: Thing[] | Thing) { - resolve(this.sort(transform(response))) - }.bind(this)) - .catch(err => { - utils.appendToOutput(`Could not reload items for Things Explorer`) - utils.handleRequestError(err).then(err => resolve([])) - }) + axios(config) + .then(function (response) { + resolve(this.sort(transform(response.data as Thing[] | Thing))) + }.bind(this)) + .catch(err => { + utils.appendToOutput(`Could not reload items for Things Explorer`) + utils.handleRequestError(err).then(err => resolve([])) + }) }) } diff --git a/client/src/Utils/ConfigManager.ts b/client/src/Utils/ConfigManager.ts new file mode 100644 index 0000000..8afc96c --- /dev/null +++ b/client/src/Utils/ConfigManager.ts @@ -0,0 +1,265 @@ +import axios, { AxiosRequestConfig } from 'axios' +import * as vscode from 'vscode' +import { OH_CONFIG_DEPRECATED, OH_CONFIG_PARAMETERS, OH_MESSAGESTRINGS } from './types' +import * as utils from './Utils' + +/** + * Handles the extension configuration. + * Provides additional logic for config changes and deprecated parameters. + * + * @author Jerome Luckenbach - Initial contribution + * + */ +export class ConfigManager { + + private static instance: ConfigManager|undefined + + private currentConfig: vscode.WorkspaceConfiguration + + private static ENCODING_MATCH: RegExp = /^(username|password)$/ + + private deprecationWarningShown: boolean + private static DEPRECATION_WARNING_MESSAGE = `You are using deprecated config values for the openHAB Extension!\n +Those values are still used for the moment, but will be removed in newer extension versions.\n +Please take a look at the current extension settings\nand update to the new config parameters and also remove the deprecated ones.` + + /** + * Initialize the ConfigManager + */ + private constructor() { + this.deprecationWarningShown = false + this.updateConfig() + + if(this.hasDeprecatedParameters()){ + this.showDeprecationWarning() + } + } + + /** + * Returns the ConfigManager instance and instanciates it before if not yet available + * @returns {ConfigManager} The ConfigManager instance + */ + private static getInstance(): ConfigManager { + // Create a new instance if there is none available yet + if(!ConfigManager.instance){ + ConfigManager.instance = new ConfigManager() + } + + return ConfigManager.instance + } + + /** + * Fetch and store the latest WorkspaceConfiguration + */ + private updateConfig() { + this.currentConfig = vscode.workspace.getConfiguration('openhab') + console.log("Update Config Manager") + } + + /** + * Searches and returns a config value or null + * + * @param configParameter The parameter to search for. Can be used with OH_CONFIG_PARAMETERS constant. + * @returns The config value or null + */ + public static get(configParameter: string): string|number|boolean|null { + let config = ConfigManager.getInstance().currentConfig; + + // Check if current parameter is available + if(config.has(configParameter) && config.get(configParameter) !== null){ + + // Double check if auth token is available and valid + if (configParameter == OH_CONFIG_PARAMETERS.connection.authToken && !ConfigManager.tokenAuthAvailable()) + return null + + return config.get(configParameter) + } + + // If no current Parameter is available, check if a deprecated parameter is available + let parameterObject = configParameter.split('.') + let parameter = parameterObject[parameterObject.length - 1] + let returnValue = null // Return null if nothing is found at all + + // Use deprecated version as return value + switch (parameterObject[0]) { + case 'connection': + returnValue = this.checkAndGet(config, parameter) + break + case 'consoleCommand': + returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.consoleCommand) + break + case 'languageserver': + switch (parameter) { + case 'remoteEnabled': + returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.remoteLspEnabled) + break + case 'remotePort': + returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.remoteLspPort) + break + } + break + } + + // Output a warning with a "Dismiss" button to prevent warning from showing too often + if(returnValue !== null){ + utils.appendToOutput(`Usage of deprecated config ${parameter} detected.`) + } + + return returnValue + } + + /** + * Checks if ther is an authToken property available and valid + * @returns {boolean} true when tokenAuth is available and useable, false otherwise + */ + public static tokenAuthAvailable(): boolean { + let tokenResult = ConfigManager.getInstance().currentConfig.get(OH_CONFIG_PARAMETERS.connection.authToken, null) + return (!tokenResult || tokenResult === '') ? false : true + } + + /** + * Checks if a parameter is available in the given config and if it has a value and returns it. + * Also encodes needed parameters directly + * @param config The workspace configuration to search in + * @param parameter The parameter to search for + * @returns The configuration value, the encoded configuration value when needed or null + */ + private static checkAndGet(config: vscode.WorkspaceConfiguration, parameter: string): string|number|boolean|null { + if(config.has(parameter) && config.get(parameter) !== null){ + // Encode basic auth credentials + if(parameter.match(ConfigManager.ENCODING_MATCH)) + return encodeURIComponent(config.get(parameter)) + + return config.get(parameter) + } + + return null + } + + /** + * Updates an openHAB specific config parameter. + */ + public static update(configParameter: string, value: any, target?: vscode.ConfigurationTarget) { + let config = vscode.workspace.getConfiguration('openhab') + + if(config.has(configParameter)) { + if(target == undefined) { + config.update(configParameter, value) + } + else { + config.update(configParameter, value, target) + } + + ConfigManager.getInstance().updateConfig() + } + } + + /** + * Watches for configuration changes and updates or reacts to openHAB config related changes. + * + * @param context The extension context + */ + public static attachConfigChangeWatcher(context){ + let instance = ConfigManager.getInstance() + + // Subscribe to all configuration changed events + context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => { + + if(e.affectsConfiguration('openhab')){ + instance.updateConfig() + } + + // Check for api token changes and check if a valid apitoken has been set. + // Output an error ortherwise + if(e.affectsConfiguration('openhab.connection.authToken') ){ + console.debug(`Auth token config has been changed. Validating token now.`) + + const token = instance.currentConfig.get(OH_CONFIG_PARAMETERS.connection.authToken, null) + + let config: AxiosRequestConfig = { + url: utils.getHost() + '/rest/auth/apitokens', + headers: { + 'X-OPENHAB-TOKEN': `${token}` + } + } + + axios(config) + .then((_response) => { + utils.appendToOutput(`Newly configured auth token validated successfully!`) + }) + .catch((error) => { + if(error.response.status === 401){ + console.error(`Could not validate configured auth token.`, error) + utils.appendToOutput(`Could not validate configured auth token.`) + ConfigManager.getInstance().handleConfigError(error, `Could not validate configured auth token.`) + } + else { + utils.handleRequestError(error) + } + }) + } + + // Refresh treeviews when a openHAB connection related setting has changed + if(e.affectsConfiguration('openhab.connection') ){ + console.debug("openHAB Extension configuration has changed.") + vscode.commands.executeCommand('openhab.command.refreshEntry'); + } + })) + + } + + /** + * Generate an error message and provide some options for solving the error + * + * @param err The current error + * @param message The specific error message + * @param baseMessage The base message available for overwriting the title + */ + private async handleConfigError(err, message: string = OH_MESSAGESTRINGS.moreInfo, baseMessage: string = OH_MESSAGESTRINGS.errors.configValidation) { + // Show error message with action buttons + const showOutput = 'Show Output' + const result = await vscode.window.showErrorMessage(`${baseMessage}\n\n${message}`, showOutput) + + // Action based on user input + if(result == showOutput) + utils.getOutputChannel().show() + } + + /** + * Check the current config for deprecated and used parameters + * @returns An array of deprecated parameter strings or a boolean + */ + private hasDeprecatedParameters() : string[]|boolean { + let currentConfig = this.currentConfig + let deprecatedParameters : string[] = [] + + // Append the parameter, if it exists and at least one config value scope has been set manually + for(const parameter in OH_CONFIG_DEPRECATED){ + if(currentConfig.has(parameter)){ + let inspectresult = currentConfig.inspect(parameter) + if(inspectresult.globalValue != undefined || inspectresult.workspaceValue != undefined){ + deprecatedParameters.push(parameter) + } + } + } + + return (deprecatedParameters.length != 0) ? deprecatedParameters : false; + } + + /** + * Show a warning message, when deprecated config values are used + */ + private async showDeprecationWarning() { + if(!this.deprecationWarningShown){ + this.deprecationWarningShown = true + // const migrateStandardValues = 'Migrate minimal config directly!' + + // let result = await vscode.window.showWarningMessage(ConfigManager.DEPRECATION_WARNING_MESSAGE, { modal: true }, migrateStandardValues) + vscode.window.showWarningMessage(ConfigManager.DEPRECATION_WARNING_MESSAGE) + + // // Action based on user input + // if(result == migrateStandardValues) + // ConfigManager.migrateDeprecatedParameters() + } + } +} \ No newline at end of file diff --git a/client/src/Utils.ts b/client/src/Utils/Utils.ts similarity index 54% rename from client/src/Utils.ts rename to client/src/Utils/Utils.ts index f8aee3f..5cf08db 100644 --- a/client/src/Utils.ts +++ b/client/src/Utils/Utils.ts @@ -1,189 +1,198 @@ -import { - commands, - Uri, - window, - workspace, -} from 'vscode' - -import {PreviewPanel} from './WebView/PreviewPanel' - -import * as _ from 'lodash' -import * as request from 'request-promise-native' -import { OutputChannel } from 'vscode' - -/** - * Create output channel as user display for relevant informations - */ -let extensionOutput: OutputChannel = null - -/** - * Humanize function adapter from the previously included underscore.string library - * - * @param str The string to convert - */ -export function humanize(str: string) : string { - return _.upperFirst( - // original 'underscored' of underscore.string - str.trim() - .replace(/([a-z\d])([A-Z]+)/g, '$1_$2') - .replace(/[-\s]+/g, '_') - .toLowerCase() - .replace(/([a-z\d])([A-Z]+)/g, '$1_$2') - .replace(/_id$/, '') - .replace(/_/g, ' ') - // original 'humanize' of underscore.string - .replace(/_id$/, '') - .replace(/_/g, ' ') - .trim() - ); -} - -/** - * Returns the host of the configured openHAB environment. - * Return value may vary depending on the user configuration (e.g. Authentication settings) - */ -export function getHost() { - let config = workspace.getConfiguration('openhab') - let host = config.host - let port = config.port - let username = encodeURIComponent(config.username) - let password = encodeURIComponent(config.password) - - let protocol = 'http' - - if (host.includes('://')) { - let split = host.split('://') - host = split[1] - protocol = split[0] - } - - let authentication = (username || '') + (password ? ':' + password : '') - authentication += authentication ? '@' : '' - - return protocol + '://' + authentication + host + (port === 80 ? '' : ':' + port) -} - -/** - * Returns the current simple mode status retreived via rest api - */ -export function getSimpleModeState(): Thenable { - return new Promise((resolve, reject) => { - request(getHost() + '/rest/services/org.eclipse.smarthome.links/config') - .then((response) => { - let responseJson = JSON.parse(response); - resolve(responseJson.autoLinks) - }).catch(() => reject([])) - }) -} - -/** - * Returns all available sitemaps of the configured openHAB environment via rest api - */ -export function getSitemaps(): Thenable { - return new Promise((resolve, reject) => { - request(getHost() + '/rest/sitemaps') - .then((response) => { - resolve(JSON.parse(response)) - }).catch(() => reject([])) - }) -} - -/** - * Opens an external browser with the given url. - * - * @param url The url to navigate to - */ -export function openBrowser(url) { - let editor = window.activeTextEditor - if (!editor) { - window.showInformationMessage('No editor is active') - return - } - - let selection = editor.selection - let text = editor.document.getText(selection) - url = url.startsWith('http') ? url : getHost() + url - url = url.replace('%s', text.replace(' ', '%20')) - return commands.executeCommand('vscode.open', Uri.parse(url)) -} - -/** - * Opens a vscode Webview panel aside, with the given data. - * - * @param extensionPath The path of this extension - * @param query The query to append. Defaults to the basic ui node. - * @param title The title, that will be shown for the UI tab. - */ -export function openUI(extensionPath: string, query: string = "/basicui/app", title?: string) { - let srcPath: string = getHost().concat(query); - appendToOutput(`URL that will be opened is: ${srcPath}`) - - PreviewPanel.createOrShow( - extensionPath, - (title !== undefined) ? title : undefined, - srcPath - ); -} - -/** - * Handle a occuring request error. - * - * @param err The current error - */ -export async function handleRequestError(err) { - - let config = workspace.getConfiguration('openhab') - const setHost = 'Set openHAB host' - const disableRest = 'Disable REST API' - const showOutput = 'Show Output' - - // Show error message with action buttons - const baseMessage = `Error while connecting to openHAB REST API.` - const message = typeof err.error === 'string' ? err.error : err.error.message - const result = await window.showErrorMessage(`${baseMessage}\nMore information may be found int the openHAB Extension output!`, setHost, disableRest, showOutput) - - // Action based on user input - switch (result) { - case setHost: - commands.executeCommand('workbench.action.openWorkspaceSettings') - break - case showOutput: - extensionOutput.show() - break - case disableRest: - config.update('useRestApi', false) - break - default: - break - } - - appendToOutput(`--- - Error: - ${baseMessage} - - Message: - ${message} ----`) -} - -/** - * This will send a message from the extension to its output channel. - * If the channel isn't existing already, it will be created during method run. - * - * @param message The message to append to the extensions output Channel - */ -export function appendToOutput(message: string){ - - if(!extensionOutput) { extensionOutput = window.createOutputChannel("openHAB Extension") } - - extensionOutput.appendLine(message) -} - -/** - * Sleep for some time - * - * @param sleepTime wanted time in milliseconds - */ -export async function sleep(sleepTime: number){ - return new Promise(resolve => setTimeout(resolve, sleepTime)) +import * as vscode from 'vscode' +import { OutputChannel } from 'vscode' +import * as _ from 'lodash' +import axios, { AxiosRequestConfig } from 'axios' +import {PreviewPanel} from '../WebView/PreviewPanel' +import { ConfigManager } from './ConfigManager' +import { OH_CONFIG_PARAMETERS, OH_MESSAGESTRINGS } from './types' + +/** + * Create output channel as user display for relevant informations + */ +let extensionOutput: OutputChannel = null +let warningShownAlready: boolean = false + +/** + * Humanize function adapter from the previously included underscore.string library + * + * @param str The string to convert + */ +export function humanize(str: string) : string { + return _.upperFirst( + // original 'underscored' of underscore.string + str.trim() + .replace(/([a-z\d])([A-Z]+)/g, '$1_$2') + .replace(/[-\s]+/g, '_') + .toLowerCase() + .replace(/([a-z\d])([A-Z]+)/g, '$1_$2') + .replace(/_id$/, '') + .replace(/_/g, ' ') + // original 'humanize' of underscore.string + .replace(/_id$/, '') + .replace(/_/g, ' ') + .trim() + ); +} + +/** + * Returns the host of the configured openHAB environment. + * Return value may vary depending on the user configuration (e.g. Authentication settings) + */ +export function getHost() { + let host = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.host) as string + let port = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.port) as number + let protocol = 'http' + + if (host.includes('://')) { + let split = host.split('://') + host = split[1] + protocol = split[0] + } + + let generatedHost = protocol + '://' + + // Prefer token auth over basic auth, if available + if(!ConfigManager.tokenAuthAvailable()){ + let username = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.basicAuth.username) as string|null + + // Also make sure that there is at least a username given + if(username != null && username != ''){ + let password = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.basicAuth.password) as string|null + + // Check if given username is a openHAB 3 token + let usernameSegments = username.split('.') + if(usernameSegments.length === 3 && usernameSegments[0] === 'oh'){ + const warningString = `Detected openHAB 3 token as username.\nConsider using the recommended **openhab.connection.authToken** config parameter instead.\n\n` + appendToOutput(warningString) + if(!warningShownAlready){ + vscode.window.showWarningMessage(warningString) + warningShownAlready = true + } + } + + let basicAuth = (username ? username : '') + (password ? ':' + password : '') + '@' + generatedHost += basicAuth + } + + } + + generatedHost += host + (port === 80 ? '' : ':' + port) + + return generatedHost +} + +/** + * Returns all available sitemaps of the configured openHAB environment via rest api + */ +export function getSitemaps(): Thenable { + return new Promise((resolve, reject) => { + let config: AxiosRequestConfig = { + url: getHost() + '/rest/sitemaps', + headers: {} + } + + if(ConfigManager.tokenAuthAvailable()){ + config.headers = { + 'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken) + } + } + + axios(config) + .then((response) => { + resolve(response.data) + }).catch(() => reject([])) + }) +} + +/** + * Opens an external browser with the given url. + * @param url The url to navigate to + */ +export function openBrowser(url) { + let editor = vscode.window.activeTextEditor + if (!editor) { + vscode.window.showInformationMessage('No editor is active') + return + } + + let selection = editor.selection + let text = editor.document.getText(selection) + url = url.startsWith('http') ? url : getHost() + url + url = url.replace('%s', text.replace(' ', '%20')) + return vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(url)) +} + +/** + * Opens a vscode Webview panel aside, with the given data. + * @param extensionPath The path of this extension + * @param query The query to append. Defaults to the basic ui node. + * @param title The title, that will be shown for the UI tab. + */ +export function openUI(extensionPath: string, query: string = "/basicui/app", title?: string) { + let srcPath: string = getHost().concat(query); + appendToOutput(`URL that will be opened is: ${srcPath}`) + + PreviewPanel.createOrShow( + extensionPath, + (title !== undefined) ? title : undefined, + srcPath + ); +} + +/** + * Handle a occuring request error. + * @param err The current error + */ +export async function handleRequestError(err) { + const disableRest = 'Disable REST API' + const showOutput = 'Show Output' + + // Show error message with action buttons + const baseMessage = `Error while connecting to openHAB REST API.` + const message = typeof err.isAxiosError === 'string' ? err.message : err.toString() + const result = await vscode.window.showErrorMessage(`${baseMessage}\n${OH_MESSAGESTRINGS.moreInfo}`, disableRest, showOutput) + + // Action based on user input + switch (result) { + case disableRest: + ConfigManager.update(OH_CONFIG_PARAMETERS.useRestApi, false) + break + case showOutput: + extensionOutput.show() + break + } + + appendToOutput(`--- + Error: + ${baseMessage} + + Message: + ${message} +---`) +} + +/** + * This will send a message from the extension to its output channel. + * If the channel isn't existing already, it will be created during method run. + * @param message The message to append to the extensions output Channel + */ +export function appendToOutput(message: string){ + getOutputChannel().appendLine(message) +} + +/** + * Gets the extensions output channel for referencing + * @returns The extensions output channel + */ +export function getOutputChannel(): OutputChannel { + if(!extensionOutput) { extensionOutput = vscode.window.createOutputChannel("openHAB Extension") } + return extensionOutput +} + +/** + * Sleep for some time + * @param sleepTime wanted time in milliseconds + */ +export async function sleep(sleepTime: number){ + return new Promise(resolve => setTimeout(resolve, sleepTime)) } \ No newline at end of file diff --git a/client/src/Utils/types.ts b/client/src/Utils/types.ts new file mode 100644 index 0000000..29e4817 --- /dev/null +++ b/client/src/Utils/types.ts @@ -0,0 +1,36 @@ +export const OH_CONFIG_PARAMETERS = { + connection : { + host : 'connection.host', + port : 'connection.port', + authToken : 'connection.authToken', + basicAuth : { + username : 'connection.basicAuth.username', + password : 'connection.basicAuth.password', + } + }, + languageserver : { + remoteEnabled : 'languageserver.remoteEnabled', + remotePort : 'languageserver.remotePort', + }, + itemCasing : 'itemCasing', + consoleCommand : 'consoleCommand', + useRestApi : 'useRestApi', +} + +export const OH_CONFIG_DEPRECATED = { + host : 'host', + port : 'port', + username : 'username', + password : 'password', + remoteLspEnabled : 'remoteLspEnabled', + remoteLspPort : 'remoteLspPort', + consoleCommand : 'karafCommand', + sitemapPreview : 'sitemapPreviewUI', +} + +export const OH_MESSAGESTRINGS = { + moreInfo : `More information may be found int the openHAB Extension output!`, + errors : { + configValidation : `Error during config validation`, + }, +} diff --git a/client/src/WebView/PreviewPanel.ts b/client/src/WebView/PreviewPanel.ts index 16f599c..5b24bc1 100644 --- a/client/src/WebView/PreviewPanel.ts +++ b/client/src/WebView/PreviewPanel.ts @@ -1,6 +1,6 @@ import * as path from 'path' import * as vscode from 'vscode' -import { appendToOutput } from "../Utils" +import { appendToOutput } from "../Utils/Utils" /** * Manages the extension WebView panel * diff --git a/client/src/extension.ts b/client/src/extension.ts index 6c75cda..94bc0c6 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -1,18 +1,7 @@ 'use strict' -import { - commands, - Disposable, - extensions, - ExtensionContext, - languages, - window, - workspace, - StatusBarItem, - StatusBarAlignment -} from 'vscode' - -import * as utils from './Utils' +import * as vscode from 'vscode' +import * as utils from './Utils/Utils' import { ItemsExplorer } from './ItemsExplorer/ItemsExplorer' import { ThingsExplorer } from './ThingsExplorer/ThingsExplorer' @@ -31,9 +20,11 @@ import * as _ from 'lodash' import * as ncp from 'copy-paste' import * as path from 'path' import * as fs from 'fs' +import axios, { AxiosRequestConfig } from 'axios' +import { ConfigManager } from './Utils/ConfigManager' let _extensionPath: string -let ohStatusBarItem: StatusBarItem +let ohStatusBarItem: vscode.StatusBarItem /** * Initializes the openHAB extension @@ -43,20 +34,15 @@ let ohStatusBarItem: StatusBarItem * @param config The extension configuration * @param context The extension context */ -async function init(disposables: Disposable[], config, context): Promise { +async function init(disposables: vscode.Disposable[], config, context): Promise { - context.subscriptions.push(workspace.onDidChangeConfiguration(e => { + // Handle configuration changes + ConfigManager.attachConfigChangeWatcher(context) - // Refresh treeviews when a connection related setting gets changed - if(e.affectsConfiguration('openhab.host') || e.affectsConfiguration('openhab.password') || e.affectsConfiguration('openhab.port') || e.affectsConfiguration('openhab.username') ){ - commands.executeCommand('openhab.command.refreshEntry'); - } - })) - - disposables.push(commands.registerCommand('openhab.basicUI', () => { - let editor = window.activeTextEditor + disposables.push(vscode.commands.registerCommand('openhab.basicUI', () => { + let editor = vscode.window.activeTextEditor if (!editor) { - window.showInformationMessage('No editor is active') + vscode.window.showInformationMessage('No editor is active') return } @@ -102,19 +88,19 @@ async function init(disposables: Disposable[], config, context): Promise { })) - disposables.push(commands.registerCommand('openhab.searchCommunity', (phrase?) => { + disposables.push(vscode.commands.registerCommand('openhab.searchCommunity', (phrase?) => { let query: string = phrase || '%s' utils.openBrowser(`https://community.openhab.org/search?q=${query}`) })) - disposables.push(commands.registerCommand('openhab.openConsole', () => { - let command = config.karafCommand.replace(/%openhabhost%/g, config.host) - const terminal = window.createTerminal('openHAB') + disposables.push(vscode.commands.registerCommand('openhab.openConsole', () => { + let command = config.consoleCommand.replace(/%openhabhost%/g, config.connection.host) + const terminal = vscode.window.createTerminal('openHAB') terminal.sendText(command, true) terminal.show(false) })) - disposables.push(commands.registerCommand('openhab.command.things.docs', (query: Thing) => + disposables.push(vscode.commands.registerCommand('openhab.command.things.docs', (query: Thing) => utils.openBrowser(`https://www.openhab.org/addons/bindings/${query.binding}/`))) if (config.useRestApi) { @@ -123,39 +109,39 @@ async function init(disposables: Disposable[], config, context): Promise { const itemsCompletion = new ItemsCompletion() const ohHoverProvider = new HoverProvider() - disposables.push(window.registerTreeDataProvider('openhabItems', itemsExplorer)) - disposables.push(window.registerTreeDataProvider('openhabThings', thingsExplorer)) - disposables.push(commands.registerCommand('openhab.command.refreshEntry', () => { + disposables.push(vscode.window.registerTreeDataProvider('openhabItems', itemsExplorer)) + disposables.push(vscode.window.registerTreeDataProvider('openhabThings', thingsExplorer)) + disposables.push(vscode.commands.registerCommand('openhab.command.refreshEntry', () => { itemsExplorer.refresh() thingsExplorer.refresh() })) - disposables.push(commands.registerCommand('openhab.command.copyName', (query) => + disposables.push(vscode.commands.registerCommand('openhab.command.copyName', (query) => ncp.copy(query.name || query.label))) - disposables.push(commands.registerCommand('openhab.command.items.copyState', (query: Item) => + disposables.push(vscode.commands.registerCommand('openhab.command.items.copyState', (query: Item) => ncp.copy(query.state))) - disposables.push(commands.registerCommand('openhab.command.items.addRule', (query: Item) => { + disposables.push(vscode.commands.registerCommand('openhab.command.items.addRule', (query: Item) => { const ruleProvider = new RuleProvider(query) ruleProvider.addRule() })) - disposables.push(commands.registerCommand('openhab.command.items.addToSitemap', (query: Item) => { + disposables.push(vscode.commands.registerCommand('openhab.command.items.addToSitemap', (query: Item) => { const sitemapProvider = new SitemapPartialProvider(query) sitemapProvider.addToSitemap() })) - disposables.push(commands.registerCommand('openhab.command.things.addItems', (query: Thing | Channel) => { + disposables.push(vscode.commands.registerCommand('openhab.command.things.addItems', (query: Thing | Channel) => { const itemsProvider = new ItemsProvider(query) itemsProvider.addToItems() })) - disposables.push(commands.registerCommand('openhab.command.things.copyUID', (query) => + disposables.push(vscode.commands.registerCommand('openhab.command.things.copyUID', (query) => ncp.copy(query.UID || query.uid))) - disposables.push(languages.registerHoverProvider({ language: 'openhab', scheme: 'file'}, { + disposables.push(vscode.languages.registerHoverProvider({ language: 'openhab', scheme: 'file'}, { provideHover(document, position, token){ @@ -181,7 +167,7 @@ async function init(disposables: Disposable[], config, context): Promise { ) // Listen for document save events, to update the cached items - workspace.onDidSaveTextDocument((savedDocument) => { + vscode.workspace.onDidSaveTextDocument((savedDocument) => { let fileEnding = savedDocument.fileName.split(".").slice(-1)[0] if(fileEnding === "items"){ @@ -195,7 +181,7 @@ async function init(disposables: Disposable[], config, context): Promise { }) } - if (config.remoteLspEnabled) { + if (config.languageserver.remoteEnabled) { const remoteLanguageClientProvider = new RemoteLanguageClientProvider() disposables.push(remoteLanguageClientProvider.connect()) } @@ -203,18 +189,18 @@ async function init(disposables: Disposable[], config, context): Promise { const localLanguageClientProvider = new LocalLanguageClientProvider() disposables.push(localLanguageClientProvider.connect(context)) - ohStatusBarItem = window.createStatusBarItem(StatusBarAlignment.Right, 20) + ohStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 20) ohStatusBarItem.text = `$(home) openHAB` ohStatusBarItem.tooltip = `openHAB extension is active currently.` ohStatusBarItem.show() } // This method is called when the extension is activated -export function activate(context: ExtensionContext) { +export function activate(context: vscode.ExtensionContext) { // Keep the stable extension deactivated, when beta version is installed let thisExtension = JSON.parse(fs.readFileSync(path.join(context.extensionPath, "package.json"), 'utf8')).name - let betaExtension = extensions.getExtension('openhab.openhab-beta') + let betaExtension = vscode.extensions.getExtension('openhab.openhab-beta') // When beta is available and we are not beta itself, this extension should not get activated if(betaExtension !== undefined && thisExtension !== "openhab-beta"){ @@ -223,12 +209,12 @@ export function activate(context: ExtensionContext) { } // Prepare disposables array, context and config - const disposables: Disposable[] = [] + const disposables: vscode.Disposable[] = [] _extensionPath = context.extensionPath - let config = workspace.getConfiguration('openhab') + let config = vscode.workspace.getConfiguration('openhab') // Spread in the disposables array to the subscription (This will include all disposables from the init method) - context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose())) + context.subscriptions.push(new vscode.Disposable(() => vscode.Disposable.from(...disposables).dispose())) init(disposables, config, context) .catch(err => console.error(err)) diff --git a/docs/USAGE.md b/docs/USAGE.md index 03308fa..d751aa0 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -9,10 +9,10 @@ description: "The openHAB vscode extension provides useful features for configur You are able to configure the hostname and port for the Sitemap preview. -- `openhab.host` (mandatory), default: openhabianpi -- `openhab.port` (optional), default: 8080 +- `openhab.connection.host` (mandatory), default: openhabianpi +- `openhab.connection.port` (optional), default: 8080 -*openhab.host* will also work with the IP address of your openHAB instance, instead of the hostname. +*openhab.connection.host* will also work with the IP address of your openHAB instance, instead of the hostname. These settings should work fine on Windows machines and openHAB installations using the recommended [openHABian](https://www.openhab.org/docs/installation/openhabian.html) setup. They should be edited if you use macOS or *NIX systems or manual openHAB installations. @@ -25,8 +25,8 @@ For further informations on how to change your settings, visit the official [Vis ```json { - "openhab.host": "localhost", - "openhab.port": 80 + "openhab.connection.host": "localhost", + "openhab.connection.port": 80 } ``` @@ -34,8 +34,8 @@ For further informations on how to change your settings, visit the official [Vis ```json { - "openhab.host": "openhabianpi.local", - "openhab.port": 8080 + "openhab.connection.host": "openhabianpi.local", + "openhab.connection.port": 8080 } ``` @@ -60,8 +60,8 @@ You may need to reload the VSCode window to take effect. Since openHAB 3 (with its on default activated api authentication) has been released you have to fulllfil some additional steps to get a working connection. 1. Generate an api token for your user -2. Add the generated token as `openhab.username` configuration -3. Leave `openhab.password` empty +2. Add the generated token as `openhab.connection.basicAuth.username` configuration +3. Leave `openhab.connection.basicAuth.password` empty 4. Reload vscode window ### openHAB REST API and SSL Certificates @@ -119,7 +119,7 @@ In the unlikely case that your language server is running on a port other than t ```json { - "openhab.remoteLspPort": 5007 + "openhab.languageserver.remotePort": 5007 } ``` @@ -127,7 +127,7 @@ If you don't want to have your openHAB files validated by Language Server, simpl ```json { - "openhab.remoteLspEnabled": false + "openhab.languageserver.remoteEnabled": false } ``` @@ -140,11 +140,11 @@ Note that LSP (content assist for rules and syntax validation) won't be exposed, The following configuration will allow you to access REST API remotely: ```json -"openhab.host": "https://home.myopenhab.org", -"openhab.port": 80, -"openhab.remoteLspEnabled": false, -"openhab.username": "your_myopenhab_email", -"openhab.password": "your_myopenhab_password", +"openhab.connection.host": "https://home.myopenhab.org", +"openhab.connection.port": 80, +"openhab.languageserver.remoteEnabled": false, +"openhab.connection.basicAuth.username": "your_myopenhab_email", +"openhab.connection.basicAuth.password": "your_myopenhab_password", ``` ## Sitemap preview with Basic UI @@ -170,10 +170,10 @@ Note that you need to have: - `ssh` installed on your environment - Console exposed to the external interface -- `openhab.host` configuration parameter set properly +- `openhab.connection.host` configuration parameter set properly This feature allows you to modify the new param and e.g. show the openHAB logs immediately: ```bash -"openhab.karafCommand": "ssh openhab@%openhabhost% -p 8101 -t 'log:tail'", +"openhab.consoleCommand": "ssh openhab@%openhabhost% -p 8101 -t 'log:tail'", ``` diff --git a/package.json b/package.json index 45faae0..7c8d16c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "openhab", "displayName": "openHAB", "description": "Robust tool for openHAB textual configurations. Includes code snippets, syntax highlighting, language server integration and more.", - "version": "0.8.2", + "version": "1.0.0", "publisher": "openhab", "icon": "openhab.png", "repository": { @@ -107,79 +107,105 @@ ], "configuration": { "type": "object", - "title": "openHAB Configuration", + "title": "openHAB", "properties": { "openhab.host": { - "type": [ - "string" - ], - "default": "openhabianpi", - "description": "Specifies the URL or IP address for the openHAB preview. (Use 'localhost' when developing locally)" - }, - "openhab.itemCasing": { "type": "string", - "default": "camel", - "enum": [ - "camel", - "snake" - ], - "markdownDescription": "Choose how the `Create Items from Channels` command generates Item names. Use `camel` for `CamelCase` or `snake` for `Upper_Snake_Case`." + "default": "openhabianpi", + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.host#` instead." }, "openhab.karafCommand": { - "type": [ - "string" - ], + "type": "string", "default": "ssh openhab@%openhabhost% -p 8101", - "description": "Directly log into openHAB console. Note that this option is available only if you exposed openHAB console." + "markdownDescription": "**Deprecated**: Please use `#openhab.consoleCommand#` instead." }, "openhab.password": { - "type": [ - "string" - ], + "type": "string", "default": "", - "description": "(optional) Specifies the Basic Auth password for accessing the openHAB preview/REST API.\nPlease leave this parameter EMPTY when you are using an api token in openHAB 3!" + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.basicAuth.password#` instead." }, "openhab.port": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "default": 8080, - "description": "Specifies the port for the openHAB preview." + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.port#` instead." + + }, + "openhab.username": { + "type": "string", + "default": "", + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.basicAuth.username#` instead." }, "openhab.remoteLspEnabled": { - "type": [ - "boolean" - ], + "type": "boolean", "default": true, - "description": "Enables communication with Language Server of openHAB instance.\nIf you are facing connection problems make sure to connect your config folder through a dedicated network drive." + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.languageserver.remoteLspEnabled#` instead." }, "openhab.remoteLspPort": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "default": 5007, - "description": "Specifies the port where openHAB is running its Language Server." + "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.languageserver.remoteLspPort#` instead." }, "openhab.sitemapPreviewUI": { "type": [ "string" ], "default": "basicui", - "description": "This parameter is deprecated and will be removed with the next major update." + "markdownDeprecationMessage": "**Deprecated**: This parameter is deprecated and will be removed with one of the next updates." + }, + "openhab.connection.authToken":{ + "type": ["string", "null"], + "default": null, + "markdownDescription": "Specifies the **auth token**, you can generate for your openHAB 3 api access.\n\nSee [Apitoken Documentation](https://openhab.org/docs/configuration/apitokens.html) for further Information!" + }, + "openhab.connection.host": { + "type": ["string", "null"], + "default": null, + "markdownDescription": "Specifies the **url** or **IP address** for your openHAB environment.\n\n(Use 'localhost' when developing locally)" + }, + "openhab.connection.port": { + "type": ["number", "null"], + "default": null, + "markdownDescription": "Specifies the **port** for your openHAB environment." + }, + "openhab.connection.basicAuth.password": { + "type": ["string", "null"], + "default": null, + "markdownDescription": "*OPTIONAL*:\n\nSpecifies the Basic Auth password for accessing the openHAB preview/REST API.\n\nPlease leave this parameter **empty** when you are using an api token in openHAB 3!" + }, + "openhab.connection.basicAuth.username": { + "type": ["string", "null"], + "default": null, + "markdownDescription": "*OPTIONAL*:\n\nSpecifies the Basic Auth username for accessing the openHAB preview/REST API." + }, + "openhab.languageserver.remoteEnabled": { + "type": "boolean", + "default": true, + "markdownDescription": "Enables communication with Language Server of openHAB instance.\n\nIf you are facing connection problems make sure to connect your config folder through a dedicated network drive." + }, + "openhab.languageserver.remotePort": { + "type": ["number", "null"], + "default": 5007, + "markdownDescription": "Specifies the port where openHAB is running its Language Server." + }, + "openhab.itemCasing": { + "type": "string", + "default": "camel", + "enum": ["camel", "snake"], + "markdownDescription": "Choose how the `Create Items from Channels` command generates Item names.\n\nUse `camel` for `CamelCase` or `snake` for `Upper_Snake_Case`.", + "markdownEnumDescriptions": [ + "Uses the `CamelCase` naming scheme.", + "Uses the `Upper_Snake_Case` naming scheme." + ] + }, + "openhab.consoleCommand": { + "type": "string", + "default": "ssh openhab@%openhabhost% -p 8101", + "markdownDescription": "Directly log into openHAB console.\n\n**Note** that this option is available only if you exposed openHAB console." }, "openhab.useRestApi": { "type": "boolean", "default": true, - "description": "Connects to openHAB REST API if set to true. If not, Items tree view and things tree view are disabled." - }, - "openhab.username": { - "type": [ - "string" - ], - "default": "", - "description": "(optional) Specifies the Basic Auth username for accessing the openHAB preview/REST API.\nPlease use this parameter for the API TOken too on openHAB 3." + "markdownDescription": "Connects to *openHAB REST API* if set to **true**.\n\nIf not, items tree view and things tree view are **disabled**." } } }, @@ -352,14 +378,12 @@ "vscode:prepublish": "npm run webpack", "watch": "tsc -b -w", "webpack": "webpack --mode production --config ./client/webpack.config.js && webpack --mode production --config ./serverJS/webpack.config.js", - "webpack-dev": "webpack --mode none --config ./client/webpack.config.js && webpack --mode none --config ./serverJS/webpack.config.js" + "webpack-dev": "webpack --mode development --config ./client/webpack.config.js && webpack --mode development --config ./serverJS/webpack.config.js" }, "devDependencies": { "@types/form-data": "^2.2.1", "@types/lodash": "^4.14.167", "@types/node": "^8.10.66", - "@types/request": "^2.48.5", - "@types/request-promise-native": "^1.0.15", "@typescript-eslint/eslint-plugin": "^4.13.0", "@typescript-eslint/parser": "^4.13.0", "eslint": "^7.18.0",