Skip to content

Commit 2f8e4cc

Browse files
authored
Merges #33 Closes #33
2 parents 173152e + 9b31bb7 commit 2f8e4cc

File tree

12 files changed

+307
-17
lines changed

12 files changed

+307
-17
lines changed

ui/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
},
1818
"dependencies": {
1919
"axios": "^1.6.8",
20+
"js-cookie": "^3.0.5",
21+
"pinia": "^3.0.0",
2022
"vue": "^3.4.21",
2123
"vue-router": "^4.3.0",
2224
"vuetify": "^3.5.9"

ui/src/App.vue

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script setup>
22
import { RouterView } from 'vue-router'
3+
import { useUserStore } from '@/store'
34
import BreadCrumbs from './components/BreadCrumbs.vue'
5+
import UserDropdown from './components/UserDropdown.vue'
6+
7+
const store = useUserStore()
48
</script>
59

610
<template>
@@ -9,8 +13,15 @@ import BreadCrumbs from './components/BreadCrumbs.vue'
913
<template #prepend>
1014
<img src="./assets/favicon.png" height="30" />
1115
</template>
16+
<v-spacer></v-spacer>
17+
<user-dropdown v-if="store.isAuthenticated" :username="store.user" />
1218
</v-app-bar>
13-
<v-navigation-drawer class="pa-2" color="transparent" permanent>
19+
<v-navigation-drawer
20+
v-if="store.isAuthenticated && $route.name !== 'signIn'"
21+
class="pa-2"
22+
color="transparent"
23+
permanent
24+
>
1425
<v-list color="primary" density="compact">
1526
<v-list-item :to="{ name: 'taskList' }">
1627
<template #prepend>

ui/src/components/UserDropdown.vue

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<v-menu offset-y left>
3+
<template #activator="{ props }">
4+
<v-btn v-bind="props" flat size="small" color="white">
5+
<v-icon size="small" start> mdi-account-circle </v-icon>
6+
{{ username }}
7+
<v-icon size="small" end> mdi-chevron-down </v-icon>
8+
</v-btn>
9+
</template>
10+
<v-list bg-color="primary" dark nav>
11+
<v-list-item @click="logOut">
12+
<template #prepend>
13+
<v-icon size="small">mdi-logout-variant</v-icon>
14+
</template>
15+
<v-list-item-title>Log out</v-list-item-title>
16+
</v-list-item>
17+
</v-list>
18+
</v-menu>
19+
</template>
20+
<script>
21+
import Cookies from 'js-cookie'
22+
import { useUserStore } from '@/store'
23+
24+
export default {
25+
name: 'UserDropdown',
26+
props: {
27+
username: {
28+
type: String,
29+
required: true
30+
}
31+
},
32+
methods: {
33+
logOut() {
34+
const store = useUserStore()
35+
36+
store.$patch({ username: null })
37+
Cookies.remove('gl_user')
38+
this.$router.push({ name: 'signIn' })
39+
}
40+
}
41+
}
42+
</script>

ui/src/main.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import './assets/main.css'
22

33
import { createApp } from 'vue'
4+
import { createPinia } from 'pinia'
45
import App from './App.vue'
56
import router from './router'
67
import vuetify from './plugins/vuetify'
78

9+
const pinia = createPinia()
810
const app = createApp(App)
911

10-
app.use(router).use(vuetify)
12+
app.use(router).use(vuetify).use(pinia)
1113

1214
app.mount('#app')

ui/src/router/index.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createRouter, createWebHistory } from 'vue-router'
2+
import { useUserStore } from '@/store'
23

