Преглед изворни кода

fix: Replace custom pagination component with picocrank pagination component

- Replace custom pagination component with picocrank pagination component
- Update package.json and package-lock.json to include picocrank
- Update style.css to include new padding class
- Update ActionDetailsView.vue and LogsListView.vue to use new pagination component
jamesread пре 7 месеци
родитељ
комит
c1508a0a65

+ 93 - 194
frontend/package-lock.json

@@ -17,7 +17,7 @@
 				"@xterm/addon-fit": "^0.10.0",
 				"@xterm/xterm": "^5.5.0",
 				"iconify-icon": "^3.0.2",
-				"picocrank": "^1.8.1",
+				"picocrank": "^1.8.7",
 				"standard": "^17.1.2",
 				"unplugin-vue-components": "^30.0.0",
 				"vite": "^7.2.2",
@@ -49,9 +49,9 @@
 			}
 		},
 		"node_modules/@babel/helper-validator-identifier": {
-			"version": "7.27.1",
-			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
-			"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+			"version": "7.28.5",
+			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+			"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
 			"license": "MIT",
 			"engines": {
 				"node": ">=6.9.0"
@@ -144,12 +144,12 @@
 			}
 		},
 		"node_modules/@babel/parser": {
-			"version": "7.28.4",
-			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
-			"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+			"version": "7.28.5",
+			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
+			"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
 			"license": "MIT",
 			"dependencies": {
-				"@babel/types": "^7.28.4"
+				"@babel/types": "^7.28.5"
 			},
 			"bin": {
 				"parser": "bin/babel-parser.js"
@@ -159,13 +159,13 @@
 			}
 		},
 		"node_modules/@babel/types": {
-			"version": "7.28.4",
-			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
-			"integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+			"version": "7.28.5",
+			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+			"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
 			"license": "MIT",
 			"dependencies": {
 				"@babel/helper-string-parser": "^7.27.1",
-				"@babel/helper-validator-identifier": "^7.27.1"
+				"@babel/helper-validator-identifier": "^7.28.5"
 			},
 			"engines": {
 				"node": ">=6.9.0"
@@ -629,53 +629,53 @@
 			}
 		},
 		"node_modules/@vue/compiler-core": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz",
-			"integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.24.tgz",
+			"integrity": "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==",
 			"license": "MIT",
 			"dependencies": {
-				"@babel/parser": "^7.28.3",
-				"@vue/shared": "3.5.21",
+				"@babel/parser": "^7.28.5",
+				"@vue/shared": "3.5.24",
 				"entities": "^4.5.0",
 				"estree-walker": "^2.0.2",
 				"source-map-js": "^1.2.1"
 			}
 		},
 		"node_modules/@vue/compiler-dom": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz",
-			"integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.24.tgz",
+			"integrity": "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/compiler-core": "3.5.21",
-				"@vue/shared": "3.5.21"
+				"@vue/compiler-core": "3.5.24",
+				"@vue/shared": "3.5.24"
 			}
 		},
 		"node_modules/@vue/compiler-sfc": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz",
-			"integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.24.tgz",
+			"integrity": "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==",
 			"license": "MIT",
 			"dependencies": {
-				"@babel/parser": "^7.28.3",
-				"@vue/compiler-core": "3.5.21",
-				"@vue/compiler-dom": "3.5.21",
-				"@vue/compiler-ssr": "3.5.21",
-				"@vue/shared": "3.5.21",
+				"@babel/parser": "^7.28.5",
+				"@vue/compiler-core": "3.5.24",
+				"@vue/compiler-dom": "3.5.24",
+				"@vue/compiler-ssr": "3.5.24",
+				"@vue/shared": "3.5.24",
 				"estree-walker": "^2.0.2",
-				"magic-string": "^0.30.18",
+				"magic-string": "^0.30.21",
 				"postcss": "^8.5.6",
 				"source-map-js": "^1.2.1"
 			}
 		},
 		"node_modules/@vue/compiler-ssr": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz",
-			"integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.24.tgz",
+			"integrity": "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/compiler-dom": "3.5.21",
-				"@vue/shared": "3.5.21"
+				"@vue/compiler-dom": "3.5.24",
+				"@vue/shared": "3.5.24"
 			}
 		},
 		"node_modules/@vue/devtools-api": {
@@ -685,53 +685,53 @@
 			"license": "MIT"
 		},
 		"node_modules/@vue/reactivity": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz",
