diff --git a/Dockerfile b/Dockerfile
index 59677c69b7ffce60fcccbea4501d5a1e92c4cc0b..19606527adbac48def6672dd4f1518ac96526048 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 # build stage
-FROM gitlab.ub.uni-bielefeld.de/cmg/clowm/dependency_proxy/containers/node:18 as build-stage
+FROM node:18 as build-stage
 WORKDIR /app
 COPY package.json ./
 COPY package-lock.json ./
@@ -8,10 +8,11 @@ COPY . .
 RUN npm run build-only
 
 # production stage
-FROM gitlab.ub.uni-bielefeld.de/cmg/clowm/dependency_proxy/containers/nginx:stable-alpine as production-stage
+FROM nginx:stable-alpine as production-stage
+EXPOSE 80
 HEALTHCHECK --interval=30s --timeout=4s CMD curl --head -f http://localhost || exit 1
 COPY --from=build-stage /app/dist /usr/share/nginx/html
 COPY --from=build-stage /app/src/assets/env.template.js /tmp
 COPY nginx.conf /etc/nginx/conf.d/default.conf
-EXPOSE 80
+
 CMD ["/bin/sh",  "-c",  "envsubst < /tmp/env.template.js > /usr/share/nginx/html/env.js && exec nginx -g 'daemon off;'"]
diff --git a/index.html b/index.html
index 61088270988b1c5c2bd89e8457bf83bc02b0d28b..cfd22a8039cba3001b171c73a005034c39761545 100644
--- a/index.html
+++ b/index.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <html lang="en" data-bs-theme="light">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<head>
+    <meta charset="UTF-8"/>
+    <link rel="icon" href="/favicon.ico"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
     <title>CloWM</title>
     <script src="/env.js"></script>
-  </head>
-  <body>
-    <div id="app" class="d-flex flex-column justify-content-between" style="min-height: 100vh"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
+</head>
+<body>
+<div id="app" class="d-flex flex-column justify-content-between" style="min-height: 100vh"></div>
+<script type="module" src="/src/main.ts"></script>
+</body>
 </html>
diff --git a/package-lock.json b/package-lock.json
index eee6e7483a2f6d9bf4b0c6c01ce3abdd00c0120a..4b52d79d5f53d93f7faabaeb424bab2043871948 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,6 +45,7 @@
         "axios": "~1.6.0",
         "eslint": "~8.48.0",
         "eslint-plugin-vue": "~9.19.0",
+        "highlight.js": "^11.9.0",
         "npm-run-all": "~4.1.5",
         "openapi-typescript-codegen": "^0.26.0",
         "prettier": "~3.0.3",
@@ -209,33 +210,33 @@
       "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
     },
     "node_modules/@aws-sdk/client-s3": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.485.0.tgz",
-      "integrity": "sha512-Vh8FRiXekwu1sSdfhS/wpNzjIljPmIXrUdEapR7EmaIwditR+mTTzNS+7y69YdPQhVEE2u9QxRlo4Eg1e1jD3w==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.490.0.tgz",
+      "integrity": "sha512-fBj3CJ3+5R+l/sc93Z9mKw8gM2b9K6vEhC9qSCG2XNymLd9YqlRft1peQ7VymrWywAHX3Koz1GCUrFEVNONiMw==",
       "dependencies": {
         "@aws-crypto/sha1-browser": "3.0.0",
         "@aws-crypto/sha256-browser": "3.0.0",
         "@aws-crypto/sha256-js": "3.0.0",
-        "@aws-sdk/client-sts": "3.485.0",
-        "@aws-sdk/core": "3.485.0",
-        "@aws-sdk/credential-provider-node": "3.485.0",
-        "@aws-sdk/middleware-bucket-endpoint": "3.485.0",
-        "@aws-sdk/middleware-expect-continue": "3.485.0",
-        "@aws-sdk/middleware-flexible-checksums": "3.485.0",
-        "@aws-sdk/middleware-host-header": "3.485.0",
-        "@aws-sdk/middleware-location-constraint": "3.485.0",
-        "@aws-sdk/middleware-logger": "3.485.0",
-        "@aws-sdk/middleware-recursion-detection": "3.485.0",
-        "@aws-sdk/middleware-sdk-s3": "3.485.0",
-        "@aws-sdk/middleware-signing": "3.485.0",
-        "@aws-sdk/middleware-ssec": "3.485.0",
-        "@aws-sdk/middleware-user-agent": "3.485.0",
-        "@aws-sdk/region-config-resolver": "3.485.0",
-        "@aws-sdk/signature-v4-multi-region": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-endpoints": "3.485.0",
-        "@aws-sdk/util-user-agent-browser": "3.485.0",
-        "@aws-sdk/util-user-agent-node": "3.485.0",
+        "@aws-sdk/client-sts": "3.490.0",
+        "@aws-sdk/core": "3.490.0",
+        "@aws-sdk/credential-provider-node": "3.490.0",
+        "@aws-sdk/middleware-bucket-endpoint": "3.489.0",
+        "@aws-sdk/middleware-expect-continue": "3.489.0",
+        "@aws-sdk/middleware-flexible-checksums": "3.489.0",
+        "@aws-sdk/middleware-host-header": "3.489.0",
+        "@aws-sdk/middleware-location-constraint": "3.489.0",
+        "@aws-sdk/middleware-logger": "3.489.0",
+        "@aws-sdk/middleware-recursion-detection": "3.489.0",
+        "@aws-sdk/middleware-sdk-s3": "3.489.0",
+        "@aws-sdk/middleware-signing": "3.489.0",
+        "@aws-sdk/middleware-ssec": "3.489.0",
+        "@aws-sdk/middleware-user-agent": "3.489.0",
+        "@aws-sdk/region-config-resolver": "3.489.0",
+        "@aws-sdk/signature-v4-multi-region": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-endpoints": "3.489.0",
+        "@aws-sdk/util-user-agent-browser": "3.489.0",
+        "@aws-sdk/util-user-agent-node": "3.489.0",
         "@aws-sdk/xml-builder": "3.485.0",
         "@smithy/config-resolver": "^2.0.23",
         "@smithy/core": "^1.2.2",
@@ -277,22 +278,22 @@
       }
     },
     "node_modules/@aws-sdk/client-sso": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.485.0.tgz",
-      "integrity": "sha512-apN2bEn0PZs0jD4jAfvwO3dlWqw9YIQJ6TAudM1bd3S5vzWqlBBcLfQpK6taHoQaI+WqgUWXLuOf7gRFbGXKPg==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.490.0.tgz",
+      "integrity": "sha512-yfxoHmCL1w/IKmFRfzCxdVCQrGlSQf4eei9iVEm5oi3iE8REFyPj3o/BmKQEHG3h2ITK5UbdYDb5TY4xoYHsyA==",
       "dependencies": {
         "@aws-crypto/sha256-browser": "3.0.0",
         "@aws-crypto/sha256-js": "3.0.0",
-        "@aws-sdk/core": "3.485.0",
-        "@aws-sdk/middleware-host-header": "3.485.0",
-        "@aws-sdk/middleware-logger": "3.485.0",
-        "@aws-sdk/middleware-recursion-detection": "3.485.0",
-        "@aws-sdk/middleware-user-agent": "3.485.0",
-        "@aws-sdk/region-config-resolver": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-endpoints": "3.485.0",
-        "@aws-sdk/util-user-agent-browser": "3.485.0",
-        "@aws-sdk/util-user-agent-node": "3.485.0",
+        "@aws-sdk/core": "3.490.0",
+        "@aws-sdk/middleware-host-header": "3.489.0",
+        "@aws-sdk/middleware-logger": "3.489.0",
+        "@aws-sdk/middleware-recursion-detection": "3.489.0",
+        "@aws-sdk/middleware-user-agent": "3.489.0",
+        "@aws-sdk/region-config-resolver": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-endpoints": "3.489.0",
+        "@aws-sdk/util-user-agent-browser": "3.489.0",
+        "@aws-sdk/util-user-agent-node": "3.489.0",
         "@smithy/config-resolver": "^2.0.23",
         "@smithy/core": "^1.2.2",
         "@smithy/fetch-http-handler": "^2.3.2",
@@ -324,23 +325,23 @@
       }
     },
     "node_modules/@aws-sdk/client-sts": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.485.0.tgz",
-      "integrity": "sha512-PI4q36kVF0fpIPZyeQhrwwJZ6SRkOGvU3rX5Qn4b5UY5X+Ct1aLhqSX8/OB372UZIcnh6eSvERu8POHleDO7Jw==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.490.0.tgz",
+      "integrity": "sha512-n2vQ5Qu2qi2I0XMI+IH99ElpIRHOJTa1+sqNC4juMYxKQBMvw+EnsqUtaL3QvTHoyxNB/R7mpkeBB6SzPQ1TtA==",
       "dependencies": {
         "@aws-crypto/sha256-browser": "3.0.0",
         "@aws-crypto/sha256-js": "3.0.0",
-        "@aws-sdk/core": "3.485.0",
-        "@aws-sdk/credential-provider-node": "3.485.0",
-        "@aws-sdk/middleware-host-header": "3.485.0",
-        "@aws-sdk/middleware-logger": "3.485.0",
-        "@aws-sdk/middleware-recursion-detection": "3.485.0",
-        "@aws-sdk/middleware-user-agent": "3.485.0",
-        "@aws-sdk/region-config-resolver": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-endpoints": "3.485.0",
-        "@aws-sdk/util-user-agent-browser": "3.485.0",
-        "@aws-sdk/util-user-agent-node": "3.485.0",
+        "@aws-sdk/core": "3.490.0",
+        "@aws-sdk/credential-provider-node": "3.490.0",
+        "@aws-sdk/middleware-host-header": "3.489.0",
+        "@aws-sdk/middleware-logger": "3.489.0",
+        "@aws-sdk/middleware-recursion-detection": "3.489.0",
+        "@aws-sdk/middleware-user-agent": "3.489.0",
+        "@aws-sdk/region-config-resolver": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-endpoints": "3.489.0",
+        "@aws-sdk/util-user-agent-browser": "3.489.0",
+        "@aws-sdk/util-user-agent-node": "3.489.0",
         "@smithy/config-resolver": "^2.0.23",
         "@smithy/core": "^1.2.2",
         "@smithy/fetch-http-handler": "^2.3.2",
@@ -374,9 +375,9 @@
       }
     },
     "node_modules/@aws-sdk/core": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.485.0.tgz",
