diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..8da02c9
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+VITE_BACKEND_URL=http://127.0.0.1:3003
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index a96210a..0894ad7 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -16,6 +16,7 @@ module.exports = {
],
parserOptions: {
extraFileExtensions: ['.svelte'],
+ sourceType: 'module',
},
overrides: [
{
diff --git a/.gitignore b/.gitignore
index adadc60..31ab9b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@
/cypress/screenshots
/src/locales
/dump.txt
+.env
+.env.local
# Editor directories and files
.DS_Store
diff --git a/README.md b/README.md
index b376d08..be0fc06 100644
--- a/README.md
+++ b/README.md
@@ -7,3 +7,13 @@ This folder will contain the Web-UI for displaying and comparing historical run
### [Issues](https://github.com/idrinth-api-bench/issues)
This is the issue repository for a typescript framework meant to performance test anything even remotely rest-like and related tools.
+
+## Setup
+
+- Make sure you're using node.js 20 or higher
+- Run `npm install` to install all dependencies
+- Run `npm run language` to build the language files
+- Create a file .env or .env.local with the following content (replace the localhost placeholder with your backend url):
+```env
+ VITE_BACKEND_URL=http://localhost:3003
+```
diff --git a/gitCommitDev.sh b/gitCommitDev.sh
deleted file mode 100644
index d719ec2..0000000
--- a/gitCommitDev.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-# Commit changes form for easy commits
-
-echo ""
-echo "Task types:"
-echo ""
-echo "build: Changes that affect the build system or external dependencies"
-echo "ci: Changes to CI configuration files and scripts"
-echo "docs: Documentation changes"
-echo "feature: A new feature"
-echo "bug: A bug fix"
-echo "refactor: A code change that neither fixes a bug nor adds a feature"
-echo ""
-read -rp "Enter your task type: " task
-
-echo ""
-echo "Enter your task scope:"
-echo ""
-echo "framework"
-echo "documentation-website"
-echo "history-microservice"
-echo "history-website"
-echo "dockerfiles"
-echo "examples"
-echo ""
-read -rp "Enter the task scope: " scope
-
-echo ""
-read -rp "Enter the task summary: " summary
-echo ""
-read -rp "Enter the task description: " description
-echo ""
-read -rp "What issue number does this address? " issue
-echo ""
-
-git add .
-git commit -m "$task($scope): $summary \n $description \n closes #$issue"
-git pull
-git push
-
-echo 'Commits made to your working branch. Happy coding!'
diff --git a/index.html b/index.html
index d5f74fe..ccd2354 100644
--- a/index.html
+++ b/index.html
@@ -1,13 +1,20 @@
-
+
-
-
- Vite + Svelte + TS
+
+
+ History Website for @idrinth-api-bench
-
+
-
+
diff --git a/language/de.yml b/language/de.yml
index 6b5695f..0c6a0c9 100644
--- a/language/de.yml
+++ b/language/de.yml
@@ -3,3 +3,10 @@ overview:
meta:
title: "Projekte"
description: "Alle Projekte in einer einfach zu verstehenden Übersicht."
+login:
+ title: "Anmelden"
+ username: "Benutzername"
+ submit: "Anmelden"
+ meta:
+ title: "Anmelden"
+ description: "Melden Sie sich bei Ihrem Konto an."
diff --git a/language/en.yml b/language/en.yml
index 0d808af..cadf928 100644
--- a/language/en.yml
+++ b/language/en.yml
@@ -1,5 +1,33 @@
overview:
- title: "Projects"
+ title: 'Projects'
meta:
- title: "Projects"
- description: "All your projects in an easy to grasp overview."
+ title: 'Projects'
+ description: 'All your projects in an easy to grasp overview.'
+login:
+ username: 'Username'
+ submit: 'Login'
+ title: 'Login'
+ meta:
+ title: 'Login'
+ description: 'Login to your account.'
+projects:
+ title: 'Projects'
+ description: 'A line graph per project to compare their global performance(user choice of Average or Median) + a bar graph with the error count'
+ meta:
+ title: 'Projects'
+project:
+ title: 'Project'
+ description: 'A line graph per route in the project to compare their global performance(user choice of Average or Median) + a bar graph with the error count'
+ meta:
+ title: 'Project'
+ routes: 'Routes'
+route:
+ title: 'Route'
+ description: 'A line graph per mean and average in the route to compare their and a bar graph with the error count'
+ meta:
+ title: 'Route'
+global-performance-chart:
+ title: 'Global Performance'
+ mean: 'Mean'
+ average: 'Average'
+loading: 'Loading...'
diff --git a/language/it.yml b/language/it.yml
index 3ef288b..ef636ab 100644
--- a/language/it.yml
+++ b/language/it.yml
@@ -1,5 +1,33 @@
overview:
- title: "Progetti"
+ title: 'Progetti'
meta:
- title: "Progetti"
+ title: 'Progetti'
description: "Tutti i tuoi progetti in un'unica semplice interfaccia."
+login:
+ title: 'Accedi'
+ username: 'Username'
+ submit: 'Accedi'
+ meta:
+ title: 'Accedi'
+ description: 'Accedi al tuo account.'
+projects:
+ title: 'Progetti'
+ description: 'Un grafico a linea per progetto per comparare la loro performance globale + un grafico a barre con il conteggio degli errori.'
+ meta:
+ title: 'Progetti'
+project:
+ title: 'Progetto'
+ description: 'Un grafico a linea per rotta per comparare la loro performance globale + un grafico a barre con il conteggio degli errori.'
+ meta:
+ title: 'Progetto'
+ routes: 'Rotte'
+route:
+ title: 'Rotta'
+ description: 'Un grafico a linea per mediana e media per la rotta per comparare la loro performance e un grafico a barre con il conteggio degli errori.'
+ meta:
+ title: 'Rotta'
+global-performance-chart:
+ title: 'Performance Globale'
+ mean: 'Mediana'
+ average: 'Media'
+loading: 'Caricamento...'
diff --git a/package-lock.json b/package-lock.json
index ce97cf5..6ec9d94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,8 +7,13 @@
"": {
"name": "@idrinth-api-bench/history-website",
"version": "2.7.4",
+ "dependencies": {
+ "chart.js": "^4.4.2",
+ "svelte-chartjs": "^3.1.5"
+ },
"devDependencies": {
"@idrinth-api-bench/assets": "https://github.com/idrinth-api-bench/assets",
+ "@idrinth-api-bench/chartjs-plugin-stdev-filler": "^1.0.5",
"@idrinth/typescript-language-from-yaml": "^1.3.0",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@tsconfig/svelte": "^5.0.2",
@@ -21,6 +26,7 @@
"svelte": "^4.2.18",
"svelte-check": "^3.8.0",
"svelte-eslint-parser": "^0.37.0",
+ "svelte-routing": "^2.13.0",
"typescript": "^5.2.2",
"vite": "^5.2.13"
},
@@ -32,7 +38,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
- "dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -539,6 +544,16 @@
"resolved": "git+ssh://git@github.com/idrinth-api-bench/assets.git#eada675b182fff362f11956921d79453770ece3a",
"dev": true
},
+ "node_modules/@idrinth-api-bench/chartjs-plugin-stdev-filler": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@idrinth-api-bench/chartjs-plugin-stdev-filler/-/chartjs-plugin-stdev-filler-1.0.5.tgz",
+ "integrity": "sha512-KfNw6Z6Bsi73tdvqqH17Z7bKUIIya8cO3gy1KUp+OO1qxvD8Ru4d4q2Nr41JDOGDgMdKktthDukrfsxq6ViAQg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "chart.js": "^4.4"
+ }
+ },
"node_modules/@idrinth/typescript-language-from-yaml": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@idrinth/typescript-language-from-yaml/-/typescript-language-from-yaml-1.3.0.tgz",
@@ -599,7 +614,6 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
- "dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
@@ -613,7 +627,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"engines": {
"node": ">=6.0.0"
}
@@ -622,7 +635,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
"engines": {
"node": ">=6.0.0"
}
@@ -630,19 +642,23 @@
"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==",
- "dev": true
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
- "dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==",
+ "license": "MIT"
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -970,8 +986,7 @@
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
- "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
- "dev": true
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
},
"node_modules/@types/mdast": {
"version": "3.0.15",
@@ -1156,7 +1171,6 @@
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
- "dev": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1261,7 +1275,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -1316,7 +1329,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
- "dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -1369,12 +1381,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -1434,6 +1447,18 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/chart.js": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz",
+ "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1493,7 +1518,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
- "dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
@@ -1681,7 +1705,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
- "dev": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
@@ -1782,7 +1805,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -2199,7 +2221,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
- "dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
@@ -2306,10 +2327,11 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -2793,7 +2815,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
- "dev": true,
"dependencies": {
"@types/estree": "*"
}
@@ -3109,8 +3130,7 @@
"node_modules/locate-character": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
- "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
- "dev": true
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
},
"node_modules/locate-path": {
"version": "6.0.0",
@@ -3180,7 +3200,6 @@
"version": "0.30.10",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
"integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
- "dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
}
@@ -3498,8 +3517,7 @@
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
- "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
- "dev": true
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
},
"node_modules/mdurl": {
"version": "2.0.0",
@@ -4433,7 +4451,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
- "dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
@@ -5475,7 +5492,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -5789,7 +5805,6 @@
"version": "4.2.18",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.18.tgz",
"integrity": "sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==",
- "dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
@@ -5810,6 +5825,16 @@
"node": ">=16"
}
},
+ "node_modules/svelte-chartjs": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz",
+ "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "chart.js": "^3.5.0 || ^4.0.0",
+ "svelte": "^4.0.0"
+ }
+ },
"node_modules/svelte-check": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.0.tgz",
@@ -5933,6 +5958,13 @@
}
}
},
+ "node_modules/svelte-routing": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/svelte-routing/-/svelte-routing-2.13.0.tgz",
+ "integrity": "sha512-/NTxqTwLc7Dq306hARJrH2HLXOBtKd7hu8nxgoFDlK0AC4SOKnzisiX/9m8Uksei1QAWtlAEdF91YphNM8iDMg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/table-layout": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz",
@@ -5993,6 +6025,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -6005,6 +6038,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
diff --git a/package.json b/package.json
index 52777c1..1eb15cd 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
},
"devDependencies": {
"@idrinth-api-bench/assets": "https://github.com/idrinth-api-bench/assets",
+ "@idrinth-api-bench/chartjs-plugin-stdev-filler": "^1.0.5",
"@idrinth/typescript-language-from-yaml": "^1.3.0",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@tsconfig/svelte": "^5.0.2",
@@ -37,11 +38,16 @@
"svelte": "^4.2.18",
"svelte-check": "^3.8.0",
"svelte-eslint-parser": "^0.37.0",
+ "svelte-routing": "^2.13.0",
"typescript": "^5.2.2",
"vite": "^5.2.13"
},
"engines": {
"node": ">=20"
},
- "engineStrict": true
+ "engineStrict": true,
+ "dependencies": {
+ "chart.js": "^4.4.2",
+ "svelte-chartjs": "^3.1.5"
+ }
}
diff --git a/src/App.svelte b/src/App.svelte
index 1f265fd..38ecf23 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -1,26 +1,7 @@
-
-
-
-
- {t('overview.title',)}
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/src/app.css b/src/app.css
index 617f5e9..fa41c65 100644
--- a/src/app.css
+++ b/src/app.css
@@ -11,25 +11,31 @@
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
+
+ --outer-padding: 2rem;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: var(--outer-padding);
}
a {
- font-weight: 500;
color: #646cff;
+ font-weight: 500;
text-decoration: inherit;
}
+
a:hover {
color: #535bf2;
}
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
h1 {
font-size: 3.2em;
line-height: 1.1;
@@ -39,13 +45,6 @@ h1 {
padding: 2em;
}
-#app {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
button {
border-radius: 8px;
border: 1px solid transparent;
@@ -57,9 +56,11 @@ button {
cursor: pointer;
transition: border-color 0.25s;
}
+
button:hover {
border-color: #646cff;
}
+
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
@@ -70,9 +71,11 @@ button:focus-visible {
color: #213547;
background-color: #ffffff;
}
+
a:hover {
color: #747bff;
}
+
button {
background-color: #f9f9f9;
}
diff --git a/src/components/Breadcrumbs.svelte b/src/components/Breadcrumbs.svelte
new file mode 100644
index 0000000..de54c64
--- /dev/null
+++ b/src/components/Breadcrumbs.svelte
@@ -0,0 +1,53 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/GlobalPerformanceLineChart.svelte b/src/components/GlobalPerformanceLineChart.svelte
new file mode 100644
index 0000000..8e57411
--- /dev/null
+++ b/src/components/GlobalPerformanceLineChart.svelte
@@ -0,0 +1,49 @@
+
+
+{t('global-performance-chart.title')}
+
+{#if data}
+
+{:else}
+ {t('loading')}
+{/if}
diff --git a/src/components/Header.svelte b/src/components/Header.svelte
new file mode 100644
index 0000000..1ac8298
--- /dev/null
+++ b/src/components/Header.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ {#if $user}
+
+ {/if}
+
+
+
diff --git a/src/components/Logo.svelte b/src/components/Logo.svelte
new file mode 100644
index 0000000..5ad7293
--- /dev/null
+++ b/src/components/Logo.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/src/components/ProjectPerformanceLineChart.svelte b/src/components/ProjectPerformanceLineChart.svelte
new file mode 100644
index 0000000..0ae808a
--- /dev/null
+++ b/src/components/ProjectPerformanceLineChart.svelte
@@ -0,0 +1,50 @@
+
+
+{t('global-performance-chart.title')}
+
+{#if data}
+
+{:else}
+ {t('loading')}
+{/if}
diff --git a/src/components/RoutePerformanceLineChart.svelte b/src/components/RoutePerformanceLineChart.svelte
new file mode 100644
index 0000000..ed004dd
--- /dev/null
+++ b/src/components/RoutePerformanceLineChart.svelte
@@ -0,0 +1,76 @@
+
+
+{t('global-performance-chart.title')}
+{#if data}
+
+{:else}
+ {t('loading')}
+{/if}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 0da72ea..f86d822 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -1,2 +1,3 @@
export const FIRST_ELEMENT = 0;
export const SECOND_ELEMENT = 1;
+export const LOCAL_STORAGE_USER_KEY = 'user';
diff --git a/src/lib/http-client.ts b/src/lib/http-client.ts
new file mode 100644
index 0000000..016e988
--- /dev/null
+++ b/src/lib/http-client.ts
@@ -0,0 +1,66 @@
+import { user } from "../stores";
+import { LOCAL_STORAGE_USER_KEY } from "./constants";
+import type { ProjectResponse, ProjectsResponse, RouteResponse, User } from "./response-types";
+
+/**
+ * Generic fetch function
+ */
+type FetcherOptions = {
+ method: "GET" | "POST" | "PUT" | "DELETE",
+ body?: any,
+ headers?: HeadersInit,
+}
+export const fetcher = async (url: string, options?: FetcherOptions): Promise => {
+ const headers = new Headers(options?.headers);
+ if (localStorage.getItem(LOCAL_STORAGE_USER_KEY)) {
+ const token = JSON.parse(localStorage.getItem(LOCAL_STORAGE_USER_KEY) || "{}")?.token;
+ headers.set("Authorization", `Bearer ${ token }`);
+ }
+ const response = await fetch(
+ `${ import.meta.env.VITE_BACKEND_URL }/${ url }`,
+ {
+ ...options,
+ headers,
+ }
+ );
+ if (! response.ok) {
+ throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
+ }
+ return await response.json();
+}
+
+export const login = async (username: string): Promise => {
+ const response = await fetcher('login', {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ username }),
+ });
+ const _user = {
+ token: response.token,
+ }
+ localStorage.setItem(LOCAL_STORAGE_USER_KEY, JSON.stringify(_user));
+ user.set(_user);
+}
+
+export const logout = (): void => {
+ localStorage.removeItem(LOCAL_STORAGE_USER_KEY);
+ user.set(null);
+}
+
+/**
+ * Projects+Routes
+ */
+
+export const getProjects = async (): Promise => {
+ return await fetcher("projects");
+}
+
+export const getProject = async (projectKey: string): Promise => {
+ return await fetcher(`project/${ projectKey }/routes`);
+}
+
+export const getRoute = async (projectKey: string, route: string): Promise => {
+ return await fetcher(`project/${ projectKey }/route/${ route }`);
+}
diff --git a/src/lib/response-types.ts b/src/lib/response-types.ts
new file mode 100644
index 0000000..a3f2d07
--- /dev/null
+++ b/src/lib/response-types.ts
@@ -0,0 +1,49 @@
+/**
+ * User
+ */
+export type User = {
+ token: string,
+}
+
+/**
+ * Projects
+ */
+
+export type ProjectMetrics = {
+ mean: number,
+ average: number,
+ stdev: number,
+}
+
+export type ProjectResponse = {
+ [endpoint: string]: {
+ [date: string]: ProjectMetrics
+ }[]
+}
+
+export type ProjectsResponse = {
+ [projectKey: string]: {
+ [date: string]: ProjectMetrics
+ }[]
+}
+
+/**
+ * Routes
+ */
+export type RouteResponse = {
+ [date: string]: {
+ errors: number,
+ msgs: { [msg: string]: number },
+ count: number,
+ stdv100: number,
+ stdv80: number,
+ avg100: number,
+ median100: number,
+ min100: number,
+ max100: number,
+ avg80: number,
+ median80: number,
+ min80: number,
+ max80: number
+ }[]
+}
diff --git a/src/locales/de-overview.ts b/src/locales/de-overview.ts
deleted file mode 100644
index 7eee030..0000000
--- a/src/locales/de-overview.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/* eslint max-len:0 */
-const lang = {
- title: 'Projekte',
- meta: {
- title: 'Projekte',
- description: 'Alle Projekte in einer einfach zu verstehenden Übersicht.',
- },
-};
-
-export default lang;
diff --git a/src/locales/de.ts b/src/locales/de.ts
deleted file mode 100644
index d584ff1..0000000
--- a/src/locales/de.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint max-len:0 */
-const lang = {
- overview: {
- title: 'Projekte',
- meta: {
- title: 'Projekte',
- description: 'Alle Projekte in einer einfach zu verstehenden Übersicht.',
- },
- },
-};
-
-export default lang;
diff --git a/src/locales/en-overview.ts b/src/locales/en-overview.ts
deleted file mode 100644
index 4878a49..0000000
--- a/src/locales/en-overview.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/* eslint max-len:0 */
-const lang = {
- title: 'Projects',
- meta: {
- title: 'Projects',
- description: 'All your projects in an easy to grasp overview.',
- },
-};
-
-export default lang;
diff --git a/src/locales/en.ts b/src/locales/en.ts
deleted file mode 100644
index 7f94df8..0000000
--- a/src/locales/en.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint max-len:0 */
-const lang = {
- overview: {
- title: 'Projects',
- meta: {
- title: 'Projects',
- description: 'All your projects in an easy to grasp overview.',
- },
- },
-};
-
-export default lang;
diff --git a/src/locales/files.ts b/src/locales/files.ts
deleted file mode 100644
index c0b90d4..0000000
--- a/src/locales/files.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-const files = [
- 'de-overview',
- 'en-overview',
-];
-export default files;
diff --git a/src/locales/language-key.ts b/src/locales/language-key.ts
deleted file mode 100644
index efca2a0..0000000
--- a/src/locales/language-key.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/* eslint max-len:0 */
-type lk = 'overview.title'|'overview.meta.title'|'overview.meta.description';
-export type languageKey = lk;
diff --git a/src/locales/languages.ts b/src/locales/languages.ts
deleted file mode 100644
index 1423e2c..0000000
--- a/src/locales/languages.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-/* eslint max-len:0 */
-const languages = [
- 'de',
- 'en',
-];
-export default languages;
diff --git a/src/locales/translations.ts b/src/locales/translations.ts
deleted file mode 100644
index f68552f..0000000
--- a/src/locales/translations.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import de_overview from './de-overview.js';
-import en_overview from './en-overview.js';
-const translations = {
- 'de-overview': de_overview,
- 'en-overview': en_overview,
-};
-export default translations;
diff --git a/src/main.ts b/src/main.ts
index a91e873..9c94b84 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,7 +3,6 @@ import './app.css';
import App from './App.svelte';
const app = new App({
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
target: document.getElementById('app',),
},);
diff --git a/src/pages/Login.svelte b/src/pages/Login.svelte
new file mode 100644
index 0000000..ed35d73
--- /dev/null
+++ b/src/pages/Login.svelte
@@ -0,0 +1,31 @@
+
+
+
+
{t('login.title')}
+
+
diff --git a/src/pages/Project.svelte b/src/pages/Project.svelte
new file mode 100644
index 0000000..13116a2
--- /dev/null
+++ b/src/pages/Project.svelte
@@ -0,0 +1,33 @@
+
+
+
+
{t('project.title')}: {project}
+
{t('project.description')}
+
+
{t('project.routes')}
+
+ {#if projectMetricsResponse}
+ {#each Object.keys(projectMetricsResponse) as route}
+ -
+ {route}
+
+ {/each}
+ {/if}
+
+
+ {#if projectMetricsResponse}
+
+ {/if}
+
diff --git a/src/pages/Projects.svelte b/src/pages/Projects.svelte
new file mode 100644
index 0000000..3525328
--- /dev/null
+++ b/src/pages/Projects.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
{t('projects.title')}
+
{t('projects.description')}
+
+
+ {#each Object.keys(projectMetricsResponse) as project}
+ -
+ {project}
+
+ {/each}
+
+
+
+
diff --git a/src/pages/Route.svelte b/src/pages/Route.svelte
new file mode 100644
index 0000000..6ea1e79
--- /dev/null
+++ b/src/pages/Route.svelte
@@ -0,0 +1,23 @@
+
+
+
+
{t('route.title')}: {project} : {route}
+
{t('route.description')}
+
+ {#if routeMetricsResponse}
+
+ {/if}
+
diff --git a/src/routes/AppRouter.svelte b/src/routes/AppRouter.svelte
new file mode 100644
index 0000000..9224e45
--- /dev/null
+++ b/src/routes/AppRouter.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/PrivateRoutes.svelte b/src/routes/PrivateRoutes.svelte
new file mode 100644
index 0000000..aba6251
--- /dev/null
+++ b/src/routes/PrivateRoutes.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/src/routes/RouteGuard.svelte b/src/routes/RouteGuard.svelte
new file mode 100644
index 0000000..10e96de
--- /dev/null
+++ b/src/routes/RouteGuard.svelte
@@ -0,0 +1,17 @@
+
+
+{#if $user}
+
+{/if}
diff --git a/src/stores.ts b/src/stores.ts
new file mode 100644
index 0000000..39c0099
--- /dev/null
+++ b/src/stores.ts
@@ -0,0 +1,7 @@
+import { type Writable, writable } from 'svelte/store'
+import { LOCAL_STORAGE_USER_KEY } from "./lib/constants";
+import type { User } from './lib/response-types';
+
+export const user: Writable = writable(
+ localStorage.getItem(LOCAL_STORAGE_USER_KEY) ? JSON.parse(localStorage.getItem(LOCAL_STORAGE_USER_KEY) || 'null') : null
+)