diff --git a/package-lock.json b/package-lock.json
index bf2590b1a6d1a2f461df42da139ed12ff91d5668..4a1883630ec573fea9a35768ea5a8c122b97f241 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,14 +48,14 @@
         "@vue/tsconfig": "~0.5.0",
         "axios": "~1.6.0",
         "eslint": "~8.57.0",
-        "eslint-plugin-vue": "~9.24.0",
+        "eslint-plugin-vue": "~9.25.0",
         "highlight.js": "^11.9.0",
         "npm-run-all": "~4.1.5",
         "openapi-typescript-codegen": "^0.29.0",
         "prettier": "~3.2.0",
         "rollup-plugin-node-polyfills": "~0.2.1",
         "sass": "^1.66.0",
-        "typescript": "~5.3.0",
+        "typescript": "~5.4.0",
         "vite": "~5.2.0",
         "vue-tsc": "~2.0.0"
       }
@@ -70,9 +70,9 @@
       }
     },
     "node_modules/@apidevtools/json-schema-ref-parser": {
-      "version": "11.5.4",
-      "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.4.tgz",
-      "integrity": "sha512-o2fsypTGU0WxRxbax8zQoHiIB4dyrkwYfcm8TxZ+bx9pCzcWZbQtiMqpgBvWA/nJ2TrGjK5adCLfTH8wUeU/Wg==",
+      "version": "11.5.5",
+      "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.5.tgz",
+      "integrity": "sha512-hv/aXDILyroHioVW27etFMV+IX6FyNn41YwbeGIAt5h/7fUTQvHI5w3ols8qYAT8aQt3kzexq5ZwxFDxNHIhdQ==",
       "dev": true,
       "dependencies": {
         "@jsdevtools/ono": "^7.1.3",
@@ -1575,9 +1575,9 @@
       }
     },
     "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz",
-      "integrity": "sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz",
+      "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==",
       "cpu": [
         "arm"
       ],
@@ -1588,9 +1588,9 @@
       ]
     },
     "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.1.tgz",
-      "integrity": "sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz",
+      "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==",
       "cpu": [
         "arm64"
       ],
@@ -1601,9 +1601,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz",
-      "integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz",
+      "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==",
       "cpu": [
         "arm64"
       ],
@@ -1614,9 +1614,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.1.tgz",
-      "integrity": "sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz",
+      "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==",
       "cpu": [
         "x64"
       ],
@@ -1627,9 +1627,22 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.1.tgz",
-      "integrity": "sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz",
+      "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz",
+      "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==",
       "cpu": [
         "arm"
       ],
@@ -1640,9 +1653,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz",
-      "integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz",
+      "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==",
       "cpu": [
         "arm64"
       ],
@@ -1653,9 +1666,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.1.tgz",
-      "integrity": "sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz",
+      "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==",
       "cpu": [
         "arm64"
       ],
@@ -1666,11 +1679,11 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.1.tgz",
-      "integrity": "sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz",
+      "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==",
       "cpu": [
-        "ppc64le"
+        "ppc64"
       ],
       "dev": true,
       "optional": true,
@@ -1679,9 +1692,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.1.tgz",
-      "integrity": "sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz",
+      "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==",
       "cpu": [
         "riscv64"
       ],
@@ -1692,9 +1705,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.1.tgz",
-      "integrity": "sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz",
+      "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==",
       "cpu": [
         "s390x"
       ],
@@ -1705,9 +1718,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz",
-      "integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz",
+      "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==",
       "cpu": [
         "x64"
       ],
@@ -1718,9 +1731,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.1.tgz",
-      "integrity": "sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz",
+      "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==",
       "cpu": [
         "x64"
       ],
@@ -1731,9 +1744,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.1.tgz",
-      "integrity": "sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz",
+      "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==",
       "cpu": [
         "arm64"
       ],
@@ -1744,9 +1757,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.1.tgz",
-      "integrity": "sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz",
+      "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==",
       "cpu": [
         "ia32"
       ],
@@ -1757,9 +1770,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.1.tgz",
-      "integrity": "sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz",
+      "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==",
       "cpu": [
         "x64"
       ],
@@ -1770,9 +1783,9 @@
       ]
     },
     "node_modules/@rushstack/eslint-patch": {
-      "version": "1.10.1",
-      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.1.tgz",
-      "integrity": "sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==",
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz",
+      "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==",
       "dev": true
     },
     "node_modules/@smithy/abort-controller": {
@@ -2169,9 +2182,9 @@
       }
     },
     "node_modules/@smithy/signature-v4": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.2.1.tgz",
-      "integrity": "sha512-j5fHgL1iqKTsKJ1mTcw88p0RUcidDu95AWSeZTgiYJb+QcfwWU/UpBnaqiB59FNH5MiAZuSbOBnZlwzeeY2tIw==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.3.0.tgz",
+      "integrity": "sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==",
       "dependencies": {
         "@smithy/is-array-buffer": "^2.2.0",
         "@smithy/types": "^2.12.0",
@@ -2482,16 +2495,16 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
-      "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
+      "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/type-utils": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/type-utils": "7.7.0",
+        "@typescript-eslint/utils": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
@@ -2517,15 +2530,15 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
-      "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
+      "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -2545,13 +2558,13 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
-      "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
+      "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0"
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -2562,13 +2575,13 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
-      "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
+      "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
+        "@typescript-eslint/utils": "7.7.0",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.3.0"
       },