-      "integrity": "sha512-Yvi80DQcbjkYCft471ClE3HuetuNVqntCs6eFOomDcrJaqdOFrXv2kJAxky84MRA/xb7bGlDGAPbTuj1ICputg==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.490.0.tgz",
+      "integrity": "sha512-TSBWkXtxMU7q1Zo6w3v5wIOr/sj7P5Jw3OyO7lJrFGsPsDC2xwpxkVqTesDxkzgMRypO52xjYEmveagn1xxBHg==",
       "dependencies": {
         "@smithy/core": "^1.2.2",
         "@smithy/protocol-http": "^3.0.12",
@@ -390,11 +391,11 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-env": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.485.0.tgz",
-      "integrity": "sha512-3XkFgwVU1XOB33dV7t9BKJ/ptdl2iS+0dxE7ecq8aqT2/gsfKmLCae1G17P8WmdD3z0kMDTvnqM2aWgUnSOkmg==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.489.0.tgz",
+      "integrity": "sha512-5PqYsx9G5SB2tqPT9/z/u0EkF6D4wP6HTMWQs+DfMdmwXihrqQAgeYaTtV3KbXqb88p6sfacwxhUvE6+Rm494w==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -404,15 +405,15 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-ini": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.485.0.tgz",
-      "integrity": "sha512-cFYF/Bdw7EnT4viSxYpNIv3IBkri/Yb+JpQXl8uDq7bfVJfAN5qZmK07vRkg08xL6TC4F41wshhMSAucGdTwIw==",
-      "dependencies": {
-        "@aws-sdk/credential-provider-env": "3.485.0",
-        "@aws-sdk/credential-provider-process": "3.485.0",
-        "@aws-sdk/credential-provider-sso": "3.485.0",
-        "@aws-sdk/credential-provider-web-identity": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.490.0.tgz",
+      "integrity": "sha512-7m63zyCpVqj9FsoDxWMWWRvL6c7zZzOcXYkHZmHujVVlmAXH0RT/vkXFkYgt+Ku+ov+v5NQrzwO5TmVoRt6O8g==",
+      "dependencies": {
+        "@aws-sdk/credential-provider-env": "3.489.0",
+        "@aws-sdk/credential-provider-process": "3.489.0",
+        "@aws-sdk/credential-provider-sso": "3.490.0",
+        "@aws-sdk/credential-provider-web-identity": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/credential-provider-imds": "^2.0.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/shared-ini-file-loader": "^2.0.6",
@@ -424,16 +425,16 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-node": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.485.0.tgz",
-      "integrity": "sha512-2DwzO2azkSzngifKDT61W/DL0tSzewuaFHiLJWdfc8Et3mdAQJ9x3KAj8u7XFpjIcGNqk7FiKjN+zeGUuNiEhA==",
-      "dependencies": {
-        "@aws-sdk/credential-provider-env": "3.485.0",
-        "@aws-sdk/credential-provider-ini": "3.485.0",
-        "@aws-sdk/credential-provider-process": "3.485.0",
-        "@aws-sdk/credential-provider-sso": "3.485.0",
-        "@aws-sdk/credential-provider-web-identity": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.490.0.tgz",
+      "integrity": "sha512-Gh33u2O5Xbout8G3z/Z5H/CZzdG1ophxf/XS3iMFxA1cazQ7swY1UMmGvB7Lm7upvax5anXouItD1Ph3gzKc4w==",
+      "dependencies": {
+        "@aws-sdk/credential-provider-env": "3.489.0",
+        "@aws-sdk/credential-provider-ini": "3.490.0",
+        "@aws-sdk/credential-provider-process": "3.489.0",
+        "@aws-sdk/credential-provider-sso": "3.490.0",
+        "@aws-sdk/credential-provider-web-identity": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/credential-provider-imds": "^2.0.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/shared-ini-file-loader": "^2.0.6",
@@ -445,11 +446,11 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-process": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.485.0.tgz",
-      "integrity": "sha512-X9qS6ZO/rDKYDgWqD1YmSX7sAUUHax9HbXlgGiTTdtfhZvQh1ZmnH6wiPu5WNliafHZFtZT2W07kgrDLPld/Ug==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.489.0.tgz",
+      "integrity": "sha512-3vKQYJZ5cZYjy0870CPmbmKRBgATw2xCygxhn4m4UDCjOXVXcGUtYD51DMWsvBo3S0W8kH+FIJV4yuEDMFqLFQ==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/shared-ini-file-loader": "^2.0.6",
         "@smithy/types": "^2.8.0",
@@ -460,13 +461,13 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-sso": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.485.0.tgz",
-      "integrity": "sha512-l0oC8GTrWh+LFQQfSmG1Jai1PX7Mhj9arb/CaS1/tmeZE0hgIXW++tvljYs/Dds4LGXUlaWG+P7BrObf6OyIXA==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.490.0.tgz",
+      "integrity": "sha512-3UUBUoPbFvT58IhS4Vb23omYj/QPNkjgxu9p9ruQ3KSjLkanI4w8t/l/jljA65q83P7CoLnM5UKG9L7RA8/V1Q==",
       "dependencies": {
-        "@aws-sdk/client-sso": "3.485.0",
-        "@aws-sdk/token-providers": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/client-sso": "3.490.0",
+        "@aws-sdk/token-providers": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/shared-ini-file-loader": "^2.0.6",
         "@smithy/types": "^2.8.0",
@@ -477,11 +478,11 @@
       }
     },
     "node_modules/@aws-sdk/credential-provider-web-identity": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.485.0.tgz",
-      "integrity": "sha512-WpBFZFE0iXtnibH5POMEKITj/hR0YV5l2n9p8BEvKjdJ63s3Xke1RN20ZdIyKDaRDwj8adnKDgNPEnAKdS4kLw==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.489.0.tgz",
+      "integrity": "sha512-mjIuE2Wg1H/ds0nXQ/7vfusEDudmdd8YzKZI1y5O4n60iZZtyB2RNIECtvLMx1EQAKclidY7/06qQkArrGau5Q==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -491,9 +492,9 @@
       }
     },
     "node_modules/@aws-sdk/lib-storage": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.485.0.tgz",
-      "integrity": "sha512-d/DppujsMu2zg2K95wS2OZ+x+wY41OeZL0duROKZRzNtPyYzlOiSw00+zSz7/sdmUad1bYIEyDJ46zI/FV6AVg==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.490.0.tgz",
+      "integrity": "sha512-JLRabk0bHzEd0G5RF+62/kyiIKSwrstW9WC0/CEvIfZbFbDPE4Ncd8q97YLUTFiIGDNsEcjW8DSbA6Feezcwhg==",
       "dependencies": {
         "@smithy/abort-controller": "^2.0.1",
         "@smithy/middleware-endpoint": "^2.3.0",
@@ -511,11 +512,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-bucket-endpoint": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.485.0.tgz",
-      "integrity": "sha512-DptPuprsx9V1LH91ZvC/7a7B1UnuSAIi1ArJHlHqJL1ISo6sH1oeXP6KRa0tj8biGMDIx0b22wg8EEpFePMy3w==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.489.0.tgz",
+      "integrity": "sha512-6rJ5bpNMKo7sEKQ6p2DMbQwM+ahMYASRxfdyH7hs18blvlcS20H1RYpNmJMqPPjxMwUWruty2JPMIRl4DFcv8w==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@aws-sdk/util-arn-parser": "3.465.0",
         "@smithy/node-config-provider": "^2.1.9",
         "@smithy/protocol-http": "^3.0.12",
@@ -528,11 +529,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-expect-continue": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.485.0.tgz",
-      "integrity": "sha512-rOwJJWM1/ydwSiJJ1l/X5h91u2Xzb8/CwOW6ZY+E8iZA0HDCtlJnKNlhHb+NHGtDamd4+1qdGSRtPQevyS58Cg==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.489.0.tgz",
+      "integrity": "sha512-2RZfnVZFaGHwzPDQJsyf9SXufu1gUd4VsMhm7dC7SWF85XmpDrozbFznS/tD22QdtyWjerLoydZJMq229hpPqg==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -542,13 +543,13 @@
       }
     },
     "node_modules/@aws-sdk/middleware-flexible-checksums": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.485.0.tgz",
-      "integrity": "sha512-5+OmVMbEwl1LDdWbaJxoSViw6vuMsdDQgASFUM37aG46q1zWSiPU171IXutEAFZZXN/t0HcOFi0AmNrS0o+dkQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.489.0.tgz",
+      "integrity": "sha512-Cy3rBUMr4P7raxzrJFWNRshfKrKV2EojawaC9Bfk/T8aFlV+FmVrRg4ISAXMOfS5pfy3xfAbvkzjOaeqCsGfrA==",
       "dependencies": {
         "@aws-crypto/crc32": "3.0.0",
         "@aws-crypto/crc32c": "3.0.0",
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/is-array-buffer": "^2.0.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/types": "^2.8.0",
@@ -560,11 +561,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-host-header": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.485.0.tgz",
-      "integrity": "sha512-1mAUX9dQNGo2RIKseVj7SI/D5abQJQ/Os8hQ0NyVAyyVYF+Yjx5PphKgfhM5yoBwuwZUl6q71XPYEGNx7be6SA==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.489.0.tgz",
+      "integrity": "sha512-Cl7HJ1jhOfllwf0CRx1eB4ypRGMqdGKWpc0eSTXty7wWSvCdMZUhwfjQqu2bIOIlgYxg/gFu6TVmVZ6g4O8PlA==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -574,11 +575,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-location-constraint": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.485.0.tgz",
-      "integrity": "sha512-Mrp4chtYliqCUSVjzLYPcZCPGmhL4QM7o6NhHBdA6omaIGdn4pJqFwN5ELZoWJDZMKyfrKi6s6u97jR9VtEXRg==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.489.0.tgz",
+      "integrity": "sha512-NIVr+kHR2N6gxFeE3TNw2mEBxgj0N9xXBLy3dNYMMlAUvQlT/0z9HlC9+3XqcTS/Z5ElF/+pei6nqXTVt0He9A==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
       },
@@ -587,11 +588,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-logger": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.485.0.tgz",
-      "integrity": "sha512-O8IgJ0LHi5wTs5GlpI7nqmmSSagkVdd1shpGgQWY2h0kMSCII8CJZHBG97dlFFpGTvx5EDlhPNek7rl/6F4dRw==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.489.0.tgz",
+      "integrity": "sha512-+EVDnWese61MdImcBNAgz/AhTcIZJaska/xsU3GWU9CP905x4a4qZdB7fExFMDu1Jlz5pJqNteFYYHCFMJhHfg==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
       },
@@ -600,11 +601,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-recursion-detection": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.485.0.tgz",
-      "integrity": "sha512-ZeVNATGNFcqkWDut3luVszROTUzkU5u+rJpB/xmeMoenlDAjPRiHt/ca3WkI5wAnIJ1VSNGpD2sOFLMCH+EWag==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.489.0.tgz",
+      "integrity": "sha512-m4rU+fTzziQcu9DKjRNZ4nQlXENEd2ZnJblJV4ONdWqqEjbmOgOj3P6aCCQlJdIbzuNvX1FBOZ5tY59ZpERo7Q==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -614,11 +615,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-sdk-s3": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.485.0.tgz",
-      "integrity": "sha512-3769c4e3UtvaNU5T6dHxhjGI1kEXymldqiP1PMZMX2jVffwSGhbvyLq0Kl6+9Jr51fj2oXN6Tex+8J9+5dzTgQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.489.0.tgz",
+      "integrity": "sha512-/GGASx7mK9qEgy1znvleYMZKVqm3sOdGghqKdy2zgoGcH2jH+fZrLM0lDMT9bvdITmOCbJJs2rVHP3xm/ZWcXg==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@aws-sdk/util-arn-parser": "3.465.0",
         "@smithy/node-config-provider": "^2.1.9",
         "@smithy/protocol-http": "^3.0.12",
@@ -633,11 +634,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-signing": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.485.0.tgz",
-      "integrity": "sha512-41xzT2p1sOibhsLkdE5rwPJkNbBtKD8Gp36/ySfu0KE415wfXKacElSVxAaBw39/j7iSWDYqqybeEYbAzk+3GQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.489.0.tgz",
+      "integrity": "sha512-rlHcWYZn6Ym3v/u0DvKNDiD7ogIzEsHlerm0lowTiQbszkFobOiUClRTALwvsUZdAAztl706qO1OKbnGnD6Ubw==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/property-provider": "^2.0.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/signature-v4": "^2.0.0",
@@ -650,11 +651,11 @@
       }
     },
     "node_modules/@aws-sdk/middleware-ssec": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.485.0.tgz",
-      "integrity": "sha512-A59WTC0egT8zLnRzB+yWKq2AonugD1DgN4710RG70JY5XUmx5TYdECbUrVeG/zhNIKbBLLFjRcVk2uo4OZcgIA==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.489.0.tgz",
+      "integrity": "sha512-5RQg8dqERAmi1OfVEV9fbTA5NKmcvKDYP79YtH08IEFIsHWU1Y5NoqL7mXkkNyBrJNBVyasYijAbTzOuM707eg==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
       },
@@ -663,12 +664,12 @@
       }
     },
     "node_modules/@aws-sdk/middleware-user-agent": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.485.0.tgz",
-      "integrity": "sha512-CddCVOn+OPQ0CcchketIg+WF6v+MDLAf3GOYTR2htUxxIm7HABuRd6R3kvQ5Jny9CV8gMt22G1UZITsFexSJlQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.489.0.tgz",
+      "integrity": "sha512-M54Cv2fAN3GGgdfUjLtZ4wFUIrfM/ivbXv4DgpcNsacEQ2g4H+weQgKp41X7XZW8MWAzl+k1zJaryK69RYNQkQ==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-endpoints": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-endpoints": "3.489.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -678,10 +679,11 @@
       }
     },
     "node_modules/@aws-sdk/region-config-resolver": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.485.0.tgz",
-      "integrity": "sha512-2FB2EQ0sIE+YgFqGtkE1lDIMIL6nYe6MkOHBwBM7bommadKIrbbr2L22bPZGs3ReTsxiJabjzxbuCAVhrpHmhg==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.489.0.tgz",
+      "integrity": "sha512-UvrnB78XTz9ddby7mr0vuUHn2MO3VTjzaIu+GQhyedMGQU0QlIQrYOlzbbu4LC5rL1O8FxFLUxRe/AAjgwyuGw==",
       "dependencies": {
+        "@aws-sdk/types": "3.489.0",
         "@smithy/node-config-provider": "^2.1.9",
         "@smithy/types": "^2.8.0",
         "@smithy/util-config-provider": "^2.1.0",
@@ -693,13 +695,13 @@
       }
     },
     "node_modules/@aws-sdk/s3-request-presigner": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.485.0.tgz",
-      "integrity": "sha512-5TCyl1H/PdBH0XDSILb9y1d/fU+tDEQ7Fkqeb2gIYENDG09dX68TtcZVGs0sMZtC9CLUFpmEp8R/3LtfuoeY6w==",
+      "version": "3.490.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.490.0.tgz",
+      "integrity": "sha512-ZHs+FlcTv9MKMM0b9svxxQio4FiRxDNstKYG8sbm9YEoahYV25h3K3butUiThaiOeYePOD7jHdbdXz4/XasxXg==",
       "dependencies": {
-        "@aws-sdk/signature-v4-multi-region": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-format-url": "3.485.0",
+        "@aws-sdk/signature-v4-multi-region": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-format-url": "3.489.0",
         "@smithy/middleware-endpoint": "^2.3.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/smithy-client": "^2.2.1",
@@ -711,12 +713,12 @@
       }
     },
     "node_modules/@aws-sdk/signature-v4-multi-region": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.485.0.tgz",
-      "integrity": "sha512-168ipXkbG75l9cKQmsBtx/4+AYjGsBoy724bXosW13t2/l/E3IzJAYUjDROiK0JXVMG85xAnGWbFwZkjxVXzrQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.489.0.tgz",
+      "integrity": "sha512-kYFM7Opu36EkFlzXdVNOBFpQApgnuaTu/U/qYhGyuzeD+HNnYgZEsd/tDro1DQ074jVy3GN9ttJSYxq5I4oTkA==",
       "dependencies": {
-        "@aws-sdk/middleware-sdk-s3": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/middleware-sdk-s3": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/protocol-http": "^3.0.12",
         "@smithy/signature-v4": "^2.0.0",
         "@smithy/types": "^2.8.0",
@@ -727,21 +729,21 @@
       }
     },
     "node_modules/@aws-sdk/token-providers": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.485.0.tgz",
-      "integrity": "sha512-kOXA1WKIVIFNRqHL8ynVZ3hCKLsgnEmGr2iDR6agDNw5fYIlCO/6N2xR6QdGcLTvUUbwOlz4OvKLUQnWMKAnnA==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.489.0.tgz",
+      "integrity": "sha512-hSgjB8CMQoA8EIQ0ripDjDtbBcWDSa+7vSBYPIzksyknaGERR/GUfGXLV2dpm5t17FgFG6irT5f3ZlBzarL8Dw==",
       "dependencies": {
         "@aws-crypto/sha256-browser": "3.0.0",
         "@aws-crypto/sha256-js": "3.0.0",
-        "@aws-sdk/middleware-host-header": "3.485.0",
-        "@aws-sdk/middleware-logger": "3.485.0",
-        "@aws-sdk/middleware-recursion-detection": "3.485.0",
-        "@aws-sdk/middleware-user-agent": "3.485.0",
-        "@aws-sdk/region-config-resolver": "3.485.0",
-        "@aws-sdk/types": "3.485.0",
-        "@aws-sdk/util-endpoints": "3.485.0",
-        "@aws-sdk/util-user-agent-browser": "3.485.0",
-        "@aws-sdk/util-user-agent-node": "3.485.0",
+        "@aws-sdk/middleware-host-header": "3.489.0",
+        "@aws-sdk/middleware-logger": "3.489.0",
+        "@aws-sdk/middleware-recursion-detection": "3.489.0",
+        "@aws-sdk/middleware-user-agent": "3.489.0",
+        "@aws-sdk/region-config-resolver": "3.489.0",
+        "@aws-sdk/types": "3.489.0",
+        "@aws-sdk/util-endpoints": "3.489.0",
+        "@aws-sdk/util-user-agent-browser": "3.489.0",
+        "@aws-sdk/util-user-agent-node": "3.489.0",
         "@smithy/config-resolver": "^2.0.23",
         "@smithy/fetch-http-handler": "^2.3.2",
         "@smithy/hash-node": "^2.0.18",
@@ -774,9 +776,9 @@
       }
     },
     "node_modules/@aws-sdk/types": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.485.0.tgz",
-      "integrity": "sha512-+QW32YQdvZRDOwrAQPo/qCyXoSjgXB6RwJwCwkd8ebJXRXw6tmGKIHaZqYHt/LtBymvnaBgBBADNa4+qFvlOFw==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.489.0.tgz",
+      "integrity": "sha512-kcDtLfKog/p0tC4gAeqJqWxAiEzfe2LRPnKamvSG2Mjbthx4R/alE2dxyIq/wW+nvRv0fqR3OD5kD1+eVfdr/w==",
       "dependencies": {
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -797,11 +799,12 @@
       }
     },
     "node_modules/@aws-sdk/util-endpoints": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.485.0.tgz",
-      "integrity": "sha512-dTd642F7nJisApF8YjniqQ6U59CP/DCtar11fXf1nG9YNBCBsNNVw5ZfZb5nSNzaIdy27mQioWTCV18JEj1mxg==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.489.0.tgz",
+      "integrity": "sha512-uGyG1u84ATX03mf7bT4xD9XD/vlYJGD5+RxMN/UpzeTfzXfh+jvCQWbOQ44z8ttFJWYQQqrLxkfpF/JgvALzLA==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
+        "@smithy/types": "^2.8.0",
         "@smithy/util-endpoints": "^1.0.8",
         "tslib": "^2.5.0"
       },
@@ -810,11 +813,11 @@
       }
     },
     "node_modules/@aws-sdk/util-format-url": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.485.0.tgz",
-      "integrity": "sha512-CW82AQ8UD88jhI2OyAgT5yA8NH2KE0mgludRXYDT5uvwj6nlA7c2B+c2UJwbkMdlsUZip/XvN+jFoRR7AJH1GQ==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.489.0.tgz",
+      "integrity": "sha512-yqIf9RMdOSxMUrv1BVDmrYp5kjLh4RxA17BTqzcQK8cXkRBqBP8ydbCQXENSv8LZSMH7AnrXNHBD1eiVuKRzZw==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/querystring-builder": "^2.0.16",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -835,22 +838,22 @@
       }
     },
     "node_modules/@aws-sdk/util-user-agent-browser": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz",
-      "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.489.0.tgz",
+      "integrity": "sha512-85B9KMsuMpAZauzWQ16r52ZBAHYnznW6BVitnBglsibN7oJKn10Hggt4QGuRhvQFCxQ8YhvBl7r+vQGFO4hxIw==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/types": "^2.8.0",
         "bowser": "^2.11.0",
         "tslib": "^2.5.0"
       }
     },
     "node_modules/@aws-sdk/util-user-agent-node": {
-      "version": "3.485.0",
-      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz",
-      "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==",
+      "version": "3.489.0",
+      "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.489.0.tgz",
+      "integrity": "sha512-CYdkBHig8sFNc0dv11Ni9WXvZQHeI5+z77OrDHKkbidFx/V4BDTuwZw4K1vWg62pzFOEfzunJFiULRcDZWJR3w==",
       "dependencies": {
-        "@aws-sdk/types": "3.485.0",
+        "@aws-sdk/types": "3.489.0",
         "@smithy/node-config-provider": "^2.1.9",
         "@smithy/types": "^2.8.0",
         "tslib": "^2.5.0"
@@ -1376,13 +1379,13 @@
       }
     },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.13",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
-      "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
+      "version": "0.11.14",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+      "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
       "dev": true,
       "dependencies": {
-        "@humanwhocodes/object-schema": "^2.0.1",
-        "debug": "^4.1.1",
+        "@humanwhocodes/object-schema": "^2.0.2",
+        "debug": "^4.3.1",
         "minimatch": "^3.0.5"
       },
       "engines": {
@@ -1403,9 +1406,9 @@
       }
     },
     "node_modules/@humanwhocodes/object-schema": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
-      "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
+      "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
       "dev": true
     },
     "node_modules/@jridgewell/sourcemap-codec": {
@@ -1481,9 +1484,9 @@
       }
     },
     "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz",
-      "integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz",
+      "integrity": "sha512-idWaG8xeSRCfRq9KpRysDHJ/rEHBEXcHuJ82XY0yYFIWnLMjZv9vF/7DOq8djQ2n3Lk6+3qfSH8AqlmHlmi1MA==",
       "cpu": [
         "arm"
       ],
@@ -1494,9 +1497,9 @@
       ]
     },
     "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz",
-      "integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.5.tgz",
+      "integrity": "sha512-f14d7uhAMtsCGjAYwZGv6TwuS3IFaM4ZnGMUn3aCBgkcHAYErhV1Ad97WzBvS2o0aaDv4mVz+syiN0ElMyfBPg==",
       "cpu": [
         "arm64"
       ],
@@ -1507,9 +1510,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz",
-      "integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.5.tgz",
+      "integrity": "sha512-ndoXeLx455FffL68OIUrVr89Xu1WLzAG4n65R8roDlCoYiQcGGg6MALvs2Ap9zs7AHg8mpHtMpwC8jBBjZrT/w==",
       "cpu": [
         "arm64"
       ],
@@ -1520,9 +1523,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz",
-      "integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.5.tgz",
+      "integrity": "sha512-UmElV1OY2m/1KEEqTlIjieKfVwRg0Zwg4PLgNf0s3glAHXBN99KLpw5A5lrSYCa1Kp63czTpVll2MAqbZYIHoA==",
       "cpu": [
         "x64"
       ],
@@ -1533,9 +1536,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz",
-      "integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.5.tgz",
+      "integrity": "sha512-Q0LcU61v92tQB6ae+udZvOyZ0wfpGojtAKrrpAaIqmJ7+psq4cMIhT/9lfV6UQIpeItnq/2QDROhNLo00lOD1g==",
       "cpu": [
         "arm"
       ],
@@ -1546,9 +1549,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz",
-      "integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.5.tgz",
+      "integrity": "sha512-dkRscpM+RrR2Ee3eOQmRWFjmV/payHEOrjyq1VZegRUa5OrZJ2MAxBNs05bZuY0YCtpqETDy1Ix4i/hRqX98cA==",
       "cpu": [
         "arm64"
       ],
@@ -1559,9 +1562,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz",
-      "integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.5.tgz",
+      "integrity": "sha512-QaKFVOzzST2xzY4MAmiDmURagWLFh+zZtttuEnuNn19AiZ0T3fhPyjPPGwLNdiDT82ZE91hnfJsUiDwF9DClIQ==",
       "cpu": [
         "arm64"
       ],
@@ -1572,9 +1575,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz",
-      "integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.5.tgz",
+      "integrity": "sha512-HeGqmRJuyVg6/X6MpE2ur7GbymBPS8Np0S/vQFHDmocfORT+Zt76qu+69NUoxXzGqVP1pzaY6QIi0FJWLC3OPA==",
       "cpu": [
         "riscv64"
       ],
@@ -1585,9 +1588,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz",
-      "integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.5.tgz",
+      "integrity": "sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA==",
       "cpu": [
         "x64"
       ],
@@ -1598,9 +1601,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz",
-      "integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.5.tgz",
+      "integrity": "sha512-ezyFUOwldYpj7AbkwyW9AJ203peub81CaAIVvckdkyH8EvhEIoKzaMFJj0G4qYJ5sw3BpqhFrsCc30t54HV8vg==",
       "cpu": [
         "x64"
       ],
@@ -1611,9 +1614,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz",
-      "integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.5.tgz",
+      "integrity": "sha512-aHSsMnUw+0UETB0Hlv7B/ZHOGY5bQdwMKJSzGfDfvyhnpmVxLMGnQPGNE9wgqkLUs3+gbG1Qx02S2LLfJ5GaRQ==",
       "cpu": [
         "arm64"
       ],
@@ -1624,9 +1627,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz",
-      "integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.5.tgz",
+      "integrity": "sha512-AiqiLkb9KSf7Lj/o1U3SEP9Zn+5NuVKgFdRIZkvd4N0+bYrTOovVd0+LmYCPQGbocT4kvFyK+LXCDiXPBF3fyA==",
       "cpu": [
         "ia32"
       ],
@@ -1637,9 +1640,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz",
-      "integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.5.tgz",
+      "integrity": "sha512-1q+mykKE3Vot1kaFJIDoUFv5TuW+QQVaf2FmTT9krg86pQrGStOSJJ0Zil7CFagyxDuouTepzt5Y5TVzyajOdQ==",
       "cpu": [
         "x64"
       ],
@@ -2344,9 +2347,9 @@
       }
     },
     "node_modules/@types/node": {
-      "version": "18.19.5",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.5.tgz",
-      "integrity": "sha512-22MG6T02Hos2JWfa1o5jsIByn+bc5iOt1IS4xyg6OG68Bu+wMonVZzdrgCw693++rpLE9RUT/Bx15BeDzO0j+g==",
+      "version": "18.19.7",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.7.tgz",
+      "integrity": "sha512-IGRJfoNX10N/PfrReRZ1br/7SQ+2vF/tK3KXNwzXz82D32z5dMQEoOlFew18nLSN+vMNcLY4GrKfzwi/yWI8/w==",
       "dev": true,
       "dependencies": {
         "undici-types": "~5.26.4"
@@ -2559,9 +2562,9 @@
       }
     },
     "node_modules/@vitejs/plugin-vue": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.2.tgz",
-      "integrity": "sha512-kEjJHrLb5ePBvjD0SPZwJlw1QTRcjjCA9sB5VyfonoXVBxTS7TMnqL6EkLt1Eu61RDeiuZ/WN9Hf6PxXhPI2uA==",
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.3.tgz",
+      "integrity": "sha512-b8S5dVS40rgHdDrw+DQi/xOM9ed+kSRZzfm1T74bMmBDCd8XO87NKlFYInzCtwvtWwXZvo1QxE2OSspTATWrbA==",
       "dev": true,
       "engines": {
         "node": "^18.0.0 || >=20.0.0"
@@ -2600,12 +2603,12 @@
       }
     },
     "node_modules/@vue/compiler-core": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.6.tgz",
-      "integrity": "sha512-9SmkpHsXqhHGMIOp4cawUqp0AxLN2fJJfxh3sR2RaouVx/Y/ww5ts3dfpD9SCvD0n8cdO/Xw+kWEpa6EkH/vTQ==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.14.tgz",
+      "integrity": "sha512-ro4Zzl/MPdWs7XwxT7omHRxAjMbDFRZEEjD+2m3NBf8YzAe3HuoSEZosXQo+m1GQ1G3LQ1LdmNh1RKTYe+ssEg==",
       "dependencies": {
         "@babel/parser": "^7.23.6",
-        "@vue/shared": "3.4.6",
+        "@vue/shared": "3.4.14",
         "entities": "^4.5.0",
         "estree-walker": "^2.0.2",
         "source-map-js": "^1.0.2"
@@ -2617,27 +2620,27 @@
       "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
     },
     "node_modules/@vue/compiler-dom": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.6.tgz",
-      "integrity": "sha512-i39ZuyHPzPb0v5yXZbvODGwLr+T7lS1rYSjMd1oCTa14aDP80kYpWXrWPF1JVD4QJJNyLgFnJ2hxvFLM7dy9NQ==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.14.tgz",
+      "integrity": "sha512-nOZTY+veWNa0DKAceNWxorAbWm0INHdQq7cejFaWM1WYnoNSJbSEKYtE7Ir6lR/+mo9fttZpPVI9ZFGJ1juUEQ==",
       "dependencies": {
-        "@vue/compiler-core": "3.4.6",
-        "@vue/shared": "3.4.6"
+        "@vue/compiler-core": "3.4.14",
+        "@vue/shared": "3.4.14"
       }
     },
     "node_modules/@vue/compiler-sfc": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.6.tgz",
-      "integrity": "sha512-kTFOiyMtuetFqi5yEPA4hR6FTD36zKKY3qaBonxGb4pgj0yK1eACqH+iycTAsEqr2u4cOhcGkx3Yjecpgh6FTQ==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.14.tgz",
+      "integrity": "sha512-1vHc9Kv1jV+YBZC/RJxQJ9JCxildTI+qrhtDh6tPkR1O8S+olBUekimY0km0ZNn8nG1wjtFAe9XHij+YLR8cRQ==",
       "dependencies": {
         "@babel/parser": "^7.23.6",
-        "@vue/compiler-core": "3.4.6",
-        "@vue/compiler-dom": "3.4.6",
-        "@vue/compiler-ssr": "3.4.6",
-        "@vue/shared": "3.4.6",
+        "@vue/compiler-core": "3.4.14",
+        "@vue/compiler-dom": "3.4.14",
+        "@vue/compiler-ssr": "3.4.14",
+        "@vue/shared": "3.4.14",
         "estree-walker": "^2.0.2",
         "magic-string": "^0.30.5",
-        "postcss": "^8.4.32",
+        "postcss": "^8.4.33",
         "source-map-js": "^1.0.2"
       }
     },
@@ -2658,12 +2661,12 @@
       }
     },
     "node_modules/@vue/compiler-ssr": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.6.tgz",
-      "integrity": "sha512-XqeojjDitjMLyOogDePNSxw9XL4FAXchO9oOfqdzLVEtYES5j+AEilPJyP0KhQPfGecY2mJ3Y7/e6kkiJQLKvg==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.14.tgz",
+      "integrity": "sha512-bXT6+oAGlFjTYVOTtFJ4l4Jab1wjsC0cfSfOe2B4Z0N2vD2zOBSQ9w694RsCfhjk+bC2DY5Gubb1rHZVii107Q==",
       "dependencies": {
-        "@vue/compiler-dom": "3.4.6",
-        "@vue/shared": "3.4.6"
+        "@vue/compiler-dom": "3.4.14",
+        "@vue/shared": "3.4.14"
       }
     },
     "node_modules/@vue/devtools-api": {
@@ -2759,48 +2762,48 @@
       }
     },
     "node_modules/@vue/reactivity": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.6.tgz",
-      "integrity": "sha512-/VuOxdWDyAeKFHjOuSKEtH9jEVPRgsXxu84utBP1SiXFcFRx2prwiC9cSR8hKOfj5nBwhLXYb6XEU69mLpuk0w==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.14.tgz",
+      "integrity": "sha512-xRYwze5Q4tK7tT2J4uy4XLhK/AIXdU5EBUu9PLnIHcOKXO0uyXpNNMzlQKuq7B+zwtq6K2wuUL39pHA6ZQzObw==",
       "dependencies": {
-        "@vue/shared": "3.4.6"
+        "@vue/shared": "3.4.14"
       }
     },
     "node_modules/@vue/runtime-core": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.6.tgz",
-      "integrity": "sha512-XDOx8iiNmP66p+goUHT5XL1AnV8406VVFQARbylqmSCBZEtxchfu2ZoQk7U07ze8G/E0/BtX/C5o29zB1W4o5A==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.14.tgz",
+      "integrity": "sha512-qu+NMkfujCoZL6cfqK5NOfxgXJROSlP2ZPs4CTcVR+mLrwl4TtycF5Tgo0QupkdBL+2kigc6EsJlTcuuZC1NaQ==",
       "dependencies": {
-        "@vue/reactivity": "3.4.6",
-        "@vue/shared": "3.4.6"
+        "@vue/reactivity": "3.4.14",
+        "@vue/shared": "3.4.14"
       }
     },
     "node_modules/@vue/runtime-dom": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.6.tgz",
-      "integrity": "sha512-8bdQR5CLfzClGvAOfbbCF8adE9oko0pRfe+dj297i0JCdCJ8AuyUMsXkt6vGPcRPqIKX4Z8f/bDPrwl+c7e4Wg==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.14.tgz",
+      "integrity": "sha512-B85XmcR4E7XsirEHVqhmy4HPbRT9WLFWV9Uhie3OapV9m1MEN9+Er6hmUIE6d8/l2sUygpK9RstFM2bmHEUigA==",
       "dependencies": {
-        "@vue/runtime-core": "3.4.6",
-        "@vue/shared": "3.4.6",
+        "@vue/runtime-core": "3.4.14",
+        "@vue/shared": "3.4.14",
         "csstype": "^3.1.3"
       }
     },
     "node_modules/@vue/server-renderer": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.6.tgz",
-      "integrity": "sha512-0LS+GXf3M93KloaK/S0ZPq5PnKERgPAV5iNCCpjyBLhAQGGEeqfJojs3yXOAMQLSvXi9FLYDHzDEOLWoLaYbTQ==",
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.14.tgz",
+      "integrity": "sha512-pwSKXQfYdJBTpvWHGEYI+akDE18TXAiLcGn+Q/2Fj8wQSHWztoo7PSvfMNqu6NDhp309QXXbPFEGCU5p85HqkA==",
       "dependencies": {
-        "@vue/compiler-ssr": "3.4.6",
-        "@vue/shared": "3.4.6"
+        "@vue/compiler-ssr": "3.4.14",
+        "@vue/shared": "3.4.14"
       },
       "peerDependencies": {
-        "vue": "3.4.6"
+        "vue": "3.4.14"
       }
     },
     "node_modules/@vue/shared": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.6.tgz",
