From a5b6232bac65c9358b730981f2b5663cb93db5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20G=C3=B6bel?= <dgoebel@techfak.uni-bielefeld.de> Date: Fri, 3 Mar 2023 11:06:55 +0100 Subject: [PATCH] Rework navbar and folder structure #35 --- Dockerfile | 2 +- index.html | 2 +- src/assets/main.css | 2 - src/components/NavbarTop.vue | 148 +++++++++--------- .../{Modals => modals}/BootstrapModal.vue | 0 .../{Modals => modals}/DeleteModal.vue | 2 +- .../{Modals => modals}/SearchUserModal.vue | 2 +- .../{ => object-storage}/BucketListItem.vue | 4 +- .../{ => object-storage}/BucketView.vue | 14 +- .../{ => object-storage}/S3KeyView.vue | 2 +- .../modals}/BucketDetailModal.vue | 2 +- .../modals}/CopyObjectModal.vue | 2 +- .../modals}/CreateBucketModal.vue | 2 +- .../modals}/CreateFolderModal.vue | 2 +- .../modals}/ObjectDetailModal.vue | 2 +- .../modals}/PermissionListModal.vue | 4 +- .../modals}/PermissionModal.vue | 8 +- .../modals}/UploadObjectModal.vue | 2 +- src/router/index.ts | 3 +- src/stores/auth.ts | 2 +- src/views/object-storage/BucketsView.vue | 6 +- src/views/object-storage/S3KeysView.vue | 2 +- 22 files changed, 111 insertions(+), 104 deletions(-) rename src/components/{Modals => modals}/BootstrapModal.vue (100%) rename src/components/{Modals => modals}/DeleteModal.vue (97%) rename src/components/{Modals => modals}/SearchUserModal.vue (98%) rename src/components/{ => object-storage}/BucketListItem.vue (96%) rename src/components/{ => object-storage}/BucketView.vue (98%) rename src/components/{ => object-storage}/S3KeyView.vue (97%) rename src/components/{Modals => object-storage/modals}/BucketDetailModal.vue (96%) rename src/components/{Modals => object-storage/modals}/CopyObjectModal.vue (98%) rename src/components/{Modals => object-storage/modals}/CreateBucketModal.vue (98%) rename src/components/{Modals => object-storage/modals}/CreateFolderModal.vue (98%) rename src/components/{Modals => object-storage/modals}/ObjectDetailModal.vue (96%) rename src/components/{Modals => object-storage/modals}/PermissionListModal.vue (96%) rename src/components/{Modals => object-storage/modals}/PermissionModal.vue (98%) rename src/components/{Modals => object-storage/modals}/UploadObjectModal.vue (99%) diff --git a/Dockerfile b/Dockerfile index eb4c7fb..a4eba23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN npm run build-only # production stage FROM nginx:stable-alpine as production-stage -HEALTHCHECK --interval=35s --timeout=4s CMD curl -f http://localhost || exit 1 +HEALTHCHECK --interval=35s --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 diff --git a/index.html b/index.html index 0aa6bdd..482eda9 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ <meta charset="UTF-8" /> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>S3 Proxy</title> + <title>CloWM</title> <script src="/env.js"></script> </head> <body> diff --git a/src/assets/main.css b/src/assets/main.css index a78c1e6..06d798e 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,7 +1,5 @@ @import "base.css"; body { - padding-top: 4rem; - max-height: 100vh; background: #181818; } diff --git a/src/components/NavbarTop.vue b/src/components/NavbarTop.vue index 2f8132b..81a6b2e 100644 --- a/src/components/NavbarTop.vue +++ b/src/components/NavbarTop.vue @@ -1,29 +1,16 @@ <script setup lang="ts"> import BootstrapIcon from "@/components/BootstrapIcon.vue"; -import { reactive, onBeforeUnmount, onMounted } from "vue"; -// import { MiscellaneousService } from "@/client/auth"; import { useAuthStore } from "@/stores/auth"; import { useRoute, useRouter } from "vue-router"; import { useCookies } from "vue3-cookies"; -import { watch, ref } from "vue"; +import { watch, ref, computed } from "vue"; +import type { ComputedRef } from "vue"; const router = useRouter(); const store = useAuthStore(); const { cookies } = useCookies(); const route = useRoute(); -const api_connection = reactive({ connected: true, timer: null }); -let timer: ReturnType<typeof setInterval> | undefined = undefined; -function checkApiHealth() { - // MiscellaneousService.miscellaneousHealthCheck() - // .then(() => { - // api_connection.connected = true; - // }) - // .catch(() => { - // api_connection.connected = false; - // }); -} - function logout() { store.logout(); cookies.remove("bearer"); @@ -31,6 +18,9 @@ function logout() { } const activeRoute = ref(""); +const objectStorageActive: ComputedRef<boolean> = computed( + () => activeRoute.value == "buckets" || activeRoute.value == "s3_keys" +); watch( () => route.name, @@ -48,19 +38,23 @@ watch( } } ); - -onMounted(() => { - checkApiHealth(); - timer = setInterval(checkApiHealth, 20000); -}); -onBeforeUnmount(() => { - clearInterval(timer); -}); </script> <template> - <nav class="navbar navbar-dark fixed-top navbar-expand-lg bg-dark"> - <div class="container-fluid text-light"> + <header class="navbar navbar-expand-lg navbar-dark bd-navbar sticky-top"> + <nav class="container-xxl bd-gutter flex-wrap flex-lg-nowrap text-light"> + <button + class="navbar-toggler" + type="button" + data-bs-toggle="collapse" + data-bs-target="#navDropdown" + aria-controls="navDropdown" + aria-expanded="false" + aria-label="Toggle navigation" + v-if="store.authenticated" + > + <span class="navbar-toggler-icon"></span> + </button> <router-link class="navbar-brand ms-3" to="/"> <img src="/src/assets/images/denbi.svg" @@ -71,53 +65,67 @@ onBeforeUnmount(() => { /> CloWM </router-link> - <button - class="navbar-toggler" - type="button" - data-bs-toggle="collapse" - data-bs-target="#navbarNavAltMarkup" - aria-controls="navbarNavAltMarkup" - aria-expanded="false" - aria-label="Toggle navigation" - v-if="store.authenticated && store.user != null" - > - <span class="navbar-toggler-icon"></span> - </button> + <div class="collapse navbar-collapse" - id="navbarNavAltMarkup" - v-if="store.authenticated && store.user != null" + id="navDropdown" + v-if="store.authenticated" > - <div class="navbar-nav"> - <router-link - class="nav-link" - :aria-current="activeRoute === 'buckets' ? 'page' : null" - :to="{ name: 'buckets' }" - :class="{ active: activeRoute === 'buckets' }" - > - Buckets - </router-link> - <router-link - class="nav-link" - :to="{ name: 's3_keys' }" - :aria-current="activeRoute === 's3_keys' ? 'page' : null" - :class="{ active: activeRoute === 's3_keys' }" - > - S3 Keys - </router-link> - </div> + <ul id="objectStorageNav" class="navbar-nav"> + <li class="nav-item dropdown"> + <a + class="nav-link dropdown-toggle" + :class="{ active: objectStorageActive }" + href="#" + role="button" + data-bs-toggle="dropdown" + aria-expanded="false" + > + Object Storage + </a> + <ul class="dropdown-menu dropdown-menu-dark"> + <li> + <router-link + class="dropdown-item" + :to="{ name: 'buckets' }" + :class="{ active: activeRoute === 'buckets' }" + >Buckets</router-link + > + </li> + <li> + <router-link + class="dropdown-item" + :to="{ name: 's3_keys' }" + :class="{ active: activeRoute === 's3_keys' }" + >S3 Keys</router-link + > + </li> + </ul> + </li> + </ul> + <ul id="workflowNav" class="navbar-nav"> + <li class="nav-item dropdown"> + <a + class="nav-link dropdown-toggle" + href="#" + role="button" + data-bs-toggle="dropdown" + aria-expanded="false" + > + Workflows + </a> + <ul class="dropdown-menu dropdown-menu-dark"> + <li> + <a class="dropdown-item" href="#">Workflows</a> + </li> + <li> + <a class="dropdown-item" href="#">Executions</a> + </li> + </ul> + </li> + </ul> </div> - - <span - v-if="!api_connection.connected" - class="navbar-text text-bg-danger p-1" - > - Backend not reachable - </span> - <div - class="dropdown d-flex me-3" - v-if="store.authenticated && store.user != null" - > + <div class="dropdown" v-if="store.authenticated && store.user != null"> <a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle-split" @@ -138,8 +146,8 @@ onBeforeUnmount(() => { </li> </ul> </div> - </div> - </nav> + </nav> + </header> </template> <style scoped> diff --git a/src/components/Modals/BootstrapModal.vue b/src/components/modals/BootstrapModal.vue similarity index 100% rename from src/components/Modals/BootstrapModal.vue rename to src/components/modals/BootstrapModal.vue diff --git a/src/components/Modals/DeleteModal.vue b/src/components/modals/DeleteModal.vue similarity index 97% rename from src/components/Modals/DeleteModal.vue rename to src/components/modals/DeleteModal.vue index 00dbff6..644cebf 100644 --- a/src/components/Modals/DeleteModal.vue +++ b/src/components/modals/DeleteModal.vue @@ -2,7 +2,7 @@ import { onMounted, ref } from "vue"; import type { Ref } from "vue"; import { Modal } from "bootstrap"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; const props = defineProps<{ modalID: string; diff --git a/src/components/Modals/SearchUserModal.vue b/src/components/modals/SearchUserModal.vue similarity index 98% rename from src/components/Modals/SearchUserModal.vue rename to src/components/modals/SearchUserModal.vue index d0fd708..e17b35e 100644 --- a/src/components/Modals/SearchUserModal.vue +++ b/src/components/modals/SearchUserModal.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> import { reactive, watch } from "vue"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; import { UserService } from "@/client/auth"; import type { User } from "@/client/auth"; diff --git a/src/components/BucketListItem.vue b/src/components/object-storage/BucketListItem.vue similarity index 96% rename from src/components/BucketListItem.vue rename to src/components/object-storage/BucketListItem.vue index cddcc0a..1412a89 100644 --- a/src/components/BucketListItem.vue +++ b/src/components/object-storage/BucketListItem.vue @@ -5,8 +5,8 @@ import type { BucketPermissionOut, } from "@/client/s3proxy"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; -import PermissionModal from "@/components/Modals/PermissionModal.vue"; -import BucketDetailModal from "@/components/Modals/BucketDetailModal.vue"; +import PermissionModal from "@/components/object-storage/modals/PermissionModal.vue"; +import BucketDetailModal from "@/components/object-storage/modals/BucketDetailModal.vue"; import dayjs from "dayjs"; import { filesize } from "filesize"; import { computed, onMounted } from "vue"; diff --git a/src/components/BucketView.vue b/src/components/object-storage/BucketView.vue similarity index 98% rename from src/components/BucketView.vue rename to src/components/object-storage/BucketView.vue index a811484..86e21c8 100644 --- a/src/components/BucketView.vue +++ b/src/components/object-storage/BucketView.vue @@ -15,13 +15,13 @@ import BootstrapIcon from "@/components/BootstrapIcon.vue"; import { filesize } from "filesize"; import dayjs from "dayjs"; import { Toast, Tooltip } from "bootstrap"; -import PermissionListModal from "@/components/Modals/PermissionListModal.vue"; -import UploadObjectModal from "@/components/Modals/UploadObjectModal.vue"; -import CopyObjectModal from "@/components/Modals/CopyObjectModal.vue"; -import PermissionModal from "@/components/Modals/PermissionModal.vue"; -import ObjectDetailModal from "@/components/Modals/ObjectDetailModal.vue"; -import CreateFolderModal from "@/components/Modals/CreateFolderModal.vue"; -import DeleteModal from "@/components/Modals/DeleteModal.vue"; +import PermissionListModal from "@/components/object-storage/modals/PermissionListModal.vue"; +import UploadObjectModal from "@/components/object-storage/modals/UploadObjectModal.vue"; +import CopyObjectModal from "@/components/object-storage/modals/CopyObjectModal.vue"; +import PermissionModal from "@/components/object-storage/modals/PermissionModal.vue"; +import ObjectDetailModal from "@/components/object-storage/modals/ObjectDetailModal.vue"; +import CreateFolderModal from "@/components/object-storage/modals/CreateFolderModal.vue"; +import DeleteModal from "@/components/modals/DeleteModal.vue"; import { S3Client, DeleteObjectCommand, diff --git a/src/components/S3KeyView.vue b/src/components/object-storage/S3KeyView.vue similarity index 97% rename from src/components/S3KeyView.vue rename to src/components/object-storage/S3KeyView.vue index c2f6e49..1f29e7e 100644 --- a/src/components/S3KeyView.vue +++ b/src/components/object-storage/S3KeyView.vue @@ -3,7 +3,7 @@ import type { S3Key } from "@/client/s3proxy"; import type { Ref } from "vue"; import { ref, watch } from "vue"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; -import DeleteModal from "@/components/Modals/DeleteModal.vue"; +import DeleteModal from "@/components/modals/DeleteModal.vue"; const props = defineProps<{ s3key: S3Key; diff --git a/src/components/Modals/BucketDetailModal.vue b/src/components/object-storage/modals/BucketDetailModal.vue similarity index 96% rename from src/components/Modals/BucketDetailModal.vue rename to src/components/object-storage/modals/BucketDetailModal.vue index 50145d6..270320f 100644 --- a/src/components/Modals/BucketDetailModal.vue +++ b/src/components/object-storage/modals/BucketDetailModal.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import type { BucketOut } from "@/client/s3proxy"; import dayjs from "dayjs"; import { filesize } from "filesize"; diff --git a/src/components/Modals/CopyObjectModal.vue b/src/components/object-storage/modals/CopyObjectModal.vue similarity index 98% rename from src/components/Modals/CopyObjectModal.vue rename to src/components/object-storage/modals/CopyObjectModal.vue index b782b44..09fb71e 100644 --- a/src/components/Modals/CopyObjectModal.vue +++ b/src/components/object-storage/modals/CopyObjectModal.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> import type { S3Client } from "@aws-sdk/client-s3"; import { CopyObjectCommand } from "@aws-sdk/client-s3"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import { Modal, Toast } from "bootstrap"; import { onMounted, reactive, watch } from "vue"; import type { S3ObjectMetaInformation } from "@/client/s3proxy"; diff --git a/src/components/Modals/CreateBucketModal.vue b/src/components/object-storage/modals/CreateBucketModal.vue similarity index 98% rename from src/components/Modals/CreateBucketModal.vue rename to src/components/object-storage/modals/CreateBucketModal.vue index 6b7a85a..b1dd71a 100644 --- a/src/components/Modals/CreateBucketModal.vue +++ b/src/components/object-storage/modals/CreateBucketModal.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> import type { BucketIn } from "@/client/s3proxy"; import { reactive, onMounted } from "vue"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import { useRouter } from "vue-router"; import { Modal } from "bootstrap"; import { useBucketStore } from "@/stores/buckets"; diff --git a/src/components/Modals/CreateFolderModal.vue b/src/components/object-storage/modals/CreateFolderModal.vue similarity index 98% rename from src/components/Modals/CreateFolderModal.vue rename to src/components/object-storage/modals/CreateFolderModal.vue index d4f0425..ef0cf39 100644 --- a/src/components/Modals/CreateFolderModal.vue +++ b/src/components/object-storage/modals/CreateFolderModal.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> import type { S3Client } from "@aws-sdk/client-s3"; import { PutObjectCommand } from "@aws-sdk/client-s3"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import { computed, onMounted, reactive } from "vue"; import type { ComputedRef } from "vue"; import type { S3ObjectMetaInformation } from "@/client/s3proxy"; diff --git a/src/components/Modals/ObjectDetailModal.vue b/src/components/object-storage/modals/ObjectDetailModal.vue similarity index 96% rename from src/components/Modals/ObjectDetailModal.vue rename to src/components/object-storage/modals/ObjectDetailModal.vue index a3cd0f4..b5946ba 100644 --- a/src/components/Modals/ObjectDetailModal.vue +++ b/src/components/object-storage/modals/ObjectDetailModal.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import type { S3ObjectMetaInformation } from "@/client/s3proxy"; import dayjs from "dayjs"; import { filesize } from "filesize"; diff --git a/src/components/Modals/PermissionListModal.vue b/src/components/object-storage/modals/PermissionListModal.vue similarity index 96% rename from src/components/Modals/PermissionListModal.vue rename to src/components/object-storage/modals/PermissionListModal.vue index 8660e3c..37b2125 100644 --- a/src/components/Modals/PermissionListModal.vue +++ b/src/components/object-storage/modals/PermissionListModal.vue @@ -4,8 +4,8 @@ import type { FolderTree } from "@/types/PseudoFolder"; import { reactive } from "vue"; import { BucketPermissionService } from "@/client/s3proxy"; import { onBeforeMount, watch } from "vue"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; -import PermissionModal from "@/components/Modals/PermissionModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; +import PermissionModal from "@/components/object-storage/modals/PermissionModal.vue"; // Props // ----------------------------------------------------------------------------- diff --git a/src/components/Modals/PermissionModal.vue b/src/components/object-storage/modals/PermissionModal.vue similarity index 98% rename from src/components/Modals/PermissionModal.vue rename to src/components/object-storage/modals/PermissionModal.vue index eab180e..ddc2899 100644 --- a/src/components/Modals/PermissionModal.vue +++ b/src/components/object-storage/modals/PermissionModal.vue @@ -1,8 +1,8 @@ <script setup lang="ts"> import { onMounted, reactive, watch, ref, computed } from "vue"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; -import DeleteModal from "@/components/Modals/DeleteModal.vue"; -import SearchUserModal from "@/components/Modals/SearchUserModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; +import DeleteModal from "@/components/modals/DeleteModal.vue"; +import SearchUserModal from "@/components/modals/SearchUserModal.vue"; import { Modal } from "bootstrap"; import dayjs from "dayjs"; import type { @@ -508,7 +508,7 @@ onMounted(() => { type="button" class="btn btn-outline-danger btn-sm float-end" @click="permission.file_prefix = undefined" - :disabled="permission.file_prefix === undefined" + :hidden="permission.file_prefix == undefined" > <bootstrap-icon icon="x-lg" diff --git a/src/components/Modals/UploadObjectModal.vue b/src/components/object-storage/modals/UploadObjectModal.vue similarity index 99% rename from src/components/Modals/UploadObjectModal.vue rename to src/components/object-storage/modals/UploadObjectModal.vue index a80296e..1285150 100644 --- a/src/components/Modals/UploadObjectModal.vue +++ b/src/components/object-storage/modals/UploadObjectModal.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> import type { S3Client } from "@aws-sdk/client-s3"; import { Upload } from "@aws-sdk/lib-storage"; -import BootstrapModal from "@/components/Modals/BootstrapModal.vue"; +import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import { computed, onMounted, reactive, watch } from "vue"; import type { ComputedRef } from "vue"; import type { S3ObjectMetaInformation } from "@/client/s3proxy"; diff --git a/src/router/index.ts b/src/router/index.ts index 1878694..9dbda65 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -18,7 +18,8 @@ const router = createRouter({ { path: ":bucketName/:subFolders*", name: "bucket", - component: () => import("../components/BucketView.vue"), + component: () => + import("../components/object-storage/BucketView.vue"), props: true, }, ], diff --git a/src/stores/auth.ts b/src/stores/auth.ts index 8cc0dfd..3926c95 100644 --- a/src/stores/auth.ts +++ b/src/stores/auth.ts @@ -30,7 +30,7 @@ export const useAuthStore = defineStore({ state.user?.roles?.includes(RoleEnum.REVIEWER) ?? false, workflowDev: (state) => state.user?.roles?.includes(RoleEnum.DEVELOPER) ?? false, - workflowAdmin: (state) => + admin: (state) => state.user?.roles?.includes(RoleEnum.ADMINISTRATOR) ?? false, }, actions: { diff --git a/src/views/object-storage/BucketsView.vue b/src/views/object-storage/BucketsView.vue index 875776f..877761c 100644 --- a/src/views/object-storage/BucketsView.vue +++ b/src/views/object-storage/BucketsView.vue @@ -4,9 +4,9 @@ import { computed, onMounted, reactive } from "vue"; import type { BucketOut } from "@/client/s3proxy"; import { useRoute, useRouter } from "vue-router"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; -import CreateBucketModal from "@/components/Modals/CreateBucketModal.vue"; -import DeleteModal from "@/components/Modals/DeleteModal.vue"; -import BucketListItem from "@/components/BucketListItem.vue"; +import CreateBucketModal from "@/components/object-storage/modals/CreateBucketModal.vue"; +import DeleteModal from "@/components/modals/DeleteModal.vue"; +import BucketListItem from "@/components/object-storage/BucketListItem.vue"; import { useBucketStore } from "@/stores/buckets"; import { Modal } from "bootstrap"; import { useAuthStore } from "@/stores/auth"; diff --git a/src/views/object-storage/S3KeysView.vue b/src/views/object-storage/S3KeysView.vue index dbca237..d234f32 100644 --- a/src/views/object-storage/S3KeysView.vue +++ b/src/views/object-storage/S3KeysView.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import S3KeyView from "@/components/S3KeyView.vue"; +import S3KeyView from "@/components/object-storage/S3KeyView.vue"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; import { reactive, onMounted, computed } from "vue"; import type { ComputedRef } from "vue"; -- GitLab