Add an user management page for admins

This commit is contained in:
2026-04-30 23:51:11 +02:00
parent d8d7bc9570
commit e29743d5fa
14 changed files with 262 additions and 4 deletions

View File

@@ -100,6 +100,14 @@ onMounted(() => {
<RouterLink v-if="authStore.user" to="/add" class="navbar-item" activeClass="is-active">
{{ $t('navbar.addbook') }}
</RouterLink>
<RouterLink
v-if="authStore.user && authStore.user.admin"
to="/admin/users"
class="navbar-item"
activeClass="is-active"
>
{{ $t('navbar.usersmgt') }}
</RouterLink>
<div
v-if="authStore.user && appInfo && !appInfo.demoMode"
class="navbar-item is-hidden-desktop"

View File

@@ -23,7 +23,7 @@ const passwordError = computed(() => {
return extractFormErrorFromField('Password', errors.value)
})
async function onSubmit(e) {
async function onSubmit() {
const res = await postLogin(user)
if (res.ok) {
let json = await res.json()
@@ -36,7 +36,7 @@ async function onSubmit(e) {
}
async function login(username, json) {
useAuthStore().login({ username: username, token: json['token'] })
useAuthStore().login({ username: username, admin: json['admin'], token: json['token'] })
}
</script>

View File

@@ -0,0 +1,76 @@
<script setup>
import { ref, computed } from 'vue'
import { getUsers } from './api.js'
const limit = 50
const pageNumber = ref(1)
const offset = computed(() => (pageNumber.value - 1) * limit)
const data = ref(null)
const error = ref(null)
let totalUsersNumber = computed(() =>
typeof data != 'undefined' && data.value != null ? data.value['count'] : 0,
)
let pageTotal = computed(() => Math.ceil(totalUsersNumber.value / limit))
fetchData()
function fetchData() {
getUsers(data, error, limit, offset.value)
}
function pageChange(newPageNumber) {
pageNumber.value = newPageNumber
data.value = null
fetchData()
}
</script>
<template>
<div v-if="error">{{ $t('usersmanagement.error', { error: error.message }) }}</div>
<div v-else-if="data">
<table class="table">
<thead>
<th>#</th>
<th>{{ $t('usersmanagement.name') }}</th>
<th>{{ $t('usersmanagement.admin') }}</th>
<th>
<abbr :title="$t('usersmanagement.addedbookshelp')">{{
$t('usersmanagement.addedbooks')
}}</abbr>
</th>
<th>
<abbr :title="$t('usersmanagement.bookshelp')">{{ $t('usersmanagement.books') }}</abbr>
</th>
</thead>
<tbody>
<tr v-for="user in data.users" :key="user.id">
<th class="numbercell">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td class="boolcell"><input type="checkbox" disabled :checked="user.admin" /></td>
<td class="numbercell">{{ user.addedbookscount }}</td>
<td class="numbercell">{{ user.userbookscount }}</td>
</tr>
</tbody>
</table>
<Pagination
:pageNumber="pageNumber"
:pageTotal="pageTotal"
maxItemDisplayed="11"
@pageChange="pageChange"
/>
</div>
<div v-else>{{ $t('usersmanagement.loading') }}</div>
</template>
<style scoped>
.boolcell {
text-align: center;
}
.numbercell {
text-align: right;
}
</style>

View File

@@ -118,6 +118,11 @@ export function getBookCall(id) {
return userFetch('/ws/book/' + id)
}
export function getUsers(data, error, limit, offset) {
const queryParams = new URLSearchParams({ limit: limit, offset: offset })
return useFetch(data, error, '/ws/admin/users' + '?' + queryParams.toString())
}
export function postBook(book) {
return genericPayloadCall('/ws/book', book.value, 'POST')
}

View File

@@ -11,6 +11,7 @@
"logout": "Log out",
"signup": "Sign up",
"search": "Search",
"usersmgt": "Users Management",
"login": "Log In"
},
"barcode": {
@@ -100,5 +101,15 @@
},
"collection": {
"error": "Error when loading collection: {error}"
},
"usersmanagement": {
"error": "Error when loading users: {error}",
"name": "Name",
"admin": "Is Admin ?",
"addedbooks": "Added Books",
"addedbookshelp": "Number of books the user created or imported.",
"books": "Books Number",
"bookshelp": "Total number of books of the user.",
"loading": "Loading..."
}
}

View File

@@ -11,6 +11,7 @@
"logout": "Se déconnecter",
"signup": "S'inscrire",
"search": "Rechercher",
"usersmgt": "Gestion Des Utilisateurs",
"login": "Se connecter"
},
"barcode": {
@@ -100,5 +101,15 @@
},
"collection": {
"error": "Erreur pendant le chargement de la liste : {error}"
},
"usersmanagement": {
"error": "Erreur pendant le chargement des utilisateurs: {error}",
"name": "Nom",
"admin": "Administrateur ?",
"addedbooks": "Livres Ajoutés",
"addedbookshelp": "Nombre de livres créés ou importés par l'utilisateur.",
"books": "Nombre De Livres",
"bookshelp": "Le nombre total de livres de cet utilisateur.",
"loading": "Chargement..."
}
}

View File

@@ -13,6 +13,7 @@ import ScanBook from './ScanBook.vue'
import SearchBook from './SearchBook.vue'
import ImportInventaire from './ImportInventaire.vue'
import InstanceBrowser from './InstanceBrowser.vue'
import UsersManagement from './UsersManagement.vue'
import { useAuthStore } from './auth.store'
const routes = [
@@ -30,6 +31,7 @@ const routes = [
{ path: '/add', component: BookFormEdit },
{ path: '/signup', component: SignUp },
{ path: '/login', component: LogIn },
{ path: '/admin/users', component: UsersManagement },
]
export const router = createRouter({