Skip to content
Snippets Groups Projects
Verified Commit 05b347af authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Add login page and basic nested router with nav guards

#2
parent 958b97a8
No related branches found
No related tags found
2 merge requests!22Version 1.0.0,!1HTTP Client and Login
<script setup lang="ts">
import NavbarTop from "./components/NavbarTop.vue";
import SidebarLeft from "./components/SidebarLeft.vue";
import { onBeforeMount } from "vue";
import { useCookies } from "vue3-cookies";
import { useAuthStore } from "@/stores/auth";
import { useRouter } from "vue-router";
const { cookies } = useCookies();
const store = useAuthStore();
const router = useRouter();
onBeforeMount(() => {
store.setToken(cookies.get("bearer"));
router.beforeEach(async (to) => {
// make sure the user is authenticated
if (
!store.authenticated &&
// ❗️ Avoid an infinite redirect
to.name !== "login"
) {
// redirect the user to the login page
return { name: "login" };
}
});
});
</script>
<template style="height: 100%">
<template>
<NavbarTop />
<SidebarLeft />
<router-view class="cona"></router-view>
<router-view></router-view>
</template>
<style scoped>
.cona {
min-height: 80vh;
}
</style>
<style scoped></style>
src/assets/images/ls-login.png

8.36 KiB

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
\ No newline at end of file
......@@ -2,8 +2,15 @@
import BootstrapIcon from "./BootstrapIcon.vue";
import { reactive, onBeforeUnmount, onMounted } from "vue";
import { MiscellaneousService } from "@/client";
import { useAuthStore } from "@/stores/auth";
import { useRouter } from "vue-router";
import { useCookies } from "vue3-cookies";
const api_connection = reactive({ connected: false, timer: null });
const router = useRouter();
const store = useAuthStore();
const { cookies } = useCookies();
const api_connection = reactive({ connected: true, timer: null });
let timer: ReturnType<typeof setInterval> | undefined = undefined;
function checkApiHealth() {
MiscellaneousService.miscellaneousHealthCheck()
......@@ -15,6 +22,12 @@ function checkApiHealth() {
});
}
function logout() {
store.logout();
cookies.remove("bearer");
router.push({ name: "login" });
}
onMounted(() => {
checkApiHealth();
timer = setInterval(checkApiHealth, 10000);
......@@ -36,7 +49,10 @@ onBeforeUnmount(() => {
>
Backend not reachable
</span>
<div class="dropdown d-flex me-3">
<div
class="dropdown d-flex me-3"
v-if="store.authenticated && store.user != null"
>
<a
href="#"
class="d-flex align-items-center text-white text-decoration-none dropdown-toggle-split"
......@@ -44,7 +60,7 @@ onBeforeUnmount(() => {
data-bs-toggle="dropdown"
aria-expanded="false"
>
<strong class="me-2">Bilbo Baggins</strong>
<strong class="me-2">{{ store.user.display_name }}</strong>
<bootstrap-icon
icon="person-circle"
fill="white"
......@@ -56,15 +72,18 @@ onBeforeUnmount(() => {
class="dropdown-menu dropdown-menu-dark text-small shadow"
aria-labelledby="dropdownUser1"
>
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
<li><hr class="dropdown-divider" /></li>
<li><a class="dropdown-item" href="#">Sign out</a></li>
<li>
<a class="dropdown-item pseudo-link" @click="logout">Sign out</a>
</li>
</ul>
</div>
</div>
</nav>
</template>
<style scoped></style>
<style scoped>
.pseudo-link {
cursor: pointer;
}
</style>
......@@ -2,32 +2,28 @@
<template>
<div
class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark"
style="width: 200px"
class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark position-fixed top-50 start-0 translate-middle-y"
style="width: 200px; min-height: 80vh"
>
<ul class="nav nav-pills flex-column mb-auto">
<li class="nav-item">
<li class="nav-item mb-1">
<button
class="btn btn-toggle align-items-center rounded collapsed text-white"
class="btn btn-lg btn-toggle align-items-center rounded collapsed text-white"
data-bs-toggle="collapse"
data-bs-target="#home-collapse"
data-bs-target="#os-collapse"
aria-expanded="true"
>
Object Storage
</button>
<div class="collapse show" id="home-collapse">
<div class="collapse show fs-5" id="os-collapse">
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
<li>
<router-link
to="/object-storage/buckets"
class="link-light rounded"
<router-link :to="{ name: 'buckets' }" class="link-light rounded"
>Buckets</router-link
>
</li>
<li>
<router-link
to="/object-storage/s3-keys"
class="link-light rounded"
<router-link :to="{ name: 's3_keys' }" class="link-light rounded"
>S3 Keys</router-link
>
</li>
......@@ -38,4 +34,5 @@
</div>
</template>
<style scoped></style>
<style scoped>
</style>
import { createRouter, createWebHistory } from "vue-router";
import BucketsView from "../views/BucketsView.vue";
import DashboardView from "../views/DashboardView.vue";
import LoginView from "../views/LoginView.vue";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/object-storage/buckets",
name: "buckets",
component: BucketsView,
path: "/dashboard",
name: "dashboard",
component: DashboardView,
children: [
{
path: "object-storage/buckets",
name: "buckets",
component: BucketsView,
},
{
path: "object-storage/s3-keys",
name: "s3_keys",
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import("../views/S3KeysView.vue"),
},
],
},
{
path: "/object-storage/s3-keys",
name: "about",
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import("../views/S3KeysView.vue"),
path: "/login",
name: "login",
component: LoginView,
},
{
path: "/",
......
import { defineStore } from "pinia";
import type { User } from "@/client";
import { UserService } from "@/client";
import { OpenAPI } from "@/client";
export type RootState = {
token: string | null;
user: User | null;
};
export const useAuthStore = defineStore({
id: "auth",
state: () =>
({
token: null,
user: null,
} as RootState),
getters: {
authenticated: (state) => state.token != null,
},
actions: {
setToken(token: string | null) {
if (token != null) {
OpenAPI.TOKEN = token;
this.token = token;
UserService.userGetLoggedInUser()
.then((user) => {
this.user = user;
})
.catch(() => {
this.token = null;
});
} else {
this.token = null;
this.user = null;
}
},
updateUser() {
this.setToken(this.token);
},
logout() {
this.setToken(null);
},
},
});
<script setup lang="ts">
import { onMounted, reactive } from "vue";
import { useCookies } from "vue3-cookies";
const { cookies } = useCookies();
const my_cookie = reactive({
val: "defaults",
});
onMounted(() => {
if (cookies.isKey("bearer")) {
my_cookie.val = cookies.get("bearer");
}
});
</script>
<script setup lang="ts"></script>
<template>
<main>
<p v-if="my_cookie.val !== 'defaults'">
Cookie Present: {{ my_cookie.val }}
</p>
<p v-else>No Cookie set</p>
<div>This the is the Buckets Page</div>
</main>
</template>
<script setup lang="ts">
import SidebarLeft from "../components/SidebarLeft.vue";
</script>
<template>
<SidebarLeft />
<router-view></router-view>
</template>
<style scoped></style>
<script setup lang="ts">
import { onBeforeMount } from "vue";
import { useAuthStore } from "@/stores/auth";
import { useRouter } from "vue-router";
import { OpenAPI } from "@/client";
const router = useRouter();
const store = useAuthStore();
onBeforeMount(() => {
if (store.authenticated) {
// If user is authenticated redirect him to the dashboard
router.push({ name: "buckets" });
}
});
</script>
<template>
<div
class="card text-center bg-dark ms-md-auto position-absolute top-50 left-50 translate-middle"
>
<div class="card-header text-dark bg-light">LoginView</div>
<div class="card-body p-5">
<h5 class="card-title">Login</h5>
<p class="card-text">Login to this service with LifeScience</p>
<a :href="OpenAPI.BASE + '/auth/login'" class="m-2">
<img src="/src/assets/images/ls-login.png" alt="[LS Login]" />
</a>
</div>
</div>
</template>
<style scoped></style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment