From fdec0c74e589338fa2a97ab0c57ded164731ebb2 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Fri, 2 Jun 2023 14:51:18 +0200 Subject: [PATCH 01/39] added tailwind --- report-viewer/package-lock.json | 630 ++++++++++++++++++++++++++++++- report-viewer/package.json | 6 +- report-viewer/postcss.config.js | 6 + report-viewer/src/main.ts | 2 + report-viewer/src/style.css | 3 + report-viewer/tailwind.config.js | 12 + 6 files changed, 650 insertions(+), 9 deletions(-) create mode 100644 report-viewer/postcss.config.js create mode 100644 report-viewer/src/style.css create mode 100644 report-viewer/tailwind.config.js diff --git a/report-viewer/package-lock.json b/report-viewer/package-lock.json index 7f01d566c..8838f2e0a 100644 --- a/report-viewer/package-lock.json +++ b/report-viewer/package-lock.json @@ -31,19 +31,34 @@ "@vue/eslint-config-typescript": "^11.0.3", "@vue/test-utils": "^2.3.0", "@vue/tsconfig": "^0.4.0", + "autoprefixer": "^10.4.14", "eslint": "^8.40.0", "eslint-plugin-vue": "^9.14.0", "husky": "^8.0.0", "jsdom": "^21.1.0", "lint-staged": "^13.2.2", "npm-run-all": "^4.1.5", + "postcss": "^8.4.24", "prettier": "^2.8.8", + "tailwindcss": "^3.3.2", "typescript": "^5.0.4", "vite": "^4.3.9", "vitest": "^0.31.2", "vue-tsc": "^1.6.5" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/parser": { "version": "7.21.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", @@ -496,11 +511,59 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1314,6 +1377,31 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1366,6 +1454,39 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1384,6 +1505,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/blueimp-md5": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", @@ -1418,6 +1548,38 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -1449,6 +1611,35 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001492", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz", + "integrity": "sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, "node_modules/chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -1505,6 +1696,45 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -1765,6 +1995,12 @@ "node": ">=0.4.0" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1777,6 +2013,12 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1831,6 +2073,12 @@ "semver": "bin/semver" } }, + "node_modules/electron-to-chromium": { + "version": "1.4.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.417.tgz", + "integrity": "sha512-8rY8HdCxuSVY8wku3i/eDac4g1b4cSbruzocenrqBlzqruAZYHjQCHIjC66dLR9DXhEHTojsC4EjhZ8KmzwXqA==", + "dev": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -1974,6 +2222,15 @@ "@esbuild/win32-x64": "0.17.14" } }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2490,6 +2747,19 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3031,6 +3301,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3282,6 +3564,15 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jiti": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", + "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-beautify": { "version": "1.14.6", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", @@ -3443,6 +3734,12 @@ "node": ">=10" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/lint-staged": { "version": "13.2.2", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.2.tgz", @@ -3882,6 +4179,17 @@ "integrity": "sha512-YVE1mIJ4VpUMqZObFndk9CJu6DBJR/GB13p3tXuNbwD4XExaI5EOuRl6BHeIDxIqXZVxSfAC+y6U1Z/IxCfKUg==", "dev": true }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -3917,6 +4225,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "dev": true + }, "node_modules/nopt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", @@ -3962,6 +4276,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -4170,6 +4493,24 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", "dev": true }, + "node_modules/object-assign": { + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -4479,6 +4820,15 @@ } } }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -4503,9 +4853,9 @@ } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "funding": [ { "type": "opencollective", @@ -4529,6 +4879,90 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-selector-parser": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", @@ -4542,6 +4976,12 @@ "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", @@ -4668,6 +5108,24 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -4708,6 +5166,18 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -4732,12 +5202,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -5329,6 +5799,57 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/sucrase": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", + "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5359,12 +5880,71 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tailwindcss": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", + "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -5443,6 +6023,12 @@ "node": ">=14" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5554,6 +6140,36 @@ "node": ">= 4.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/report-viewer/package.json b/report-viewer/package.json index 2aaad53cd..eb16c7a1c 100644 --- a/report-viewer/package.json +++ b/report-viewer/package.json @@ -39,15 +39,17 @@ "@vue/eslint-config-typescript": "^11.0.3", "@vue/test-utils": "^2.3.0", "@vue/tsconfig": "^0.4.0", + "autoprefixer": "^10.4.14", "eslint": "^8.40.0", "eslint-plugin-vue": "^9.14.0", "husky": "^8.0.0", "jsdom": "^21.1.0", "lint-staged": "^13.2.2", "npm-run-all": "^4.1.5", - "typescript": "^5.0.4", + "postcss": "^8.4.24", "prettier": "^2.8.8", - + "tailwindcss": "^3.3.2", + "typescript": "^5.0.4", "vite": "^4.3.9", "vitest": "^0.31.2", "vue-tsc": "^1.6.5" diff --git a/report-viewer/postcss.config.js b/report-viewer/postcss.config.js new file mode 100644 index 000000000..33ad091d2 --- /dev/null +++ b/report-viewer/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/report-viewer/src/main.ts b/report-viewer/src/main.ts index 878da2a5a..cf759354e 100644 --- a/report-viewer/src/main.ts +++ b/report-viewer/src/main.ts @@ -10,6 +10,8 @@ import 'highlight.js/styles/vs.css' import 'gitart-vue-dialog/dist/style.css' import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' +import './style.css' + const app = createApp(App) app.use(createPinia()) diff --git a/report-viewer/src/style.css b/report-viewer/src/style.css new file mode 100644 index 000000000..bd6213e1d --- /dev/null +++ b/report-viewer/src/style.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/report-viewer/tailwind.config.js b/report-viewer/tailwind.config.js new file mode 100644 index 000000000..de76228b9 --- /dev/null +++ b/report-viewer/tailwind.config.js @@ -0,0 +1,12 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,vue}" + ], + theme: { + extend: {}, + }, + plugins: [], +} + From 0320ff791a72270f8c7772ce2723d3164634eda6 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Fri, 2 Jun 2023 15:43:30 +0200 Subject: [PATCH 02/39] Added base components --- report-viewer/package-lock.json | 71 +++++++++++++++++++ report-viewer/package.json | 5 ++ report-viewer/src/App.vue | 31 ++++---- .../src/components/ButtonComponent.vue | 9 +++ .../src/components/ContainerComponent.vue | 8 +++ .../src/components/InteractableComponent.vue | 9 +++ .../src/components/SearchBarComponent.vue | 41 +++++++++++ report-viewer/src/style.css | 14 +++- 8 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 report-viewer/src/components/ButtonComponent.vue create mode 100644 report-viewer/src/components/ContainerComponent.vue create mode 100644 report-viewer/src/components/InteractableComponent.vue create mode 100644 report-viewer/src/components/SearchBarComponent.vue diff --git a/report-viewer/package-lock.json b/report-viewer/package-lock.json index 8838f2e0a..12769c395 100644 --- a/report-viewer/package-lock.json +++ b/report-viewer/package-lock.json @@ -8,6 +8,11 @@ "name": "report-viewer", "version": "0.0.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-brands-svg-icons": "^6.4.0", + "@fortawesome/free-regular-svg-icons": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/vue-fontawesome": "^3.0.3", "chart.js": "^3.9.1", "chartjs-plugin-datalabels": "^2.2.0", "gitart-vue-dialog": "^3.0.2", @@ -478,6 +483,72 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz", + "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz", + "integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.0.tgz", + "integrity": "sha512-qvxTCo0FQ5k2N+VCXb/PZQ+QMhqRVM4OORiO6MXdG6bKolIojGU/srQ1ptvKk0JTbRgaJOfL2qMqGvBEZG7Z6g==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz", + "integrity": "sha512-ZfycI7D0KWPZtf7wtMFnQxs8qjBXArRzczABuMQqecA/nXohquJ5J/RCR77PmY5qGWkxAZDxpnUFVXKwtY/jPw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", + "integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/vue-fontawesome": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.3.tgz", + "integrity": "sha512-KCPHi9QemVXGMrfuwf3nNnNo129resAIQWut9QTAMXmXqL2ErABC6ohd2yY5Ipq0CLWNbKHk8TMdTXL/Zf3ZhA==", + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "vue": ">= 3.0.0 < 4" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", diff --git a/report-viewer/package.json b/report-viewer/package.json index eb16c7a1c..ebdcc1958 100644 --- a/report-viewer/package.json +++ b/report-viewer/package.json @@ -16,6 +16,11 @@ "prepare": "cd .. && husky install report-viewer/.husky" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-brands-svg-icons": "^6.4.0", + "@fortawesome/free-regular-svg-icons": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/vue-fontawesome": "^3.0.3", "chart.js": "^3.9.1", "chartjs-plugin-datalabels": "^2.2.0", "gitart-vue-dialog": "^3.0.2", diff --git a/report-viewer/src/App.vue b/report-viewer/src/App.vue index 7049f4071..35c835de6 100644 --- a/report-viewer/src/App.vue +++ b/report-viewer/src/App.vue @@ -1,12 +1,19 @@ - - + + diff --git a/report-viewer/src/components/ButtonComponent.vue b/report-viewer/src/components/ButtonComponent.vue new file mode 100644 index 000000000..7ab7d0a38 --- /dev/null +++ b/report-viewer/src/components/ButtonComponent.vue @@ -0,0 +1,9 @@ + + + diff --git a/report-viewer/src/components/ContainerComponent.vue b/report-viewer/src/components/ContainerComponent.vue new file mode 100644 index 000000000..b4e647bcb --- /dev/null +++ b/report-viewer/src/components/ContainerComponent.vue @@ -0,0 +1,8 @@ + + + + diff --git a/report-viewer/src/components/InteractableComponent.vue b/report-viewer/src/components/InteractableComponent.vue new file mode 100644 index 000000000..cec5e059a --- /dev/null +++ b/report-viewer/src/components/InteractableComponent.vue @@ -0,0 +1,9 @@ + + + diff --git a/report-viewer/src/components/SearchBarComponent.vue b/report-viewer/src/components/SearchBarComponent.vue new file mode 100644 index 000000000..f85d1e0f8 --- /dev/null +++ b/report-viewer/src/components/SearchBarComponent.vue @@ -0,0 +1,41 @@ + + + diff --git a/report-viewer/src/style.css b/report-viewer/src/style.css index bd6213e1d..64f8a62b8 100644 --- a/report-viewer/src/style.css +++ b/report-viewer/src/style.css @@ -1,3 +1,15 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@layer base { + #app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + h2 { + @apply text-2xl underline; + } +} \ No newline at end of file From 33a82e7bebca98e470700d39afadaf4019edc655 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Tue, 6 Jun 2023 19:19:47 +0200 Subject: [PATCH 03/39] Overview and parts of Comparison View reworked --- report-viewer/src/App.vue | 55 ++-- .../src/assets/jplag-dark-transparent.png | Bin 0 -> 31928 bytes .../src/assets/jplag-light-transparent.png | Bin 0 -> 30837 bytes report-viewer/src/assets/logo-nobg.png | Bin 8944 -> 0 bytes report-viewer/src/components/CodePanel.vue | 123 ++------ .../src/components/ComparisonsTable.vue | 280 ++++++------------ .../src/components/ContainerComponent.vue | 4 +- .../src/components/DistributionDiagram.vue | 100 +++---- .../src/components/FilesContainer.vue | 17 +- .../src/components/InteractableComponent.vue | 4 +- report-viewer/src/components/LineOfCode.vue | 39 +-- .../components/OptionsSelectorComponent.vue | 46 +++ .../src/components/ScrollableComponent.vue | 7 + .../src/components/SearchBarComponent.vue | 2 +- .../src/components/TextInformation.vue | 136 +-------- report-viewer/src/main.ts | 6 +- report-viewer/src/views/ComparisonView.vue | 178 +++-------- report-viewer/src/views/FileUploadView.vue | 68 ++++- report-viewer/src/views/OverviewView.vue | 223 ++++---------- report-viewer/tailwind.config.js | 37 ++- 20 files changed, 463 insertions(+), 862 deletions(-) create mode 100644 report-viewer/src/assets/jplag-dark-transparent.png create mode 100644 report-viewer/src/assets/jplag-light-transparent.png delete mode 100644 report-viewer/src/assets/logo-nobg.png create mode 100644 report-viewer/src/components/OptionsSelectorComponent.vue create mode 100644 report-viewer/src/components/ScrollableComponent.vue diff --git a/report-viewer/src/App.vue b/report-viewer/src/App.vue index 35c835de6..7da841050 100644 --- a/report-viewer/src/App.vue +++ b/report-viewer/src/App.vue @@ -1,8 +1,16 @@ @@ -10,34 +18,17 @@ - - + diff --git a/report-viewer/src/assets/jplag-dark-transparent.png b/report-viewer/src/assets/jplag-dark-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce965f401a9b6470844f22cc80f12f07392430c GIT binary patch literal 31928 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 AjQ{`u literal 0 HcmV?d00001 diff --git a/report-viewer/src/assets/jplag-light-transparent.png b/report-viewer/src/assets/jplag-light-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..732b433f211db4d6023e56720e6a2b1c705eb128 GIT binary patch literal 30837 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 u - - diff --git a/report-viewer/src/components/ComparisonsTable.vue b/report-viewer/src/components/ComparisonsTable.vue index 4719c4d49..6317f83f3 100644 --- a/report-viewer/src/components/ComparisonsTable.vue +++ b/report-viewer/src/components/ComparisonsTable.vue @@ -2,95 +2,80 @@ Table which display all of the comparisons with their participating ids and similarity percentage for the selected metric. --> - diff --git a/report-viewer/src/components/ContainerComponent.vue b/report-viewer/src/components/ContainerComponent.vue index b4e647bcb..acb63a948 100644 --- a/report-viewer/src/components/ContainerComponent.vue +++ b/report-viewer/src/components/ContainerComponent.vue @@ -1,6 +1,8 @@ diff --git a/report-viewer/src/components/DistributionDiagram.vue b/report-viewer/src/components/DistributionDiagram.vue index 974d37202..60202f270 100644 --- a/report-viewer/src/components/DistributionDiagram.vue +++ b/report-viewer/src/components/DistributionDiagram.vue @@ -2,16 +2,15 @@ Bar diagram, displaying the distribution for the selected metric. --> - - diff --git a/report-viewer/src/components/FilesContainer.vue b/report-viewer/src/components/FilesContainer.vue index 0508f1254..93dc98533 100644 --- a/report-viewer/src/components/FilesContainer.vue +++ b/report-viewer/src/components/FilesContainer.vue @@ -2,9 +2,11 @@ Container containing CodePanels for all of the files in a submission. --> diff --git a/report-viewer/src/components/OptionsSelectorComponent.vue b/report-viewer/src/components/OptionsSelectorComponent.vue new file mode 100644 index 000000000..df51e1e4d --- /dev/null +++ b/report-viewer/src/components/OptionsSelectorComponent.vue @@ -0,0 +1,46 @@ + + + diff --git a/report-viewer/src/components/ScrollableComponent.vue b/report-viewer/src/components/ScrollableComponent.vue new file mode 100644 index 000000000..b33e17e22 --- /dev/null +++ b/report-viewer/src/components/ScrollableComponent.vue @@ -0,0 +1,7 @@ + diff --git a/report-viewer/src/components/SearchBarComponent.vue b/report-viewer/src/components/SearchBarComponent.vue index f85d1e0f8..52982f42d 100644 --- a/report-viewer/src/components/SearchBarComponent.vue +++ b/report-viewer/src/components/SearchBarComponent.vue @@ -7,7 +7,7 @@ /> diff --git a/report-viewer/src/components/TextInformation.vue b/report-viewer/src/components/TextInformation.vue index b91609039..c1a1a16b5 100644 --- a/report-viewer/src/components/TextInformation.vue +++ b/report-viewer/src/components/TextInformation.vue @@ -3,147 +3,29 @@ in a drop down container. --> - - diff --git a/report-viewer/src/main.ts b/report-viewer/src/main.ts index cf759354e..24a3f93f0 100644 --- a/report-viewer/src/main.ts +++ b/report-viewer/src/main.ts @@ -1,4 +1,4 @@ -import { createApp } from 'vue' +import { createApp, ref } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' @@ -12,6 +12,8 @@ import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' import './style.css' +const useDarkMode = ref(false) + const app = createApp(App) app.use(createPinia()) @@ -19,3 +21,5 @@ app.use(router) app.use(VueVirtualScroller) app.mount('#app') + +export { useDarkMode } diff --git a/report-viewer/src/views/ComparisonView.vue b/report-viewer/src/views/ComparisonView.vue index a6f70fef0..ec516f9a3 100644 --- a/report-viewer/src/views/ComparisonView.vue +++ b/report-viewer/src/views/ComparisonView.vue @@ -2,8 +2,43 @@ A view displaying the .json file of a comparison from a JPlag report. --> - - diff --git a/report-viewer/src/views/FileUploadView.vue b/report-viewer/src/views/FileUploadView.vue index 6c91a6abe..f1da11ddc 100644 --- a/report-viewer/src/views/FileUploadView.vue +++ b/report-viewer/src/views/FileUploadView.vue @@ -2,23 +2,42 @@ Starting view of the application. Presents the options for loading a JPlag report. --> @@ -29,6 +48,8 @@ import jszip from 'jszip' import router from '@/router' import store from '@/stores/store' import slash from 'slash' +import Button from '@/components/ButtonComponent.vue' +import { useDarkMode } from '../main' class LoadError extends Error {} @@ -230,7 +251,7 @@ async function handleFile(file: Blob) { * Handles file drop. * @param e Drag event of file drop */ -async function uploadFile(e: DragEvent) { +async function uploadFileOnDrag(e: DragEvent) { let dropped = e.dataTransfer?.files try { if (dropped?.length === 1) { @@ -248,6 +269,25 @@ async function uploadFile(e: DragEvent) { } } +async function uploadFileThroughWindow() { + let input = document.createElement('input') + input.type = 'file' + input.accept = '.zip,.json' + input.multiple = false + input.onchange = () => { + const files = input.files + if (!files) { + return + } + const file = files.item(0) + if (!file) { + return + } + handleFile(file) + } + input.click() +} + /** * Handles click on Continue with query file. */ diff --git a/report-viewer/src/views/OverviewView.vue b/report-viewer/src/views/OverviewView.vue index 0acec8861..7562e0483 100644 --- a/report-viewer/src/views/OverviewView.vue +++ b/report-viewer/src/views/OverviewView.vue @@ -2,85 +2,54 @@ A view displaying the overview file of a JPlag report. --> @@ -91,14 +60,18 @@ import type { Ref } from 'vue' import { computed, onErrorCaptured, ref } from 'vue' import router from '@/router' -import TextInformation from '../components/TextInformation.vue' import DistributionDiagram from '@/components/DistributionDiagram.vue' -import MetricButton from '@/components/MetricButton.vue' import ComparisonsTable from '@/components/ComparisonsTable.vue' import { OverviewFactory } from '@/model/factories/OverviewFactory' -import IDsList from '@/components/IDsList.vue' import { Overview } from '@/model/Overview' import store from '@/stores/store' +import Container from '@/components/ContainerComponent.vue' +import Button from '@/components/ButtonComponent.vue' +import ScrollableComponent from '@/components/ScrollableComponent.vue' +import OptionsSelectorComponent from '@/components/OptionsSelectorComponent.vue' +import MetricType from '@/model/ui/MetricType' +import SearchBarComponent from '@/components/SearchBarComponent.vue' +import TextInformation from '@/components/TextInformation.vue' /** * Gets the overview file based on the used mode (zip, local, single). @@ -176,19 +149,17 @@ function handleId(ids: Array) { } //Metrics -const selectedMetric = ref(overview.metrics.map(() => false)) +// const selectedMetric = ref(overview.metrics.map(() => false)) -const selectedMetricIndex = ref(0) -selectedMetric.value[selectedMetricIndex.value] = true +const selectedMetric = ref(MetricType.AVERAGE) /** * Switch between metrics * @param metric Metric to switch to */ function selectMetric(metric: number) { - selectedMetric.value = selectedMetric.value.map(() => false) - selectedMetric.value[metric] = true - selectedMetricIndex.value = metric + selectedMetric.value = metric + console.log('Selected metric: ' + metric) } const distributions = ref(overview.metrics.map((m) => m.distribution)) @@ -203,7 +174,7 @@ const submissionPathValue = hasMoreSubmissionPaths : overview.submissionFolderPath[0] const shownComparisons = computed(() => { - return overview.metrics[selectedMetricIndex.value]?.comparisons.length + return overview.metrics[selectedMetric.value]?.comparisons.length }) const missingComparisons = overview.totalComparisons - shownComparisons.value @@ -220,91 +191,3 @@ onErrorCaptured(() => { return false }) - - diff --git a/report-viewer/tailwind.config.js b/report-viewer/tailwind.config.js index de76228b9..beeda0d4a 100644 --- a/report-viewer/tailwind.config.js +++ b/report-viewer/tailwind.config.js @@ -1,11 +1,46 @@ +import colors from 'tailwindcss/colors' + /** @type {import('tailwindcss').Config} */ export default { + darkMode: 'class', content: [ "./index.html", "./src/**/*.{js,ts,vue}" ], theme: { - extend: {}, + extend: { + colors: { + font: { + light: '#000000', + dark: colors.amber[50] + }, + backgorund: { + light: colors.slate[300], + dark: '#010409' + }, + container: { + light: colors.slate[200], + dark: colors.slate[800], + border: { + light: colors.slate[400], + dark: colors.slate[700] + } + }, + interactable: { + light: colors.slate[50], + dark: colors.slate[900], + border: { + light: colors.slate[400], + dark: '#bbbbbb' + } + }, + accent: { + DEFAULT: '#be1622', + dark: '#7F0F18' + }, + + } + }, }, plugins: [], } From f090b6575b652a5572f3c9f422c9ffa62504eb28 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Wed, 7 Jun 2023 09:04:30 +0200 Subject: [PATCH 04/39] Comparion view nearly finished --- report-viewer/src/components/CodePanel.vue | 82 +++++++--------- report-viewer/src/components/LineOfCode.vue | 14 +-- .../{MatchTable.vue => MatchList.vue} | 25 ++++- .../src/components/ScrollableComponent.vue | 2 +- .../src/components/TextInformation.vue | 4 +- report-viewer/src/main.ts | 1 - report-viewer/src/model/ui/MetricType.ts | 6 ++ report-viewer/src/views/ComparisonView.vue | 98 +++++++------------ report-viewer/src/views/OverviewView.vue | 17 ++-- 9 files changed, 112 insertions(+), 137 deletions(-) rename report-viewer/src/components/{MatchTable.vue => MatchList.vue} (71%) create mode 100644 report-viewer/src/model/ui/MetricType.ts diff --git a/report-viewer/src/components/CodePanel.vue b/report-viewer/src/components/CodePanel.vue index 515e4faf4..87e2361fb 100644 --- a/report-viewer/src/components/CodePanel.vue +++ b/report-viewer/src/components/CodePanel.vue @@ -13,40 +13,40 @@
{{ title }}
-
-
-
- +
+
+
+ :key="index" + > + +
+
+
+