34
const router = createRouter({
45
history: createWebHistory(import.meta.env.BASE_URL),
@@ -12,6 +13,7 @@ const router = createRouter({
1213
path: '/datajobs',
1314
name: 'tasks',
1415
meta: {
16+
requiresAuth: true,
1517
breadcrumb: {
1618
title: 'Tasks',
1719
to: { name: 'tasks' }
@@ -87,8 +89,36 @@ const router = createRouter({
8789
]
8890
}
8991
]
92+
},
93+
{
94+
path: '/signin',
95+
name: 'signIn',
96+
component: () => import('../views/SignIn.vue')
9097
}
9198
]
9299
})
93100

101+
router.beforeEach((to, from, next) => {
102+
const store = useUserStore()
103+
104+
if (to.matched.some((record) => record.meta.requiresAuth)) {
105+
if (!store.isAuthenticated) {
106+
next({
107+
name: 'signIn',
108+
query: {
109+
redirect: to.fullPath
110+
}
111+
})
112+
} else {
113+
next()
114+
}
115+
} else if (to.name === 'signIn' && store.isAuthenticated) {
116+
next({
117+
path: ''
118+
})
119+
} else {
120+
next()
121+
}
122+
})
123+
94124
export default router

ui/src/services/api/auth.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { client } from './client'
2+
3+
export const auth = {
4+
login: (data) => client.post('login', data)
5+
}

ui/src/services/api/client.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import axios from 'axios'
2+
3+
const base = import.meta.env.VITE_API_ENDPOINT || 'http://localhost:8000'
4+
5+
export const client = axios.create({
6+
baseURL: base,
7+
withCredentials: true,
8+
withXSRFToken: true,
9+
xsrfCookieName: 'csrftoken',
10+
xsrfHeaderName: 'X-CSRFToken'
11+
})

ui/src/services/api/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { auth } from './auth'
12
import { scheduler } from './scheduler'
23

34
export const API = {
5+
auth,
46
scheduler
57
}

ui/src/services/api/scheduler.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
1-
import axios from 'axios'
2-
3-
const base = import.meta.env.VITE_API_ENDPOINT || 'http://localhost:8000'
4-
5-
const client = axios.create({
6-
baseURL: `${base}/scheduler`
7-
})
1+
import { client } from './client'
82

93
export const scheduler = {
10-
list: (params) => client.get(`/tasks`, { params }),
11-
get: (taskId) => client.get(`/tasks/${taskId}`),
12-
create: (data) => client.post(`/add_task`, data),
13-
delete: (taskId) => client.post(`/remove_task`, { taskId }),
14-
reschedule: (taskId) => client.post(`/reschedule_task`, { taskId }),
15-
getTaskJobs: (taskId, params) => client.get(`/tasks/${taskId}/jobs/`, { params }),
16-
getJob: (taskId, jobId) => client.get(`/tasks/${taskId}/jobs/${jobId}`),
17-
getJobLogs: (taskId, jobId) => client.get(`/tasks/${taskId}/jobs/${jobId}/logs/`)
4+
list: (params) => client.get(`/scheduler/tasks`, { params }),
5+
get: (taskId) => client.get(`/scheduler/tasks/${taskId}`),
6+
create: (data) => client.post(`/scheduler/add_task`, data),
7+
delete: (taskId) => client.post(`/scheduler/remove_task`, { taskId }),
8+
reschedule: (taskId) => client.post(`/scheduler/reschedule_task`, { taskId }),
9+
getTaskJobs: (taskId, params) => client.get(`/scheduler/tasks/${taskId}/jobs/`, { params }),
10+
getJob: (taskId, jobId) => client.get(`/scheduler/tasks/${taskId}/jobs/${jobId}`),
11+
getJobLogs: (taskId, jobId) => client.get(`/scheduler/tasks/${taskId}/jobs/${jobId}/logs/`)
1812
}

ui/src/store/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Cookies from 'js-cookie'
2+
import { defineStore } from 'pinia'
3+
4+
export const useUserStore = defineStore('user', {
5+
state: () => ({
6+
username: Cookies.get('gl_user')
7+
}),
8+
getters: {
9+
user: (state) => state.username,
10+
isAuthenticated: (state) => !!state.username
11+
}
12+
})

0 commit comments

Comments
 (0)