@@ -2589,9 +2602,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
-      "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
+      "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -2602,13 +2615,13 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
-      "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
+      "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
@@ -2630,17 +2643,17 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
-      "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
+      "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
         "@types/json-schema": "^7.0.15",
         "@types/semver": "^7.5.8",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
         "semver": "^7.6.0"
       },
       "engines": {
@@ -2655,12 +2668,12 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
-      "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
+      "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
+        "@typescript-eslint/types": "7.7.0",
         "eslint-visitor-keys": "^3.4.3"
       },
       "engines": {
@@ -2691,43 +2704,43 @@
       }
     },
     "node_modules/@volar/language-core": {
-      "version": "2.2.0-alpha.7",
-      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.7.tgz",
-      "integrity": "sha512-igpp+nTkyl8faVzRJMpSCeA4XlBJ5UVSyc/WGyksmUmP10YbfufbcQCFlxEXv2uMBV+a3L4JVCj+Vju+08FOSA==",
+      "version": "2.2.0-alpha.8",
+      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.8.tgz",
+      "integrity": "sha512-Ew1Iw7/RIRNuDLn60fWJdOLApAlfTVPxbPiSLzc434PReC9kleYtaa//Wo2WlN1oiRqneW0pWQQV0CwYqaimLQ==",
       "dev": true,
       "dependencies": {
-        "@volar/source-map": "2.2.0-alpha.7"
+        "@volar/source-map": "2.2.0-alpha.8"
       }
     },
     "node_modules/@volar/source-map": {
-      "version": "2.2.0-alpha.7",
-      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.7.tgz",
-      "integrity": "sha512-iIZM2EovdEnr6mMwlsnt4ciix4xz7HSGHyUSviRaY5cii5PMXGHeUU9UDeb+xzLCx8kdk3L5J4z+ts50AhkYcg==",
+      "version": "2.2.0-alpha.8",
+      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.8.tgz",
+      "integrity": "sha512-E1ZVmXFJ5DU4fWDcWHzi8OLqqReqIDwhXvIMhVdk6+VipfMVv4SkryXu7/rs4GA/GsebcRyJdaSkKBB3OAkIcA==",
       "dev": true,
       "dependencies": {
         "muggle-string": "^0.4.0"
       }
     },
     "node_modules/@volar/typescript": {
-      "version": "2.2.0-alpha.7",
-      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.7.tgz",
-      "integrity": "sha512-qy04/hx4UbW1BdPlzaxlH60D4plubcyqdbYM6Y5vZiascZxFowtd6vE39Td9FYzDxwcKgzb/Crvf/ABhdHnuBA==",
+      "version": "2.2.0-alpha.8",
+      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.8.tgz",
+      "integrity": "sha512-RLbRDI+17CiayHZs9HhSzlH0FhLl/+XK6o2qoiw2o2GGKcyD1aDoY6AcMd44acYncTOrqoTNoY6LuCiRyiJiGg==",
       "dev": true,
       "dependencies": {
-        "@volar/language-core": "2.2.0-alpha.7",
+        "@volar/language-core": "2.2.0-alpha.8",
         "path-browserify": "^1.0.1"
       }
     },
     "node_modules/@vue/compiler-core": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz",
-      "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.22.tgz",
+      "integrity": "sha512-FBDRCBE/rFPA8OfTUrARx2c49N7zoImlGT7hsFikv0pZxQlFhffQwewpEXaLynZW0/DspVXmNA+QQ9dXINpWmg==",
       "dependencies": {
-        "@babel/parser": "^7.23.9",
-        "@vue/shared": "3.4.21",
+        "@babel/parser": "^7.24.1",
+        "@vue/shared": "3.4.22",
         "entities": "^4.5.0",
         "estree-walker": "^2.0.2",
-        "source-map-js": "^1.0.2"
+        "source-map-js": "^1.2.0"
       }
     },
     "node_modules/@vue/compiler-core/node_modules/estree-walker": {
@@ -2736,28 +2749,28 @@
       "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
     },
     "node_modules/@vue/compiler-dom": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz",
-      "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.22.tgz",
+      "integrity": "sha512-YkAS+jZc6Ip360kT3lZbMQZteiYBbHDSVKr94Jdd8Zjr7VjSkkXKAFFR/FW+2tNtBYXOps6xrWlOquy3GeYB0w==",
       "dependencies": {
-        "@vue/compiler-core": "3.4.21",
-        "@vue/shared": "3.4.21"
+        "@vue/compiler-core": "3.4.22",
+        "@vue/shared": "3.4.22"
       }
     },
     "node_modules/@vue/compiler-sfc": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz",
-      "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==",
-      "dependencies": {
-        "@babel/parser": "^7.23.9",
-        "@vue/compiler-core": "3.4.21",
-        "@vue/compiler-dom": "3.4.21",
-        "@vue/compiler-ssr": "3.4.21",
-        "@vue/shared": "3.4.21",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.22.tgz",
+      "integrity": "sha512-Pncp5Vc8E2Ef1o5uveO8WA1IqM7rt0R1jN8D4qitQYOUxC97iITGYA8oMInQ3UcDS7ip+SegyA2HbAEB4V6NMQ==",
+      "dependencies": {
+        "@babel/parser": "^7.24.1",
+        "@vue/compiler-core": "3.4.22",
+        "@vue/compiler-dom": "3.4.22",
+        "@vue/compiler-ssr": "3.4.22",
+        "@vue/shared": "3.4.22",
         "estree-walker": "^2.0.2",
-        "magic-string": "^0.30.7",
-        "postcss": "^8.4.35",
-        "source-map-js": "^1.0.2"
+        "magic-string": "^0.30.8",
+        "postcss": "^8.4.38",
+        "source-map-js": "^1.2.0"
       }
     },
     "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
@@ -2777,12 +2790,12 @@
       }
     },
     "node_modules/@vue/compiler-ssr": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz",
-      "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.22.tgz",
+      "integrity": "sha512-ycb2sL0SW6AkgVMrvaU/TIAEk7FQWyv/oYya44E/V9xURM+ij9Oev5bVobSS7GLJzkUieWW3SrYcK/PZpb5i4A==",
       "dependencies": {
-        "@vue/compiler-dom": "3.4.21",
-        "@vue/shared": "3.4.21"
+        "@vue/compiler-dom": "3.4.22",
+        "@vue/shared": "3.4.22"
       }
     },
     "node_modules/@vue/devtools-api": {
@@ -2829,12 +2842,12 @@
       }
     },
     "node_modules/@vue/language-core": {
-      "version": "2.0.12",
-      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.12.tgz",
-      "integrity": "sha512-aIStDPt69SHOpiIckGTIIjEz/sXc6ZfCMS5uWYL1AcbcRMhzFCLZscGAVte1+ad+RRFepSpKBjGttyPcgKJ7ww==",
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.13.tgz",
+      "integrity": "sha512-oQgM+BM66SU5GKtUMLQSQN0bxHFkFpLSSAiY87wVziPaiNQZuKVDt/3yA7GB9PiQw0y/bTNL0bOc0jM/siYjKg==",
       "dev": true,
       "dependencies": {
-        "@volar/language-core": "2.2.0-alpha.7",
+        "@volar/language-core": "2.2.0-alpha.8",
         "@vue/compiler-dom": "^3.4.0",
         "@vue/shared": "^3.4.0",
         "computeds": "^0.0.1",
@@ -2852,48 +2865,48 @@
       }
     },
     "node_modules/@vue/reactivity": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz",