-      "integrity": "sha512-O16vewA05D0IwfG2N/OFEuVeb17pieaI32mmYXp36V8lp+/pI1YV04rRL9Eyjndj3xQO5SNjAxTh6ul4IlBa3A=="
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.14.tgz",
+      "integrity": "sha512-nmi3BtLpvqXAWoRZ6HQ+pFJOHBU4UnH3vD3opgmwXac7vhaHKA9nj1VeGjMggdB9eLtW83eHyPCmOU1qzdsC7Q=="
     },
     "node_modules/@vue/tsconfig": {
       "version": "0.5.1",
@@ -3571,9 +3574,9 @@
       }
     },
     "node_modules/eslint-plugin-prettier": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.2.tgz",
-      "integrity": "sha512-dhlpWc9vOwohcWmClFcA+HjlvUpuyynYs0Rf+L/P6/0iQE6vlHW9l5bkfzN62/Stm9fbq8ku46qzde76T1xlSg==",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+      "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
       "dev": true,
       "dependencies": {
         "prettier-linter-helpers": "^1.0.0",
@@ -3934,9 +3937,9 @@
       "dev": true
     },
     "node_modules/follow-redirects": {
-      "version": "1.15.4",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
-      "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
+      "version": "1.15.5",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+      "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
       "dev": true,
       "funding": [
         {
@@ -4302,6 +4305,15 @@
         "he": "bin/he"
       }
     },
+    "node_modules/highlight.js": {
+      "version": "11.9.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz",
+      "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/hosted-git-info": {
       "version": "2.8.9",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -5638,9 +5650,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.9.4",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz",
-      "integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.5.tgz",
+      "integrity": "sha512-E4vQW0H/mbNMw2yLSqJyjtkHY9dslf/p0zuT1xehNRqUTBOFMqEjguDvqhXr7N7r/4ttb2jr4T41d3dncmIgbQ==",
       "dev": true,
       "dependencies": {
         "@types/estree": "1.0.5"
@@ -5653,19 +5665,19 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.9.4",
-        "@rollup/rollup-android-arm64": "4.9.4",
-        "@rollup/rollup-darwin-arm64": "4.9.4",
-        "@rollup/rollup-darwin-x64": "4.9.4",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.9.4",
-        "@rollup/rollup-linux-arm64-gnu": "4.9.4",
-        "@rollup/rollup-linux-arm64-musl": "4.9.4",
-        "@rollup/rollup-linux-riscv64-gnu": "4.9.4",
-        "@rollup/rollup-linux-x64-gnu": "4.9.4",
-        "@rollup/rollup-linux-x64-musl": "4.9.4",
-        "@rollup/rollup-win32-arm64-msvc": "4.9.4",
-        "@rollup/rollup-win32-ia32-msvc": "4.9.4",
-        "@rollup/rollup-win32-x64-msvc": "4.9.4",
+        "@rollup/rollup-android-arm-eabi": "4.9.5",
+        "@rollup/rollup-android-arm64": "4.9.5",
+        "@rollup/rollup-darwin-arm64": "4.9.5",
+        "@rollup/rollup-darwin-x64": "4.9.5",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.9.5",
+        "@rollup/rollup-linux-arm64-gnu": "4.9.5",
+        "@rollup/rollup-linux-arm64-musl": "4.9.5",
+        "@rollup/rollup-linux-riscv64-gnu": "4.9.5",
+        "@rollup/rollup-linux-x64-gnu": "4.9.5",
+        "@rollup/rollup-linux-x64-musl": "4.9.5",
+        "@rollup/rollup-win32-arm64-msvc": "4.9.5",
+        "@rollup/rollup-win32-ia32-msvc": "4.9.5",
+        "@rollup/rollup-win32-x64-msvc": "4.9.5",
         "fsevents": "~2.3.2"
       }
     },
@@ -5723,13 +5735,13 @@
       }
     },
     "node_modules/safe-array-concat": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
-      "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
+      "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.2.1",
+        "call-bind": "^1.0.5",
+        "get-intrinsic": "^1.2.2",
         "has-symbols": "^1.0.3",
         "isarray": "^2.0.5"
       },
@@ -5760,15 +5772,18 @@
       ]
     },
     "node_modules/safe-regex-test": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
-      "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz",
+      "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.3",
+        "call-bind": "^1.0.5",
+        "get-intrinsic": "^1.2.2",
         "is-regex": "^1.1.4"
       },
+      "engines": {
+        "node": ">= 0.4"
+      },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
@@ -5805,15 +5820,16 @@
       }
     },
     "node_modules/set-function-length": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
