platypush/platypush/backend/http/webapp/src/components/panels/Settings/Users.vue

346 lines
8.2 KiB
Vue

<template>
<Loading v-if="loading" />
<Modal ref="addUserModal" title="Add User">
<form action="#" method="POST" ref="addUserForm" @submit="createUser">
<label>
<input type="text" name="username" placeholder="Username" :disabled="commandRunning">
</label>
<label>
<input type="password" name="password" placeholder="Password" :disabled="commandRunning">
</label>
<label>
<input type="password" name="confirm_password" placeholder="Confirm password" :disabled="commandRunning">
</label>
<label>
<input type="submit" class="btn btn-primary" value="Create User" :disabled="commandRunning">
</label>
</form>
</Modal>
<Modal ref="changePasswordModal" title="Change Password">
<form action="#" method="POST" ref="changePasswordForm" @submit="changePassword">
<label>
<input type="text" name="username" placeholder="Username" :value="selectedUser" disabled="disabled">
</label>
<label>
<input type="password" name="password" placeholder="Current password" :disabled="commandRunning">
</label>
<label>
<input type="password" name="new_password" placeholder="New password" :disabled="commandRunning">
</label>
<label>
<input type="password" name="confirm_new_password" placeholder="Confirm new password" :disabled="commandRunning">
</label>
<label>
<input type="submit" class="btn btn-primary" value="Change Password" :disabled="commandRunning">
</label>
</form>
</modal>
<div class="body">
<ul class="users-list">
<li v-for="user in users" :key="user.user_id" class="item user" @click="selectedUser = user.username">
<div class="name col-8" v-text="user.username" />
<div class="actions pull-right col-4">
<Dropdown title="User Actions" icon-class="fa fa-ellipsis">
<DropdownItem text="Change Password" :disabled="commandRunning" icon-class="fa fa-key"
@click="showChangePasswordModal(user)" />
<DropdownItem text="Delete User" :disabled="commandRunning" icon-class="fa fa-trash"
@click="$refs.deleteUserDialog.show()" />
</Dropdown>
</div>
</li>
</ul>
<FloatingButton icon-class="fa fa-plus" text="Add User" @click="showAddUserModal" />
<ConfirmDialog ref="deleteUserDialog" @input="deleteUser(selectedUser)">
Are you sure that you want to remove the user {{ selectedUser }}?
</ConfirmDialog>
</div>
</template>
<script>
import ConfirmDialog from "@/components/elements/ConfirmDialog";
import Dropdown from "@/components/elements/Dropdown";
import Modal from "@/components/Modal";
import Loading from "@/components/Loading";
import Utils from "@/Utils";
import DropdownItem from "@/components/elements/DropdownItem";
import FloatingButton from "@/components/elements/FloatingButton";
export default {
name: "Users",
components: {ConfirmDialog, Dropdown, DropdownItem, FloatingButton, Loading, Modal},
mixins: [Utils],
props: {
sessionToken: {
type: String,
required: true,
},
currentUser: {
type: Object,
required: true,
}
},
data() {
return {
users: [],
commandRunning: false,
loading: false,
selectedUser: null,
}
},
methods: {
async refresh() {
this.loading = true
try {
this.users = await this.request('user.get_users')
} finally {
this.loading = false
}
},
async createUser(event) {
event.preventDefault()
const form = [...this.$refs.addUserForm.querySelectorAll('input[name]')].reduce((map, input) => {
map[input.name] = input.value
return map
}, {})
if (form.password !== form.confirm_password) {
this.notify({
title: 'Unable to create user',
text: 'Please check that the passwords match',
error: true,
image: {
iconClass: 'fas fa-times',
},
})
return
}
this.commandRunning = true
try {
await this.request('user.create_user', {
username: form.username,
password: form.password,
session_token: this.sessionToken,
})
} finally {
this.commandRunning = false
}
this.notify({
text: 'User ' + form.username + ' created',
image: {
iconClass: 'fas fa-check',
},
})
this.$refs.addUserModal.close()
await this.refresh()
},
async changePassword(event) {
event.preventDefault()
const form = [...this.$refs.changePasswordForm.querySelectorAll('input[name]')].reduce((map, input) => {
map[input.name] = input.value
return map
}, {})
if (form.new_password !== form.confirm_new_password) {
this.notify({
title: 'Unable to update password',
text: 'Please check that the passwords match',
error: true,
image: {
iconClass: 'fas fa-times',
},
})
return
}
this.commandRunning = true
let success = false
try {
success = await this.request('user.update_password', {
username: form.username,
old_password: form.password,
new_password: form.new_password,
})
} finally {
this.commandRunning = false
}
if (success) {
this.$refs.changePasswordModal.close()
this.notify({
text: 'Password successfully updated',
image: {
iconClass: 'fas fa-check',
},
})
} else {
this.notify({
title: 'Unable to update password',
text: 'The current password is incorrect',
error: true,
image: {
iconClass: 'fas fa-times',
},
})
}
},
async deleteUser(user) {
this.commandRunning = true
try {
await this.request('user.delete_user', {
username: user,
session_token: this.sessionToken,
})
} finally {
this.commandRunning = false
}
this.notify({
text: `User ${user} removed`,
image: {
iconClass: 'fas fa-check',
},
})
this.selectedUser = null
await this.refresh()
},
showAddUserModal() {
this.$refs.addUserModal.show()
this.$nextTick(() => {
this.$refs.addUserForm.reset()
this.$refs.addUserForm.username.focus()
})
},
showChangePasswordModal(user) {
this.$refs.changePasswordModal.show()
this.$nextTick(() => {
this.$refs.changePasswordForm.password.focus()
this.selectedUser = user.username
})
},
},
mounted() {
this.refresh()
},
}
</script>
<style lang="scss" scoped>
.settings-container {
.body {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
}
.modal {
.body {
height: auto;
}
}
form {
label {
display: block;
text-align: center;
}
}
.users-list {
background: $background-color;
margin-top: .15em;
height: max-content;
.user {
display: flex;
align-items: center;
padding: .75em;
&:not(:last-child) {
box-shadow: $border-shadow-bottom;
}
&:hover {
background: $hover-bg;
}
.actions {
display: inline-flex;
justify-content: right;
button {
background: none !important;
width: min-content;
}
}
}
}
@media screen and (max-width: $desktop) {
.users-list {
width: 100%;
}
}
@media screen and (min-width: $desktop) {
.users-list {
min-width: 400pt;
max-width: 600pt;
margin-top: 1em;
border-radius: 1em;
box-shadow: $border-shadow-bottom;
.user {
border-radius: 0;
&:first-child {
border-top-left-radius: 1em;
border-top-right-radius: 1em;
}
&:last-child {
border-bottom-left-radius: 1em;
border-bottom-right-radius: 1em;
}
}
}
}
}
:deep(.dropdown-container) {
button {
background: none !important;
}
}
:deep(.modal) {
.btn {
border-radius: 1em;
}
}
</style>