diff --git a/client/src/features/book/components/VirtualBookTable.vue b/client/src/features/book/components/VirtualBookTable.vue
index 6c538187a..e10e08663 100644
--- a/client/src/features/book/components/VirtualBookTable.vue
+++ b/client/src/features/book/components/VirtualBookTable.vue
@@ -878,7 +878,12 @@ defineExpose({
@click="focusTableCell(vItem.index, colIdx, $event, rowBook(vItem.index).id, col.id)"
>
-
+
= {}): BookCard {
const collapsedSeriesBook = makeBook(1, {
seriesId: 7,
seriesName: 'Discworld',
+ authors: ['Terry Pratchett'],
collapsedSeries: { bookCount: 3, readCount: 0, coverBookIds: [1], seriesLatestAddedAt: null },
})
const plainBook = makeBook(2)
@@ -139,4 +140,13 @@ describe('VirtualBookTable collapsed series rows', () => {
expect(wrapper.emitted('select')?.[0]?.[0]).toBe(plainBook.id)
})
+
+ it('gives a collapsed series row the author link used by book rows', () => {
+ const wrapper = mountTable()
+ const authorsCell = wrapper.findAllComponents({ name: 'BookTableCollapsedSeriesCell' }).find((cell) => cell.props('colId') === 'authors')
+ const linkFn = authorsCell?.props('linkFn') as ((chip: string) => string | null) | undefined
+
+ expect(authorsCell?.props('book')).toMatchObject({ authors: ['Terry Pratchett'] })
+ expect(linkFn?.('Terry Pratchett')).toBe('/authors?q=Terry%20Pratchett')
+ })
})
diff --git a/client/src/features/book/components/table/BookTableCollapsedSeriesCell.vue b/client/src/features/book/components/table/BookTableCollapsedSeriesCell.vue
index f0791197d..62aa37581 100644
--- a/client/src/features/book/components/table/BookTableCollapsedSeriesCell.vue
+++ b/client/src/features/book/components/table/BookTableCollapsedSeriesCell.vue
@@ -4,12 +4,14 @@ import { useI18n } from 'vue-i18n'
import { ChevronRight, LibraryBig } from '@lucide/vue'
import { FORMAT_TO_GROUP, type BookCard } from '@bookorbit/types'
import BookCoverSurface from '../BookCoverSurface.vue'
+import BookTableChipsCell from './BookTableChipsCell.vue'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { useCoverVersions } from '@/features/book/composables/useCoverVersions'
const props = defineProps<{
book: BookCard
colId: string
+ linkFn?: (chip: string) => string | null
}>()
const emit = defineEmits<{
@@ -95,6 +97,8 @@ function handleOpenSeries() {
>
+
+
diff --git a/client/src/features/book/components/table/__tests__/BookTableCollapsedSeriesCell.spec.ts b/client/src/features/book/components/table/__tests__/BookTableCollapsedSeriesCell.spec.ts
index f70e6ffbe..bb6468240 100644
--- a/client/src/features/book/components/table/__tests__/BookTableCollapsedSeriesCell.spec.ts
+++ b/client/src/features/book/components/table/__tests__/BookTableCollapsedSeriesCell.spec.ts
@@ -1,4 +1,4 @@
-import { mount } from '@vue/test-utils'
+import { mount, RouterLinkStub } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import type { BookCard } from '@bookorbit/types'
import BookTableCollapsedSeriesCell from '../BookTableCollapsedSeriesCell.vue'
@@ -12,7 +12,7 @@ vi.mock('@/features/book/composables/useCoverVersions', () => ({
}),
}))
-function makeBook(format: string | null): BookCard {
+function makeBook(format: string | null, overrides: Partial = {}): BookCard {
return {
id: 1,
status: 'present',
@@ -50,6 +50,7 @@ function makeBook(format: string | null): BookCard {
coverUpdatedAtByBookId: { 10: '2024-01-01T00:00:00.000Z', 11: '2024-02-01T00:00:00.000Z' },
seriesLatestAddedAt: null,
},
+ ...overrides,
} as BookCard
}
@@ -59,11 +60,16 @@ const CoverSurfaceStub = {
template: '
',
}
-function mountCell(format: string | null, colId = 'cover') {
+function mountCell(
+ format: string | null,
+ colId = 'cover',
+ options: { overrides?: Partial; linkFn?: (chip: string) => string | null } = {},
+) {
return mount(BookTableCollapsedSeriesCell, {
- props: { book: makeBook(format), colId },
+ props: { book: makeBook(format, options.overrides), colId, linkFn: options.linkFn },
global: {
stubs: {
+ RouterLink: RouterLinkStub,
BookCoverSurface: CoverSurfaceStub,
Tooltip: { template: '
' },
TooltipTrigger: { template: '
' },
@@ -115,4 +121,23 @@ describe('BookTableCollapsedSeriesCell comic flag', () => {
await button.trigger('click')
expect(wrapper.emitted('open-series')).toEqual([[]])
})
+
+ it('links the series authors in the authors column', () => {
+ const wrapper = mountCell('epub', 'authors', {
+ overrides: { authors: ['Terry Pratchett', 'Neil Gaiman', 'Stephen Baxter'] },
+ linkFn: (name) => `/authors?q=${encodeURIComponent(name)}`,
+ })
+ const links = wrapper.findAllComponents(RouterLinkStub)
+
+ expect(links.map((link) => link.text())).toEqual(['Terry Pratchett', 'Neil Gaiman'])
+ expect(links.map((link) => link.props('to'))).toEqual(['/authors?q=Terry%20Pratchett', '/authors?q=Neil%20Gaiman'])
+ expect(wrapper.text()).toContain('+1')
+ })
+
+ it('shows a dash in the authors column when the series has no authors', () => {
+ const wrapper = mountCell('epub', 'authors', { linkFn: (name) => `/authors?q=${name}` })
+
+ expect(wrapper.findAllComponents(RouterLinkStub)).toHaveLength(0)
+ expect(wrapper.text()).toBe('-')
+ })
})