stuff for users page

This commit is contained in:
Gauthier Roebroeck 2025-06-30 15:40:45 +08:00
parent e69ee0aed1
commit 0af88c664c
4 changed files with 120 additions and 4 deletions

View file

@ -4,6 +4,7 @@ import { releasesHandlers } from '@/mocks/api/handlers/releases'
import { HttpResponse } from 'msw'
import { librariesHandlers } from '@/mocks/api/handlers/libraries'
import { referentialHandlers } from '@/mocks/api/handlers/referential'
import { usersHandlers } from '@/mocks/api/handlers/users'
export const handlers = [
...librariesHandlers,
@ -11,6 +12,7 @@ export const handlers = [
...actuatorHandlers,
...announcementHandlers,
...releasesHandlers,
...usersHandlers,
]
export const response401Unauthorized = () =>

View file

@ -0,0 +1,45 @@
import { httpTyped } from '@/mocks/api/httpTyped'
export const users = [
{
id: '0JEDA00AV4Z7G',
email: 'admin@example.org',
roles: ['ADMIN', 'FILE_DOWNLOAD', 'KOBO_SYNC', 'KOREADER_SYNC', 'PAGE_STREAMING', 'USER'],
sharedAllLibraries: true,
sharedLibrariesIds: [],
labelsAllow: [],
labelsExclude: [],
ageRestriction: null,
},
{
id: '0JEDA00AZ4QXH',
email: 'user@example.org',
roles: ['KOBO_SYNC', 'PAGE_STREAMING', 'USER'],
sharedAllLibraries: true,
sharedLibrariesIds: [],
labelsAllow: [],
labelsExclude: ['book'],
ageRestriction: null,
},
]
const latestActivity = {
userId: '0JEDA00AV4Z7G',
email: 'admin@example.org',
apiKeyId: null,
apiKeyComment: null,
ip: '127.0.0.1',
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:139.0) Gecko/20100101 Firefox/139.0',
success: true,
error: null,
dateTime: new Date('2025-06-30T06:56:33Z'),
source: 'Password',
}
export const usersHandlers = [
httpTyped.get('/api/v2/users/me', ({ response }) => response(200).json(users[0])),
httpTyped.get('/api/v2/users', ({ response }) => response(200).json(users)),
httpTyped.get('/api/v2/users/{userId}/authentication-activity/latest', ({ response }) =>
response(200).json(latestActivity),
),
]

View file

@ -0,0 +1,44 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import users from './users.vue'
import { http, delay } from 'msw'
import { response401Unauthorized } from '@/mocks/api/handlers'
const meta = {
component: users,
render: (args: object) => ({
components: { users },
setup() {
return { args }
},
template: '<users />',
}),
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
},
args: {},
} satisfies Meta<typeof users>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {},
}
export const Loading: Story = {
parameters: {
msw: {
handlers: [http.all('*', async () => await delay(5_000))],
},
},
}
export const Error: Story = {
parameters: {
msw: {
handlers: [http.all('*', response401Unauthorized)],
},
},
}

View file

@ -51,27 +51,34 @@
</div>
</template>
<template #[`item.activity`]="{ value }">
{{ $formatDate(value, { dateStyle: 'medium', timeStyle: 'short' }) }}
</template>
<template #[`item.actions`]="{ item: user }">
<div class="d-flex ga-1 justify-end">
<v-icon-btn
v-tooltip:bottom="'Change password'"
v-tooltip:bottom="$formatMessage(messages.changePassword)"
icon="i-mdi:lock-reset"
@click="showDialog(ACTION.PASSWORD, user)"
@mouseenter="dialogConfirmEdit.activator = $event.currentTarget"
:aria-label="$formatMessage(messages.changePassword)"
/>
<v-icon-btn
v-tooltip:bottom="'Edit user'"
v-tooltip:bottom="$formatMessage(messages.editUser)"
icon="i-mdi:pencil"
:disabled="me?.id == user.id"
@click="showDialog(ACTION.EDIT, user)"
@mouseenter="dialogConfirmEdit.activator = $event.currentTarget"
:aria-label="$formatMessage(messages.editUser)"
/>
<v-icon-btn
v-tooltip:bottom="'Delete user'"
v-tooltip:bottom="$formatMessage(messages.deleteUser)"
icon="i-mdi:delete"
:disabled="me?.id == user.id"
@click="showDialog(ACTION.DELETE, user)"
@mouseenter="dialogConfirm.activator = $event.currentTarget"
:aria-label="$formatMessage(messages.deleteUser)"
/>
</div>
</template>
@ -96,7 +103,7 @@ import { commonMessages } from '@/utils/i18n/common-messages'
import { storeToRefs } from 'pinia'
import { useDialogsStore } from '@/stores/dialogs'
import { useMessagesStore } from '@/stores/messages'
import { useIntl } from 'vue-intl'
import { defineMessage, useIntl } from 'vue-intl'
import { useDisplay } from 'vuetify'
import UserDeletionWarning from '@/components/user/DeletionWarning.vue'
import UserFormCreateEdit from '@/fragments/fragment/user/form/CreateEdit.vue'
@ -348,6 +355,24 @@ function handleDialogConfirmation(
setLoading(false)
})
}
const messages = {
deleteUser: defineMessage({
description: 'Tooltip for the delete user button in the users table',
defaultMessage: 'Delete user',
id: 'r6CqyT',
}),
editUser: defineMessage({
description: 'Tooltip for the edit user button in the users table',
defaultMessage: 'Edit user',
id: 'K40g4r',
}),
changePassword: defineMessage({
description: 'Tooltip for the change password button in the users table',
defaultMessage: 'Change password',
id: 'r7xCeA',
}),
}
</script>
<route lang="yaml">