-			"integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.24.tgz",
+			"integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/shared": "3.5.21"
+				"@vue/shared": "3.5.24"
 			}
 		},
 		"node_modules/@vue/runtime-core": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz",
-			"integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.24.tgz",
+			"integrity": "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/reactivity": "3.5.21",
-				"@vue/shared": "3.5.21"
+				"@vue/reactivity": "3.5.24",
+				"@vue/shared": "3.5.24"
 			}
 		},
 		"node_modules/@vue/runtime-dom": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz",
-			"integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.24.tgz",
+			"integrity": "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/reactivity": "3.5.21",
-				"@vue/runtime-core": "3.5.21",
-				"@vue/shared": "3.5.21",
+				"@vue/reactivity": "3.5.24",
+				"@vue/runtime-core": "3.5.24",
+				"@vue/shared": "3.5.24",
 				"csstype": "^3.1.3"
 			}
 		},
 		"node_modules/@vue/server-renderer": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz",
-			"integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.24.tgz",
+			"integrity": "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/compiler-ssr": "3.5.21",
-				"@vue/shared": "3.5.21"
+				"@vue/compiler-ssr": "3.5.24",
+				"@vue/shared": "3.5.24"
 			},
 			"peerDependencies": {
-				"vue": "3.5.21"
+				"vue": "3.5.24"
 			}
 		},
 		"node_modules/@vue/shared": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz",
-			"integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.24.tgz",
+			"integrity": "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==",
 			"license": "MIT"
 		},
 		"node_modules/@xterm/addon-fit": {
@@ -806,19 +806,6 @@
 				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
 			}
 		},
-		"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==",
-			"license": "ISC",
-			"dependencies": {
-				"normalize-path": "^3.0.0",
-				"picomatch": "^2.0.4"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
 		"node_modules/argparse": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1025,18 +1012,6 @@
 			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
 			"license": "MIT"
 		},
-		"node_modules/binary-extensions": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
-			"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
 		"node_modules/brace-expansion": {
 			"version": "1.1.12",
 			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -1051,6 +1026,7 @@
 			"version": "3.0.3",
 			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
 			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+			"dev": true,
 			"dependencies": {
 				"fill-range": "^7.1.1"
 			},
@@ -2277,9 +2253,9 @@
 			}
 		},
 		"node_modules/femtocrank": {
-			"version": "2.4.4",
-			"resolved": "https://registry.npmjs.org/femtocrank/-/femtocrank-2.4.4.tgz",
-			"integrity": "sha512-MG0s8QPivocTXCElfqvLCW0m9uRGlCauoyRr3obEu8mz7/s1LsUs46b29Xdn4DQpdu3eagWYj6rkuVqEO6g4TQ==",
+			"version": "2.4.11",
+			"resolved": "https://registry.npmjs.org/femtocrank/-/femtocrank-2.4.11.tgz",
+			"integrity": "sha512-IDEcr8+w5/ux58F2N1heaxse7BvjJ0mJfJcCGx15QZCn8wi+hiQaIBud0ctlzRR3+SPmy7UCY5Ym+ZeyE4Bslg==",
 			"license": "AGPL-3.0"
 		},
 		"node_modules/file-entry-cache": {
@@ -2298,6 +2274,7 @@
 			"version": "7.1.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
 			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+			"dev": true,
 			"dependencies": {
 				"to-regex-range": "^5.0.1"
 			},
@@ -2500,6 +2477,7 @@
 			"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"
 			},
@@ -2869,18 +2847,6 @@
 				"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==",