-      "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.22.tgz",
+      "integrity": "sha512-+golHRRfcGoahBrhoTauFNIIAhxntRV3BI8HHqVvCdsuWivxW1MI0E9AOXVsz4H/ZlWM1ahudWTX6PhUrNR2yQ==",
       "dependencies": {
-        "@vue/shared": "3.4.21"
+        "@vue/shared": "3.4.22"
       }
     },
     "node_modules/@vue/runtime-core": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz",
-      "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.22.tgz",
+      "integrity": "sha512-cbA8lcL4g1907EdY1a1KmP5IRWfbqjgBRcgJPkF//yn96XSC1/VAJBZiAGLiyw0P77Rw2Ao7d9U51vU1GC6yUQ==",
       "dependencies": {
-        "@vue/reactivity": "3.4.21",
-        "@vue/shared": "3.4.21"
+        "@vue/reactivity": "3.4.22",
+        "@vue/shared": "3.4.22"
       }
     },
     "node_modules/@vue/runtime-dom": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz",
-      "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.22.tgz",
+      "integrity": "sha512-AXxRHrFkLX1y2+70CO2wDKRxW0WZcQKTOXS31AK+jZ1RLPtI6sEHVpYNfyE9WgbgXOqPtX4gfIfuoFYi8iCu2w==",
       "dependencies": {
-        "@vue/runtime-core": "3.4.21",
-        "@vue/shared": "3.4.21",
+        "@vue/runtime-core": "3.4.22",
+        "@vue/shared": "3.4.22",
         "csstype": "^3.1.3"
       }
     },
     "node_modules/@vue/server-renderer": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz",
-      "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.22.tgz",
+      "integrity": "sha512-okiNxiCOhJlx6IOrTZvhIVwf2UYKay0hnIPqWu4h19bkNv1gmG4Ic6U3zXY287AWF26lQuFMa515Qzc+R0aAYg==",
       "dependencies": {
-        "@vue/compiler-ssr": "3.4.21",
-        "@vue/shared": "3.4.21"
+        "@vue/compiler-ssr": "3.4.22",
+        "@vue/shared": "3.4.22"
       },
       "peerDependencies": {
-        "vue": "3.4.21"
+        "vue": "3.4.22"
       }
     },
     "node_modules/@vue/shared": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz",
-      "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g=="
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.22.tgz",
+      "integrity": "sha512-cg7R9XNk4ovV3bKka/1a464O2oY0l5Fyt0rwGR4hSJRPjUJ0WVjrPdsr4W0JbUriwiM8EKcCcCjeKN5pRMs2Zg=="
     },
     "node_modules/@vue/tsconfig": {
       "version": "0.5.1",
@@ -3800,9 +3813,9 @@
       }
     },
     "node_modules/eslint-plugin-vue": {
-      "version": "9.24.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz",
-      "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==",
+      "version": "9.25.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz",
+      "integrity": "sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
@@ -5899,9 +5912,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.14.1",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.1.tgz",
-      "integrity": "sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==",
+      "version": "4.14.3",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz",
+      "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==",
       "dev": true,
       "dependencies": {
         "@types/estree": "1.0.5"
@@ -5914,21 +5927,22 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.14.1",
-        "@rollup/rollup-android-arm64": "4.14.1",
-        "@rollup/rollup-darwin-arm64": "4.14.1",
-        "@rollup/rollup-darwin-x64": "4.14.1",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.14.1",
-        "@rollup/rollup-linux-arm64-gnu": "4.14.1",
-        "@rollup/rollup-linux-arm64-musl": "4.14.1",
-        "@rollup/rollup-linux-powerpc64le-gnu": "4.14.1",
-        "@rollup/rollup-linux-riscv64-gnu": "4.14.1",
-        "@rollup/rollup-linux-s390x-gnu": "4.14.1",
-        "@rollup/rollup-linux-x64-gnu": "4.14.1",
-        "@rollup/rollup-linux-x64-musl": "4.14.1",
-        "@rollup/rollup-win32-arm64-msvc": "4.14.1",
-        "@rollup/rollup-win32-ia32-msvc": "4.14.1",
-        "@rollup/rollup-win32-x64-msvc": "4.14.1",
+        "@rollup/rollup-android-arm-eabi": "4.14.3",
+        "@rollup/rollup-android-arm64": "4.14.3",
+        "@rollup/rollup-darwin-arm64": "4.14.3",
+        "@rollup/rollup-darwin-x64": "4.14.3",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.14.3",
+        "@rollup/rollup-linux-arm-musleabihf": "4.14.3",
+        "@rollup/rollup-linux-arm64-gnu": "4.14.3",
+        "@rollup/rollup-linux-arm64-musl": "4.14.3",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3",
+        "@rollup/rollup-linux-riscv64-gnu": "4.14.3",
+        "@rollup/rollup-linux-s390x-gnu": "4.14.3",
+        "@rollup/rollup-linux-x64-gnu": "4.14.3",
+        "@rollup/rollup-linux-x64-musl": "4.14.3",
+        "@rollup/rollup-win32-arm64-msvc": "4.14.3",
+        "@rollup/rollup-win32-ia32-msvc": "4.14.3",
+        "@rollup/rollup-win32-x64-msvc": "4.14.3",
         "fsevents": "~2.3.2"
       }
     },