Empty File

-
-
-

Empty File

@@ -144,18 +144,6 @@ function isEmpty(lines: string[]) { */ const linksArray: Ref> = ref({}) -/** - * Indicates whether the line is last line of match. Key is line number, value is true or false. - * @type {Ref>} - */ -const isLast: Ref> = ref({}) - -/** - * Indicates whether the line is the first line of a match. Key is line number, value is true or false. - * @type {Ref>} - */ -const isFirst: Ref> = ref({}) - // Initializing the the upper arrays. props.matches?.forEach((m) => { for (let i = m.start; i <= m.end; i++) { @@ -168,17 +156,13 @@ props.matches?.forEach((m) => { line: m.linked_line } } - isFirst.value[m.start - 1] = true - isLast.value[m.end - 1] = true }) //assign default values for all line which are not contained in matches for (let i = 0; i < props.lines.length; i++) { if (!coloringArray.value[i]) { - coloringArray.value[i] = '#FFFFFF' + coloringArray.value[i] = 'hsla(0, 0%, 0%, 0)' linksArray.value[i] = {} - isFirst.value[i] = false - isLast.value[i] = false } } diff --git a/report-viewer/src/components/LineOfCode.vue b/report-viewer/src/components/LineOfCode.vue index e6fbc3a79..908978d76 100644 --- a/report-viewer/src/components/LineOfCode.vue +++ b/report-viewer/src/components/LineOfCode.vue @@ -3,13 +3,7 @@ --> @@ -39,12 +33,6 @@ const props = defineProps({ }, fileIndex: { type: Number - }, - isFirst: { - type: Boolean - }, - isLast: { - type: Boolean } }) diff --git a/report-viewer/src/components/MatchTable.vue b/report-viewer/src/components/MatchList.vue similarity index 71% rename from report-viewer/src/components/MatchTable.vue rename to report-viewer/src/components/MatchList.vue index df28192eb..442a06701 100644 --- a/report-viewer/src/components/MatchTable.vue +++ b/report-viewer/src/components/MatchList.vue @@ -2,7 +2,23 @@ Table which contains all of the matches for a comparison with navigation links. --> diff --git a/report-viewer/src/components/ErrorRouter.vue b/report-viewer/src/components/ErrorRouter.vue deleted file mode 100644 index b5de74498..000000000 --- a/report-viewer/src/components/ErrorRouter.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - - diff --git a/report-viewer/src/views/ErrorView.vue b/report-viewer/src/views/ErrorView.vue index 94a1da5d0..3ee4d7324 100644 --- a/report-viewer/src/views/ErrorView.vue +++ b/report-viewer/src/views/ErrorView.vue @@ -1,14 +1,42 @@ - - + diff --git a/report-viewer/src/components/ComparisonsTable.vue b/report-viewer/src/components/ComparisonsTable.vue index 6317f83f3..ca5e117fc 100644 --- a/report-viewer/src/components/ComparisonsTable.vue +++ b/report-viewer/src/components/ComparisonsTable.vue @@ -13,7 +13,7 @@
Maximum
-
Cluster
+
Cluster
@@ -49,22 +49,35 @@
-
{{ formattedMatchPercentage(item.similarity) }}%
-
{{ formattedMatchPercentage(item.similarity) }}%
+
+ {{ formattedMatchPercentage(item.averageSimilarity) }}% +
+
+ {{ formattedMatchPercentage(item.maximumSimilarity) }}% +
-
- -
- {{ - getClustersFor(item.firstSubmissionId, item.secondSubmissionId)[0].members - .size - }} - +
+ +
+ {{ clusters?.[index].members?.length }} + {{ formattedMatchPercentage( - getClustersFor(item.firstSubmissionId, item.secondSubmissionId)[0] - .averageSimilarity / 100 + (clusters?.[index].averageSimilarity as number) / 100 ) }}%
@@ -81,7 +94,6 @@ @@ -201,7 +180,7 @@ function getClustersFor(id1: string, id2: string): Array { } .tableCellSimilarity { - @apply w-64 tableCell; + @apply w-40 tableCell; } .tableCellCluster { diff --git a/report-viewer/src/components/DropDownSelector.vue b/report-viewer/src/components/DropDownSelector.vue new file mode 100644 index 000000000..d2b0016c4 --- /dev/null +++ b/report-viewer/src/components/DropDownSelector.vue @@ -0,0 +1,30 @@ + + + diff --git a/report-viewer/src/model/ClusterListElement.ts b/report-viewer/src/model/ClusterListElement.ts index 2a52c43c3..8a4339430 100644 --- a/report-viewer/src/model/ClusterListElement.ts +++ b/report-viewer/src/model/ClusterListElement.ts @@ -12,5 +12,5 @@ type ClusterListElement = { /** * The ids of the submissions in the cluster, and the matches between them */ -type ClusterListElementMember = Map> +type ClusterListElementMember = Map> export type { ClusterListElement, ClusterListElementMember } diff --git a/report-viewer/src/model/ComparisonListElement.ts b/report-viewer/src/model/ComparisonListElement.ts index 1c6f37c95..e34c693a8 100644 --- a/report-viewer/src/model/ComparisonListElement.ts +++ b/report-viewer/src/model/ComparisonListElement.ts @@ -11,5 +11,6 @@ export type ComparisonListElement = { id: number firstSubmissionId: string secondSubmissionId: string - similarity: number + averageSimilarity: number + maximumSimilarity: number } diff --git a/report-viewer/src/model/Distribution.ts b/report-viewer/src/model/Distribution.ts new file mode 100644 index 000000000..ea34fbabe --- /dev/null +++ b/report-viewer/src/model/Distribution.ts @@ -0,0 +1,11 @@ +export default class Distribution { + private readonly _distribution: Array + + constructor(distribution: Array) { + this._distribution = distribution + } + + public asLinearArray(): Array { + return this._distribution + } +} diff --git a/report-viewer/src/model/Overview.ts b/report-viewer/src/model/Overview.ts index 1e574b562..a59e2ccd0 100644 --- a/report-viewer/src/model/Overview.ts +++ b/report-viewer/src/model/Overview.ts @@ -1,5 +1,6 @@ -import type { Metric } from './Metric' +import type Distribution from './Distribution' import type { Cluster } from '@/model/Cluster' +import type { ComparisonListElement } from './ComparisonListElement' /** * Model of the Overview file generated by JPlag @@ -13,7 +14,8 @@ export class Overview { private readonly _submissionIdsToComparisonFileName: Map> private readonly _dateOfExecution: string private readonly _durationOfExecution: number - private readonly _metrics: Array + private readonly _topComparisons: Array + private readonly _distributions: Array private readonly _clusters: Array private readonly _totalComparisons: number @@ -25,7 +27,8 @@ export class Overview { matchSensitivity: number, dateOfExecution: string, durationOfExecution: number, - metrics: Array, + topComparisons: Array, + distributions: Array, clusters: Array, totalComparisons: number, submissionIdsToComparisonFileName: Map> @@ -37,7 +40,8 @@ export class Overview { this._matchSensitivity = matchSensitivity this._dateOfExecution = dateOfExecution this._durationOfExecution = durationOfExecution - this._metrics = metrics + this._topComparisons = topComparisons + this._distributions = distributions this._clusters = clusters this._submissionIdsToComparisonFileName = submissionIdsToComparisonFileName this._totalComparisons = totalComparisons @@ -99,11 +103,15 @@ export class Overview { return this._durationOfExecution } + get topComparisons() { + return this._topComparisons + } + /** - * @return Metrics used in the JPlag Comparison + * @return Distributions used in the JPlag Comparison */ - get metrics() { - return this._metrics + get distribution() { + return this._distributions } /** diff --git a/report-viewer/src/model/factories/ComparisonFactory.ts b/report-viewer/src/model/factories/ComparisonFactory.ts index a0993a66d..ccda03c55 100644 --- a/report-viewer/src/model/factories/ComparisonFactory.ts +++ b/report-viewer/src/model/factories/ComparisonFactory.ts @@ -3,6 +3,7 @@ import type { Match } from '../Match' import type { SubmissionFile } from '../SubmissionFile' import type { MatchInSingleFile } from '../MatchInSingleFile' import store from '@/stores/store' +import { generateHuesForInterval, toHSLAArray } from '@/utils/ColorUtils' /** * Factory class for creating Comparison objects @@ -99,26 +100,12 @@ export class ComparisonFactory { } private static generateColorsForMatches(num: number): Array { - const colors: Array = [] const numberOfColorsInFirstInterval = Math.round(((80 - 20) / (80 - 20 + (340 - 160))) * num) // number of colors from the first interval const numberOfColorsInSecondInterval = num - numberOfColorsInFirstInterval // number of colors from the second interval - ComparisonFactory.generateColorsForInterval(20, 80, numberOfColorsInFirstInterval, colors) - ComparisonFactory.generateColorsForInterval(160, 340, numberOfColorsInSecondInterval, colors) - return colors - } - private static generateColorsForInterval( - intervalStart: number, - intervalEnd: number, - numberOfColorsInInterval: number, - colors: Array - ) { - const interval = intervalEnd - intervalStart - const hueDelta = Math.trunc(interval / numberOfColorsInInterval) - for (let i = 0; i < numberOfColorsInInterval; i++) { - const hue = intervalStart + i * hueDelta - colors.push(`hsla(${hue}, 80%, 50%, 0.3)`) - } + const hues: Array = generateHuesForInterval(20, 80, numberOfColorsInFirstInterval) + hues.push(...generateHuesForInterval(160, 340, numberOfColorsInSecondInterval)) + return toHSLAArray(hues, 0.8, 0.5, 0.3) } private static mapMatch(match: Record, color: string): Match { diff --git a/report-viewer/src/model/factories/OverviewFactory.ts b/report-viewer/src/model/factories/OverviewFactory.ts index b63af96ba..ed9c9781e 100644 --- a/report-viewer/src/model/factories/OverviewFactory.ts +++ b/report-viewer/src/model/factories/OverviewFactory.ts @@ -1,10 +1,10 @@ import { Overview } from '../Overview' -import type { Metric } from '../Metric' import type { ComparisonListElement } from '../ComparisonListElement' import type { Cluster } from '@/model/Cluster' import store from '@/stores/store' import type { Version } from '../Version' import versionJson from '@/version.json' +import Distribution from '../Distribution' export class OverviewFactory { static reportViewerVersion: Version = @@ -16,7 +16,7 @@ export class OverviewFactory { * Creates an overview object from a json object created by by JPlag * @param json the json object */ - static getOverview(json: Record): Overview { + static extractOverview(json: Record): Overview { const versionField = json.jplag_version as Record const jplagVersion: Version = { major: versionField.major, @@ -35,33 +35,41 @@ export class OverviewFactory { const map = new Map(Object.entries(jsonSubmissions)) const dateOfExecution = json.date_of_execution as string const duration = json.execution_time as number as number - const metrics = [] as Array const clusters = [] as Array const totalComparisons = json.total_comparisons as number - ;(json.metrics as Array).forEach((jsonMetric) => { - const metric = jsonMetric as Record - const comparisons = [] as Array - - ;(metric.topComparisons as Array>).forEach( - (jsonComparison, index) => { - const comparison: ComparisonListElement = { - id: (index + 1) as number, - firstSubmissionId: jsonComparison.first_submission as string, - secondSubmissionId: jsonComparison.second_submission as string, - similarity: jsonComparison.similarity as number - } - comparisons.push(comparison) - } + + const distributions = [] as Array + const averageSimilarities: Map = new Map() + const comparisons = [] as Array + + const metrics = json.metrics as Array as Array> + // Average + distributions.push(new Distribution(metrics[0].distribution as Array)) + for (const comparison of metrics[0].topComparisons as Array>) { + averageSimilarities.set( + (comparison.first_submission as string) + '-' + (comparison.second_submission as string), + comparison.similarity as number ) - metrics.push({ - metricName: metric.name as string, - metricThreshold: metric.threshold as number, - distribution: metric.distribution as Array, - comparisons: comparisons, - description: metric.description as string + } + + // Max + distributions.push(new Distribution(metrics[1].distribution as Array)) + let counter = 1 + for (const comparison of metrics[1].topComparisons as Array>) { + const avg = averageSimilarities.get( + (comparison.first_submission as string) + '-' + (comparison.second_submission as string) + ) + comparisons.push({ + id: counter++, + firstSubmissionId: comparison.first_submission as string, + secondSubmissionId: comparison.second_submission as string, + averageSimilarity: avg as number, + maximumSimilarity: comparison.similarity as number }) - }) + } + store().saveSubmissionNames(map) + if (json.clusters) { ;(json.clusters as Array).forEach((jsonCluster) => { const cluster = jsonCluster as Record @@ -83,13 +91,61 @@ export class OverviewFactory { matchSensitivity, dateOfExecution, duration, - metrics, + comparisons, + distributions, clusters, totalComparisons, new Map() ) } + /** + * Gets the overview file based on the used mode (zip, local, single). + */ + static getOverview(): Overview { + console.log('Generating overview...') + let temp!: Overview + //Gets the overview file based on the used mode (zip, local, single). + if (store().local) { + const request = new XMLHttpRequest() + request.open('GET', '/files/overview.json', false) + request.send() + + if (request.status == 200) { + temp = OverviewFactory.extractOverview(JSON.parse(request.response)) + } else { + throw 'Could not find overview.json in folder.' + } + } else if (store().zip) { + console.log('Start finding overview.json in state...') + const index = Object.keys(store().files).find((name) => name.endsWith('overview.json')) + const overviewFile = + index != undefined ? store().files[index] : console.log('Could not find overview.json') + + if (overviewFile === undefined) { + return new Overview( + [], + '', + '', + [], + 0, + '', + 0, + [], + [], + [], + 0, + new Map>() + ) + } + const overviewJson = JSON.parse(overviewFile) + temp = OverviewFactory.extractOverview(overviewJson) + } else if (store().single) { + temp = OverviewFactory.extractOverview(JSON.parse(store().fileString)) + } + return temp + } + /** * Compares the two versions and shows an alert if they are not equal and puts out a warning if they are not * @param jsonVersion the version of the json file diff --git a/report-viewer/src/router/index.ts b/report-viewer/src/router/index.ts index 0615990be..108764fa7 100644 --- a/report-viewer/src/router/index.ts +++ b/report-viewer/src/router/index.ts @@ -3,6 +3,7 @@ import FileUploadView from '@/views/FileUploadView.vue' import OverviewView from '@/views/OverviewView.vue' import ComparisonView from '@/views/ComparisonView.vue' import ErrorView from '@/views/ErrorView.vue' +import ClusterView from '@/views/ClusterView.vue' /** * The router is used to navigate between the different views of the application. @@ -30,6 +31,12 @@ const router = createRouter({ path: '/error', name: 'ErrorView', component: ErrorView + }, + { + path: '/cluster/:clusterIndex', + name: 'ClusterView', + component: ClusterView, + props: true } ] }) diff --git a/report-viewer/src/utils/ColorUtils.ts b/report-viewer/src/utils/ColorUtils.ts new file mode 100644 index 000000000..65377fefa --- /dev/null +++ b/report-viewer/src/utils/ColorUtils.ts @@ -0,0 +1,37 @@ +function generateHuesForInterval( + intervalStart: number, + intervalEnd: number, + numberOfColorsInInterval: number +) { + const colors: Array = [] + const interval = intervalEnd - intervalStart + const hueDelta = Math.trunc(interval / numberOfColorsInInterval) + for (let i = 0; i < numberOfColorsInInterval; i++) { + const hue = intervalStart + i * hueDelta + colors.push(hue) + } + return colors +} + +/** + * + * @param hues + * @param saturation [0,1] + * @param lightness [0,1] + * @param alpha [0,1] + * @returns + */ +function toHSLAArray( + hues: Array, + saturation: number, + lightness: number, + alpha +): Array { + const colors: Array = [] + hues.forEach((hue) => { + colors.push(`hsla(${hue}, ${saturation * 100}%, ${lightness * 100}%, ${alpha})`) + }) + return colors +} + +export { generateHuesForInterval, toHSLAArray } diff --git a/report-viewer/src/views/ClusterView.vue b/report-viewer/src/views/ClusterView.vue new file mode 100644 index 000000000..6c2d3dd0c --- /dev/null +++ b/report-viewer/src/views/ClusterView.vue @@ -0,0 +1,73 @@ + + + diff --git a/report-viewer/src/views/ErrorView.vue b/report-viewer/src/views/ErrorView.vue index 3ee4d7324..f514288bd 100644 --- a/report-viewer/src/views/ErrorView.vue +++ b/report-viewer/src/views/ErrorView.vue @@ -26,11 +26,6 @@
- - - diff --git a/report-viewer/src/views/OverviewView.vue b/report-viewer/src/views/OverviewView.vue index 606a4f44e..2380dce62 100644 --- a/report-viewer/src/views/OverviewView.vue +++ b/report-viewer/src/views/OverviewView.vue @@ -22,7 +22,10 @@

Distribution of Comparisons:

- +

Options:

@@ -43,7 +46,7 @@
@@ -52,15 +55,11 @@ - - diff --git a/report-viewer/src/components/ComparisonsTable.vue b/report-viewer/src/components/ComparisonsTable.vue index ca5e117fc..81bcb80a4 100644 --- a/report-viewer/src/components/ComparisonsTable.vue +++ b/report-viewer/src/components/ComparisonsTable.vue @@ -4,6 +4,7 @@ - - diff --git a/report-viewer/src/components/MetricButton.vue b/report-viewer/src/components/MetricButton.vue deleted file mode 100644 index d4b675c46..000000000 --- a/report-viewer/src/components/MetricButton.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - diff --git a/report-viewer/src/router/index.ts b/report-viewer/src/router/index.ts index 108764fa7..4d4212d82 100644 --- a/report-viewer/src/router/index.ts +++ b/report-viewer/src/router/index.ts @@ -4,6 +4,7 @@ import OverviewView from '@/views/OverviewView.vue' import ComparisonView from '@/views/ComparisonView.vue' import ErrorView from '@/views/ErrorView.vue' import ClusterView from '@/views/ClusterView.vue' +import InformationView from '@/views/InformationView.vue' /** * The router is used to navigate between the different views of the application. @@ -37,6 +38,11 @@ const router = createRouter({ name: 'ClusterView', component: ClusterView, props: true + }, + { + path: '/info', + name: 'InfoView', + component: InformationView } ] }) diff --git a/report-viewer/src/views/InformationView.vue b/report-viewer/src/views/InformationView.vue new file mode 100644 index 000000000..249c76aad --- /dev/null +++ b/report-viewer/src/views/InformationView.vue @@ -0,0 +1,62 @@ + + + diff --git a/report-viewer/src/views/OverviewView.vue b/report-viewer/src/views/OverviewView.vue index 2380dce62..73b9a8f34 100644 --- a/report-viewer/src/views/OverviewView.vue +++ b/report-viewer/src/views/OverviewView.vue @@ -14,7 +14,7 @@ {{ overview.totalComparisons }} - +
@@ -55,7 +55,7 @@ diff --git a/report-viewer/src/assets/radar-chart-configuration.ts b/report-viewer/src/assets/radar-chart-configuration.ts deleted file mode 100644 index 6f1b31cc2..000000000 --- a/report-viewer/src/assets/radar-chart-configuration.ts +++ /dev/null @@ -1,21 +0,0 @@ -const radarChartStyle = { - fill: true, - backgroundColor: 'rgba(149, 168, 241, 0.5)', - borderColor: 'rgba(149, 168, 241, 1)', - pointBackgroundColor: 'rgba(149, 168, 241, 1)', - pointBorderColor: '#fff', - pointHoverBackgroundColor: '#fff', - pointHoverBorderColor: 'rgb(255, 99, 132)' -} -const radarChartOptions = { - legend: { - display: false - }, - scales: { - r: { - suggestedMin: 50, - suggestedMax: 100 - } - } -} -export { radarChartStyle, radarChartOptions } diff --git a/report-viewer/src/components/ClusterRadarChart.vue b/report-viewer/src/components/ClusterRadarChart.vue index 759a91ce7..8147b9b3f 100644 --- a/report-viewer/src/components/ClusterRadarChart.vue +++ b/report-viewer/src/components/ClusterRadarChart.vue @@ -3,13 +3,13 @@ participants in the cluster. -->