-			"license": "MIT",
-			"dependencies": {
-				"binary-extensions": "^2.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
 		"node_modules/is-boolean-object": {
 			"version": "1.2.2",
 			"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
@@ -3047,6 +3013,7 @@
 			"version": "7.0.0",
 			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+			"dev": true,
 			"engines": {
 				"node": ">=0.12.0"
 			}
@@ -3255,9 +3222,9 @@
 			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
 		},
 		"node_modules/js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+			"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
 			"license": "MIT",
 			"dependencies": {
 				"argparse": "^2.0.1"
@@ -3532,9 +3499,9 @@
 			}
 		},
 		"node_modules/magic-string": {
-			"version": "0.30.19",
-			"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
-			"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+			"version": "0.30.21",
+			"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+			"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
 			"license": "MIT",
 			"dependencies": {
 				"@jridgewell/sourcemap-codec": "^1.5.5"
@@ -3686,6 +3653,7 @@
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
 			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+			"dev": true,
 			"engines": {
 				"node": ">=0.10.0"
 			}
@@ -3972,96 +3940,26 @@
 			"license": "ISC"
 		},
 		"node_modules/picocrank": {
-			"version": "1.8.1",
-			"resolved": "https://registry.npmjs.org/picocrank/-/picocrank-1.8.1.tgz",
-			"integrity": "sha512-g3JIVY8W5EVDGG+tG83Z0vzhMnj+J/RYkt6/ssdzZofR+6EWfFqE1+DQiyqb6rzjNuj0Y3xy3bpIprtzY9SQ6Q==",
+			"version": "1.8.7",
+			"resolved": "https://registry.npmjs.org/picocrank/-/picocrank-1.8.7.tgz",
+			"integrity": "sha512-A9eRkiGLtzCsi4aS+rkCw6MzPgEQUwDYNJJwGPGujwEtEKZcZk+wg9o/0yR/06qG3atip5H/aLGP7vPYS6iA5Q==",
 			"license": "ISC",
 			"dependencies": {
-				"@hugeicons/core-free-icons": "^1.0.16",
+				"@hugeicons/core-free-icons": "^1.2.1",
 				"@hugeicons/vue": "^1.0.3",
 				"@vitejs/plugin-vue": "^6.0.1",
-				"femtocrank": "^2.4.4",
-				"unplugin-vue-components": "^29.0.0",
-				"vite": "^7.1.3",
-				"vue": "^3.5.19",
-				"vue-router": "^4.5.1"
-			}
-		},
-		"node_modules/picocrank/node_modules/chokidar": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-			"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-			"license": "MIT",
-			"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"
-			},
-			"funding": {
-				"url": "https://paulmillr.com/funding/"
-			},
-			"optionalDependencies": {
-				"fsevents": "~2.3.2"
-			}
-		},
-		"node_modules/picocrank/node_modules/readdirp": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-			"license": "MIT",
-			"dependencies": {
-				"picomatch": "^2.2.1"
-			},
-			"engines": {
-				"node": ">=8.10.0"
-			}
-		},
-		"node_modules/picocrank/node_modules/unplugin-vue-components": {
-			"version": "29.2.0",
-			"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-29.2.0.tgz",
-			"integrity": "sha512-QxBeBdmEflgtJRgMQMc/z/JVV5lcwXN5nOy5ehX6CKDGylIu6Qn4Goy8X95S0qOxF7EdI+uNhdBd4v5i0bvzCw==",
-			"license": "MIT",
-			"dependencies": {
-				"chokidar": "^3.6.0",
-				"debug": "^4.4.3",
-				"local-pkg": "^1.1.2",
-				"magic-string": "^0.30.19",
-				"mlly": "^1.8.0",
-				"tinyglobby": "^0.2.15",
-				"unplugin": "^2.3.10",
-				"unplugin-utils": "^0.3.1"
-			},
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/antfu"
-			},
-			"peerDependencies": {
-				"@babel/parser": "^7.15.8",
-				"@nuxt/kit": "^3.2.2 || ^4.0.0",
-				"vue": "2 || 3"
-			},
-			"peerDependenciesMeta": {
-				"@babel/parser": {
-					"optional": true
-				},
-				"@nuxt/kit": {
-					"optional": true
-				}
+				"femtocrank": "^2.4.11",
+				"unplugin-vue-components": "^30.0.0",
+				"vite": "^7.2.2",
+				"vue": "^3.5.24",
+				"vue-router": "^4.6.3"
 			}
 		},
 		"node_modules/picomatch": {
 			"version": "2.3.1",
 			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
 			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+			"dev": true,
 			"engines": {
 				"node": ">=8.6"
 			},
@@ -5286,6 +5184,7 @@
 			"version": "5.0.1",
 			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+			"dev": true,
 			"dependencies": {
 				"is-number": "^7.0.0"
 			},
@@ -5645,16 +5544,16 @@
 			}
 		},
 		"node_modules/vue": {
-			"version": "3.5.21",
-			"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
-			"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
+			"version": "3.5.24",
+			"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.24.tgz",
+			"integrity": "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==",
 			"license": "MIT",
 			"dependencies": {
-				"@vue/compiler-dom": "3.5.21",
-				"@vue/compiler-sfc": "3.5.21",
-				"@vue/runtime-dom": "3.5.21",
-				"@vue/server-renderer": "3.5.21",
-				"@vue/shared": "3.5.21"
+				"@vue/compiler-dom": "3.5.24",
+				"@vue/compiler-sfc": "3.5.24",
+				"@vue/runtime-dom": "3.5.24",
+				"@vue/server-renderer": "3.5.24",
+				"@vue/shared": "3.5.24"
 			},
 			"peerDependencies": {
 				"typescript": "*"

+ 1 - 1
frontend/package.json

@@ -30,7 +30,7 @@
 		"@xterm/addon-fit": "^0.10.0",
 		"@xterm/xterm": "^5.5.0",
 		"iconify-icon": "^3.0.2",
-		"picocrank": "^1.8.1",
+		"picocrank": "^1.8.7",
 		"standard": "^17.1.2",
 		"unplugin-vue-components": "^30.0.0",
 		"vite": "^7.2.2",

+ 3 - 3
frontend/resources/vue/App.vue

@@ -40,11 +40,11 @@
                         <a href="https://github.com/OliveTin/OliveTin/issues/new/choose" target="_new">{{ t('raise-issue') }}</a>
                     </span>
 
-                    <span>{{ t('connected') }}</span>
-
                     <span>
                         <a href="#" @click.prevent="openLanguageDialog">{{ currentLanguageName }}</a>
                     </span>
+
+                    <span>{{ t('connected') }}</span>
                 </p>
                 <p>
                     <a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
@@ -58,7 +58,7 @@
             <h2>{{ t('language-dialog.title') }}</h2>
             <select v-model="selectedLanguage" @change="changeLanguage" class="language-select">
                 <option v-for="(name, code) in availableLanguages" :key="code" :value="code">
-                    {{ name }}
+                    {{ code === 'auto' ? name : `${name} (${code})` }}
                 </option>
             </select>
             <p class="browser-languages">

+ 0 - 284
frontend/resources/vue/components/Pagination.vue

@@ -1,284 +0,0 @@
-<template>
-  <div class="pagination">
-    <div class="pagination-info">
-      <span class="pagination-text">
-        Showing {{ startItem + 1 }}-{{ endItem }} of {{ total }} {{ itemTitle }}
-      </span>
-    </div>
-    
-    <div class="pagination-controls">
-      <button 
-        class="pagination-btn"
-        :disabled="currentPage === 1"
-        @click="goToPage(currentPage - 1)"
-        title="Previous page"
-      >
-        <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
-          <path fill="currentColor" d="M15.41 7.41L14 6l-6 6l6 6l1.41-1.41L10.83 12z"/>
-        </svg>
-      </button>
-
-      
-      <div class="pagination-pages">
-        <!-- First page -->
-        <button 
-          v-if="showFirstPage"
-          class="pagination-btn"
-          :class="{ active: currentPage === 1 }"
-          @click="goToPage(1)"
-        >
-          1
-        </button>
-        
-        <!-- Ellipsis after first page -->
-        <span v-if="showFirstEllipsis" class="pagination-ellipsis">...</span>
-        
-        <!-- Page numbers around current page -->
-        <button 
-          v-for="page in visiblePages" 
-          :key="page"
-          class="pagination-btn"
-          :class="{ active: currentPage === page }"
-          @click="goToPage(page)"
-        >
-          {{ page }}
-        </button>
-        
-        <!-- Ellipsis before last page -->
-        <span v-if="showLastEllipsis" class="pagination-ellipsis">...</span>
-        
-        <!-- Last page -->
-        <button 
-          v-if="showLastPage"
-          class="pagination-btn"
-          :class="{ active: currentPage === totalPages }"
-          @click="goToPage(totalPages)"
-        >
-          {{ totalPages }}
-        </button>
-      </div>
-      
-      <button 
-        class="pagination-btn"
-        :disabled="currentPage === totalPages"
-        @click="goToPage(currentPage + 1)"
-        title="Next page"
-      >
-        <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
-          <path fill="currentColor" d="M8.59 16.59L10 18l6-6l-6-6L8.59 7.41L13.17 12z"/>
-        </svg>
-      </button>
-    </div>
-    
-    <div class="pagination-size" v-if="canChangePageSize">
-      <label for="page-size">Items per page:</label>
-      <select 
-        id="page-size" 
-        v-model="localPageSize" 
-        @change="handlePageSizeChange"
-        class="page-size-select"
-      >
-        <option value="10">10</option>
-        <option value="25">25</option>
-        <option value="50">50</option>
-        <option value="100">100</option>
-      </select>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { ref, computed, watch } from 'vue'
-
-const props = defineProps({
-  pageSize: {
-    type: Number,
-    default: 25
-  },
-  total: {
-    type: Number,
-    required: true
-  },
-  currentPage: {
-    type: Number,
-    default: 1
-  },
-  canChangePageSize: {
-    type: Boolean,
-    default: false
-  },
-  itemTitle: {
-    type: String,
-    default: 'items'
-  }
-})
-
-const emit = defineEmits(['page-change', 'page-size-change'])
-
-const localPageSize = ref(props.pageSize)
-const localCurrentPage = ref(props.currentPage)
-
-// Computed properties
-const totalPages = computed(() => Math.ceil(props.total / localPageSize.value))
-
-const startItem = computed(() => (localCurrentPage.value - 1) * localPageSize.value)
-const endItem = computed(() => Math.min(localCurrentPage.value * localPageSize.value, props.total))
-
-// Pagination logic
-const maxVisiblePages = 5
-const visiblePages = computed(() => {
-  const pages = []
-  const halfVisible = Math.floor(maxVisiblePages / 2)
-  
-  let start = Math.max(1, localCurrentPage.value - halfVisible)
-  let end = Math.min(totalPages.value, start + maxVisiblePages - 1)
-  
-  // Adjust start if we're near the end
-  if (end - start < maxVisiblePages - 1) {
-    start = Math.max(1, end - maxVisiblePages + 1)
-  }
-  
-  for (let i = start; i <= end; i++) {
-    pages.push(i)
-  }
-  
-  return pages
-})
-
-const showFirstPage = computed(() => visiblePages.value[0] > 1)
-const showLastPage = computed(() => visiblePages.value[visiblePages.value.length - 1] < totalPages.value)
-const showFirstEllipsis = computed(() => visiblePages.value[0] > 2)
-const showLastEllipsis = computed(() => visiblePages.value[visiblePages.value.length - 1] < totalPages.value - 1)
-
-// Methods
-function goToPage(page) {
-  if (page >= 1 && page <= totalPages.value && page !== localCurrentPage.value) {
-    localCurrentPage.value = page
-    emit('page-change', page)
-  }
-}
-
-function handlePageSizeChange() {
-  // Reset to first page when changing page size
-  localCurrentPage.value = 1
-  emit('page-size-change', localPageSize.value)
-  emit('page-change', 1)
-}
-
-// Watch for prop changes
-watch(() => props.currentPage, (newPage) => {
-  localCurrentPage.value = newPage
-})
-
-watch(() => props.pageSize, (newSize) => {
-  localPageSize.value = newSize
-})
-</script>
-
-<style scoped>
-.pagination {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-top: 1rem;
-}
-
-.pagination-info {
-  flex: 1;
-}
-
-.pagination-text {
-  font-size: 0.875rem;
-  color: #6c757d;
-}
-
-.pagination-controls {
-  display: flex;
-  align-items: center;
-  gap: 0.5rem;
-}
-
-.pagination-pages {
-  display: flex;
-  align-items: center;
-  gap: 0.25rem;
-}
-
-.pagination-btn {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  min-width: 2.5rem;
-  height: 2.5rem;
-  padding: 0.5rem;
-  border: 1px solid #dee2e6;
-  background: #fff;
-  color: #495057;
-  text-decoration: none;
-  border-radius: 4px;
-  cursor: pointer;
-  transition: all 0.2s ease;
-  font-size: 0.875rem;
-}
-
-.pagination-btn:hover:not(:disabled) {
-  background: #e9ecef;
-  border-color: #adb5bd;
-  color: #495057;
-}
-
-.pagination-btn.active {
-  background: #c6d0d7;
-  color: #333;
-}
-
-.pagination-btn:disabled {
-  opacity: 0.5;
-  cursor: not-allowed;
-}
-
-.pagination-ellipsis {
-  padding: 0.5rem;
-  color: #6c757d;
-  font-size: 0.875rem;
-}
-
-.pagination-size {
-  display: flex;
-  align-items: center;
-  gap: 0.5rem;
-  font-size: 0.875rem;
-  color: #6c757d;
-}
-
-.page-size-select {
-  padding: 0.25rem 0.5rem;
-  border: 1px solid #dee2e6;
-  border-radius: 4px;
-  background: #fff;
-  font-size: 0.875rem;
-}
-
-.page-size-select:focus {
-  outline: none;
-  border-color: #5681af;
-  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
-}
-
-/* Responsive design */
-@media (max-width: 768px) {
-  .pagination {
-    flex-direction: column;
-    gap: 1rem;
-    align-items: stretch;
-  }
-  
-  .pagination-controls {
-    justify-content: center;
-  }
-  
-  .pagination-size {
-    justify-content: center;
-  }
-}
-</style> 

+ 1 - 1
frontend/resources/vue/views/ActionDetailsView.vue

@@ -92,7 +92,7 @@
 <script setup>
 import { ref, computed, onMounted, watch } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
-import Pagination from '../components/Pagination.vue'
+import Pagination from 'picocrank/vue/components/Pagination.vue'
 import Section from 'picocrank/vue/components/Section.vue'
 
 const route = useRoute()

+ 17 - 15
frontend/resources/vue/views/LogsListView.vue

@@ -67,7 +67,7 @@
 
 <script setup>
 import { ref, computed, onMounted } from 'vue'
-import Pagination from '../components/Pagination.vue'
+import Pagination from 'picocrank/vue/components/Pagination.vue'
 import Section from 'picocrank/vue/components/Section.vue'
 import { useI18n } from 'vue-i18n'
 
@@ -172,16 +172,20 @@ onMounted(() => {
   display: flex;
   align-items: center;
   gap: 0.5rem;
-  border: 1px solid #ddd;
-  border-radius: 4px;
   padding: 0.5rem;
+  border: 1px solid var(--border-color);
+  border-radius: 0.25rem;
+  background: var(--section-background);
+  width: 100%;
+  max-width: 300px;
 }
 
 .input-with-icons input {
   border: none;
   outline: none;
+  background: transparent;
   flex: 1;
-  font-size: 1rem;
+  color: var(--text-primary);
 }
 
 .input-with-icons button {
@@ -192,9 +196,6 @@ onMounted(() => {
   border-radius: 3px;
 }
 
-.input-with-icons button:hover:not(:disabled) {
-}
-
 .input-with-icons button:disabled {
   opacity: 0.5;
   cursor: not-allowed;
@@ -221,24 +222,25 @@ onMounted(() => {
   text-decoration: underline;
 }
 
-.status-success {
-  color: #28a745;
+.annotation {
   font-weight: 500;
+  font-size: smaller;
+}
+
+.status-success {
+  color: var(--karma-good-fg);
 }
 
 .status-error {
-  color: #dc3545;
-  font-weight: 500;
+  color: var(--karma-bad-fg);
 }
 
 .status-timeout {
-  color: #ffc107;
-  font-weight: 500;
+  color: var(--karma-warning-fg);
 }
 
 .status-blocked {
-  color: #6c757d;
-  font-weight: 500;
+  color: var(--karma-neutral-fg);
 }
 
 .empty-state {

+ 0 - 5
frontend/style.css

@@ -32,11 +32,6 @@ legend {
 	padding-top: 1.5em;
 }
 
-button.neutral {
-	background-color: transparent;
-	color: white;
-}
-
 section {
 	padding: 0;
 }