-      "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
+      "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==",
       "dev": true,
       "dependencies": {
         "define-data-property": "^1.1.1",
-        "get-intrinsic": "^1.2.1",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.2",
         "gopd": "^1.0.1",
-        "has-property-descriptors": "^1.0.0"
+        "has-property-descriptors": "^1.0.1"
       },
       "engines": {
         "node": ">= 0.4"
@@ -6398,15 +6414,15 @@
       }
     },
     "node_modules/vue": {
-      "version": "3.4.6",
-      "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.6.tgz",
-      "integrity": "sha512-gAzw5oP0/h34/yq1LjLNpn4wrCKYMuWp2jbs/JirFiZAFWYhd9jTkXp4wIi5ApgMJrMgD6YFyyXwKsqFYR31IQ==",
-      "dependencies": {
-        "@vue/compiler-dom": "3.4.6",
-        "@vue/compiler-sfc": "3.4.6",
-        "@vue/runtime-dom": "3.4.6",
-        "@vue/server-renderer": "3.4.6",
-        "@vue/shared": "3.4.6"
+      "version": "3.4.14",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.14.tgz",
+      "integrity": "sha512-Rop5Al/ZcBbBz+KjPZaZDgHDX0kUP4duEzDbm+1o91uxYUNmJrZSBuegsNIJvUGy+epLevNRNhLjm08VKTgGyw==",
+      "dependencies": {
+        "@vue/compiler-dom": "3.4.14",
+        "@vue/compiler-sfc": "3.4.14",
+        "@vue/runtime-dom": "3.4.14",
+        "@vue/server-renderer": "3.4.14",
+        "@vue/shared": "3.4.14"
       },
       "peerDependencies": {
         "typescript": "*"
diff --git a/package.json b/package.json
index c2043a5ef6a6f5b139896330faa509936a0a61a3..c803ad82b119752aa1aa9c6cea6eea7b3cd2f80c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
 {
   "name": "clowm-ui",
   "version": "2.0.0",
+  "type": "module",
   "scripts": {
     "dev": "vite",
     "build": "run-p type-check build-only",
@@ -51,6 +52,7 @@
     "axios": "~1.6.0",
     "eslint": "~8.48.0",
     "eslint-plugin-vue": "~9.19.0",
+    "highlight.js": "^11.9.0",
     "npm-run-all": "~4.1.5",
     "openapi-typescript-codegen": "^0.26.0",
     "prettier": "~3.0.3",
diff --git a/src/assets/main.css b/src/assets/main.css
index 5197334f91704d2434152d9854af2c6a8ad5c74f..cb6974cba0e2a5c6b64ede79fec9c1befe81c2f9 100644
--- a/src/assets/main.css
+++ b/src/assets/main.css
@@ -1,4 +1,5 @@
 @import "base.css";
+@import "highlight.js/styles/default.min.css";
 
 .fs-0 {
     font-size: 3.5rem;
@@ -28,3 +29,7 @@ pre {
     transform: translateY(-2px);
     backdrop-filter: brightness(0.95);
 }
+
+.hover-info:hover {
+    color: var(--bs-info) !important;
+}
diff --git a/src/components/BootstrapToast.vue b/src/components/BootstrapToast.vue
index cc2f27fa4ccb1d85280c05efe080bd4ea0e240c7..02b92fa3213f8d2e33e508645718abd4a6cadea4 100644
--- a/src/components/BootstrapToast.vue
+++ b/src/components/BootstrapToast.vue
@@ -10,9 +10,6 @@ const props = defineProps({
 const colorClassName = computed<string>(() => {
   return "text-bg-" + props.colorClass;
 });
-const emit = defineEmits<{
-  (e: "hidden.bs.toast"): void;
-}>();
 </script>
 
 <template>
@@ -25,7 +22,6 @@ const emit = defineEmits<{
       :class="colorClassName"
       data-bs-autohide="true"
       :id="props.toastId"
-      v-on="{ 'hidden.bs.toast': () => emit('hidden.bs.toast') }"
     >
       <div v-if="slots.body" class="toast-header" :class="colorClassName">
         <div class="me-auto">
diff --git a/src/components/CopyToClipboardIcon.vue b/src/components/CopyToClipboardIcon.vue
index ca9627edae2f091439e74c99253b5baf85519d72..b0d34b4967cf27383093ed940df08e07f934be79 100644
--- a/src/components/CopyToClipboardIcon.vue
+++ b/src/components/CopyToClipboardIcon.vue
@@ -6,6 +6,7 @@ import BootstrapToast from "@/components/BootstrapToast.vue";
 
 const props = defineProps<{
   text: string;
+  button?: boolean;
 }>();
 
 let successToast: Toast | null = null;
@@ -27,7 +28,9 @@ function copyToClipboard() {
 }
 
 onMounted(() => {
-  new Tooltip("#tooltip-" + randomIDSuffix);
+  if (!props.button) {
+    new Tooltip("#tooltip-" + randomIDSuffix);
+  }
   successToast = new Toast("#successToast-" + randomIDSuffix);
   failToast = new Toast("#failToast-" + randomIDSuffix);
 });
@@ -35,14 +38,18 @@ onMounted(() => {
 
 <template>
   <bootstrap-toast :toast-id="'successToast-' + randomIDSuffix"
-    >Successfully copied to clipboard</bootstrap-toast
-  >
+    >Successfully copied to clipboard
+  </bootstrap-toast>
   <bootstrap-toast
     :toast-id="'failToast-' + randomIDSuffix"
     color-class="danger"
     >Can't copy to clipboard
   </bootstrap-toast>
+  <button v-if="props.button" @click="copyToClipboard" class="btn btn-primary">
+    Copy to Clipboard
+  </button>
   <span
+    v-else
     class="hover-info cursor-pointer"
     data-bs-toggle="tooltip"
     data-bs-title="Copy to Clipboard"
@@ -52,8 +59,4 @@ onMounted(() => {
   </span>
 </template>
 
-<style scoped>
-.hover-info:hover {
-  color: var(--bs-info) !important;
-}
-</style>
+<style scoped></style>
diff --git a/src/components/modals/BootstrapModal.vue b/src/components/modals/BootstrapModal.vue
index 4e6fd34d52d553fe70460bc048f0d9461572f383..93e2a516247693235ce2f35e8001cd6c250d0a9e 100644
--- a/src/components/modals/BootstrapModal.vue
+++ b/src/components/modals/BootstrapModal.vue
@@ -1,9 +1,19 @@
 <script setup lang="ts">
-defineProps<{
+import { computed } from "vue";
+
+const props = defineProps<{
   modalID: string;
   modalLabel: string;
-  staticBackdrop: boolean;
+  staticBackdrop?: boolean;
+  sizeModifier?: string; // https://getbootstrap.com/docs/5.3/components/modal/#optional-sizes, e.g. sm, lg and xl
 }>();
+
+const modalSizeClass = computed<string>(() => {
+  if (props.sizeModifier == undefined) {
+    return "";
+  }
+  return "modal-" + props.sizeModifier;
+});
 </script>
 
 <template>
@@ -17,7 +27,7 @@ defineProps<{
   >
     <div
       class="modal-dialog modal-dialog-centered modal-dialog-scrollable"
-      style="min-width: 30%"
+      :class="[modalSizeClass]"
     >
       <div class="modal-content">
         <div class="modal-header">
@@ -38,7 +48,15 @@ defineProps<{
           <slot name="body" />
         </div>
         <div class="modal-footer">
-          <slot name="footer" />
+          <slot name="footer">
+            <button
+              type="button"
+              class="btn btn-secondary"
+              data-bs-dismiss="modal"
+            >
+              Close
+            </button>
+          </slot>
         </div>
       </div>
     </div>
diff --git a/src/components/resources/CreateResourceModal.vue b/src/components/resources/CreateResourceModal.vue
index 0f4e66decbabc00cf016b9b6bc77de7c069adc01..73dff643642779f6db6ea04235e1571fbc5a711d 100644
--- a/src/components/resources/CreateResourceModal.vue
+++ b/src/components/resources/CreateResourceModal.vue
@@ -4,6 +4,8 @@ import BootstrapModal from "@/components/modals/BootstrapModal.vue";
 import { Modal } from "bootstrap";
 import { useResourceStore } from "@/stores/resources";
 import type { ResourceIn } from "@/client/resource";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
+import { Tooltip } from "bootstrap";
 
 const resourceRepository = useResourceStore();
 
@@ -33,13 +35,8 @@ const props = defineProps<{
 
 let createResourceModal: Modal | null = null;
 
-onMounted(() => {
-  CreateResourceModal = new Modal("#" + props.modalID);
-});
-
 function createResource() {
   formState.validated = true;
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
   formState.resourceNameTaken = false;
   resource.description = resource.description.trim();
   resource.name = resource.name.trim();
@@ -49,7 +46,7 @@ function createResource() {
     resourceRepository
       .createResource(resource)
       .then(() => {
-        CreateResourceModal?.hide();
+        createResourceModal?.hide();
         resource.name = "";
         resource.description = "";
         resource.source = "";
@@ -81,17 +78,23 @@ function modalClosed() {
   formState.resourceNameTaken = false;
   resourceNameElement.value?.setCustomValidity("");
 }
+
+onMounted(() => {
+  createResourceModal = new Modal("#" + props.modalID);
+  new Tooltip("#tooltip-new-resource-source");
+  new Tooltip("#tooltip-new-resource-release");
+});
 </script>
 
 <template>
   <bootstrap-modal
     :modalID="modalID"
-    :static-backdrop="true"
+    static-backdrop
     modal-label="Create Resource Modal"
     v-on="{ 'hidden.bs.modal': modalClosed }"
   >
-    <template v-slot:header> Create new Resource</template>
-    <template v-slot:body>
+    <template #header> Create new Resource</template>
+    <template #body>
       <form
         id="resourceCreateForm"
         :class="{ 'was-validated': formState.validated }"
@@ -152,6 +155,9 @@ function modalClosed() {
         <div class="mb-3">
           <label for="resourceSourceInput" class="form-label"> Source </label>
           <div class="input-group">
+            <div class="input-group-text">
+              <font-awesome-icon icon="fa-solid fa-link" />
+            </div>
             <input
               class="form-control"
               id="resourceSourceInput"
@@ -161,11 +167,22 @@ function modalClosed() {
               v-model="resource.source"
               placeholder="The source of the resource (e.g. a link)"
             />
+            <div
+              class="input-group-text hover-info"
+              id="tooltip-new-resource-source"
+              data-bs-toggle="tooltip"
+              data-bs-title="The source from where the resource comes"
+            >
+              <font-awesome-icon icon="fa-solid fa-circle-question" />
+            </div>
           </div>
         </div>
         <div class="mb-3">
           <label for="resourceReleaseInput" class="form-label"> Release </label>
           <div class="input-group">
+            <div class="input-group-text">
+              <font-awesome-icon icon="fa-solid fa-tag" />
+            </div>
             <input
               class="form-control"
               id="resourceReleaseInput"
@@ -173,8 +190,16 @@ function modalClosed() {
               minlength="3"
               maxlength="32"
               v-model="resource.release"
-              placeholder="The name of the release"
+              placeholder="Initial release name"
             />
+            <div
+              class="input-group-text hover-info"
+              id="tooltip-new-resource-release"
+              data-bs-toggle="tooltip"
+              data-bs-title="The name of the first resource version"
+            >
+              <font-awesome-icon icon="fa-solid fa-circle-question" />
+            </div>
           </div>
         </div>
       </form>
diff --git a/src/components/resources/ResourceCard.vue b/src/components/resources/ResourceCard.vue
index 3aa21f21d83f3d2532a08f180d9d6d3ba322291f..ffcedbd14e886781a82c43eb4682f1f330439249 100644
--- a/src/components/resources/ResourceCard.vue
+++ b/src/components/resources/ResourceCard.vue
@@ -4,24 +4,77 @@ import {
   type ResourceVersionOut,
   Status,
 } from "@/client/resource";
-import { computed } from "vue";
+import { computed, onMounted, ref } from "vue";
 import dayjs from "dayjs";
 import { useAuthStore } from "@/stores/users";
 import CopyToClipboardIcon from "@/components/CopyToClipboardIcon.vue";
 import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
+import { useS3ObjectStore } from "@/stores/s3objects";
+import { useResourceStore } from "@/stores/resources";
+import { Tooltip } from "bootstrap";
 
 const randomIDSuffix: string = Math.random().toString(16).substring(2, 8);
 const userRepository = useAuthStore();
+const objectRepository = useS3ObjectStore();
+const resourceRepository = useResourceStore();
 
 const props = defineProps<{
   resource: ResourceOut;
   loading: boolean;
   extended?: boolean;
 }>();
+let refreshTimeout: NodeJS.Timeout | undefined = undefined;
+
+const emit = defineEmits<{
+  (e: "click-info", resourceVersion: ResourceVersionOut): void;
+}>();
+
+const resourceVersionS3Ready = ref<Record<string, boolean>>({});
 
 const resourceVersions = computed<ResourceVersionOut[]>(
   () => props.resource.versions,
 );
+
+function checkS3Resource(resourceVersion: ResourceVersionOut) {
+  const bucket = resourceVersion.s3_path.slice(5).split("/")[0];
+  const key = resourceVersion.s3_path.split(bucket)[1].slice(1);
+  objectRepository
+    .fetchS3ObjectMeta(bucket, key)
+    .then(() => {
+      resourceVersionS3Ready.value[resourceVersion.resource_version_id] = true;
+    })
+    .catch(() => {
+      resourceVersionS3Ready.value[resourceVersion.resource_version_id] = false;
+    });
+}
+
+function clickCheckS3Resource(resourceVersion: ResourceVersionOut) {
+  clearTimeout(refreshTimeout);
+  refreshTimeout = setTimeout(() => {
+    checkS3Resource(resourceVersion);
+  }, 500);
+}
+
+function requestSynchronization(resourceVersion: ResourceVersionOut) {
+  resourceRepository.requestSynchronization(resourceVersion);
+}
+
+onMounted(() => {
+  if (!props.loading) {
+    for (const r of props.resource.versions) {
+      if (r.status == Status.RESOURCE_REQUESTED) {
+        checkS3Resource(r);
+      }
+    }
+    [
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+      // @ts-ignore
+      ...(document
+        .querySelector("#resource-card-" + randomIDSuffix)
+        ?.querySelectorAll("[data-bs-toggle='tooltip']") ?? []),
+    ].map((el) => new Tooltip(el));
+  }
+});
 </script>
 
 <template>
@@ -63,7 +116,8 @@ const resourceVersions = computed<ResourceVersionOut[]>(
               <button
                 class="accordion-button"
                 :class="{
-                  collapsed: resourceVersion.status != Status.LATEST,
+                  collapsed:
+                    resourceVersion.status != Status.LATEST || props.extended,
                 }"
                 type="button"
                 data-bs-toggle="collapse"
@@ -71,7 +125,9 @@ const resourceVersions = computed<ResourceVersionOut[]>(
                   '#collapseResourceVersion-' +
                   resourceVersion.resource_version_id
                 "
-                :aria-expanded="resourceVersion.status == Status.LATEST"
+                :aria-expanded="
+                  resourceVersion.status == Status.LATEST && !props.extended
+                "
                 :aria-controls="
                   '#collapseResourceVersion-' +
                   resourceVersion.resource_version_id
@@ -85,16 +141,60 @@ const resourceVersions = computed<ResourceVersionOut[]>(
                 'collapseResourceVersion-' + resourceVersion.resource_version_id
               "
               class="accordion-collapse collapse"
-              :class="{ show: resourceVersion.status == Status.LATEST }"
+              :class="{
+                show:
+                  resourceVersion.status == Status.LATEST && !props.extended,
+              }"
               :data-bs-parent="'#accordion-' + props.resource.resource_id"
             >
               <div class="accordion-body">
                 <div>
-                  Last Updated:
+                  Created at:
                   {{
                     dayjs.unix(resourceVersion.created_at).format("DD MMM YYYY")
                   }}
                 </div>
+                <div
+                  v-if="
+                    props.extended &&
+                    (resourceVersion.status == Status.RESOURCE_REQUESTED ||
+                      resourceVersion.status == Status.CLUSTER_DELETED)
+                  "
+                >
+                  <div class="btn-group" role="group">
+                    <button
+                      type="button"
+                      class="btn btn-primary"
+                      data-bs-toggle="modal"
+                      data-bs-target="#uploadResourceInfoModal"
+                      @click="emit('click-info', resourceVersion)"
+                    >
+                      <font-awesome-icon icon="fa-solid fa-circle-question" />
+                    </button>
+                    <button
+                      type="button"
+                      class="btn btn-primary"
+                      :disabled="
+                        !resourceVersionS3Ready[
+                          resourceVersion.resource_version_id
+                        ]
+                      "
+                      @click="requestSynchronization(resourceVersion)"
+                    >
+                      Request Synchronization
+                    </button>
+                    <button
+                      v-if="resourceVersion.status == Status.RESOURCE_REQUESTED"
+                      type="button"
+                      class="btn btn-primary"
+                      @click="clickCheckS3Resource(resourceVersion)"
+                    >
+                      <font-awesome-icon
+                        icon="fa-solid fa-arrow-rotate-right"
+                      />
+                    </button>
+                  </div>
+                </div>
                 <div
                   v-if="
                     resourceVersion.status === Status.SYNCHRONIZED ||
@@ -111,6 +211,17 @@ const resourceVersions = computed<ResourceVersionOut[]>(
                     >Nextflow Access Path:</label
                   >
                   <div class="input-group fs-4 mb-3">
+                    <div
+                      class="input-group-text hover-info"
+                      :id="
+                        'tooltip-cluster-path-' +
+                        resourceVersion.resource_version_id
+                      "
+                      data-bs-toggle="tooltip"
+                      data-bs-title="Path on the cluster where a workflow can access the resource"
+                    >
+                      <font-awesome-icon icon="fa-solid fa-circle-question" />
+                    </div>
                     <input
                       :id="
                         'nextflow-access-path-' +
@@ -124,7 +235,7 @@ const resourceVersions = computed<ResourceVersionOut[]>(
                     />
                     <span class="input-group-text"
                       ><copy-to-clipboard-icon
-                        :text="resourceVersion.cluster_path"
+                        :text="resourceVersion.cluster_path ?? ''"
                     /></span>
                   </div>
                 </div>
@@ -140,9 +251,19 @@ const resourceVersions = computed<ResourceVersionOut[]>(
                       's3-access-path-' + resourceVersion.resource_version_id
                     "
                     class="form-label"
-                    >S3 Path:</label
+                    >S3 Upload Path:</label
                   >
                   <div class="input-group fs-4 mb-3">
+                    <div
+                      class="input-group-text hover-info"
+                      :id="
+                        'tooltip-s3-path-' + resourceVersion.resource_version_id
+                      "
+                      data-bs-toggle="tooltip"
+                      data-bs-title="S3 Path where the resource should be uploaded"
+                    >
+                      <font-awesome-icon icon="fa-solid fa-circle-question" />
+                    </div>
                     <input
                       :id="
                         's3-access-path-' + resourceVersion.resource_version_id
diff --git a/src/components/resources/UploadResourceInfoModal.vue b/src/components/resources/UploadResourceInfoModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5d72c70b9be927fa586bfb3cca16eb778bc03771
--- /dev/null
+++ b/src/components/resources/UploadResourceInfoModal.vue
@@ -0,0 +1,337 @@
+<script setup lang="ts">
+import BootstrapModal from "@/components/modals/BootstrapModal.vue";
+import { type ResourceVersionOut, Status } from "@/client/resource";
+import { computed, onMounted, ref, watch } from "vue";
+import { environment } from "@/environment";
+import CopyToClipboardIcon from "@/components/CopyToClipboardIcon.vue";
+import { useS3KeyStore } from "@/stores/s3keys";
+import type { S3Key } from "@/client/s3proxy";
+import { useS3ObjectStore } from "@/stores/s3objects";
+import { useResourceStore } from "@/stores/resources";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
+import { Modal } from "bootstrap";
+
+const props = defineProps<{
+  modalId: string;
+  resourceVersion?: ResourceVersionOut;
+}>();
+
+const s3KeyRepository = useS3KeyStore();
+const objectRepository = useS3ObjectStore();
+const resourceRepository = useResourceStore();
+
+let infoResourceModal: Modal | null = null;
+let refreshTimeout: NodeJS.Timeout | undefined = undefined;
+
+enum Tool {
+  PYTHON = "python",
+  S5CMD = "s5cmd",
+  MINIO = "minio",
+}
+
+watch(
+  () => props.resourceVersion,
+  (newVersion, oldVersion) => {
+    if (newVersion?.resource_version_id !== oldVersion?.resource_version_id) {
+      resourceSynchronizationEnabled.value = false;
+      if (newVersion?.status === Status.RESOURCE_REQUESTED) {
+        checkS3Resource(newVersion);
+      }
+    }
+  },
+);
+
+const activeTool = ref<Tool>(Tool.S5CMD);
+const resourceSynchronizationEnabled = ref<boolean>(false);
+
+const resourceS3Path = computed<string>(() => {
+  return (
+    props.resourceVersion?.s3_path ??
+    "s3://examplebucket/RESOURCE-ID/RESOURCE-VERSION-ID/resource.tar.gz"
+  );
+});
+const resourceMinioS3Path = computed<string>(() => {
+  return resourceS3Path.value.slice(5);
+});
+const resourceBucket = computed<string>(() => {
+  return resourceMinioS3Path.value.split("/")[0];
+});
+const resourceKey = computed<string>(() => {
+  return resourceS3Path.value.split(resourceBucket.value)[1].slice(1);
+});
+const codeExample = computed<string>(() => {
+  if (activeTool.value === Tool.S5CMD) {
+    return `export AWS_REGION="us-west-1"
+export AWS_ACCESS_KEY_ID="${s3Key.value.access_key}"
+export AWS_SECRET_ACCESS_KEY="${s3Key.value.secret_key}"
+export S3_ENDPOINT="${environment.S3_URL}"
+
+s5cmd cp --show-progress /PATH/TO/RESOURCE \\
+  ${resourceS3Path.value}`;
+  } else if (activeTool.value === Tool.MINIO) {
+    return `mc alias set ${environment.S3_URL} "${s3Key.value.access_key}" "${s3Key.value.secret_key}"
+mc cp /PATH/TO/RESOURCE \\
+  clowm-s3/clowm-resources/CLDB-eaa7aae4/eaaa1c99b14911ee9f5d0242ac120004/resource.tar.gz`;
+  } else if (activeTool.value === Tool.PYTHON) {
+    return `import boto3
+
+s3 = boto3.resource(
+  service_name="s3",
+  aws_access_key_id="${s3Key.value.access_key}",
+  aws_secret_access_key="${s3Key.value.secret_key}",
+  endpoint_url="${environment.S3_URL}",
+  verify=True,
+)
+
+with open("/PATH/TO/RESOURCE", "rb") as f:
+  s3.Object(
+    bucket="${resourceBucket.value}",
+    key="${resourceKey.value}"
+  ).upload_fileobj(f)`;
+  }
+  return "";
+});
+
+const s3Key = computed<S3Key>(() => {
+  return (
+    s3KeyRepository.keys[0] ?? {
+      access_key: "abc",
+      secret_key: "def",
+    }
+  );
+});
+
+function checkS3Resource(resourceVersion: ResourceVersionOut) {
+  const bucket = resourceVersion.s3_path.slice(5).split("/")[0];
+  const key = resourceVersion.s3_path.split(bucket)[1].slice(1);
+  objectRepository
+    .fetchS3ObjectMeta(bucket, key)
+    .then(() => {
+      resourceSynchronizationEnabled.value = true;
+    })
+    .catch(() => {
+      resourceSynchronizationEnabled.value = false;
+    });
+}
+
+function clickCheckS3Resource(resourceVersion: ResourceVersionOut) {
+  clearTimeout(refreshTimeout);
+  refreshTimeout = setTimeout(() => {
+    checkS3Resource(resourceVersion);
+  }, 500);
+}
+
+function requestSynchronization(resourceVersion: ResourceVersionOut) {
+  resourceRepository.requestSynchronization(resourceVersion).then(() => {
+    infoResourceModal?.hide();
+  });
+}
+
+onMounted(() => {
+  infoResourceModal = new Modal("#" + props.modalId);
+});
+</script>
+
+<template>
+  <bootstrap-modal
+    :modalID="props.modalId"
+    modal-label="Upload Resource Info Modal"
+    sizeModifier="lg"
+  >
+    <template #header>How to upload a resource to the cluster</template>
+    <template #body>
+      <ol>
+        <li :class="{ 'text-decoration-line-through': props.resourceVersion }">
+          <h6>
+            Prerequisite: Prepare a single compressed tar archive of your data
+          </h6>
+          <p :hidden="props.resourceVersion != undefined">
+            The data of your resource must be compressed into a single tar
+            archive to save bandwidth and storage space.<br />
+            <code>tar -czf resource.tar.gz /PATH/TO/MY/RESOURCE/DATA</code>
+          </p>
+        </li>
+        <li :class="{ 'text-decoration-line-through': props.resourceVersion }">
+          <h6>Request a resource in CloWM</h6>
+          <p :hidden="props.resourceVersion != undefined">
+            Click on <b>Create Resource</b> and fill out the form
+          </p>
+        </li>
+        <li
+          :class="{
+            'text-decoration-line-through': resourceSynchronizationEnabled,
+          }"
+        >
+          <h6>Upload the resource</h6>
+          <template v-if="!resourceSynchronizationEnabled">
+            <p>
+              Upload the tar archive to the provided S3 path with a tool of your
+              choice.
+            </p>
+            <ul class="nav nav-tabs mb-2">
+              <li class="nav-item">
+                <a
+                  class="nav-link"
+                  :class="{ active: activeTool === Tool.S5CMD }"
+                  aria-current="page"
+                  href="#"
+                  @click="activeTool = Tool.S5CMD"
+                  >s5cmd</a
+                >
+              </li>
+              <li class="nav-item">
+                <a
+                  class="nav-link"
+                  :class="{ active: activeTool === Tool.MINIO }"
+                  href="#"
+                  @click="activeTool = Tool.MINIO"
+                  >Minio</a
+                >
+              </li>
+              <li class="nav-item">
+                <a
+                  class="nav-link"
+                  :class="{ active: activeTool === Tool.PYTHON }"
+                  href="#"
+                  @click="activeTool = Tool.PYTHON"
+                  >Python</a
+                >
+              </li>
+            </ul>
+            <template v-if="activeTool === Tool.S5CMD">
+              <p>
+                <code>s5cmd</code> is a very fast S3 and local filesystem
+                execution tool. It comes with support for a multitude of
+                operations including tab completion and wildcard support for
+                files, which can be very handy for your object storage workflow
+                while working with large number of files.
+              </p>
+              <p>
+                The GitHub repository contains a
+                <a
+                  href="https://github.com/peak/s5cmd?tab=readme-ov-file#installation"
+                  target="_blank"
+                  >installation guide</a
+                >.
+              </p>
+              <pre class="w-100"><code class="hljs language-bash"><span
+                  class="hljs-built_in">export</span> AWS_REGION=<span class="hljs-string">"us-west-1"</span>
+<span class="hljs-built_in">export</span> AWS_ACCESS_KEY_ID=<span class="hljs-string">"{{ s3Key.access_key }}"</span>
+<span class="hljs-built_in">export</span> AWS_SECRET_ACCESS_KEY=<span class="hljs-string">"{{
+                    s3Key.secret_key
+                  }}"</span>
+<span class="hljs-built_in">export</span> S3_ENDPOINT=<span class="hljs-string">"{{ environment.S3_URL }}"</span>
+
+<span class="hljs-built_in">s5cmd</span> cp --show-progress /PATH/TO/RESOURCE \
+  {{ resourceS3Path }}</code></pre>
+            </template>
+            <template v-else-if="activeTool === Tool.MINIO">
+              <p>
+                The MinIO Client <code>mc</code> command line tool provides a
+                modern alternative to UNIX commands like <code>ls</code>,
+                <code>cat</code>, <code>cp</code>, <code>mirror</code>, and
+                <code>diff</code> with support for both filesystems and Amazon
+                S3-compatible cloud storage services.
+              </p>
+              <p>
+                The official documentation contains a
+                <a
+                  href="https://min.io/docs/minio/linux/reference/minio-mc.html#install-mc"
+                  target="_blank"
+                  >installation guide</a
+                >.
+              </p>
+              <pre
+                class="w-100"
+              ><code class="hljs language-bash">mc <span class="hljs-built_in">alias</span> <span
+                  class="hljs-built_in">set</span> {{ environment.S3_URL }} <span
+                  class="hljs-string">"{{ s3Key.access_key }}"</span> <span
+                  class="hljs-string">"{{ s3Key.secret_key }}"</span>
+mc <span class="hljs-built_in">cp</span> /PATH/TO/RESOURCE \
+  clowm-s3/{{ resourceMinioS3Path }}</code></pre>
+            </template>
+            <template v-else-if="activeTool === Tool.PYTHON">
+              <p>
+                You use the AWS SDK for Python (<a
+                  href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"
+                  target="_blank"
+                  >Boto3</a
+                >) to create, configure, and manage AWS services, such as Amazon
+                Elastic Compute Cloud (Amazon EC2) and Amazon Simple Storage
+                Service (Amazon S3). The SDK provides an object-oriented API as
+                well as low-level access to AWS services.
+              </p>
+              <p>
+                The package can be installed with pip:
+                <code>pip install boto3</code>
+              </p>
+              <pre
+                class="w-100"
+              ><code class="hljs language-python"><span class="hljs-keyword">import</span> boto3
+
+s3 = boto3.resource(
+  service_name=<span class="hljs-string">"s3"</span>,
+  aws_access_key_id=<span class="hljs-string">"{{ s3Key.access_key }}"</span>,
+  aws_secret_access_key=<span class="hljs-string">"{{ s3Key.secret_key }}"</span>,
+  endpoint_url=<span class="hljs-string">"{{ environment.S3_URL }}"</span>,
+  verify=<span class="hljs-literal">True</span>,
+)
+
+<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">"/PATH/TO/RESOURCE"</span>, <span
+                    class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f:
+  s3.Object(
+    bucket=<span class="hljs-string">"{{ resourceBucket }}"</span>,
+    key=<span class="hljs-string">"{{ resourceKey }}"</span>
+  ).upload_fileobj(f)</code></pre>
+            </template>
+          </template>
+        </li>
+        <li>
+          <h6>Request a synchronization</h6>
+          <p>
+            Click <b>Request Synchronization</b> to request the synchronization
+            to CloWM's compute cluster.
+          </p>
+          <div class="btn-group" role="group" v-if="props.resourceVersion">
+            <button
+              type="button"
+              class="btn btn-primary"
+              :disabled="!resourceSynchronizationEnabled"
+              @click="requestSynchronization(props.resourceVersion)"
+            >
+              Request Synchronization
+            </button>
+            <button
+              v-if="props.resourceVersion.status === Status.RESOURCE_REQUESTED"
+              type="button"
+              class="btn btn-primary"
+              @click="clickCheckS3Resource(props.resourceVersion)"
+            >
+              <font-awesome-icon icon="fa-solid fa-arrow-rotate-right" />
+            </button>
+          </div>
+        </li>
+        <li>
+          <h6>Resource availability</h6>
+          <p>
+            Once a Reviewer approves your resource synchronization request, the
+            resource will be made available in CloWM and is accessible for every
+            workflow via its <b>Nextflow Access Path</b>.
+          </p>
+        </li>
+      </ol>
+    </template>
+    <template #footer>
+      <copy-to-clipboard-icon
+        v-if="props.resourceVersion && !resourceSynchronizationEnabled"
+        button
+        :text="codeExample"
+      />
+      <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
+        Close
+      </button>
+    </template>
+  </bootstrap-modal>
+</template>
+
+<style scoped></style>
diff --git a/src/components/workflows/modals/ArbitraryWorkflowModal.vue b/src/components/workflows/modals/ArbitraryWorkflowModal.vue
index 65fce9d4fdd315b462ea2d30d1efef49c07a3238..18dedf30b4120162f9e23b1d71bc5e1d0536cc1a 100644
--- a/src/components/workflows/modals/ArbitraryWorkflowModal.vue
+++ b/src/components/workflows/modals/ArbitraryWorkflowModal.vue
@@ -424,8 +424,4 @@ onMounted(() => {
   </bootstrap-modal>
 </template>
 
-<style scoped>
-.hover-info:hover {
-  color: var(--bs-info) !important;
-}
-</style>
+<style scoped></style>
diff --git a/src/components/workflows/modals/CreateWorkflowModal.vue b/src/components/workflows/modals/CreateWorkflowModal.vue
index 7c24bca94610127acde85bb4d3bcaa635158ca5f..29c41c3d872c296de6de777bc4181336c41ddd0a 100644
--- a/src/components/workflows/modals/CreateWorkflowModal.vue
+++ b/src/components/workflows/modals/CreateWorkflowModal.vue
@@ -684,8 +684,4 @@ onMounted(() => {
   </bootstrap-modal>
 </template>
 
-<style scoped>
-.hover-info:hover {
-  color: var(--bs-info) !important;
-}
-</style>
+<style scoped></style>
diff --git a/src/router/workflowRoutes.ts b/src/router/workflowRoutes.ts
index 05aab0ef40732d2b879ef9b3f80063e8fa340fe7..9d53737130d2766e62b44667122b634c71713747 100644
--- a/src/router/workflowRoutes.ts
+++ b/src/router/workflowRoutes.ts
@@ -47,7 +47,7 @@ export const workflowRoutes: RouteRecordRaw[] = [
       versionId: route.params.versionId ?? undefined,
       workflowId: route.params.workflowId,
       workflowModeId: route.query.workflowModeId ?? undefined,
-      developerView: route.query.developerView == "true" ?? false,
+      developerView: route.query.developerView == "true",
     }),
     children: [
       {
diff --git a/src/stores/resources.ts b/src/stores/resources.ts
index ab5e18d1eb9c25978c0f6663daf896e6c65e5fb4..49516a1437df2aa594ee2b45d56225b6cb8b9fa2 100644
--- a/src/stores/resources.ts
+++ b/src/stores/resources.ts
@@ -1,6 +1,10 @@
 import { defineStore } from "pinia";
-import type { ResourceIn, ResourceOut } from "@/client/resource";
-import { ResourceService } from "@/client/resource";
+import type {
+  ResourceIn,
+  ResourceOut,
+  ResourceVersionOut,
+} from "@/client/resource";
+import { ResourceService, ResourceVersionService } from "@/client/resource";
 import { useAuthStore } from "@/stores/users";
 import { Status } from "@/client/resource";
 
@@ -38,6 +42,23 @@ export const useResourceStore = defineStore({
         })
         .finally(onFinally);
     },
+    fetchOwnResource(
+      resource_id: string,
+      onFinally?: () => void,
+    ): Promise<ResourceOut> {
+      if (this.ownResourceMapping[resource_id]) {
+        onFinally?.();
+      }
+      return ResourceService.resourceGetResource(
+        resource_id,
+        Object.values(Status),
+      )
+        .then((resource) => {
+          this.ownResourceMapping[resource.resource_id] = resource;
+          return resource;
+        })
+        .finally(onFinally);
+    },
     fetchOwnResources(onFinally?: () => void): Promise<ResourceOut[]> {
       const authStore = useAuthStore();
       if (Object.keys(this.ownResourceMapping).length > 0) {
@@ -63,5 +84,37 @@ export const useResourceStore = defineStore({
       this.ownResourceMapping[createdResource.resource_id] = createdResource;
       return createdResource;
     },
+    requestSynchronization(
+      resourceVersion: ResourceVersionOut,
+    ): Promise<ResourceVersionOut> {
+      return ResourceVersionService.resourceVersionRequestResourceVersionSync(
+        resourceVersion.resource_id,
+        resourceVersion.resource_version_id,
+      ).then((changedResourceVersion) => {
+        if (
+          this.ownResourceMapping[changedResourceVersion.resource_id] ==
+          undefined
+        ) {
+          this.fetchOwnResource(resourceVersion.resource_id);
+        }
+        const versionIndex = this.ownResourceMapping[
+          changedResourceVersion.resource_id
+        ].versions.findIndex(
+          (version) =>
+            version.resource_version_id ==
+            changedResourceVersion.resource_version_id,
+        );
+        if (versionIndex > -1) {
+          this.ownResourceMapping[changedResourceVersion.resource_id].versions[
+            versionIndex
+          ] = changedResourceVersion;
+        } else {
+          this.ownResourceMapping[
+            changedResourceVersion.resource_id
+          ].versions.push(changedResourceVersion);
+        }
+        return changedResourceVersion;
+      });
+    },
   },
 });
diff --git a/src/views/resources/MyResourcesView.vue b/src/views/resources/MyResourcesView.vue
index bb6bcccdef8ec7d35e0018924ae687b84472f20c..11dcacb77b685acd8835e7258b14199d3e807840 100644
--- a/src/views/resources/MyResourcesView.vue
+++ b/src/views/resources/MyResourcesView.vue
@@ -4,48 +4,114 @@ import { useResourceStore } from "@/stores/resources";
 import CardTransitionGroup from "@/components/transitions/CardTransitionGroup.vue";
 import ResourceCard from "@/components/resources/ResourceCard.vue";
 import CreateResourceModal from "@/components/resources/CreateResourceModal.vue";
+import UploadResourceInfoModal from "@/components/resources/UploadResourceInfoModal.vue";
+import { useS3KeyStore } from "@/stores/s3keys";
+import type { ResourceVersionOut } from "@/client/resource";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
 
 const resourceRepository = useResourceStore();
+const s3KeyRepository = useS3KeyStore();
 
 const resourceState = reactive<{
   loading: boolean;
+  resourceVersionInfo?: ResourceVersionOut;
 }>({
   loading: true,
+  resourceVersionInfo: undefined,
 });
 
+function setResourceVersionInfo(resourceVersionInfo?: ResourceVersionOut) {
+  resourceState.resourceVersionInfo = resourceVersionInfo;
+}
+
 onMounted(() => {
-  resourceRepository.fetchOwnResources(() => {
-    resourceState.loading = false;
+  let fetchedResources = false;
+  s3KeyRepository.fetchS3Keys(() => {
+    if (!fetchedResources) {
+      fetchedResources = true;
+      resourceRepository.fetchOwnResources(() => {
+        resourceState.loading = false;
+      });
+    }
   });
 });
 </script>
 
 <template>
   <create-resource-modal modal-i-d="createResourceModal" />
+  <upload-resource-info-modal
+    modal-id="uploadResourceInfoModal"
+    :resource-version="resourceState.resourceVersionInfo"
+  />
   <div
     class="row m-2 border-bottom mb-4 justify-content-between align-items-center pb-2"
   >
     <h2 class="w-fit">My Resources</h2>
-    <button
-      class="btn btn-lg btn-primary w-fit"
-      data-bs-toggle="modal"
-      data-bs-target="#createResourceModal"
+    <div class="w-fit">
+      <button
+        type="button"
+        class="btn btn-info btn-lg w-fit me-3"
+        data-bs-toggle="modal"
+        data-bs-target="#uploadResourceInfoModal"
+        @click="setResourceVersionInfo(undefined)"
+      >
+        Tutorial
+      </button>
+      <button
+        class="btn btn-lg btn-primary w-fit"
+        data-bs-toggle="modal"
+        data-bs-target="#createResourceModal"
+      >
+        Create Resource
+      </button>
+    </div>
+  </div>
+  <div v-if="!resourceState.loading">
+    <div
+      v-if="resourceRepository.ownResources.length === 0"
+      class="text-center fs-2 mt-5"
+    >
+      <font-awesome-icon
+        icon="fa-solid fa-x"
+        class="my-5 fs-0"
+        style="color: var(--bs-secondary)"
+      />
+      <p>You don't have any resources registered in the system.</p>
+    </div>
+    <CardTransitionGroup
+      v-else
+      class="d-flex flex-wrap align-items-center justify-content-between"
     >
-      Create
-    </button>
+      <resource-card
+        v-for="resource in resourceRepository.ownResources"
+        :key="resource.resource_id"
+        :resource="resource"
+        :loading="false"
+        style="width: 48%"
+        extended
+        @click-info="setResourceVersionInfo"
+      />
+    </CardTransitionGroup>
   </div>
-  <CardTransitionGroup
+  <div
+    v-else
     class="d-flex flex-wrap align-items-center justify-content-between"
   >
     <resource-card
-      v-for="resource in resourceRepository.ownResources"
-      :key="resource.resource_id"
-      :resource="resource"
-      :loading="false"
-      style="width: 48%"
-      extended
+      v-for="resource in 4"
+      :key="resource"
+      :resource="{
+        name: '',
+        description: '',
+        source: '',
+        resource_id: '',
+        versions: [],
+        maintainer_id: '',
+      }"
+      style="min-width: 48%"
+      loading
     />
-  </CardTransitionGroup>
+  </div>
 </template>
 
 <style scoped></style>
diff --git a/src/views/workflows/WorkflowView.vue b/src/views/workflows/WorkflowView.vue
index 2ece0235006271559b4ecc77ba7946f48e5f0a49..01af1de7bc9f51bc266acb9537eaf915083809f7 100644
--- a/src/views/workflows/WorkflowView.vue
+++ b/src/views/workflows/WorkflowView.vue
@@ -157,7 +157,7 @@ const activeVersionIcon = computed<string | undefined>(
 );
 
 const versionLaunchable = computed<boolean>(
-  () => activeVersion.value?.status == Status.PUBLISHED ?? false,
+  () => activeVersion.value?.status == Status.PUBLISHED,
 );
 
 const gitIcon = computed<string>(() =>