unavailable libraries marker

This commit is contained in:
Gauthier Roebroeck 2026-01-21 16:59:18 +08:00
parent 2dbae701fa
commit 40944eb253
5 changed files with 69 additions and 17 deletions

View file

@ -4,7 +4,7 @@ import ReorderLibraries from './ReorderLibraries.vue'
import { httpTyped } from '@/mocks/api/httpTyped'
import { CLIENT_SETTING_USER, type ClientSettingUserLibrary } from '@/types/ClientSettingsUser'
import type { components } from '@/generated/openapi/komga'
import { libraries } from '@/mocks/api/handlers/libraries'
import { mockLibraries } from '@/mocks/api/handlers/libraries'
const meta = {
component: ReorderLibraries,
@ -31,21 +31,21 @@ type Story = StoryObj<typeof meta>
const libHandler = httpTyped.get('/api/v1/libraries', ({ response }) => {
const bds = {
...libraries[0],
...mockLibraries[0],
id: '3',
name: 'BDs',
} as components['schemas']['LibraryDto']
const magazines = {
...libraries[0],
...mockLibraries[0],
id: '4',
name: 'Magazines',
} as components['schemas']['LibraryDto']
const manga = {
...libraries[0],
...mockLibraries[0],
id: '5',
name: 'Mangas',
} as components['schemas']['LibraryDto']
const libs = [...libraries, bds, magazines, manga]
const libs = [...mockLibraries, bds, magazines, manga]
return response(200).json(libs)
})

View file

@ -12,6 +12,7 @@ import DialogConfirmInstance from '@/components/dialog/ConfirmInstance.vue'
import SnackQueue from '@/components/SnackQueue.vue'
import { delay, http } from 'msw'
import { response401Unauthorized } from '@/mocks/api/handlers'
import { mockLibraries } from '@/mocks/api/handlers/libraries'
const meta = {
component: Libraries,
@ -46,6 +47,37 @@ export const Default: Story = {
},
}
export const Unavailable: Story = {
args: {},
parameters: {
msw: {
handlers: [
httpTyped.get('/api/v1/libraries', ({ response }) =>
response(200).json(mockLibraries.map((it) => ({ ...it, unavailable: true }))),
),
httpTyped.get('/api/v1/client-settings/user/list', ({ response }) => {
const userLibraries: Record<string, ClientSettingUserLibrary> = {
'2': {
unpinned: true,
},
}
const settings: Record<string, components['schemas']['ClientSettingUserUpdateDto']> = {
[CLIENT_SETTING_USER.NEXTUI_LIBRARIES]: {
value: JSON.stringify(userLibraries),
},
}
return response(200).json(settings)
}),
],
},
},
play: async ({ canvas, userEvent }) => {
await waitFor(() => userEvent.click(canvas.getByText(/more/i)))
await waitFor(() => expect(canvas.queryByText(/comics/i)).toBeVisible())
await waitFor(() => expect(canvas.queryAllByText(/unavailable/i)).toHaveLength(2))
},
}
export const NonAdmin: Story = {
parameters: {
msw: {

View file

@ -51,6 +51,13 @@
:to="`/libraries/${library.id}`"
prepend-icon="blank"
>
<template
v-if="library.unavailable"
#subtitle
>
<span class="text-error">{{ unavailableMessage }}</span>
</template>
<template #append>
<v-icon-btn
v-if="isAdmin"
@ -98,6 +105,13 @@
:to="`/libraries/${library.id}`"
prepend-icon="blank"
>
<template
v-if="library.unavailable"
#subtitle
>
<span class="text-error">{{ unavailableMessage }}</span>
</template>
<template #append>
<v-icon-btn
v-if="isAdmin"
@ -203,4 +217,10 @@ function createLibrary() {
})
}
}
const unavailableMessage = intl.formatMessage({
description: 'Library list item subtitle: unavailable',
defaultMessage: 'Unavailable',
id: '5rziSG',
})
</script>

View file

@ -4,7 +4,7 @@ import { createMockColada } from '@/mocks/pinia-colada'
import { enableAutoUnmount } from '@vue/test-utils'
import { useGetLibrariesById } from '@/composables/libraries'
import { httpTyped } from '@/mocks/api/httpTyped'
import { libraries } from '@/mocks/api/handlers/libraries'
import { mockLibraries } from '@/mocks/api/handlers/libraries'
import type { components } from '@/generated/openapi/komga'
import { CLIENT_SETTING_USER, type ClientSettingUserLibrary } from '@/types/ClientSettingsUser'
import { waitFor } from 'storybook/test'
@ -15,17 +15,17 @@ beforeEach(() =>
server.use(
httpTyped.get('/api/v1/libraries', ({ response }) => {
const bds = {
...libraries[0],
...mockLibraries[0],
id: '3',
name: 'BDs',
} as components['schemas']['LibraryDto']
const magazines = {
...libraries[0],
...mockLibraries[0],
id: '4',
name: 'Magazines',
} as components['schemas']['LibraryDto']
const manga = {
...libraries[0],
...mockLibraries[0],
id: '5',
name: 'Mangas',
} as components['schemas']['LibraryDto']

View file

@ -2,7 +2,7 @@ import { httpTyped } from '@/mocks/api/httpTyped'
import type { components } from '@/generated/openapi/komga'
import { response400BadRequest, response404NotFound } from '@/mocks/api/handlers'
export const libraries = [
export const mockLibraries = [
{
id: '1',
name: 'eBooks',
@ -69,16 +69,16 @@ export const libraries = [
]
export const librariesHandlers = [
httpTyped.get('/api/v1/libraries', ({ response }) => response(200).json(libraries)),
httpTyped.get('/api/v1/libraries', ({ response }) => response(200).json(mockLibraries)),
httpTyped.post('/api/v1/libraries', async ({ request, response }) => {
const body = await request.json()
if (libraries.some((it) => it.id === body.name)) {
if (mockLibraries.some((it) => it.id === body.name)) {
return response.untyped(response400BadRequest())
}
const lib = Object.assign({}, body, { unavailable: false, id: body.name })
libraries.push(lib)
mockLibraries.push(lib)
return response(200).json(lib)
}),
@ -86,26 +86,26 @@ export const librariesHandlers = [
const body = await request.json()
const libraryId = params['libraryId']
const existing = libraries.find((it) => it.id === libraryId)
const existing = mockLibraries.find((it) => it.id === libraryId)
if (!existing) {
return response.untyped(response404NotFound())
}
libraries[libraries.indexOf(existing)] = Object.assign({}, existing, body)
mockLibraries[mockLibraries.indexOf(existing)] = Object.assign({}, existing, body)
return response(204).empty()
}),
httpTyped.delete('/api/v1/libraries/{libraryId}', ({ params, response }) => {
const libraryId = params['libraryId']
const existing = libraries.find((it) => it.id === libraryId)
const existing = mockLibraries.find((it) => it.id === libraryId)
if (!existing) {
return response.untyped(response404NotFound())
}
libraries.splice(libraries.indexOf(existing), 1)
mockLibraries.splice(mockLibraries.indexOf(existing), 1)
return response(204).empty()
}),