@@ -6040,9 +6054,9 @@
       }
     },
     "node_modules/sass": {
-      "version": "1.74.1",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.74.1.tgz",
-      "integrity": "sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA==",
+      "version": "1.75.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz",
+      "integrity": "sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==",
       "dev": true,
       "dependencies": {
         "chokidar": ">=3.0.0 <4.0.0",
@@ -6538,9 +6552,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.3.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
-      "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
       "devOptional": true,
       "bin": {
         "tsc": "bin/tsc",
@@ -6629,9 +6643,9 @@
       }
     },
     "node_modules/vite": {
-      "version": "5.2.8",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
-      "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
+      "version": "5.2.9",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz",
+      "integrity": "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw==",
       "dev": true,
       "dependencies": {
         "esbuild": "^0.20.1",
@@ -6684,15 +6698,15 @@
       }
     },
     "node_modules/vue": {
-      "version": "3.4.21",
-      "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz",
-      "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==",
+      "version": "3.4.22",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.22.tgz",
+      "integrity": "sha512-CIx7NiP+n5WHBCG/fDNaUPP4qbQ5CIa8XIHZE3HpfS/rb2vmSIsp74BxsZyrrGKF0vHW3GoToqP3l0hzrMTecw==",
       "dependencies": {
-        "@vue/compiler-dom": "3.4.21",
-        "@vue/compiler-sfc": "3.4.21",
-        "@vue/runtime-dom": "3.4.21",
-        "@vue/server-renderer": "3.4.21",
-        "@vue/shared": "3.4.21"
+        "@vue/compiler-dom": "3.4.22",
+        "@vue/compiler-sfc": "3.4.22",
+        "@vue/runtime-dom": "3.4.22",
+        "@vue/server-renderer": "3.4.22",
+        "@vue/shared": "3.4.22"
       },
       "peerDependencies": {
         "typescript": "*"
@@ -6761,13 +6775,13 @@
       }
     },
     "node_modules/vue-tsc": {
-      "version": "2.0.12",
-      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.12.tgz",
-      "integrity": "sha512-thlBBWlPYrNdba535oDdxz7PRUufZgRZRVP5Aql5wBVpGSWSeqou4EzFXeKVoZr59lp9hJROubDVzlhACmcEhg==",
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.13.tgz",
+      "integrity": "sha512-a3nL3FvguCWVJUQW/jFrUxdeUtiEkbZoQjidqvMeBK//tuE2w6NWQAbdrEpY2+6nSa4kZoKZp8TZUMtHpjt4mQ==",
       "dev": true,
       "dependencies": {
-        "@volar/typescript": "2.2.0-alpha.7",
-        "@vue/language-core": "2.0.12",
+        "@volar/typescript": "2.2.0-alpha.8",
+        "@vue/language-core": "2.0.13",
         "semver": "^7.5.4"
       },
       "bin": {
diff --git a/package.json b/package.json
index 01186efc90d71fac891447278c16eba031914d16..ce1e49354058d471e9000a1af852e4099e6b8e62 100644
--- a/package.json
+++ b/package.json
@@ -55,14 +55,14 @@
     "@vue/tsconfig": "~0.5.0",
     "axios": "~1.6.0",
     "eslint": "~8.57.0",
-    "eslint-plugin-vue": "~9.24.0",
+    "eslint-plugin-vue": "~9.25.0",
     "highlight.js": "^11.9.0",
     "npm-run-all": "~4.1.5",
     "openapi-typescript-codegen": "^0.29.0",
     "prettier": "~3.2.0",
     "rollup-plugin-node-polyfills": "~0.2.1",
     "sass": "^1.66.0",
-    "typescript": "~5.3.0",
+    "typescript": "~5.4.0",
     "vite": "~5.2.0",
     "vue-tsc": "~2.0.0"
   }
diff --git a/src/client/s3proxy/index.ts b/src/client/s3proxy/index.ts
index ae0ab189c9503085dd7cdbaa77e2bc5bcd08f160..69ca1247859c17ce872d0b36ceef666bc065a3c2 100644
--- a/src/client/s3proxy/index.ts
+++ b/src/client/s3proxy/index.ts
@@ -7,6 +7,7 @@ export { CancelablePromise, CancelError } from './core/CancelablePromise';
 export { OpenAPI } from './core/OpenAPI';
 export type { OpenAPIConfig } from './core/OpenAPI';
 
+export type { Body_Bucket_update_bucket_public_state } from './models/Body_Bucket_update_bucket_public_state';
 export type { BucketIn } from './models/BucketIn';
 export type { BucketOut } from './models/BucketOut';
 export type { BucketPermissionIn } from './models/BucketPermissionIn';
diff --git a/src/client/s3proxy/models/Body_Bucket_update_bucket_public_state.ts b/src/client/s3proxy/models/Body_Bucket_update_bucket_public_state.ts
new file mode 100644
index 0000000000000000000000000000000000000000..105f5ecfc334dd76e653f78b2adaa77761c14d7d
--- /dev/null
+++ b/src/client/s3proxy/models/Body_Bucket_update_bucket_public_state.ts
@@ -0,0 +1,11 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type Body_Bucket_update_bucket_public_state = {
+    /**
+     * New State
+     */
+    public: boolean;
+};
+
diff --git a/src/client/s3proxy/models/BucketOut.ts b/src/client/s3proxy/models/BucketOut.ts
index f2fd7dd0b46dcad36bc88533172a2e05be934612..87a20c6eac77702b29452506e250b1a9583a8554 100644
--- a/src/client/s3proxy/models/BucketOut.ts
+++ b/src/client/s3proxy/models/BucketOut.ts
@@ -23,17 +23,13 @@ export type BucketOut = {
      * UID of the owner
      */
     owner_id: string;
-    /**
-     * Number of Objects in this bucket
-     */
-    num_objects: number;
-    /**
-     * Total size of objects in this bucket in bytes
-     */
-    size: number;
     /**
      * Constraint for the owner of the bucket
      */
     owner_constraint?: (Constraint | null);
+    /**
+     * Flag if the bucket is anonymously readable
+     */
+    public: boolean;
 };
 
diff --git a/src/client/s3proxy/services/BucketService.ts b/src/client/s3proxy/services/BucketService.ts
index 75d01ee454cb0e952b4fdd9b0c4b1b3ca1e00558..1984645f7bec8774a6318dcfdb59c0f9e4e32c92 100644
--- a/src/client/s3proxy/services/BucketService.ts
+++ b/src/client/s3proxy/services/BucketService.ts
@@ -2,6 +2,7 @@
 /* istanbul ignore file */
 /* tslint:disable */
 /* eslint-disable */
+import type { Body_Bucket_update_bucket_public_state } from '../models/Body_Bucket_update_bucket_public_state';
 import type { BucketIn } from '../models/BucketIn';
 import type { BucketOut } from '../models/BucketOut';
 import type { BucketType } from '../models/BucketType';
@@ -131,4 +132,36 @@ export class BucketService {
             },
         });
     }
+    /**
+     * update public status
+     * Toggle the buckets public state. A bucket with an owner constraint can't be made public.
+     *
+     * Permission `bucket:update` required if the current user is the owner of the bucket,
+     * otherwise `bucket:update_any` required.
+     * @param bucketName Name of bucket
+     * @param requestBody
+     * @returns BucketOut Successful Response
+     * @throws ApiError
+     */
+    public static bucketUpdateBucketPublicState(
+        bucketName: string,
+        requestBody: Body_Bucket_update_bucket_public_state,
+    ): CancelablePromise<BucketOut> {
+        return __request(OpenAPI, {
+            method: 'PATCH',
+            url: '/buckets/{bucket_name}/public',
+            path: {
+                'bucket_name': bucketName,
+            },
+            body: requestBody,
+            mediaType: 'application/json',
+            errors: {
+                400: `Error decoding JWT Token`,
+                401: `Not authenticated`,
+                403: `Not authorized`,
+                404: `Entity not Found`,
+                422: `Validation Error`,
+            },
+        });
+    }
 }
diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue
index 254d21853a90ea25ff81d6242c1875168bc1f83d..11802cc744409b3f7f2886de688e696f6d247d8c 100644
--- a/src/components/AppHeader.vue
+++ b/src/components/AppHeader.vue
@@ -289,7 +289,7 @@ watch(
     modal-id="advancedUsageModal"
     modal-label="Advanced Usage Modal"
     v-if="store.authenticated"
-    size-modifier="lg"
+    size-modifier-modal="lg"
   >
     <template v-slot:header>
       <h3>Advanced Usage</h3>
diff --git a/src/components/modals/BootstrapModal.vue b/src/components/modals/BootstrapModal.vue
index 7d6cc6cd2efbf855c48defec2e51adda0b16cbce..7757d10c35bcae608badb2ce8f321d2c1957d206 100644
--- a/src/components/modals/BootstrapModal.vue
+++ b/src/components/modals/BootstrapModal.vue
@@ -41,7 +41,7 @@ function trackModalShow() {
   >
     <div
       class="modal-dialog modal-dialog-centered modal-dialog-scrollable"
-      :class="[modalSizeClass]"
+      :class="modalSizeClass"
     >
       <div class="modal-content">
         <div class="modal-header justify-content-between">
diff --git a/src/components/modals/ReasonModal.vue b/src/components/modals/ReasonModal.vue
index 561c27a546e54c5f1e17f3feef84f11d68eee376..d3ab5e0e0b49ea1e54b36b365682ff2af5c3813c 100644
--- a/src/components/modals/ReasonModal.vue
+++ b/src/components/modals/ReasonModal.vue
@@ -39,7 +39,7 @@ function sendSaveEvent() {
   <bootstrap-modal
     :modal-id="props.modalId"
     :modal-label="props.modalLabel"
-    size-modifier="lg"
+    size-modifier-modal="lg"
   >
     <template #header>
       <slot name="header" />
diff --git a/src/components/object-storage/BucketListItem.vue b/src/components/object-storage/BucketListItem.vue
index ddb729e1c3110db94984597815db294e389ed67b..4a5bdcd89d924fefcdec0521a483936d07aa5888 100644
--- a/src/components/object-storage/BucketListItem.vue
+++ b/src/components/object-storage/BucketListItem.vue
@@ -5,14 +5,17 @@ import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
 import PermissionModal from "@/components/object-storage/modals/PermissionModal.vue";
 import BucketDetailModal from "@/components/object-storage/modals/BucketDetailModal.vue";
 import dayjs from "dayjs";
-import { filesize } from "filesize";
-import { computed, onMounted } from "vue";
-import { Tooltip } from "bootstrap";
+import { computed, onMounted, reactive, ref } from "vue";
+import { Toast, Tooltip } from "bootstrap";
 import { useBucketStore } from "@/stores/buckets";
 import { useRouter } from "vue-router";
 import { useAuthStore } from "@/stores/users";
 import type { FolderTree } from "@/types/PseudoFolder";
 import { useNameStore } from "@/stores/names";
+import { environment } from "@/environment";
+import { useS3ObjectStore } from "@/stores/s3objects";
+import { filesize } from "filesize";
+import BootstrapToast from "@/components/BootstrapToast.vue";
 
 const props = defineProps<{
   active: boolean;
@@ -21,12 +24,26 @@ const props = defineProps<{
   deletable: boolean;
 }>();
 
+const publicCheckbox = ref<HTMLInputElement | undefined>(undefined);
 const randomIDSuffix = Math.random().toString(16).substring(2, 8);
 const permissionRepository = useBucketStore();
 const userRepository = useAuthStore();
 const nameRepository = useNameStore();
+const bucketRepository = useBucketStore();
+const objectRepository = useS3ObjectStore();
 const router = useRouter();
 
+let successToast: Toast | null;
+let errorToast: Toast | null;
+
+const requestState = reactive<{
+  error: string;
+  loading: boolean;
+}>({
+  error: "",
+  loading: false,
+});
+
 const permission = computed<BucketPermissionOut | undefined>(
   () => permissionRepository.ownPermissions[props.bucket.name],
 );
@@ -38,6 +55,10 @@ const subFolder = computed<FolderTree>(() => {
   return { subFolders: subFolders, files: [] };
 });
 
+const bucketMeta = computed<[number, number]>(() =>
+  objectRepository.getMeta(props.bucket.name),
+);
+
 const emit = defineEmits<{
   (e: "delete-bucket", bucketName: string): void;
 }>();
@@ -46,16 +67,52 @@ function permissionDeleted() {
   router.push({ name: "buckets" });
 }
 
+function toggleBucketPublicState() {
+  requestState.loading = true;
+  bucketRepository
+    .togglePublicState(props.bucket.name, !props.bucket.public)
+    .then(() => {
+      successToast?.show();
+    })
+    .catch((err) => {
+      requestState.error = err.toString();
+      if (publicCheckbox.value) {
+        publicCheckbox.value.checked = props.bucket.public;
+      }
+      errorToast?.show();
+    })
+    .finally(() => {
+      requestState.loading = false;
+    });
+}
+
 onMounted(() => {
   if (!props.loading) {
     new Tooltip("#tooltip-" + randomIDSuffix);
     new Tooltip("#ownBucketIcon-" + randomIDSuffix);
     new Tooltip("#sharedBucketIcon-" + randomIDSuffix);
+    successToast = new Toast("#success-public-bucket-" + randomIDSuffix);
+    errorToast = new Toast("#error-public-bucket-" + randomIDSuffix);
   }
 });
 </script>
 
 <template>
+  <bootstrap-toast
+    :toast-id="'success-public-bucket-' + randomIDSuffix"
+    v-if="!loading"
+  >
+    Bucket {{ bucket.name }} is now {{ bucket.public ? "public" : "private" }}
+  </bootstrap-toast>
+  <bootstrap-toast
+    :toast-id="'error-public-bucket-' + randomIDSuffix"
+    color-class="danger"
+    v-if="!loading"
+  >
+    Error making the bucket {{ bucket.name }}
+    {{ !bucket.public ? "public" : "private" }}:<br />
+    {{ requestState.error }}
+  </bootstrap-toast>
   <permission-modal
     v-if="permission != undefined && props.active"
     :modalId="'view-permission-modal' + randomIDSuffix"
@@ -207,12 +264,45 @@ onMounted(() => {
             </tr>
             <tr>
               <th scope="row" class="fw-bold">Objects:</th>
-              <td>{{ bucket.num_objects }}</td>
+              <td>{{ bucketMeta[0] }}</td>
             </tr>
             <tr>
               <th scope="row" class="fw-bold">Size:</th>
               <td>
-                {{ filesize(bucket.size, { base: 2, standard: "jedec" }) }}
+                {{ filesize(bucketMeta[1], { base: 2, standard: "jedec" }) }}
+              </td>
+            </tr>
+            <tr v-if="bucket.owner_constraint == undefined">
+              <th scope="row">
+                <div
+                  :class="{ 'form-check': !loading && permission == undefined }"
+                >
+                  <input
+                    v-if="!loading && permission == undefined"
+                    ref="publicCheckbox"
+                    class="form-check-input"
+                    type="checkbox"
+                    :disabled="requestState.loading"
+                    :checked="bucket.public"
+                    :id="'public-checkbox-' + randomIDSuffix"
+                    @change="toggleBucketPublicState"
+                  />
+                  <label
+                    :for="'public-checkbox-' + randomIDSuffix"
+                    class="fw-bold"
+                  >
+                    Public</label
+                  >
+                </div>
+              </th>
+              <td>
+                <a
+                  v-if="bucket.public"
+                  target="_blank"
+                  :href="environment.S3_URL + '/' + bucket.name"
+                  >Link</a
+                >
+                <span v-else>Disabled</span>
               </td>
             </tr>
           </tbody>
diff --git a/src/components/object-storage/modals/BucketDetailModal.vue b/src/components/object-storage/modals/BucketDetailModal.vue
index 503b2c0216602aba446f49cb3b029edc71b18ee2..7115147c0940f9743770f48fd3dd93a86c1faa45 100644
--- a/src/components/object-storage/modals/BucketDetailModal.vue
+++ b/src/components/object-storage/modals/BucketDetailModal.vue
@@ -3,11 +3,25 @@ import BootstrapModal from "@/components/modals/BootstrapModal.vue";
 import type { BucketOut } from "@/client/s3proxy";
 import dayjs from "dayjs";
 import { filesize } from "filesize";
+import { useS3ObjectStore } from "@/stores/s3objects";
+import { computed } from "vue";
+import { environment } from "../../../environment";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
 
 const props = defineProps<{
   modalId: string;
   bucket: BucketOut;
 }>();
+
+const objectRepository = useS3ObjectStore();
+
+const bucketMeta = computed<[number, number]>(() =>
+  objectRepository.getMeta(props.bucket.name),
+);
+const publicHttpLink = computed<string>(
+  () => environment.S3_URL + "/" + props.bucket.name,
+);
+const s3Link = computed<string>(() => "s3://" + props.bucket.name);
 </script>
 
 <template>
@@ -15,7 +29,7 @@ const props = defineProps<{
     :modalId="modalId"
     :static-backdrop="false"
     modal-label="Bucket Detail Modal"
-    size-modifier="lg"
+    size-modifier-modal="lg"
     :track-modal-value="bucket.name"
   >
     <template v-slot:header>
@@ -43,21 +57,37 @@ const props = defineProps<{
               </td>
             </tr>
             <tr>
-              <th scope="row">Number of Objects</th>
-              <td>{{ props.bucket.num_objects }}</td>
+              <th scope="row">Objects</th>
+              <td>{{ bucketMeta[0] }}</td>
             </tr>
             <tr>
               <th scope="row">Size</th>
               <td>
-                {{
-                  filesize(props.bucket.size, { base: 2, standard: "jedec" })
-                }}
+                {{ filesize(bucketMeta[1], { base: 2, standard: "jedec" }) }}
               </td>
             </tr>
             <tr>
               <th scope="row">Description</th>
               <td class="text-break">{{ props.bucket.description }}</td>
             </tr>
+            <tr v-if="bucket.public">
+              <th scope="row">Public HTTP link</th>
+              <td>
+                <a :href="publicHttpLink" target="_blank"
+                  >{{ publicHttpLink }}
+                  <font-awesome-icon
+                    icon="fa-solid fa-arrow-up-right-from-square"
+                    class="ms-1"
+                  />
+                </a>
+              </td>
+            </tr>
+            <tr>
+              <th scope="row">S3 link</th>
+              <td>
+                {{ s3Link }}
+              </td>
+            </tr>
           </tbody>
         </table>
       </div>
diff --git a/src/components/object-storage/modals/CreateBucketModal.vue b/src/components/object-storage/modals/CreateBucketModal.vue
index c2044fbad0a419e7f57d1babbf315dd45acec07c..1f0aa226b784a52c8a34a8c08a031460d2b9aae9 100644
--- a/src/components/object-storage/modals/CreateBucketModal.vue
+++ b/src/components/object-storage/modals/CreateBucketModal.vue
@@ -140,7 +140,7 @@ function modalClosed() {
               id="bucketDescriptionInput"
               required
               rows="3"
-              minlength="32"
+              minlength="16"
               maxlength="65536"
               v-model="bucket.description"
               placeholder="Describe the purpose of the bucket"
@@ -148,7 +148,7 @@ function modalClosed() {
             <div class="invalid-feedback">
               Requirements
               <ul>
-                <li>At least 32 Characters long</li>
+                <li>At least 16 Characters long</li>
               </ul>
             </div>
           </div>
diff --git a/src/components/parameter-schema/UploadParameterFileModal.vue b/src/components/parameter-schema/UploadParameterFileModal.vue
index fef305d95d3697ed1b9c6f87aa24331847c746a5..5c4cbbec09477d086d82c0cead2c85eb7f654ff9 100644
--- a/src/components/parameter-schema/UploadParameterFileModal.vue
+++ b/src/components/parameter-schema/UploadParameterFileModal.vue
@@ -60,7 +60,7 @@ function fileChange() {
     :modalId="props.modalId"
     :static-backdrop="true"
     modal-label="Confirm Delete Modal"
-    size-modifier="lg"
+    size-modifier-modal="lg"
   >
     <template #header>Upload Parameter File</template>
     <template #body>
diff --git a/src/components/resources/modals/ResourceVersionInfoModal.vue b/src/components/resources/modals/ResourceVersionInfoModal.vue
index ce39b060c9c1df8d5a5099d1ca037e36c4329061..13ace3a48316db4917febec9ac2b0739b528a1e5 100644
--- a/src/components/resources/modals/ResourceVersionInfoModal.vue
+++ b/src/components/resources/modals/ResourceVersionInfoModal.vue
@@ -23,7 +23,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
   <bootstrap-modal
     :modal-id="props.modalId"
     modal-label="Resource Version Info Modal"
-    size-modifier="lg"
+    size-modifier-modal="lg"
   >
     <template #header
       >Resource
@@ -34,11 +34,11 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
     <template #body>
       <h5>Resource</h5>
       <div class="mb-3 row">
-        <div class="col-8">
+        <div class="col-7">
           <label
             for="resource-version-info-modal-resource-id"
             class="form-label"
-            >ID</label
+            >Resource ID</label
           >
           <div class="input-group">
             <input
@@ -54,7 +54,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
             /></span>
           </div>
         </div>
-        <div class="col-4">
+        <div class="col-5">
           <label
             for="resource-version-info-modal-resource-name"
             class="form-label"
@@ -72,7 +72,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
         </div>
       </div>
       <div class="mb-3 row">
-        <div class="col-8">
+        <div class="col-7">
           <label
             for="resource-version-info-modal-maintainer-id"
             class="form-label"
@@ -92,7 +92,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
             /></span>
           </div>
         </div>
-        <div class="col-4">
+        <div class="col-5">
           <label
             for="resource-version-info-modal-maintainer-name"
             class="form-label"
@@ -143,7 +143,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
       </div>
       <h5>Resource Version</h5>
       <div class="mb-3 row">
-        <div class="col-8">
+        <div class="col-7">
           <label
             for="resource-version-info-modal-resource-version-id"
             class="form-label"
@@ -163,7 +163,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
             /></span>
           </div>
         </div>
-        <div class="col-4">
+        <div class="col-5">
           <label
             for="resource-version-info-modal-resource-version-release"
             class="form-label"
diff --git a/src/components/workflows/WorkflowCard.vue b/src/components/workflows/WorkflowCard.vue
index c0de6f6821004902b839d11ba4fedb516b366e6b..9284e74222fcae9eb55c117bf2c605954f373e4e 100644
--- a/src/components/workflows/WorkflowCard.vue
+++ b/src/components/workflows/WorkflowCard.vue
@@ -2,7 +2,7 @@
 import type { WorkflowOut, WorkflowVersion } from "@/client/workflow";
 import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
 import dayjs from "dayjs";
-import { onMounted, ref, computed } from "vue";
+import { onMounted, computed } from "vue";
 import { Tooltip } from "bootstrap";
 import { latestVersion as calculateLatestVersion } from "@/utils/Workflow";
 
@@ -12,7 +12,6 @@ const props = defineProps<{
 }>();
 
 const randomIDSuffix: string = Math.random().toString(16).substring(2, 8);
-const truncateDescription = ref<boolean>(true);
 const latestVersion = computed<WorkflowVersion | undefined>(() =>
   calculateLatestVersion(props.workflow.versions),
 );
@@ -55,18 +54,11 @@ onMounted(() => {
           class="img-fluid float-end icon"
         />
       </div>
-      <p class="card-text" :class="{ 'text-truncate': truncateDescription }">
+      <p class="card-text">
         <span v-if="props.loading" class="placeholder-glow"
           ><span class="placeholder col-12"></span
         ></span>
-        <span
-          v-else
-          @click="truncateDescription = false"
-          :class="{
-            'cursor-pointer': truncateDescription,
-          }"
-          >{{ props.workflow.short_description }}</span
-        >
+        <span v-else>{{ props.workflow.short_description }}</span>
       </p>
       <div class="d-flex justify-content-between mb-0">
         <div v-if="props.loading" class="placeholder-glow w-50">
diff --git a/src/components/workflows/modals/ParameterModal.vue b/src/components/workflows/modals/ParameterModal.vue
index 5b7d852eda2546c4390295f1f9818c3682ac5a29..9bb1d5260e27a4e4aadb02780f65b67bd14d7ccc 100644
--- a/src/components/workflows/modals/ParameterModal.vue
+++ b/src/components/workflows/modals/ParameterModal.vue
@@ -177,7 +177,7 @@ onMounted(() => {
     :modalId="modalId"
     :static-backdrop="false"
     modal-label="Workflow Execution Parameters Modal"
-    size-modifier="lg"
+    size-modifier-modal="lg"
     :track-modal-value="executionId"
   >
     <template v-slot:header
diff --git a/src/components/workflows/modals/UpdateWorkflowCredentialsModal.vue b/src/components/workflows/modals/UpdateWorkflowCredentialsModal.vue
index 1b9bf27bb49c2bc31d7dd467aeb2980665ec2397..a6180547ba405a7fce7e7953a8804a13aeaf86f0 100644
--- a/src/components/workflows/modals/UpdateWorkflowCredentialsModal.vue
+++ b/src/components/workflows/modals/UpdateWorkflowCredentialsModal.vue
@@ -139,7 +139,7 @@ onMounted(() => {
     :modalId="modalId"
     :static-backdrop="true"
     modal-label="Update Workflow Version Icon Modal"
-    size-modifier="lg"
+    size-modifier-modal="lg"
     v-on="{ 'hidden.bs.modal': modalClosed }"
     :track-modal-value="workflow.workflow_id"
   >
diff --git a/src/components/workflows/modals/UpdateWorkflowModal.vue b/src/components/workflows/modals/UpdateWorkflowModal.vue
index b69487c2725d96e22eaca180582eeb324541352c..114f51c8e04bbad57d32ab8dec8472c9a89b0b4e 100644
--- a/src/components/workflows/modals/UpdateWorkflowModal.vue
+++ b/src/components/workflows/modals/UpdateWorkflowModal.vue
@@ -316,7 +316,7 @@ onMounted(() => {
     :static-backdrop="true"
     modal-label="Update Workflow Modal"
     v-on="{ 'hidden.bs.modal': modalClosed }"
-    size-modifier="lg"
+    size-modifier-modal="lg"
     :track-modal-value="workflow.workflow_id"
   >
     <template #header>
diff --git a/src/stores/buckets.ts b/src/stores/buckets.ts
index 9c9c92b5c05e60492e71ef13b9b3fe5cdff3d6c2..6c13662648423e263ab02b66d3a9e914d5a7e109 100644
--- a/src/stores/buckets.ts
+++ b/src/stores/buckets.ts
@@ -267,5 +267,16 @@ export const useBucketStore = defineStore({
         return permissionOut;
       });
     },
+    togglePublicState(
+      bucketName: string,
+      public_: boolean,
+    ): Promise<BucketOut> {
+      return BucketService.bucketUpdateBucketPublicState(bucketName, {
+        public: public_,
+      }).then((bucket) => {
+        this.bucketMapping[bucketName] = bucket;
+        return bucket;
+      });
+    },
   },
 });
diff --git a/src/stores/resources.ts b/src/stores/resources.ts
index 61fb1e9f27fb68fc05f87587b2736712fe3a58cc..0c9a78176fa4531e24ba19585cbd540d966aca5e 100644
--- a/src/stores/resources.ts
+++ b/src/stores/resources.ts
@@ -115,6 +115,10 @@ export const useResourceStore = defineStore({
       return ResourceService.resourceListSyncRequests()
         .then((requests) => {
           this.__syncRequestsFetched = true;
+          const userStore = useAuthStore();
+          userStore.fetchUsernames(
+            requests.map((request) => request.requester_id),
+          );
           const newMapping: Record<string, UserSynchronizationRequestOut> = {};
           for (const request of requests) {
             newMapping[request.resource_version_id] = request;
@@ -136,6 +140,10 @@ export const useResourceStore = defineStore({
         searchString,
         _public,
       ).then((resources) => {
+        const userStore = useAuthStore();
+        userStore.fetchUsernames(
+          resources.map((resource) => resource.maintainer_id),
+        );
         const nameStore = useNameStore();
         for (const resource of resources) {
           nameStore.addNameToMapping(resource.resource_id, resource.name);
diff --git a/src/stores/s3objects.ts b/src/stores/s3objects.ts
index ab6889076b69551a521fb5476d810ce20df9fc01..e314ae5a2b69e679997eb655aa47d7ed0bba6589 100644
--- a/src/stores/s3objects.ts
+++ b/src/stores/s3objects.ts
@@ -56,6 +56,18 @@ export const useS3ObjectStore = defineStore({
         });
       };
     },
+    getMeta(): (bucketName: string) => [number, number] {
+      // Compute the number of objects and the cumulative size of all objects in a bucket
+      return (bucketName) => {
+        return [
+          this.objectMapping[bucketName]?.length ?? 0,
+          this.objectMapping[bucketName]?.reduce(
+            (acc, obj) => acc + (obj.Size ?? 0),
+            0,
+          ) ?? 0,
+        ];
+      };
+    },
   },
   actions: {
     _pushObject(bucketName: string, newObj: S3Object) {
diff --git a/src/views/admin/AdminUsersView.vue b/src/views/admin/AdminUsersView.vue
index 58eeccc300fc1d69a492e5886059aa84ea0a55dc..34df43a3486840b63b056c42d8f1c196f4889e5b 100644
--- a/src/views/admin/AdminUsersView.vue
+++ b/src/views/admin/AdminUsersView.vue
@@ -92,12 +92,22 @@ function searchUsers() {
       Search
     </button>
   </form>
-  <table class="table table-striped align-middle" v-if="userState.users">
+  <table
+    class="table table-striped align-middle caption-top"
+    v-if="userState.users"
+  >
+    <caption>
+      Displaying
+      {{
+        userState.users.length
+      }}
+      Users
+    </caption>
     <thead>
       <tr>
         <th scope="col"><b>Name</b></th>
         <th scope="col">UID</th>
-        <th scope="col" class="text-center">Normal User</th>
+        <th scope="col" class="text-center">Approved User</th>
         <th scope="col" class="text-center">Developer</th>
         <th scope="col" class="text-center">Resource Maintainer</th>
         <th scope="col" class="text-center">Reviewer</th>
diff --git a/src/views/object-storage/BucketsView.vue b/src/views/object-storage/BucketsView.vue
index d47ff0905b8c53b979c281fdafd6523995db15f8..fc184434ea38ef5031edf34aedfb71c4512a6a22 100644
--- a/src/views/object-storage/BucketsView.vue
+++ b/src/views/object-storage/BucketsView.vue
@@ -175,8 +175,7 @@ onMounted(() => {
               description: '',
               created_at: 0,
               owner_id: '',
-              size: 0,
-              num_objects: 0,
+              public: false,
               owner_constraint: null,
             }"
           ></bucket-list-item>
diff --git a/src/views/workflows/ListWorkflowsView.vue b/src/views/workflows/ListWorkflowsView.vue
index baf7d7aeb28e8435a0f632306107261065ecfb1c..3316af5eeae702dc950b8af8d879e1deabafa9d1 100644
--- a/src/views/workflows/ListWorkflowsView.vue
+++ b/src/views/workflows/ListWorkflowsView.vue
@@ -13,12 +13,12 @@ const workflowRepository = useWorkflowStore();
 const workflowsState = reactive<{
   loading: boolean;
   filterString: string;
-  sortByAttribute: string;
+  sortByAttribute: "name" | "release";
   sortDesc: boolean;
 }>({
   loading: true,
   filterString: "",
-  sortByAttribute: "name",
+  sortByAttribute: "release",
   sortDesc: true,
 });
 
diff --git a/src/views/workflows/WorkflowView.vue b/src/views/workflows/WorkflowView.vue
index f9023fc7f3e106e9d4ce8b1a0484336904146cc4..89bb7a07056b570364b1f215d5d1d717aef063c5 100644
--- a/src/views/workflows/WorkflowView.vue
+++ b/src/views/workflows/WorkflowView.vue
@@ -357,10 +357,6 @@ onMounted(() => {
         >
           <font-awesome-icon :icon="gitIcon" class="me-1" />
           <span class="align-middle"> {{ workflow?.repository_url }}</span>
-          <font-awesome-icon
-            icon="fa-solid fa-arrow-up-right-from-square"
-            class="ms-1"
-          />
           <font-awesome-icon
             v-if="workflow?.private"
             icon="fa-solid fa-lock"