Skip to content
Snippets Groups Projects
Commit b07e27dc authored by Edward Alexander Jaya's avatar Edward Alexander Jaya
Browse files

Merge branch 'feature-usermanagement' into 'dev'

Feature usermanagement

See merge request !5
parents ddfbed91 8174ee69
Branches
6 merge requests!40Release First Version,!31Output feature,!25Feature collab,!23CI script,!21Add dockerize,!5Feature usermanagement
Showing
with 549 additions and 202 deletions
No preview for this file type
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
cursor: pointer; cursor: pointer;
} }
@media only screen and (min-width: 768px) { @media only screen and (min-width: 768px) {
.table-width { .table-width {
width: calc(80vw - 260px); width: calc(80vw - 260px);
...@@ -37,6 +39,30 @@ ...@@ -37,6 +39,30 @@
/* Forms */ /* Forms */
.form-title, .form-content, .btn-content, .form-error {
font-size: 0.85rem;
color: #1E889B;
letter-spacing: 0.025rem;
font-family: 'Open Sans Regular';
}
.form-error {
color: red;
font-size: 0.7rem;
font-family: 'Open Sans Bold';
}
.btn-content {
color: white;
margin-top: 5px;
margin-left: -5px;
}
.form-title-margin {
margin-top: -5px;
}
.field-length { .field-length {
width: 16.5rem; width: 16.5rem;
height: 2.25rem; height: 2.25rem;
...@@ -44,20 +70,46 @@ ...@@ -44,20 +70,46 @@
margin-bottom: 0.65rem; margin-bottom: 0.65rem;
} }
.form-border, .btn-border { .form-border, .btn-border, .form-border-error {
border-radius: 8px; border-radius: 8px;
border: 1px solid #1E889B; border: 1px solid #1E889B;
} }
.form-border-error {
border: 1px solid red;
}
/* Buttons */
.btn-action { .btn-action {
cursor: pointer;
background-color: #1E889B; background-color: #1E889B;
height: 2.3rem; height: 2.3rem;
} }
.btn-disabled {
background-color: gray;
}
.btn-action:hover { .btn-action:hover {
background-color: #23B1CB; background-color: #23B1CB;
} }
/* Center */
.center {
align-items: center;
display: flex;
}
.center-inside {
margin-left: calc(50vw - 8.25rem);
}
.center-inside-add-user {
margin-left: calc(50vw - 300px);
margin-top: -160px;
}
.page-item .page-link { .page-item .page-link {
color: #1E889B !important; color: #1E889B !important;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</div> </div>
<!-- Role --> <!-- Role -->
<div id="role"> <div id="role">
Role: {{ role }} Role: {{ role.charAt(0).toUpperCase() + role.slice(1) }}
</div> </div>
</b-nav-item> </b-nav-item>
...@@ -26,64 +26,69 @@ ...@@ -26,64 +26,69 @@
</div> </div>
</b-nav-item> </b-nav-item>
<!-- Edit Dataset --> <div v-if="role === 'editor' || role === 'admin'">
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('edit-dataset')"> <!-- Edit Dataset -->
<div id="edit-dataset"> <b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('edit-dataset')">
Edit Dataset <div id="edit-dataset">
</div> Edit Dataset
</b-nav-item>
<!-- User Management -->
<b-nav-item
v-b-toggle.collapse-user-management
link-classes="side-bar-color mt-3 ml-4">
<div class="icon-text-wrapper">
User Management
<i class="ml-3 mt-1 fas fa-caret-down" />
</div>
</b-nav-item>
<b-collapse id="collapse-user-management" visible role="tabpanel">
<!-- Show All Users -->
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('show-all-users')">
<div class="icon-text-wrapper">
<i class="mt-1 mr-3 fas fa-users" />
<div id="show-all-users">
Show All Users
</div>
</div> </div>
</b-nav-item> </b-nav-item>
</div>
<!-- Add User -->
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('add-user')"> <div v-if="role === 'admin'">
<!-- User Management -->
<b-nav-item
v-b-toggle.collapse-user-management
link-classes="side-bar-color mt-3 ml-4"
>
<div class="icon-text-wrapper"> <div class="icon-text-wrapper">
<i class="mt-1 mr-3 fas fa-plus-circle" /> User Management
<div id="add-user"> <i class="ml-3 mt-1 fas fa-caret-down" />
Add User
</div>
</div> </div>
</b-nav-item> </b-nav-item>
<!-- Edit User --> <b-collapse id="collapse-user-management" visible role="tabpanel">
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('edit-user')"> <!-- Show All Users -->
<div class="icon-text-wrapper"> <b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('show-all-users')">
<i class="mt-1 mr-3 fas fa-pen" /> <div class="icon-text-wrapper">
<div id="edit-user"> <i class="mt-1 mr-3 fas fa-users" />
Edit User <div id="show-all-users">
Show All Users
</div>
</div> </div>
</div> </b-nav-item>
</b-nav-item>
<!-- Add User -->
<!-- Delete User --> <b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('add-user')">
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('delete-user')"> <div class="icon-text-wrapper">
<div class="icon-text-wrapper"> <i class="mt-1 mr-3 fas fa-plus-circle" />
<i class="mt-1 mr-3 fas fa-trash" /> <div id="add-user">
<div id="delete-user"> Add User
Delete User </div>
</div> </div>
</div> </b-nav-item>
</b-nav-item>
</b-collapse> <!-- Edit User -->
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('edit-user')">
<div class="icon-text-wrapper">
<i class="mt-1 mr-3 fas fa-pen" />
<div id="edit-user">
Edit User
</div>
</div>
</b-nav-item>
<!-- Delete User -->
<b-nav-item link-classes="side-bar-color mt-3 ml-4" @click="changeActiveElmtID('delete-user')">
<div class="icon-text-wrapper">
<i class="mt-1 mr-3 fas fa-trash" />
<div id="delete-user">
Delete User
</div>
</div>
</b-nav-item>
</b-collapse>
</div>
</b-nav> </b-nav>
</template> </template>
...@@ -106,13 +111,15 @@ export default { ...@@ -106,13 +111,15 @@ export default {
}, },
watch: { watch: {
activeElmtID (newElmtID, oldElmtID) { activeElmtID (newElmtID, oldElmtID) {
console.log("newElmtID: ", newElmtID)
console.log("oldElmtID: ", oldElmtID)
this.setClass(oldElmtID, '') this.setClass(oldElmtID, '')
this.setClass(newElmtID, 'active') this.setClass(newElmtID, 'active')
} }
}, },
mounted () { mounted () {
this.onPathChangeHandler(window.location.pathname) this.onPathChangeHandler(window.location.pathname)
console.log(/^\/main\/label(\/|(\?)|$)/.test(window.location.pathname)) // console.log(/^\/main\/label(\/|(\?)|$)/.test(window.location.pathname))
}, },
methods: { methods: {
setClass (elmtID, className) { setClass (elmtID, className) {
...@@ -124,6 +131,7 @@ export default { ...@@ -124,6 +131,7 @@ export default {
this.redirectRoute(elmtID) this.redirectRoute(elmtID)
}, },
redirectRoute (elmtID) { redirectRoute (elmtID) {
console.log("elmtID: ", elmtID)
switch (elmtID) { switch (elmtID) {
case 'label-dataset': case 'label-dataset':
this.$nuxt.$router.replace({ path: '/main/label'}) this.$nuxt.$router.replace({ path: '/main/label'})
...@@ -149,7 +157,9 @@ export default { ...@@ -149,7 +157,9 @@ export default {
} }
}, },
onPathChangeHandler (browserURL) { onPathChangeHandler (browserURL) {
console.log(browserURL)
if ((/^\/main\/label(\/|(\?)|$)/.test(browserURL))) { if ((/^\/main\/label(\/|(\?)|$)/.test(browserURL))) {
console.log("dataset panggil")
this.changeActiveElmtID('label-dataset') this.changeActiveElmtID('label-dataset')
} else if ((/^\/main\/json(\/|(\?)|$)/.test(browserURL))) { } else if ((/^\/main\/json(\/|(\?)|$)/.test(browserURL))) {
this.changeActiveElmtID('json-outputs') this.changeActiveElmtID('json-outputs')
......
...@@ -11,12 +11,14 @@ ...@@ -11,12 +11,14 @@
<!-- Delete row --> <!-- Delete row -->
<template v-slot:cell(delete)="row"> <template v-slot:cell(delete)="row">
<div class="icon-layout"> <div class="icon-layout">
<i <div v-if="row.item['user_id'] !== 1">
class="fas fa-trash trash-icon" <i
@mouseover="row.item['_rowVariant'] = 'danger'" class="margin-icon fas fa-trash trash-icon"
@mouseleave="row.item['_rowVariant'] = ''" @mouseover="row.item['_rowVariant'] = 'danger'"
@click="handleOnDelete(row.item.id, row.item.username)" @mouseleave="row.item['_rowVariant'] = ''"
/> @click="handleOnDelete(row.item.user_id, row.item.username)"
/>
</div>
</div> </div>
</template> </template>
</b-table> </b-table>
...@@ -42,8 +44,7 @@ export default { ...@@ -42,8 +44,7 @@ export default {
var text = name + " will be deleted." var text = name + " will be deleted."
this.showDeleteConfirmation("Are You Sure?", text).then((result) => { this.showDeleteConfirmation("Are You Sure?", text).then((result) => {
if (result.value) { if (result.value) {
this.deleteRowContent(id) this.sendDeleteToBackEnd(id)
this.showDeletedAlert()
} }
}) })
} else { } else {
...@@ -62,15 +63,21 @@ export default { ...@@ -62,15 +63,21 @@ export default {
}) })
}, },
sendDeleteToBackEnd (id) {
var url = '/api/user/' + id
this.$axios.delete(url).then(
this.deleteRowContent(id),
this.showDeletedAlert()
)
},
deleteRowContent (id) { deleteRowContent (id) {
for (let idx = 0; idx < this.rows.length; idx++) { for (let idx = 0; idx < this.rows.length; idx++) {
if (this.rows[idx].id === id) { if (this.rows[idx].user_id === id) {
this.rows.splice(idx, 1) this.rows.splice(idx, 1)
break break
} }
} }
// TO DO:
// Send changes to backend!
}, },
showDeletedAlert () { showDeletedAlert () {
...@@ -104,4 +111,9 @@ export default { ...@@ -104,4 +111,9 @@ export default {
display: flex; display: flex;
} }
.margin-icon {
margin-right: -30px;
/* margin-lefet: 30px; */
}
</style> </style>
\ No newline at end of file
...@@ -9,22 +9,24 @@ ...@@ -9,22 +9,24 @@
class="table table-width table-borderless" class="table table-width table-borderless"
> >
<!-- Role in Table --> <!-- Role in Table -->
<template v-slot:cell(role)="row"> <template v-slot:cell(user_role)="row">
<div v-if="!row.item.isRoleEditMode" @click="handleRoleChange(row.item.id)"> <div v-if="row.item.user_id !== 1">
{{ row.item.role }} <div v-if="!row.item.isRoleEditMode" @click="handleRoleChange(row.item.user_id)">
<div class="icon-layout"> {{ row.item.user_role }}
<i class="fas fa-caret-down icon" /> <div class="icon-layout">
<i class="fas fa-caret-down icon" />
</div>
</div>
<div v-else>
<b-form-select
class="form-height select-font"
:options="roles"
:value="row.item.user_role"
autofocus
@change.native="handleOnChange($event, row.item.user_id, 'user_role', row.item.user_role)"
@blur.native="row.item.isRoleEditMode = false"
/>
</div> </div>
</div>
<div v-else>
<b-form-select
class="form-height select-font"
:options="roles"
:value="row.item.role"
autofocus
@change.native="handleOnChange($event, row.item.id, 'role', row.item.role)"
@blur.native="row.item.isRoleEditMode = false"
/>
</div> </div>
</template> </template>
</b-table> </b-table>
...@@ -56,7 +58,7 @@ export default { ...@@ -56,7 +58,7 @@ export default {
methods: { methods: {
handleRoleChange (id) { handleRoleChange (id) {
var index = this.rows.findIndex(function (val) { var index = this.rows.findIndex(function (val) {
return val.id === id return val.user_id === id
}) })
this.rows[index].isRoleEditMode = true this.rows[index].isRoleEditMode = true
...@@ -71,14 +73,23 @@ export default { ...@@ -71,14 +73,23 @@ export default {
}) })
}, },
approveConfirmation (value, id, type) { approveConfirmation (role, id, type) {
var payloadUsername = ''
this.rows.forEach((row) => { this.rows.forEach((row) => {
if (row.id === id) { if (row.user_id === id) {
row[type] = value row[type] = role
payloadUsername = row['username']
} }
}) })
// TO DO:
// Send changes to backend! var url = 'api/user/' + id
this.$axios.put(url, {
username: payloadUsername,
user_role: role.toLowerCase()
}).then(
this.showApprovedAlert()
).catch(error => console.error(error))
}, },
showApprovedAlert () { showApprovedAlert () {
...@@ -96,17 +107,17 @@ export default { ...@@ -96,17 +107,17 @@ export default {
}, },
// Type can be: name, email, or department // Type can be: name, email, or department
handleOnChange (event, id, type, originalValue) { handleOnChange (event, id, type, originalValue) {
var text = "You will change " + originalValue + " to " + event.target.value if (originalValue !== event.target.value) {
this.showConfirmation("Are You Sure?", text).then((result) => { var text = "You will change " + originalValue + " to " + event.target.value
console.log("Result: ", result) this.showConfirmation("Are You Sure?", text).then((result) => {
// If user confirms the changes: // If user confirms the changes:
if (result.value) { if (result.value) {
this.approveConfirmation(event.target.value, id, type) this.approveConfirmation(event.target.value, id, type)
this.showApprovedAlert() } else {
} else { this.showCancelledAlert()
this.showCancelledAlert() }
} })
}) }
} }
} }
} }
......
// Environment Variables // Environment Variables
// For development // For development
export const backendURL = "http://localhost:8080" export const backendURL = "http://localhost:8081"
export const frontendURL = 'http://localhost:3000' export const frontendURL = 'http://localhost:3000'
// For deployment // For deployment
......
export default { // This is a nuxtjs' axios-module configuration
import cookieParser from 'cookieparser'
import cookies from 'js-cookie'
// This is a javascript middleware which utilizes cookies and JSON web token (JWT) authentication.
export default async function ({ req, route, redirect, store, $axios }) {
var userData = await getUserInfo({ req, $axios })
var isUserLoggedIn = !!userData
console.log("userData: ", userData)
// Then test the url
var urlRequiresNonAuth = route.fullPath === '/'
if (!isUserLoggedIn && !urlRequiresNonAuth) {
store.dispatch(('user/deleteUser'))
return redirect('/')
}
if (isUserLoggedIn && urlRequiresNonAuth) {
return redirect('/main/label')
}
store.dispatch('user/setUser', userData)
return Promise.resolve()
}
async function getUserInfo ({ req, $axios }) {
// Send accessToken to backend and check it.
let payload = {
cookie: ''
}
if (process.server) {
payload.cookie = cookieParser.parse(req.headers.cookie || '')['Authorization']
} else {
payload.cookie = cookies.get('Authorization')
}
var url = '/api/user/validatesession'
try {
var response = await $axios.post(url, payload).catch(error => { console.error(error); throw error })
return response.data.data
} catch (err) {
return false
}
} }
\ No newline at end of file
export default {
data () {
return {
rows: []
}
},
methods: {
async getAllUsers () {
var url = '/api/user'
var response = await this.$axios(url).catch(error => console.error(error))
console.log("response: ", response)
if (response && response.status === 200) {
return response.data.data
} else {
return null
}
}
},
async mounted () {
var usersData = await this.getAllUsers()
if (usersData) {
usersData.forEach(user => {
user['_rowVariant'] = ''
user['isRoleEditMode'] = false
var role = user['user_role']
user['user_role'] = role.charAt(0).toUpperCase() + role.slice(1)
this.rows.push(user)
})
}
}
}
\ No newline at end of file
...@@ -49,7 +49,7 @@ export default { ...@@ -49,7 +49,7 @@ export default {
'@nuxtjs/axios' '@nuxtjs/axios'
], ],
router: { router: {
middleware: ['auth']
}, },
axios: { axios: {
// See https://github.com/nuxt-community/axios-module#options // See https://github.com/nuxt-community/axios-module#options
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
"@nuxtjs/axios": "^5.9.5", "@nuxtjs/axios": "^5.9.5",
"bootstrap": "^4.1.3", "bootstrap": "^4.1.3",
"bootstrap-vue": "^2.0.0", "bootstrap-vue": "^2.0.0",
"cookie-parser": "^1.4.4", "cookieparser": "^0.1.0",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"nuxt": "^2.0.0", "nuxt": "^2.0.0",
"vue-sweetalert2": "^3.0.1" "vue-sweetalert2": "^3.0.1"
......
<template> <template>
<div> <div class="container-fluid">
<div class="row bg-auth center">
<div class="col center-inside">
<!-- Username -->
<div class="row">
<div class="col">
<h5 class="form-title font-auth">
Username
</h5>
</div>
</div>
<div class="row mt-1">
<div class="col">
<input
v-model="usernameForm.name"
type="text"
:class="['form-control', 'field-length', 'form-content', usernameForm.isDirty && isUsernameFormEmpty ? 'form-border-error': 'form-border']"
placeholder="Type username..."
name="username"
@focus="usernameForm.isDirty = true"
>
<div v-if="isUsernameFormEmpty && usernameForm.isDirty">
<p class="form-error">
Username cannot be empty.
</p>
</div>
</div>
</div>
<!-- Passcode -->
<div class="row mt-2">
<div class="col">
<h5 class="form-title font-auth">
Passcode
</h5>
</div>
</div>
<div class="row mt-1">
<div class="col">
<input
v-model="passcodeForm.name"
type="password"
:class="['form-control', 'field-length', 'form-content', passcodeForm.isDirty && isPasscodeFormEmpty ? 'form-border-error': 'form-border']"
placeholder="Type passcode..."
name="passcode"
@focus="passcodeForm.isDirty = true"
>
<div v-if="isPasscodeFormEmpty && passcodeForm.isDirty">
<p class="form-error">
Passcode cannot be empty.
</p>
</div>
</div>
</div>
<!-- Button -->
<div class="row mt-2">
<div class="col">
<button
:class="['btn-border', 'btn-action', 'field-length', 'form-content']" @click="handleOnLogin()"
>
<p class="btn-content">
Login
</p>
</button>
</div>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import cookies from 'js-cookie'
export default { export default {
data () { data () {
return { return {
usernameForm: {
name: '',
isDirty: ''
},
passcodeForm: {
name: '',
isDirty: ''
}
}
},
computed: {
isUsernameFormEmpty () {
return this.usernameForm.name === ''
},
isPasscodeFormEmpty () {
return this.passcodeForm.name === ''
} }
},
methods: {
async handleOnLogin () {
if (!this.isUsernameFormEmpty && !this.isPasscodeFormEmpty) {
var payload = {
"username": this.usernameForm.name,
"passcode": this.passcodeForm.name
}
var url = '/api/user/login'
const response = await this.$axios.post(url, payload).catch(error => console.error(error))
console.log("Response: ", response)
this.handleResponse(response)
} else {
this.usernameForm.isDirty = true
this.passcodeForm.isDirty = true
}
},
handleResponse (response) {
if (response && response.status === 200) {
this.handleSuccessResponse(response)
} else {
this.handleIncorrectResponse()
}
},
handleSuccessResponse (response) {
// Set cookie
cookies.remove('Authorization')
cookies.set('Authorization', response.data.data.cookie)
this.$router.push('/main/label')
},
handleIncorrectResponse () {
this.$swal.fire({
title: "Wrong Credentials",
icon: 'error',
text: 'Please fill your credentials again.'
})
}
} }
} }
</script> </script>
\ No newline at end of file
<style scoped>
.bg-auth {
background-color: #005362;
height: 100vh;
}
.font-auth {
color: white;
}
.form-error {
color: white;
font-family: "Open Sans Regular";
}
.form-border-error {
border: 1px solid white;
}
.btn-border {
border: 1px solid white;
}
.btn-action {
background-color: #005362;
}
.btn-action:hover {
background-color: #11616F;
}
</style>
\ No newline at end of file
<template> <template>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<Navbar username="Edward" role="Admin" /> <Navbar :username="user.username" :role="user.role" />
<nuxt-child /> <nuxt-child />
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// import { mapGetters } from 'vuex'
import Navbar from '~/components/root/Navbar' import Navbar from '~/components/root/Navbar'
import { mapGetters } from 'vuex'
export default { export default {
components: { components: {
Navbar Navbar
} },
computed: {
...mapGetters({
user: 'user/getUser'
})
}
} }
</script> </script>
\ No newline at end of file
<template> <template>
<div class="col"> <div class="col center center-inside-add-user">
<div class="ml-4"> <div class="ml-4">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
...@@ -21,16 +21,42 @@ ...@@ -21,16 +21,42 @@
id="username" id="username"
v-model="username" v-model="username"
type="text" type="text"
class="form-control form-border field-length form-content" :class="['form-control', 'field-length', 'form-content', isFormDirty && isUsernameEmpty ? 'form-border-error': 'form-border']"
placeholder="Type username..." placeholder="Type username..."
name="username" name="username"
@focus="isFormDirty = true"
> >
<div v-if="isUsernameEmpty && isFormDirty">
<p class="form-error">
Username cannot be empty.
</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<p class="form-title">
Role
</p>
</div>
</div>
<div class="row form-title-margin">
<div class="col">
<b-form-select
id="role"
v-model="role"
type="text"
class="form-control form-border field-length form-content"
:options="roles"
placeholder="Type role..."
name="role"
/>
</div> </div>
</div> </div>
<div class="row mt-2"> <div class="row mt-2">
<div class="col"> <div class="col">
<button <button
class="btn-border btn-action field-length form-content" @click="handleOnSubmit()" :class="['btn-border', isUsernameEmpty ? 'btn-disabled': 'btn-action', 'field-length', 'form-content']" @click="handleOnSubmit()"
> >
<p class="btn-content"> <p class="btn-content">
Add User Add User
...@@ -46,43 +72,50 @@ ...@@ -46,43 +72,50 @@
export default { export default {
data () { data () {
return { return {
username: '' username: '',
role: 'Labeler',
roles: ['Admin', 'Labeler', 'Editor'],
isFormDirty: false
}
},
computed: {
isUsernameEmpty () {
return this.username === ''
} }
}, },
methods: { methods: {
handleOnSubmit () { async handleOnSubmit () {
// Send to backend if (!this.isUsernameEmpty) {
this.showPassCode(this.username) var payload = {
'username': this.username,
'user_role': this.role.toLowerCase()
}
var url = '/api/user/register'
// Send to backend
var response = await this.$axios.post(url, payload).catch(error => console.log(error))
if (response && response.status === 200) {
this.showInfo(this.username, response.data.data.passcode)
} else {
this.handleIncorrectResponse()
}
} else {
this.isFormDirty = true
}
}, },
showPassCode (username) { showInfo (username, passcode) {
this.$swal.fire({ this.$swal.fire({
title: username + ' is Added!', title: username + ' is Added!',
icon: 'success', icon: 'success',
text: 'Passcode : ...' text: 'Passcode : ' + passcode
})
},
handleIncorrectResponse () {
this.$swal.fire({
title: "User already exists",
icon: 'error',
text: 'Please try with another user!'
}) })
} }
} }
} }
</script> </script>
\ No newline at end of file
<style scoped>
.form-title, .form-content, .btn-content {
font-size: 0.85rem;
color: #1E889B;
letter-spacing: 0.025rem;
font-family: 'Open Sans Regular';
}
.btn-action .btn-content {
color: white;
margin-top: 5px;
margin-left: -5px;
}
.form-title-margin {
margin-top: -5px;
}
</style>
\ No newline at end of file
...@@ -23,20 +23,14 @@ ...@@ -23,20 +23,14 @@
<script> <script>
import DeleteableTable from '~/components/user-management/DeleteableTable' import DeleteableTable from '~/components/user-management/DeleteableTable'
import getAllUsers from '~/mixins/user-management/getAllUsers'
export default { export default {
components: { components: {
DeleteableTable DeleteableTable
}, },
mixins: [getAllUsers],
data () { data () {
return { return {
rows: [
{ id: 1, isRoleEditMode: false, username: 'Edward Alexander Jaya', role: 'Labeler', passcode: 'ABCD', _rowVariant: '' },
{ id: 2, isRoleEditMode: false, username: 'Rayza Mahendra', role: 'Labeler', passcode: 'DEFG', _rowVariant: ''},
{ id: 3, isRoleEditMode: false, username: 'Muhammad Nurdin Husen', role: 'Editor', passcode: 'HIJK', _rowVariant: '' },
{ id: 4, isRoleEditMode: false, username: 'Eka Sunandika', role: 'Editor', passcode: 'LMNO', _rowVariant: '' },
{ id: 5, isRoleEditMode: false, username: 'Ahmad Rizal Alifio', role: 'Labeler', passcode: 'PQRS', _rowVariant: '' },
{ id: 6, isRoleEditMode: false, username: 'Ardian Umam', role: 'Admin', passcode: 'TUVW', _rowVariant: ''}
],
columns: [ columns: [
{ {
key: 'username', key: 'username',
...@@ -44,7 +38,7 @@ export default { ...@@ -44,7 +38,7 @@ export default {
sortable: true sortable: true
}, },
{ {
key: 'role', key: 'user_role',
label: 'Role', label: 'Role',
sortable: true sortable: true
}, },
......
...@@ -23,20 +23,15 @@ ...@@ -23,20 +23,15 @@
<script> <script>
import EditableTable from '~/components/user-management/EditableTable' import EditableTable from '~/components/user-management/EditableTable'
import getAllUsers from '~/mixins/user-management/getAllUsers'
export default { export default {
components: { components: {
EditableTable EditableTable
}, },
mixins: [getAllUsers],
data () { data () {
return { return {
rows: [
{ id: 1, isRoleEditMode: false, username: 'Edward Alexander Jaya', role: 'Labeler', passcode: 'ABCD', _rowVariant: '' },
{ id: 2, isRoleEditMode: false, username: 'Rayza Mahendra', role: 'Labeler', passcode: 'DEFG', _rowVariant: ''},
{ id: 3, isRoleEditMode: false, username: 'Muhammad Nurdin Husen', role: 'Editor', passcode: 'HIJK', _rowVariant: '' },
{ id: 4, isRoleEditMode: false, username: 'Eka Sunandika', role: 'Editor', passcode: 'LMNO', _rowVariant: '' },
{ id: 5, isRoleEditMode: false, username: 'Ahmad Rizal Alifio', role: 'Labeler', passcode: 'PQRS', _rowVariant: '' },
{ id: 6, isRoleEditMode: false, username: 'Ardian Umam', role: 'Admin', passcode: 'TUVW', _rowVariant: ''}
],
columns: [ columns: [
{ {
key: 'username', key: 'username',
...@@ -44,7 +39,7 @@ export default { ...@@ -44,7 +39,7 @@ export default {
sortable: true sortable: true
}, },
{ {
key: 'role', key: 'user_role',
label: 'Role', label: 'Role',
sortable: true sortable: true
} }
......
...@@ -23,29 +23,24 @@ ...@@ -23,29 +23,24 @@
<script> <script>
import ReadOnlyTable from '~/components/user-management/ReadOnlyTable' import ReadOnlyTable from '~/components/user-management/ReadOnlyTable'
import getAllUsers from '~/mixins/user-management/getAllUsers'
export default { export default {
components: { components: {
ReadOnlyTable ReadOnlyTable
}, },
mixins: [getAllUsers],
data () { data () {
return { return {
rows: [
{ id: 1, isRoleEditMode: false, username: 'Edward Alexander Jaya', role: 'Labeler', passcode: 'ABCD', _rowVariant: '' },
{ id: 2, isRoleEditMode: false, username: 'Rayza Mahendra', role: 'Labeler', passcode: 'DEFG', _rowVariant: ''},
{ id: 3, isRoleEditMode: false, username: 'Muhammad Nurdin Husen', role: 'Editor', passcode: 'HIJK', _rowVariant: '' },
{ id: 4, isRoleEditMode: false, username: 'Eka Sunandika', role: 'Editor', passcode: 'LMNO', _rowVariant: '' },
{ id: 5, isRoleEditMode: false, username: 'Ahmad Rizal Alifio', role: 'Labeler', passcode: 'PQRS', _rowVariant: '' },
{ id: 6, isRoleEditMode: false, username: 'Ardian Umam', role: 'Admin', passcode: 'TUVW', _rowVariant: ''}
],
columns: [ columns: [
{ {
key: 'role', key: 'username',
label: 'Role', label: 'Username',
sortable: true sortable: true
}, },
{ {
key: 'username', key: 'user_role',
label: 'Username', label: 'Role',
sortable: true sortable: true
}, },
{ {
......
// This is a nuxtjs' axios-module configuration // This is a nuxtjs' axios-module configuration
import cookieParser from 'cookieparser'
import cookieParser from 'cookie-parser'
import cookies from 'js-cookie' import cookies from 'js-cookie'
import { frontendURL } from '~/config.js' import { frontendURL } from '~/config.js'
...@@ -9,38 +8,26 @@ export default function ({ $axios, req, redirect, route }) { ...@@ -9,38 +8,26 @@ export default function ({ $axios, req, redirect, route }) {
// Set all headers with Authorization header on request // Set all headers with Authorization header on request
$axios.onRequest((config) => { $axios.onRequest((config) => {
var token = '' var token = ''
var user_id = ''
if (process.server) { if (process.server) {
token = cookieParser.parse(req.headers.cookie || '')['Authorization'] token = 'Basic ' + cookieParser.parse(req.headers.cookie || '')['Authorization']
user_id = cookieParser.parse(req.headers.cookie || '')['user_id']
} else { } else {
token = cookies.get('Authorization') token = 'Basic ' + cookies.get('Authorization')
user_id = cookies.get('user_id')
} }
config.headers.common['Authorization'] = token config.headers.common['Authorization'] = token
config.headers.common['user_id'] = user_id
}) })
// Handle on error
$axios.onError((error) => { $axios.onError((error) => {
const code = parseInt(error.response && error.response.status) const code = parseInt(error.response && error.response.status)
if (code === 401 || code === 429) { if (code === 401 || code === 429) {
// Remove all cookies
if (process.server) { if (process.server) {
if (route.fullPath !== '/auth') { if (route.fullPath !== '/') {
redirect('/auth') redirect('/')
}
} else {
if (window.location.pathname !== '/auth') {
window.location.href = frontendURL + '/auth'
}
}
} else if (code === 500) {
if (process.server) {
if (route.fullPath !== '/auth/activate/500') {
// redirect('/auth/activate/500')
} }
} else { } else {
if (window.location.pathname !== '/auth/activate/500') { if (window.location.pathname !== '/') {
// window.location.href = frontendURL + '/auth/activate/500' window.location.href = frontendURL + ''
} }
} }
} }
......
# STORE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Vuex Store files.
Vuex Store option is implemented in the Nuxt.js framework.
Creating a file in this directory automatically activates the option in the framework.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
const state = () => ({
user: {
username: '',
role: ''
}
})
const getters = {
getUser: state => state.user
}
const actions = {
setUser: ({ commit }, payload) => {
commit('setUser', payload)
},
deleteUser: ({ commit }) => {
commit('deleteUser')
}
}
const mutations = {
setUser (state, payload) {
state.user.username = payload['username']
state.user.role = payload['user_role']
},
deleteUser (state) {
state.user.username = ''
state.user.role = ''
}
}
export default {
state,
getters,
actions,
mutations,
namespaced: true
}
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment