From 04b56e300aab75b0658e0ed9d4dbb2ecb107ed87 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Fri, 27 Sep 2024 16:53:40 -0400 Subject: [PATCH 1/8] Generate mock data for incidents Add diagnostics Add incident data to workspace state Reset / sync state between diagnostics and webview Add in patternfly Update views to use patternfly Signed-off-by: Ian Bolton --- vscode/package-lock.json | 384 +++++++++++++++++- vscode/package.json | 16 +- vscode/src/KonveyorGUIWebviewViewProvider.ts | 21 +- vscode/src/VsCodeExtension.ts | 27 +- vscode/src/commands.ts | 100 +++-- vscode/src/extensionState.ts | 18 +- vscode/src/generateMockData.ts | 99 +++++ vscode/src/webview/components/App.tsx | 82 ++-- .../src/webview/components/IncidentList.tsx | 79 ++++ vscode/src/webview/globals.ts | 14 + vscode/src/webview/index.tsx | 2 + vscode/src/webview/types.ts | 7 + vscode/src/webviewContent.ts | 61 +-- vscode/src/webviewMessageHandler.ts | 43 +- vscode/webpack.config.js | 13 +- 15 files changed, 852 insertions(+), 114 deletions(-) create mode 100644 vscode/src/generateMockData.ts create mode 100644 vscode/src/webview/components/IncidentList.tsx create mode 100644 vscode/src/webview/globals.ts create mode 100644 vscode/src/webview/types.ts diff --git a/vscode/package-lock.json b/vscode/package-lock.json index fb1545f..a3dd60d 100644 --- a/vscode/package-lock.json +++ b/vscode/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { + "@patternfly/patternfly": "^5.4.1", + "@patternfly/react-core": "^5.4.0", "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -26,15 +28,21 @@ "@typescript-eslint/parser": "^8.7.0", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", + "css-loader": "^7.1.2", "eslint": "^9.11.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.36.1", "eslint-plugin-unused-imports": "^4.1.4", +<<<<<<< HEAD "husky": "^9.1.6", "lint-staged": "^15.2.10", +======= + "mini-css-extract-plugin": "^2.9.1", +>>>>>>> 528a683 (Generate mock data for incidents) "prettier": "^3.0.2", "rimraf": "^4.4.1", + "style-loader": "^4.0.0", "ts-loader": "^9.5.1", "typescript": "^5.6.2", "typescript-eslint": "^8.7.0", @@ -764,6 +772,47 @@ "node": ">= 8" } }, + "node_modules/@patternfly/patternfly": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.4.1.tgz", + "integrity": "sha512-0+KxsQJrFzOMANALW82BHAO7bSm9tEbG1RrOlGT23ME1CaBoetGSMRLymutvojn/b/EKfJIr5rLzQa+14Lvg2g==" + }, + "node_modules/@patternfly/react-core": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-5.4.1.tgz", + "integrity": "sha512-PJjwN4OCR7jTdWKi0RzuFdtlSQ8gBR+0REczuDHHPW8ky0bs1cIcqGsn5p/b6OgPlztl3UaXqRYLsroiEMasOw==", + "dependencies": { + "@patternfly/react-icons": "^5.4.0", + "@patternfly/react-styles": "^5.4.0", + "@patternfly/react-tokens": "^5.4.0", + "focus-trap": "7.5.4", + "react-dropzone": "^14.2.3", + "tslib": "^2.6.3" + }, + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, + "node_modules/@patternfly/react-icons": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-5.4.0.tgz", + "integrity": "sha512-2M3qN/naultvRHeG2laJMmoIroFCGAyfwTVrnCjSkG6/KnRoXV0+dqd+Xrh7xzpzvIJB1klvifC0oX42cEkDrA==", + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, + "node_modules/@patternfly/react-styles": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-5.4.0.tgz", + "integrity": "sha512-4ZE0s6LkX/0KsN0FOeogrDoj18m+BPA73YKnabZGB4SDRzrBNeBh2a6bSt546ZseEjkoJ+S81kOG0G8YckPQYg==" + }, + "node_modules/@patternfly/react-tokens": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.4.0.tgz", + "integrity": "sha512-KONkwCVOMyklhuuaYeYgcAsGtCBQXnsBGZeolhOdSzr2Mj0RVSW0oMrQPgZuPVzhhC/kbqgClHJJl6xuG9xheA==" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1616,6 +1665,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -2254,6 +2311,53 @@ "node": ">= 8" } }, + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -3177,6 +3281,17 @@ "node": ">=16.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3343,6 +3458,14 @@ "dev": true, "license": "ISC" }, + "node_modules/focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "dependencies": { + "tabbable": "^6.2.0" + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3727,6 +3850,7 @@ "node": ">= 14" } }, +<<<<<<< HEAD "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -3751,6 +3875,18 @@ }, "funding": { "url": "https://github.com/sponsors/typicode" +======= + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" +>>>>>>> 528a683 (Generate mock data for incidents) } }, "node_modules/ieee754": { @@ -5116,6 +5252,7 @@ "node": ">=6" } }, +<<<<<<< HEAD "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", @@ -5127,6 +5264,79 @@ }, "funding": { "url": "https://github.com/sponsors/sindresorhus" +======= + "node_modules/mini-css-extract-plugin": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", + "integrity": "sha512-+Vyi+GCCOHnrJ2VPS+6aPoXN2k2jgUzDRhTFLjjTBn23qyXJXkjUWQgTL+mXpF5/A8ixLdCc6kWsoeOjKGejKQ==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" +>>>>>>> 528a683 (Generate mock data for incidents) } }, "node_modules/minimatch": { @@ -5328,6 +5538,24 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5390,7 +5618,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5889,6 +6116,112 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5939,7 +6272,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -6009,11 +6341,26 @@ "react": "^18.3.1" } }, + "node_modules/react-dropzone": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.6.tgz", + "integrity": "sha512-arXJyFVV+ld869AOS7ikqYJLuSklxXfiiD/+b+umknqC+u0hg+K3HMYgzKDLAi6RVnfBiILk5oluGZ8Z/PVrEw==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 20.17" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, "node_modules/readable-stream": { @@ -6558,6 +6905,15 @@ "node": ">= 8" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -6826,6 +7182,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "dev": true, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, "node_modules/supports-color": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", @@ -6869,6 +7241,11 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -7058,7 +7435,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { diff --git a/vscode/package.json b/vscode/package.json index 6d01635..f442e68 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -31,7 +31,6 @@ "MTA", "Analyze" ], - "activationEvents": [], "main": "./out/extension.js", "contributes": { "commands": [ @@ -276,6 +275,7 @@ "prepare": "cd .. && husky vscode/.husky" }, "devDependencies": { + "@eslint/js": "^9.11.1", "@types/mocha": "^10.0.7", "@types/node": "20.x", "@types/react": "^18.3.8", @@ -284,25 +284,29 @@ "@types/vscode": "^1.93.0", "@typescript-eslint/eslint-plugin": "^8.7.0", "@typescript-eslint/parser": "^8.7.0", - "typescript-eslint": "^8.7.0", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", + "css-loader": "^7.1.2", "eslint": "^9.11.1", - "@eslint/js": "^9.11.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.36.1", "eslint-plugin-unused-imports": "^4.1.4", "husky": "^9.1.6", "lint-staged": "^15.2.10", + "mini-css-extract-plugin": "^2.9.1", + "prettier": "^3.0.2", + "rimraf": "^4.4.1", + "style-loader": "^4.0.0", "ts-loader": "^9.5.1", "typescript": "^5.6.2", + "typescript-eslint": "^8.7.0", "webpack": "^5.94.0", - "webpack-cli": "^5.1.4", - "prettier": "^3.0.2", - "rimraf": "^4.4.1" + "webpack-cli": "^5.1.4" }, "dependencies": { + "@patternfly/patternfly": "^5.4.1", + "@patternfly/react-core": "^5.4.0", "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/vscode/src/KonveyorGUIWebviewViewProvider.ts b/vscode/src/KonveyorGUIWebviewViewProvider.ts index a75c1d7..f04853d 100644 --- a/vscode/src/KonveyorGUIWebviewViewProvider.ts +++ b/vscode/src/KonveyorGUIWebviewViewProvider.ts @@ -1,5 +1,7 @@ import * as vscode from "vscode"; import { getWebviewContent } from "./webviewContent"; +import { ExtensionState } from "./extensionState"; +import { setupWebviewMessageListener } from "./webviewMessageHandler"; export class KonveyorGUIWebviewViewProvider implements vscode.WebviewViewProvider { public static readonly viewType = "konveyor.konveyorGUIView"; @@ -10,9 +12,10 @@ export class KonveyorGUIWebviewViewProvider implements vscode.WebviewViewProvide constructor( private readonly windowId: string, - private readonly extensionContext: vscode.ExtensionContext, + private readonly extensionState: ExtensionState, ) { this.outputChannel = vscode.window.createOutputChannel("Konveyor"); + this.extensionState.webviewProviders.add(this); } get isVisible() { @@ -41,12 +44,22 @@ export class KonveyorGUIWebviewViewProvider implements vscode.WebviewViewProvide webviewView.webview.options = { enableScripts: true, localResourceRoots: [ - vscode.Uri.joinPath(this.extensionContext.extensionUri, "media"), - vscode.Uri.joinPath(this.extensionContext.extensionUri, "out"), + vscode.Uri.joinPath(this.extensionState.extensionContext.extensionUri, "media"), + vscode.Uri.joinPath(this.extensionState.extensionContext.extensionUri, "out"), ], }; - webviewView.webview.html = getWebviewContent(this.extensionContext, webviewView.webview, true); + webviewView.webview.html = getWebviewContent( + this.extensionState.extensionContext, + webviewView.webview, + true, + ); + + setupWebviewMessageListener(webviewView.webview, this.extensionState, this); + + webviewView.onDidDispose(() => { + this.extensionState.webviewProviders.delete(this); + }); if (this.webviewReadyCallback) { this.webviewReadyCallback(webviewView.webview); diff --git a/vscode/src/VsCodeExtension.ts b/vscode/src/VsCodeExtension.ts index 5e1c1ee..39651c0 100644 --- a/vscode/src/VsCodeExtension.ts +++ b/vscode/src/VsCodeExtension.ts @@ -3,7 +3,7 @@ import { v4 as uuidv4 } from "uuid"; import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider"; import { registerAllCommands } from "./commands"; import { setupWebviewMessageListener } from "./webviewMessageHandler"; -import { ExtensionState } from "./extensionState"; +import { ExtensionState, SharedState } from "./extensionState"; export class VsCodeExtension { private extensionContext: vscode.ExtensionContext; @@ -14,10 +14,17 @@ export class VsCodeExtension { this.extensionContext = context; this.windowId = uuidv4(); - const sidebarProvider = new KonveyorGUIWebviewViewProvider( - this.windowId, - this.extensionContext, - ); + this.state = { + sharedState: new SharedState(), + webviewProviders: new Set(), + sidebarProvider: undefined as any, + extensionContext: context, + }; + + const sidebarProvider = new KonveyorGUIWebviewViewProvider(this.windowId, this.state); + + this.state.sidebarProvider = sidebarProvider; + this.state.webviewProviders.add(sidebarProvider); // Check for multi-root workspace if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 1) { @@ -26,11 +33,6 @@ export class VsCodeExtension { ); } - this.state = { - sidebarProvider, - }; - - // Sidebar context.subscriptions.push( vscode.window.registerWebviewViewProvider("konveyor.konveyorGUIView", sidebarProvider, { webviewOptions: { @@ -40,10 +42,9 @@ export class VsCodeExtension { ); sidebarProvider.onWebviewReady((webview) => { - setupWebviewMessageListener(webview); + setupWebviewMessageListener(webview, this.state, sidebarProvider); }); - // Commands - registerAllCommands(this.extensionContext, this.state); + registerAllCommands(this.state); } } diff --git a/vscode/src/commands.ts b/vscode/src/commands.ts index 7e055aa..d52a70d 100644 --- a/vscode/src/commands.ts +++ b/vscode/src/commands.ts @@ -3,6 +3,9 @@ import { setupWebviewMessageListener } from "./webviewMessageHandler"; import { ExtensionState } from "./extensionState"; import { getWebviewContent } from "./webviewContent"; import { sourceOptions, targetOptions } from "./config/labels"; +import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider"; +import { Incident } from "./webview/types"; +import { generateMockIncidentData } from "./generateMockData"; let fullScreenPanel: vscode.WebviewPanel | undefined; @@ -11,13 +14,60 @@ function getFullScreenTab() { return tabs.find((tab) => (tab.input as any)?.viewType?.endsWith("konveyor.konveyorGUIView")); } -const commandsMap: ( - extensionContext: vscode.ExtensionContext, - state: ExtensionState, -) => { +async function analyzeFileContent(contentString: string, state: ExtensionState) { + const { extensionContext } = state; + + const incidentDataString = extensionContext.workspaceState.get("incidentData", "[]"); + const incidentData = JSON.parse(incidentDataString) as Incident[]; + + const diagnosticCollection = vscode.languages.createDiagnosticCollection("konveyor"); + const diagnosticsMap: Map = new Map(); + + incidentData.forEach((incident) => { + const fileUri = vscode.Uri.parse(incident.file); + + const lineNumber = incident.line ? incident.line - 1 : 0; + const severity = + incident.severity === "High" + ? vscode.DiagnosticSeverity.Error + : incident.severity === "Medium" + ? vscode.DiagnosticSeverity.Warning + : vscode.DiagnosticSeverity.Information; + + const diagnostic = new vscode.Diagnostic( + new vscode.Range( + new vscode.Position(lineNumber, 0), + new vscode.Position(lineNumber, Number.MAX_VALUE), + ), + incident.message, + severity, + ); + + const diagnostics = diagnosticsMap.get(fileUri.toString()) || []; + diagnostics.push(diagnostic); + diagnosticsMap.set(fileUri.toString(), diagnostics); + }); + + diagnosticsMap.forEach((diagnostics, fileUri) => { + diagnosticCollection.set(vscode.Uri.parse(fileUri), diagnostics); + }); + + const sidebarProvider = state.sidebarProvider; + if (sidebarProvider && sidebarProvider.webview) { + sidebarProvider.webview.postMessage({ + command: "incidentData", + data: incidentData, + }); + } + + // Optionally, show an information message upon completion + vscode.window.showInformationMessage("Diagnostics created based on mock analysis."); +} + +const commandsMap: (state: ExtensionState) => { [command: string]: (...args: any) => any; -} = (extensionContext, state) => { - const { sidebarProvider } = state; +} = (state) => { + const { sidebarProvider, extensionContext } = state; return { "konveyor.startAnalysis": async (resource: vscode.Uri) => { if (!resource) { @@ -25,22 +75,18 @@ const commandsMap: ( return; } - // Get the file path const filePath = resource.fsPath; - // Perform your analysis logic here try { - // For example, read the file content const fileContent = await vscode.workspace.fs.readFile(resource); const contentString = Buffer.from(fileContent).toString("utf8"); - console.log(contentString, fileContent); - - // TODO: Analyze the file content - vscode.window.showInformationMessage(`Analyzing file: ${filePath}`); + await extensionContext.workspaceState.update( + "incidentData", + JSON.stringify(generateMockIncidentData()), + ); - // Call your analysis function/module - // analyzeFileContent(contentString); + await analyzeFileContent(contentString, state); } catch (error) { vscode.window.showErrorMessage(`Failed to analyze file: ${error}`); } @@ -49,10 +95,8 @@ const commandsMap: ( "konveyor.focusKonveyorInput": async () => { const fullScreenTab = getFullScreenTab(); if (!fullScreenTab) { - // focus sidebar vscode.commands.executeCommand("konveyor.konveyorGUIView.focus"); } else { - // focus fullscreen fullScreenPanel?.reveal(); } // sidebar.webviewProtocol?.request("focusInput", undefined); @@ -77,28 +121,30 @@ const commandsMap: ( //create the full screen panel const panel = vscode.window.createWebviewPanel( - "konveyor.konveyorGUIView", + "konveyor.konveyorFullScreenView", "Konveyor", vscode.ViewColumn.One, { retainContextWhenHidden: true, enableScripts: true, + localResourceRoots: [ + vscode.Uri.joinPath(extensionContext.extensionUri, "media"), + vscode.Uri.joinPath(extensionContext.extensionUri, "out"), + ], }, ); fullScreenPanel = panel; //Add content to the panel - panel.webview.html = getWebviewContent( - extensionContext, - sidebarProvider?.webview || panel.webview, - true, - ); + panel.webview.html = getWebviewContent(extensionContext, panel.webview, true); - setupWebviewMessageListener(panel.webview); + setupWebviewMessageListener(panel.webview, state, sidebarProvider); //When panel closes, reset the webview and focus panel.onDidDispose( () => { + state.webviewProviders.delete(sidebarProvider); + fullScreenPanel = undefined; vscode.commands.executeCommand("konveyor.focusKonveyorInput"); }, null, @@ -297,8 +343,8 @@ const commandsMap: ( }; }; -export function registerAllCommands(context: vscode.ExtensionContext, state: ExtensionState) { - for (const [command, callback] of Object.entries(commandsMap(context, state))) { - context.subscriptions.push(vscode.commands.registerCommand(command, callback)); +export function registerAllCommands(state: ExtensionState) { + for (const [command, callback] of Object.entries(commandsMap(state))) { + state.extensionContext.subscriptions.push(vscode.commands.registerCommand(command, callback)); } } diff --git a/vscode/src/extensionState.ts b/vscode/src/extensionState.ts index c16df25..af8f980 100644 --- a/vscode/src/extensionState.ts +++ b/vscode/src/extensionState.ts @@ -1,7 +1,21 @@ -// extensionState.ts import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider"; +import * as vscode from "vscode"; + +export class SharedState { + private state: Map = new Map(); + + get(key: string) { + return this.state.get(key); + } + + set(key: string, value: any) { + this.state.set(key, value); + } +} export interface ExtensionState { + sharedState: SharedState; + webviewProviders: Set; sidebarProvider: KonveyorGUIWebviewViewProvider; - // Add other shared components as needed + extensionContext: vscode.ExtensionContext; // Add this line } diff --git a/vscode/src/generateMockData.ts b/vscode/src/generateMockData.ts new file mode 100644 index 0000000..774e3f9 --- /dev/null +++ b/vscode/src/generateMockData.ts @@ -0,0 +1,99 @@ +import { Incident } from "./webview/types"; + +export function generateMockIncidentData(): Incident[] { + const mockData = [ + { + id: "0000", + name: "configuration-utils", + rulesets: [ + { + name: "java/code-quality", + description: + "This ruleset analyzes Java applications for best practices and code quality improvements.", + violations: { + "use-logging-framework-00001": { + description: + "Replace System.out.println statements with a logging framework.", + category: "mandatory", + labels: [ + "konveyor.io/source", + "konveyor.io/target=java", + "konveyor.io/category=logging", + ], + incidents: [ + { + uri: "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/src/main/java/io/konveyor/demo/config/ApplicationConfiguration.java", + message: + "Replace `System.out.println` with a logging framework for better flexibility and control over logging levels.", + lineNumber: 20, // Assuming line 20 contains System.out.println + variables: { + matchingText: "System.out.println", + }, + }, + ], + effort: 1, + }, + "handle-exceptions-properly-00002": { + description: + "Handle exceptions appropriately instead of using generic catch blocks.", + category: "potential", + labels: [ + "konveyor.io/source", + "konveyor.io/target=java", + "konveyor.io/category=exception-handling", + ], + incidents: [ + { + uri: "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/src/main/java/io/konveyor/demo/config/ApplicationConfiguration.java", + message: + "Consider handling specific exceptions or rethrowing them after logging.", + lineNumber: 17, // Assuming line 17 contains 'catch (Exception e)' + variables: { + matchingText: "catch (Exception e)", + }, + }, + ], + effort: 2, + }, + }, + }, + ], + depItems: [ + { + fileURI: + "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/pom.xml", + provider: "java", + dependencies: [], + }, + ], + }, + ]; + + const incidents: Incident[] = []; + + mockData.forEach((app) => { + app.rulesets.forEach((ruleset) => { + if (ruleset.violations) { + Object.values(ruleset.violations).forEach((violation: any) => { + violation.incidents.forEach((incident: any) => { + incidents.push({ + id: `${incident.uri}:${incident.lineNumber}`, + file: incident.uri, + line: incident.lineNumber, + severity: + violation.category === "mandatory" + ? "High" + : violation.category === "potential" + ? "Medium" + : "Low", + message: incident.message, + // Include additional fields if needed + }); + }); + }); + } + }); + }); + + return incidents; +} \ No newline at end of file diff --git a/vscode/src/webview/components/App.tsx b/vscode/src/webview/components/App.tsx index f1c1ad4..d375c2f 100644 --- a/vscode/src/webview/components/App.tsx +++ b/vscode/src/webview/components/App.tsx @@ -1,35 +1,69 @@ -import * as React from "react"; +import React, { useState, useEffect } from "react"; +import { Incident } from "../types"; +import { vscode } from "../globals"; +import { + Page, + PageSection, + PageSectionVariants, + Title, + EmptyState, + EmptyStateIcon, + EmptyStateBody, + Button, +} from "@patternfly/react-core"; +import { SearchIcon } from "@patternfly/react-icons"; +import IncidentList from "./IncidentList"; -// Global variable vscode pulled from the window object. -interface vscode { - postMessage(message: any): void; -} -declare const vscode: vscode; +const App: React.FC = () => { + const [incidents, setIncidents] = useState([]); -const sendMessage = () => { - console.log("button clicked"); - vscode.postMessage({ command: "testing" }); -}; - -const App = () => { - const [buttonText, setButtonText] = React.useState("The brain is pending"); + useEffect(() => { + vscode.postMessage({ command: "requestIncidentData" }); - React.useEffect(() => { - window.addEventListener("message", (event) => { - const message = event.data; // The json data that the extension sent + const handleMessage = (event: MessageEvent) => { + const message = event.data; switch (message.command) { - case "refactor": - setButtonText("The brain is working"); + case "incidentData": + if (message.data && message.data.length > 0) { + setIncidents(message.data); + } break; + // Handle other messages... } - }); - }); + }; + + window.addEventListener("message", handleMessage); + + return () => { + window.removeEventListener("message", handleMessage); + }; + }, []); return ( -
-

Functional Components Work!

- -
+ + + Konveyor Analysis Results + + + {incidents.length > 0 ? ( + + ) : ( + + + + No Incidents Found + + Run an analysis to see results here. + + + )} + + ); }; diff --git a/vscode/src/webview/components/IncidentList.tsx b/vscode/src/webview/components/IncidentList.tsx new file mode 100644 index 0000000..608d5e5 --- /dev/null +++ b/vscode/src/webview/components/IncidentList.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { Incident } from "../types"; +import { vscode } from "../globals"; +import { + DataList, + DataListItem, + DataListItemRow, + DataListItemCells, + DataListCell, + DataListAction, + Button, + Label, +} from "@patternfly/react-core"; +import { + ExclamationCircleIcon, + ExclamationTriangleIcon, + InfoCircleIcon, +} from "@patternfly/react-icons"; + +interface IncidentListProps { + incidents: Incident[]; +} + +const severityIconMap = { + High: , + Medium: , + Low: , +}; + +const IncidentList: React.FC = ({ incidents }) => { + const handleIncidentClick = (incident: Incident) => { + vscode.postMessage({ + command: "openFile", + file: incident.file, + line: incident.line, + }); + }; + + if (!incidents || incidents.length === 0) { + return
No incidents found.
; + } + + return ( + + {incidents.map((incident) => ( + + + {severityIconMap[incident.severity]}, + +
+ {incident.message} +
+
+ +
+
File: {incident.file}
+
Line: {incident.line}
+
, + ]} + /> + + + +
+
+ ))} +
+ ); +}; + +export default IncidentList; diff --git a/vscode/src/webview/globals.ts b/vscode/src/webview/globals.ts new file mode 100644 index 0000000..c586b8d --- /dev/null +++ b/vscode/src/webview/globals.ts @@ -0,0 +1,14 @@ +export interface VscodeApi { + postMessage(message: any): void; + // Include other methods if needed (e.g., setState, getState) +} + +// Declare the global window interface to include 'vscode' +declare global { + interface Window { + vscode: VscodeApi; + } +} + +// Export 'vscode' from 'window' +export const vscode = window.vscode; diff --git a/vscode/src/webview/index.tsx b/vscode/src/webview/index.tsx index 77fc371..3326233 100644 --- a/vscode/src/webview/index.tsx +++ b/vscode/src/webview/index.tsx @@ -1,3 +1,5 @@ +import "@patternfly/patternfly/patternfly.css"; + import React from "react"; import { createRoot } from "react-dom/client"; diff --git a/vscode/src/webview/types.ts b/vscode/src/webview/types.ts new file mode 100644 index 0000000..fc820d8 --- /dev/null +++ b/vscode/src/webview/types.ts @@ -0,0 +1,7 @@ +export interface Incident { + id: string; + file: string; + line: number; + severity: "High" | "Medium" | "Low"; + message: string; +} diff --git a/vscode/src/webviewContent.ts b/vscode/src/webviewContent.ts index 4ea699d..4893d20 100644 --- a/vscode/src/webviewContent.ts +++ b/vscode/src/webviewContent.ts @@ -7,34 +7,47 @@ export function getWebviewContent( isFullScreen: boolean = false, ): string { const extensionUri = context.extensionUri; + const scriptUri = webview.asWebviewUri( vscode.Uri.joinPath(extensionUri, "out", "webview", "main.wv.js"), ); - const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, "media", "styles.css")); + + const styleUri = webview.asWebviewUri( + vscode.Uri.joinPath(extensionUri, "out", "webview", "main.css"), + ); + const nonce = getNonce(); return ` - - - - - - Konveyor - - - -
- - ${``} - - - `; + + + + + + Konveyor + + + + +
+ + + + +`; } diff --git a/vscode/src/webviewMessageHandler.ts b/vscode/src/webviewMessageHandler.ts index 04fee5d..541928e 100644 --- a/vscode/src/webviewMessageHandler.ts +++ b/vscode/src/webviewMessageHandler.ts @@ -1,16 +1,43 @@ import * as vscode from "vscode"; +import { ExtensionState } from "./extensionState"; +import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider"; + +export function setupWebviewMessageListener( + webview: vscode.Webview, + state: ExtensionState, + provider: KonveyorGUIWebviewViewProvider, +) { + const incidentDataString = state.extensionContext.workspaceState.get( + "incidentData", + "[]", + ); + const incidentData = JSON.parse(incidentDataString); + + webview.onDidReceiveMessage(async (message) => { + const fileUri = vscode.Uri.parse(message.file); -export function setupWebviewMessageListener(webview: vscode.Webview) { - return webview.onDidReceiveMessage(async (message: any) => { switch (message.command) { - case "startup": - console.log("received startup message from webview"); + case "requestIncidentData": + webview.postMessage({ + command: "incidentData", + data: incidentData, + }); break; - case "testing": - console.log("received testing message from webview"); - webview.postMessage({ command: "refactor" }); + + case "openFile": + try { + const doc = await vscode.workspace.openTextDocument(fileUri); + const editor = await vscode.window.showTextDocument(doc, { + preview: true, + }); + const position = new vscode.Position(message.line - 1, 0); + const range = new vscode.Range(position, position); + editor.selection = new vscode.Selection(position, position); + editor.revealRange(range, vscode.TextEditorRevealType.InCenter); + } catch (error) { + vscode.window.showErrorMessage(`Failed to open file: ${error}`); + } break; - // Add more cases as needed } }); } diff --git a/vscode/webpack.config.js b/vscode/webpack.config.js index 5f7b7a8..4d089b0 100644 --- a/vscode/webpack.config.js +++ b/vscode/webpack.config.js @@ -1,4 +1,5 @@ const path = require("path"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = (env, argv) => { const mode = argv.mode || "none"; @@ -57,13 +58,21 @@ module.exports = (env, argv) => { }, module: { rules: [ - { test: /\.tsx?$/, use: ["babel-loader", "ts-loader"] }, + { + test: /\.tsx?$/, + use: ["babel-loader", "ts-loader"], + }, { test: /\.css$/, - use: ["style-loader", "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"], }, ], }, + plugins: [ + new MiniCssExtractPlugin({ + filename: "[name].css", + }), + ], devtool: isDev ? "inline-cheap-module-source-map" : false, watch: isDev, watchOptions: { From ae3ff1d52269316a684811078394876cdf8c3d06 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Wed, 2 Oct 2024 17:53:51 -0400 Subject: [PATCH 2/8] Package-lock regen Signed-off-by: Ian Bolton --- vscode/package-lock.json | 75 ++++++---------------------------------- 1 file changed, 10 insertions(+), 65 deletions(-) diff --git a/vscode/package-lock.json b/vscode/package-lock.json index a3dd60d..df927fd 100644 --- a/vscode/package-lock.json +++ b/vscode/package-lock.json @@ -34,12 +34,9 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.36.1", "eslint-plugin-unused-imports": "^4.1.4", -<<<<<<< HEAD "husky": "^9.1.6", "lint-staged": "^15.2.10", -======= "mini-css-extract-plugin": "^2.9.1", ->>>>>>> 528a683 (Generate mock data for incidents) "prettier": "^3.0.2", "rimraf": "^4.4.1", "style-loader": "^4.0.0", @@ -50,7 +47,7 @@ "webpack-cli": "^5.1.4" }, "engines": { - "node": ">=20.12.2", + "node": ">=20.13.0", "npm": "^9.5.0 || ^10.5.2", "vscode": "^1.93.0" } @@ -1470,7 +1467,6 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, - "license": "MIT", "dependencies": { "environment": "^1.0.0" }, @@ -2102,7 +2098,6 @@ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, - "license": "MIT", "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" @@ -2119,7 +2114,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2131,15 +2125,13 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cli-truncate/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -2157,7 +2149,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2553,7 +2544,6 @@ "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -3135,8 +3125,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/events": { "version": "3.3.0", @@ -3152,7 +3141,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", @@ -3176,7 +3164,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -3189,7 +3176,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, - "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" }, @@ -3563,7 +3549,6 @@ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -3596,7 +3581,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -3850,13 +3834,11 @@ "node": ">= 14" } }, -<<<<<<< HEAD "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=16.17.0" } @@ -3866,7 +3848,6 @@ "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", "dev": true, - "license": "MIT", "bin": { "husky": "bin.js" }, @@ -3875,7 +3856,8 @@ }, "funding": { "url": "https://github.com/sponsors/typicode" -======= + } + }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", @@ -3886,7 +3868,6 @@ }, "peerDependencies": { "postcss": "^8.1.0" ->>>>>>> 528a683 (Generate mock data for incidents) } }, "node_modules/ieee754": { @@ -4366,7 +4347,6 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4759,7 +4739,6 @@ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "dev": true, - "license": "MIT", "engines": { "node": ">=14" }, @@ -4772,7 +4751,6 @@ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "~5.3.0", "commander": "~12.1.0", @@ -4800,7 +4778,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -4813,7 +4790,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" } @@ -4823,7 +4799,6 @@ "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, - "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -4841,7 +4816,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -4854,7 +4828,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -4866,15 +4839,13 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/listr2/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -4892,7 +4863,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -4908,7 +4878,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -4975,7 +4944,6 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "license": "MIT", "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", @@ -4995,7 +4963,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -5008,7 +4975,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -5021,7 +4987,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, - "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" }, @@ -5036,15 +5001,13 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, - "license": "MIT", "dependencies": { "get-east-asian-width": "^1.0.0" }, @@ -5060,7 +5023,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, - "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" }, @@ -5076,7 +5038,6 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "license": "MIT", "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" @@ -5093,7 +5054,6 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" @@ -5110,7 +5070,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -5128,7 +5087,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -5144,7 +5102,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -5252,19 +5209,18 @@ "node": ">=6" } }, -<<<<<<< HEAD "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" -======= + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", @@ -5336,7 +5292,6 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" ->>>>>>> 528a683 (Generate mock data for incidents) } }, "node_modules/minimatch": { @@ -5590,7 +5545,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^4.0.0" }, @@ -5606,7 +5560,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -6029,7 +5982,6 @@ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" }, @@ -6554,8 +6506,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/rimraf": { "version": "4.4.1", @@ -6857,7 +6808,6 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" @@ -6874,7 +6824,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -6887,7 +6836,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -6964,7 +6912,6 @@ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.6.19" } @@ -7161,7 +7108,6 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -8081,7 +8027,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", "dev": true, - "license": "ISC", "bin": { "yaml": "bin.mjs" }, From f58c2d65f386538f3a055ff6f5ef9a210774a656 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Thu, 3 Oct 2024 12:47:06 -0400 Subject: [PATCH 3/8] Add violations / incidents tab approach --- vscode/package-lock.json | 23 ++++ vscode/package.json | 1 + vscode/src/commands.ts | 3 +- .../webview/components/AnalysisResults.tsx | 26 ++++ vscode/src/webview/components/App.tsx | 90 +++++++++--- .../webview/components/IncidentDetails.tsx | 30 ++++ .../src/webview/components/IncidentList.tsx | 129 +++++++++--------- .../src/webview/components/IncidentsPanel.tsx | 92 +++++++++++++ .../src/webview/components/ViolationsList.tsx | 33 +++++ .../mockData.ts} | 44 ++++-- vscode/src/webview/types.ts | 71 ++++++++++ vscode/src/webviewMessageHandler.ts | 6 +- 12 files changed, 446 insertions(+), 102 deletions(-) create mode 100644 vscode/src/webview/components/AnalysisResults.tsx create mode 100644 vscode/src/webview/components/IncidentDetails.tsx create mode 100644 vscode/src/webview/components/IncidentsPanel.tsx create mode 100644 vscode/src/webview/components/ViolationsList.tsx rename vscode/src/{generateMockData.ts => webview/mockData.ts} (72%) diff --git a/vscode/package-lock.json b/vscode/package-lock.json index df927fd..adb29f6 100644 --- a/vscode/package-lock.json +++ b/vscode/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@patternfly/patternfly": "^5.4.1", "@patternfly/react-core": "^5.4.0", + "@patternfly/react-table": "^5.4.1", "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -805,6 +806,23 @@ "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-5.4.0.tgz", "integrity": "sha512-4ZE0s6LkX/0KsN0FOeogrDoj18m+BPA73YKnabZGB4SDRzrBNeBh2a6bSt546ZseEjkoJ+S81kOG0G8YckPQYg==" }, + "node_modules/@patternfly/react-table": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.4.1.tgz", + "integrity": "sha512-T05djy6YPqjbGWjpnwUs9oqup8oqqIOBnDOcThnHukgzlwnZvLNywgdoMR5XAKxTcIx/iBE1cu8ieETlITOGLw==", + "dependencies": { + "@patternfly/react-core": "^5.4.1", + "@patternfly/react-icons": "^5.4.0", + "@patternfly/react-styles": "^5.4.0", + "@patternfly/react-tokens": "^5.4.0", + "lodash": "^4.17.21", + "tslib": "^2.6.3" + }, + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, "node_modules/@patternfly/react-tokens": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.4.0.tgz", @@ -4915,6 +4933,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/vscode/package.json b/vscode/package.json index f442e68..1e6ff6d 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -307,6 +307,7 @@ "dependencies": { "@patternfly/patternfly": "^5.4.1", "@patternfly/react-core": "^5.4.0", + "@patternfly/react-table": "^5.4.1", "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/vscode/src/commands.ts b/vscode/src/commands.ts index d52a70d..f5bf2d7 100644 --- a/vscode/src/commands.ts +++ b/vscode/src/commands.ts @@ -3,9 +3,8 @@ import { setupWebviewMessageListener } from "./webviewMessageHandler"; import { ExtensionState } from "./extensionState"; import { getWebviewContent } from "./webviewContent"; import { sourceOptions, targetOptions } from "./config/labels"; -import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider"; import { Incident } from "./webview/types"; -import { generateMockIncidentData } from "./generateMockData"; +import { generateMockIncidentData } from "./webview/mockData"; let fullScreenPanel: vscode.WebviewPanel | undefined; diff --git a/vscode/src/webview/components/AnalysisResults.tsx b/vscode/src/webview/components/AnalysisResults.tsx new file mode 100644 index 0000000..d856651 --- /dev/null +++ b/vscode/src/webview/components/AnalysisResults.tsx @@ -0,0 +1,26 @@ +import React from "react"; + +interface AnalysisResultsProps { + results: string[]; +} + +const AnalysisResults: React.FC = ({ results }) => { + return ( +
+

Analysis Results

+ {results.length === 0 ? ( +

No results yet. Start the analysis to see results.

+ ) : ( +
    + {results.map((result, index) => ( +
  • + {result} +
  • + ))} +
+ )} +
+ ); +}; + +export default AnalysisResults; diff --git a/vscode/src/webview/components/App.tsx b/vscode/src/webview/components/App.tsx index d375c2f..9ee4173 100644 --- a/vscode/src/webview/components/App.tsx +++ b/vscode/src/webview/components/App.tsx @@ -1,10 +1,11 @@ import React, { useState, useEffect } from "react"; -import { Incident } from "../types"; -import { vscode } from "../globals"; import { Page, PageSection, - PageSectionVariants, + Tabs, + Tab, + TabTitleText, + TabContent, Title, EmptyState, EmptyStateIcon, @@ -12,23 +13,29 @@ import { Button, } from "@patternfly/react-core"; import { SearchIcon } from "@patternfly/react-icons"; -import IncidentList from "./IncidentList"; +import ViolationsList from "./ViolationsList"; +import IncidentsPanel from "./IncidentsPanel"; +import { RuleSet } from "../types"; +import { vscode } from "../globals"; +import { generateMockRuleSet } from "../mockData"; const App: React.FC = () => { - const [incidents, setIncidents] = useState([]); + const [ruleSet, setRuleSet] = useState(null); + const [selectedViolation, setSelectedViolation] = useState(null); + const [isAnalyzing, setIsAnalyzing] = useState(false); + const [activeTabKey, setActiveTabKey] = useState(0); useEffect(() => { - vscode.postMessage({ command: "requestIncidentData" }); + vscode.postMessage({ command: "requestAnalysisData" }); const handleMessage = (event: MessageEvent) => { const message = event.data; switch (message.command) { - case "incidentData": - if (message.data && message.data.length > 0) { - setIncidents(message.data); + case "analysisData": + if (message.data) { + setRuleSet(message.data); } break; - // Handle other messages... } }; @@ -39,26 +46,71 @@ const App: React.FC = () => { }; }, []); + const handleViolationClick = (violationId: string) => { + setSelectedViolation(violationId); + setActiveTabKey(1); // Switch to Incidents tab + }; + + const startAnalysis = () => { + setIsAnalyzing(true); + // Simulate analysis delay + setTimeout(() => { + setRuleSet(generateMockRuleSet()); + setIsAnalyzing(false); + }, 2000); + }; + + const handleTabClick = ( + event: React.MouseEvent, + tabIndex: string | number, + ) => { + setActiveTabKey(tabIndex); + }; + return ( - - Konveyor Analysis Results - - {incidents.length > 0 ? ( - + + Konveyor Analysis + + {ruleSet && ruleSet.violations ? ( + + Violations}> + + + + + Incidents}> + + + + + ) : ( - - No Incidents Found + <Title headingLevel="h2" size="lg"> + No Analysis Results Run an analysis to see results here. )} diff --git a/vscode/src/webview/components/IncidentDetails.tsx b/vscode/src/webview/components/IncidentDetails.tsx new file mode 100644 index 0000000..9e2473d --- /dev/null +++ b/vscode/src/webview/components/IncidentDetails.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { Incident } from "../types"; +import { TextContent, Text, TextVariants } from "@patternfly/react-core"; + +interface IncidentDetailsProps { + incident: Incident | null; +} + +const IncidentDetails: React.FC = ({ incident }) => { + if (!incident) { + return
Select an incident to see details.
; + } + + return ( + + {incident.message} + + Severity: {incident.severity} + + + File: {incident.file} + + + Line: {incident.line} + + + ); +}; + +export default IncidentDetails; diff --git a/vscode/src/webview/components/IncidentList.tsx b/vscode/src/webview/components/IncidentList.tsx index 608d5e5..7929e05 100644 --- a/vscode/src/webview/components/IncidentList.tsx +++ b/vscode/src/webview/components/IncidentList.tsx @@ -1,79 +1,76 @@ import React from "react"; -import { Incident } from "../types"; -import { vscode } from "../globals"; -import { - DataList, - DataListItem, - DataListItemRow, - DataListItemCells, - DataListCell, - DataListAction, - Button, - Label, -} from "@patternfly/react-core"; -import { - ExclamationCircleIcon, - ExclamationTriangleIcon, - InfoCircleIcon, -} from "@patternfly/react-icons"; +import { Table, Thead, Tbody, Tr, Th, Td } from "@patternfly/react-table"; +import { Card, CardBody, CardHeader, CardTitle } from "@patternfly/react-core"; -interface IncidentListProps { +interface Incident { + id: string; + title: string; + severity: "Low" | "Medium" | "High" | "Critical"; + status: "Open" | "In Progress" | "Resolved" | "Closed"; + lastUpdated: string; +} + +interface IncidentsListProps { incidents: Incident[]; } -const severityIconMap = { - High: , - Medium: , - Low: , -}; +const IncidentsList: React.FC = ({ incidents }) => { + const [sortBy, setSortBy] = React.useState({ + index: 0, + direction: "asc" as "asc" | "desc", + }); + + const columns = ["ID", "Title", "Severity", "Status", "Last Updated"]; -const IncidentList: React.FC = ({ incidents }) => { - const handleIncidentClick = (incident: Incident) => { - vscode.postMessage({ - command: "openFile", - file: incident.file, - line: incident.line, - }); + const onSort = (index: number) => { + setSortBy((prev) => ({ + index, + direction: prev.index === index && prev.direction === "asc" ? "desc" : "asc", + })); }; - if (!incidents || incidents.length === 0) { - return
No incidents found.
; - } + const sortedIncidents = [...incidents].sort((a, b) => { + const aValue = Object.values(a)[sortBy.index]; + const bValue = Object.values(b)[sortBy.index]; + if (aValue < bValue) { + return sortBy.direction === "asc" ? -1 : 1; + } + if (aValue > bValue) { + return sortBy.direction === "asc" ? 1 : -1; + } + return 0; + }); return ( - - {incidents.map((incident) => ( - - - {severityIconMap[incident.severity]}, - -
- {incident.message} -
-
- -
-
File: {incident.file}
-
Line: {incident.line}
-
, - ]} - /> - - - -
-
- ))} -
+ + + Incidents + + + + + + {columns.map((column, index) => ( + + ))} + + + + {sortedIncidents.map((incident, rowIndex) => ( + + {Object.values(incident).map((value, cellIndex) => ( + + ))} + + ))} + +
onSort(index)}> + {column} + {sortBy.index === index && (sortBy.direction === "asc" ? " ▲" : " ▼")} +
{value}
+
+
); }; -export default IncidentList; +export default IncidentsList; diff --git a/vscode/src/webview/components/IncidentsPanel.tsx b/vscode/src/webview/components/IncidentsPanel.tsx new file mode 100644 index 0000000..39e8efc --- /dev/null +++ b/vscode/src/webview/components/IncidentsPanel.tsx @@ -0,0 +1,92 @@ +import React, { useState } from "react"; +import { Violation, Incident } from "../types"; +import { + Split, + SplitItem, + List, + ListItem, + ListVariant, + Button, + Label, + Card, + CardBody, + CardTitle, + TextContent, + Text, + TextVariants, +} from "@patternfly/react-core"; +import { ArrowRightIcon } from "@patternfly/react-icons"; +import { vscode } from "../globals"; + +interface IncidentsPanelProps { + violation: Violation | null; +} + +const IncidentsPanel: React.FC = ({ violation }) => { + const [selectedIncident, setSelectedIncident] = useState(null); + + if (!violation) { + return
Select a violation to see incidents.
; + } + + const handleIncidentClick = (incident: Incident) => { + setSelectedIncident(incident); + vscode.postMessage({ + command: "openFile", + file: incident.file, + line: incident.line, + }); + }; + + return ( + + + + {violation.incidents.map((incident) => ( + handleIncidentClick(incident)} + // isActive={selectedIncident?.id === incident.id} + style={{ cursor: "pointer" }} + > + + + {incident.message} + + + + + + + {incident.severity} + + ))} + + + + + + ); + }, + [expandedViolations, handleIncidentClick, ruleSet.violations, toggleViolation], + ); + + const getItemSize = useCallback( + (index: number) => { + const violationId = Object.keys(ruleSet.violations || {})[index]; + const violation = ruleSet.violations?.[violationId]; + const isExpanded = expandedViolations.has(violationId); + return isExpanded && violation ? 50 + violation.incidents.length * 40 : 50; // Adjust these values as needed + }, + [expandedViolations, ruleSet.violations], + ); + + return ( + + + + {({ width }) => ( + + {renderViolation} + + )} + + + {selectedIncident && ( + + + + + {selectedIncident.message} + + Severity: {selectedIncident.severity} + + + File: {selectedIncident.file} + + + Line: {selectedIncident.line} + + + + + )} + + ); +}; + +export default ViolationIncidentsList; diff --git a/vscode/src/webview/index.css b/vscode/src/webview/index.css new file mode 100644 index 0000000..930e639 --- /dev/null +++ b/vscode/src/webview/index.css @@ -0,0 +1,11 @@ +@import "@patternfly/react-core/dist/styles/base.css"; + +#root { + height: 100vh; + overflow: hidden; +} + +.pf-c-page__main-section { + height: calc(100vh - 76px); /* Adjust this value based on your header height */ + overflow-y: auto; +} diff --git a/vscode/src/webview/index.tsx b/vscode/src/webview/index.tsx index 3326233..65db734 100644 --- a/vscode/src/webview/index.tsx +++ b/vscode/src/webview/index.tsx @@ -1,4 +1,5 @@ import "@patternfly/patternfly/patternfly.css"; +import "./index.css"; // Add this line import React from "react"; import { createRoot } from "react-dom/client"; diff --git a/vscode/src/webview/mockData.ts b/vscode/src/webview/mockData.ts index 7e69618..19985d9 100644 --- a/vscode/src/webview/mockData.ts +++ b/vscode/src/webview/mockData.ts @@ -1,119 +1,58 @@ import { Incident, RuleSet } from "./types"; -export function generateMockIncidentData(): Incident[] { - const mockData = [ - { - id: "0000", - name: "configuration-utils", - rulesets: [ - { - name: "java/code-quality", - description: - "This ruleset analyzes Java applications for best practices and code quality improvements.", - violations: { - "use-logging-framework-00001": { - description: "Replace System.out.println statements with a logging framework.", - category: "mandatory", - labels: [ - "konveyor.io/source", - "konveyor.io/target=java", - "konveyor.io/category=logging", - ], - incidents: [ - { - uri: "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/src/main/java/io/konveyor/demo/config/ApplicationConfiguration.java", - message: - "Replace `System.out.println` with a logging framework for better flexibility and control over logging levels.", - lineNumber: 20, - variables: { - matchingText: "System.out.println", - }, - }, - ], - effort: 1, - }, - "handle-exceptions-properly-00002": { - description: "Handle exceptions appropriately instead of using generic catch blocks.", - category: "potential", - labels: [ - "konveyor.io/source", - "konveyor.io/target=java", - "konveyor.io/category=exception-handling", - ], - incidents: [ - { - uri: "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/src/main/java/io/konveyor/demo/config/ApplicationConfiguration.java", - message: - "Consider handling specific exceptions or rethrowing them after logging.", - lineNumber: 17, - variables: { - matchingText: "catch (Exception e)", - }, - }, - ], - effort: 2, - }, - }, - }, - ], - depItems: [ - { - fileURI: - "file:///Users/ibolton/Development/tackle-testapp-public/configuration-utils/pom.xml", - provider: "java", - dependencies: [], - }, - ], - }, +function generateRandomIncident(violationId: string, index: number): Incident { + const severities = ["High", "Medium", "Low"]; + const files = [ + "/src/main/java/com/example/App.java", + "/src/main/java/com/example/Service.java", + "/src/main/java/com/example/Repository.java", + "/src/main/java/com/example/Controller.java", + "/src/main/java/com/example/Model.java", ]; - const incidents: Incident[] = []; - - mockData.forEach((app) => { - app.rulesets.forEach((ruleset) => { - if (ruleset.violations) { - Object.entries(ruleset.violations).forEach(([violationId, violation]: [string, any]) => { - violation.incidents.forEach((incident: any) => { - incidents.push({ - id: `${incident.uri}:${incident.lineNumber}`, - file: incident.uri, - line: incident.lineNumber, - severity: - violation.category === "mandatory" - ? "High" - : violation.category === "potential" - ? "Medium" - : "Low", - message: incident.message, - }); - }); - }); - } - }); - }); - - return incidents; + return { + id: `${violationId}-${index}`, + file: files[Math.floor(Math.random() * files.length)], + line: Math.floor(Math.random() * 1000) + 1, + severity: severities[Math.floor(Math.random() * severities.length)] as + | "High" + | "Medium" + | "Low", + message: `Mock incident ${index} for violation ${violationId}`, + }; } export function generateMockRuleSet(): RuleSet { - const mockData = generateMockIncidentData(); const violations: { [key: string]: any } = {}; + const violationTypes = [ + "use-logging-framework", + "handle-exceptions-properly", + "avoid-hardcoded-credentials", + "use-prepared-statements", + "implement-proper-error-handling", + "avoid-null-pointer-exceptions", + "use-dependency-injection", + "implement-proper-authentication", + "use-secure-communication", + "implement-input-validation", + ]; + + violationTypes.forEach((violationType, index) => { + const violationId = `${violationType}-${index.toString().padStart(5, "0")}`; + const incidentCount = Math.floor(Math.random() * 20) + 5; // 5 to 24 incidents per violation - mockData.forEach((incident) => { - const violationId = incident.id.split(":")[0]; - if (!violations[violationId]) { - violations[violationId] = { - description: "Mock violation description", - category: incident.severity === "High" ? "mandatory" : "potential", - incidents: [], - }; - } - violations[violationId].incidents.push(incident); + violations[violationId] = { + description: `${violationType.split("-").join(" ")} violation`, + category: index % 3 === 0 ? "mandatory" : index % 3 === 1 ? "potential" : "optional", + incidents: Array.from({ length: incidentCount }, (_, i) => + generateRandomIncident(violationId, i), + ), + }; }); return { - name: "Mock RuleSet", - description: "Mock RuleSet Description", + name: "Mock RuleSet with Many Violations", + description: "This ruleset contains many violations to demonstrate scrolling", violations: violations, }; } From 3fc82476747f7821d4b83ad7fa15e64f2ba5e2f3 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Thu, 3 Oct 2024 16:18:48 -0400 Subject: [PATCH 6/8] Iterate on violations list --- .../components/ViolationIncidentsList.tsx | 30 ++++++++++++----- .../src/webview/components/ViolationsList.tsx | 33 ------------------- vscode/src/webview/index.css | 16 +++++++++ 3 files changed, 37 insertions(+), 42 deletions(-) delete mode 100644 vscode/src/webview/components/ViolationsList.tsx diff --git a/vscode/src/webview/components/ViolationIncidentsList.tsx b/vscode/src/webview/components/ViolationIncidentsList.tsx index 43bbac5..b255aac 100644 --- a/vscode/src/webview/components/ViolationIncidentsList.tsx +++ b/vscode/src/webview/components/ViolationIncidentsList.tsx @@ -14,6 +14,7 @@ import { Button, Stack, StackItem, + Tooltip, } from "@patternfly/react-core"; import { ArrowLeftIcon } from "@patternfly/react-icons"; import { vscode } from "../globals"; @@ -67,7 +68,11 @@ const ViolationIncidentsList: React.FC = ({ ruleSet + {violation.description} + + } onToggle={() => toggleViolation(violationId)} isExpanded={isExpanded} > @@ -77,9 +82,15 @@ const ViolationIncidentsList: React.FC = ({ ruleSet {violation.incidents.map((incident) => ( - + + + {incident.severity} ))} @@ -98,22 +109,23 @@ const ViolationIncidentsList: React.FC = ({ ruleSet const violationId = Object.keys(ruleSet.violations || {})[index]; const violation = ruleSet.violations?.[violationId]; const isExpanded = expandedViolations.has(violationId); - return isExpanded && violation ? 50 + violation.incidents.length * 40 : 50; // Adjust these values as needed + return isExpanded && violation ? 70 + violation.incidents.length * 40 : 70; // Increased base height }, [expandedViolations, ruleSet.violations], ); return ( - - - {({ width }) => ( + + + {({ width, height }) => ( {renderViolation} diff --git a/vscode/src/webview/components/ViolationsList.tsx b/vscode/src/webview/components/ViolationsList.tsx deleted file mode 100644 index be5445b..0000000 --- a/vscode/src/webview/components/ViolationsList.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; -import { Violation } from "../types"; -import { List, ListItem, ListVariant, Badge } from "@patternfly/react-core"; - -interface ViolationsListProps { - violations: { [key: string]: Violation }; - selectedViolation: string | null; - onViolationClick: (violationId: string) => void; -} - -const ViolationsList: React.FC = ({ - violations, - selectedViolation, - onViolationClick, -}) => { - return ( - - {Object.entries(violations).map(([id, violation]) => ( - onViolationClick(id)} - // isActive={id === selectedViolation} - style={{ cursor: "pointer" }} - > - {violation.description} - {violation.incidents.length} - - ))} - - ); -}; - -export default ViolationsList; diff --git a/vscode/src/webview/index.css b/vscode/src/webview/index.css index 930e639..45f5fc1 100644 --- a/vscode/src/webview/index.css +++ b/vscode/src/webview/index.css @@ -9,3 +9,19 @@ height: calc(100vh - 76px); /* Adjust this value based on your header height */ overflow-y: auto; } + +.truncate-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + display: inline-block; +} + +.pf-c-expandable-section__toggle-text { + width: 100%; +} + +.pf-c-expandable-section__content { + margin-bottom: 10px; +} From 871faf32deda1adda340d596f7ab67c5d960c1eb Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Thu, 3 Oct 2024 16:35:08 -0400 Subject: [PATCH 7/8] Handle narrow screens better --- vscode/package-lock.json | 48 ------- vscode/package.json | 2 - .../components/ViolationIncidentsList.tsx | 134 ++++++++---------- 3 files changed, 59 insertions(+), 125 deletions(-) diff --git a/vscode/package-lock.json b/vscode/package-lock.json index f56c6a2..b66f7bf 100644 --- a/vscode/package-lock.json +++ b/vscode/package-lock.json @@ -16,8 +16,6 @@ "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-virtualized-auto-sizer": "^1.0.24", - "react-window": "^1.8.10", "uuid": "^10.0.0" }, "devDependencies": { @@ -364,17 +362,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", - "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", @@ -5190,11 +5177,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6362,31 +6344,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/react-virtualized-auto-sizer": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz", - "integrity": "sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==", - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0", - "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-window": { - "version": "1.8.10", - "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz", - "integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==", - "dependencies": { - "@babel/runtime": "^7.0.0", - "memoize-one": ">=3.1.1 <6" - }, - "engines": { - "node": ">8.0.0" - }, - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -6451,11 +6408,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", diff --git a/vscode/package.json b/vscode/package.json index 0925324..7f98f28 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -312,8 +312,6 @@ "babel-loader": "^9.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-virtualized-auto-sizer": "^1.0.24", - "react-window": "^1.8.10", "uuid": "^10.0.0" } } diff --git a/vscode/src/webview/components/ViolationIncidentsList.tsx b/vscode/src/webview/components/ViolationIncidentsList.tsx index b255aac..5ff875d 100644 --- a/vscode/src/webview/components/ViolationIncidentsList.tsx +++ b/vscode/src/webview/components/ViolationIncidentsList.tsx @@ -1,7 +1,5 @@ -import React, { useState, useCallback, useRef } from "react"; -import { RuleSet, Incident } from "../types"; -import { VariableSizeList as List } from "react-window"; -import AutoSizer from "react-virtualized-auto-sizer"; +import React, { useState, useCallback } from "react"; +import { RuleSet, Violation, Incident } from "../types"; import { ExpandableSection, Badge, @@ -26,7 +24,6 @@ interface ViolationIncidentsListProps { const ViolationIncidentsList: React.FC = ({ ruleSet }) => { const [expandedViolations, setExpandedViolations] = useState>(new Set()); const [selectedIncident, setSelectedIncident] = useState(null); - const listRef = useRef(null); const toggleViolation = useCallback((violationId: string) => { setExpandedViolations((prev) => { @@ -38,9 +35,6 @@ const ViolationIncidentsList: React.FC = ({ ruleSet } return newSet; }); - if (listRef.current) { - listRef.current.resetAfterIndex(0); - } }, []); const handleIncidentClick = useCallback((incident: Incident) => { @@ -53,84 +47,74 @@ const ViolationIncidentsList: React.FC = ({ ruleSet }, []); const renderViolation = useCallback( - ({ index, style }: { index: number; style: React.CSSProperties }) => { - const violationId = Object.keys(ruleSet.violations || {})[index]; - const violation = ruleSet.violations?.[violationId]; - - if (!violation) { - return null; - } - + (violationId: string, violation: Violation) => { const isExpanded = expandedViolations.has(violationId); return ( -
- - - - {violation.description} - - } - onToggle={() => toggleViolation(violationId)} - isExpanded={isExpanded} - > - - - Incidents: - - {violation.incidents.map((incident) => ( - - - - - {incident.severity} - - ))} - - - - -
+ + + + + {violation.description} + + + } + onToggle={() => toggleViolation(violationId)} + isExpanded={isExpanded} + > + + + Incidents: + + {violation.incidents.map((incident) => ( + + + + + + + + + {incident.severity} + + + + ))} + + + + ); }, - [expandedViolations, handleIncidentClick, ruleSet.violations, toggleViolation], - ); - - const getItemSize = useCallback( - (index: number) => { - const violationId = Object.keys(ruleSet.violations || {})[index]; - const violation = ruleSet.violations?.[violationId]; - const isExpanded = expandedViolations.has(violationId); - return isExpanded && violation ? 70 + violation.incidents.length * 40 : 70; // Increased base height - }, - [expandedViolations, ruleSet.violations], + [expandedViolations, handleIncidentClick, toggleViolation], ); return ( - - {({ width, height }) => ( - - {renderViolation} - +
+ {Object.entries(ruleSet.violations || {}).map(([violationId, violation]) => + renderViolation(violationId, violation), )} - +
{selectedIncident && ( From 473c5a87beefe95653b3cdd84bd0a64d8ba3cece Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Thu, 3 Oct 2024 16:53:46 -0400 Subject: [PATCH 8/8] Adjust incident details positioning --- .../components/ViolationIncidentsList.tsx | 59 ++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/vscode/src/webview/components/ViolationIncidentsList.tsx b/vscode/src/webview/components/ViolationIncidentsList.tsx index 5ff875d..7158aee 100644 --- a/vscode/src/webview/components/ViolationIncidentsList.tsx +++ b/vscode/src/webview/components/ViolationIncidentsList.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from "react"; +import React, { useState, useCallback, useMemo } from "react"; import { RuleSet, Violation, Incident } from "../types"; import { ExpandableSection, @@ -13,6 +13,8 @@ import { Stack, StackItem, Tooltip, + TextInput, + Divider, } from "@patternfly/react-core"; import { ArrowLeftIcon } from "@patternfly/react-icons"; import { vscode } from "../globals"; @@ -24,6 +26,7 @@ interface ViolationIncidentsListProps { const ViolationIncidentsList: React.FC = ({ ruleSet }) => { const [expandedViolations, setExpandedViolations] = useState>(new Set()); const [selectedIncident, setSelectedIncident] = useState(null); + const [searchTerm, setSearchTerm] = useState(""); const toggleViolation = useCallback((violationId: string) => { setExpandedViolations((prev) => { @@ -46,6 +49,36 @@ const ViolationIncidentsList: React.FC = ({ ruleSet }); }, []); + const filteredViolations = useMemo(() => { + if (!searchTerm) { + return ruleSet.violations || {}; + } + + const lowercaseSearchTerm = searchTerm.toLowerCase(); + return Object.entries(ruleSet.violations || {}).reduce( + (acc, [violationId, violation]) => { + const matchingIncidents = violation.incidents.filter( + (incident) => + incident.message.toLowerCase().includes(lowercaseSearchTerm) || + incident.file.toLowerCase().includes(lowercaseSearchTerm), + ); + + if ( + matchingIncidents.length > 0 || + violation.description.toLowerCase().includes(lowercaseSearchTerm) + ) { + acc[violationId] = { + ...violation, + incidents: matchingIncidents, + }; + } + + return acc; + }, + {} as Record, + ); + }, [ruleSet.violations, searchTerm]); + const renderViolation = useCallback( (violationId: string, violation: Violation) => { const isExpanded = expandedViolations.has(violationId); @@ -109,12 +142,16 @@ const ViolationIncidentsList: React.FC = ({ ruleSet return ( - -
- {Object.entries(ruleSet.violations || {}).map(([violationId, violation]) => - renderViolation(violationId, violation), - )} -
+ + setSearchTerm(value)} + // icon={} + /> {selectedIncident && ( @@ -139,8 +176,16 @@ const ViolationIncidentsList: React.FC = ({ ruleSet
+ )} + +
+ {Object.entries(filteredViolations).map(([violationId, violation]) => + renderViolation(violationId, violation), + )} +
+
); };