このコミットが含まれているのは:
@@ -396,7 +396,9 @@ RSpec.describe 'Tags API', type: :request do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'prefers Tag when Tag and ExternalTag have the same id' do
|
it 'prefers Tag when Tag and ExternalTag have the same id' do
|
||||||
internal = create(:tag, name: 'internal_collision')
|
internal = create(
|
||||||
|
:tag,
|
||||||
|
tag_name: create(:tag_name, name: 'internal_collision'))
|
||||||
create(
|
create(
|
||||||
:external_tag,
|
:external_tag,
|
||||||
id: internal.id,
|
id: internal.id,
|
||||||
@@ -407,8 +409,8 @@ RSpec.describe 'Tags API', type: :request do
|
|||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json).to include(
|
expect(json).to include(
|
||||||
'id' => internal.id,
|
'id' => internal.id,
|
||||||
'name' => 'internal_collision')
|
'name' => 'internal_collision',
|
||||||
expect(json.fetch('category')).not_to eq('nico')
|
'category' => internal.category)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
import type { FC } from 'react'
|
import type { ComponentProps, FC } from 'react'
|
||||||
|
|
||||||
type Props = { children: React.ReactNode; className?: string }
|
type Props = ComponentProps<'h1'>
|
||||||
|
|
||||||
|
|
||||||
const PageTitle: FC<Props> = ({ children, className, ...rest }) => (
|
const PageTitle: FC<Props> = ({ children, className, ...rest }) => (
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const tagsKeys = {
|
|||||||
index: (p: FetchTagsParams) => ['tags', 'index', p] as const,
|
index: (p: FetchTagsParams) => ['tags', 'index', p] as const,
|
||||||
nicoRoot: ['tags', 'nico'] as const,
|
nicoRoot: ['tags', 'nico'] as const,
|
||||||
nicoIndex: (p: FetchNicoTagsParams) => ['tags', 'nico', 'index', p] as const,
|
nicoIndex: (p: FetchNicoTagsParams) => ['tags', 'nico', 'index', p] as const,
|
||||||
|
externalShow: (id: string) => ['tags', 'nico', id] as const,
|
||||||
show: (name: string) => ['tags', name] as const,
|
show: (name: string) => ['tags', name] as const,
|
||||||
changes: (p: { id?: string; page: number; limit: number }) =>
|
changes: (p: { id?: string; page: number; limit: number }) =>
|
||||||
['tags', 'changes', p] as const,
|
['tags', 'changes', p] as const,
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ export const fetchTag = async (id: string): Promise<Tag | null> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const fetchExternalTag = async (id: string): Promise<Tag | null> => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await apiGet (`/tags/nico/${ id }`)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const fetchTagByName = async (name: string): Promise<Tag | null> => {
|
export const fetchTagByName = async (name: string): Promise<Tag | null> => {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { waitFor } from '@testing-library/react'
|
import { screen, waitFor } from '@testing-library/react'
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import PostHistoryPage from '@/pages/posts/PostHistoryPage'
|
import PostHistoryPage from '@/pages/posts/PostHistoryPage'
|
||||||
|
import { buildTag } from '@/test/factories'
|
||||||
import { renderWithProviders } from '@/test/render'
|
import { renderWithProviders } from '@/test/render'
|
||||||
|
|
||||||
const postsApi = vi.hoisted (() => ({
|
const postsApi = vi.hoisted (() => ({
|
||||||
@@ -10,7 +11,8 @@ const postsApi = vi.hoisted (() => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const tagsApi = vi.hoisted (() => ({
|
const tagsApi = vi.hoisted (() => ({
|
||||||
fetchTag: vi.fn (),
|
fetchTag: vi.fn (),
|
||||||
|
fetchExternalTag: vi.fn (),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
vi.mock ('@/lib/posts', () => postsApi)
|
vi.mock ('@/lib/posts', () => postsApi)
|
||||||
@@ -19,13 +21,22 @@ vi.mock ('@/lib/tags', () => tagsApi)
|
|||||||
describe ('PostHistoryPage', () => {
|
describe ('PostHistoryPage', () => {
|
||||||
beforeEach (() => {
|
beforeEach (() => {
|
||||||
vi.clearAllMocks ()
|
vi.clearAllMocks ()
|
||||||
|
|
||||||
postsApi.fetchPostChanges.mockResolvedValue ({
|
postsApi.fetchPostChanges.mockResolvedValue ({
|
||||||
versions: [],
|
versions: [],
|
||||||
count: 0,
|
count: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it ('filters by external_tag without resolving the id as an internal tag', async () => {
|
it ('shows the external tag name when filtering by external_tag', async () => {
|
||||||
|
const external = buildTag ({
|
||||||
|
id: 7,
|
||||||
|
name: 'nico:external_history',
|
||||||
|
category: 'nico',
|
||||||
|
})
|
||||||
|
|
||||||
|
tagsApi.fetchExternalTag.mockResolvedValue (external)
|
||||||
|
|
||||||
renderWithProviders (
|
renderWithProviders (
|
||||||
<PostHistoryPage/>,
|
<PostHistoryPage/>,
|
||||||
{ route: '/posts/changes?external_tag=7' },
|
{ route: '/posts/changes?external_tag=7' },
|
||||||
@@ -39,6 +50,14 @@ describe ('PostHistoryPage', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect (tagsApi.fetchExternalTag).toHaveBeenCalledWith ('7')
|
||||||
expect (tagsApi.fetchTag).not.toHaveBeenCalled ()
|
expect (tagsApi.fetchTag).not.toHaveBeenCalled ()
|
||||||
|
|
||||||
|
expect (
|
||||||
|
await screen.findByRole ('heading', {
|
||||||
|
level: 1,
|
||||||
|
name: '耕作履歴(nico:external_history)',
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument ()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { clientAnimationTransition,
|
|||||||
clientScrollBehaviour } from '@/lib/clientAnimation'
|
clientScrollBehaviour } from '@/lib/clientAnimation'
|
||||||
import { fetchPostChanges, updatePost } from '@/lib/posts'
|
import { fetchPostChanges, updatePost } from '@/lib/posts'
|
||||||
import { postsKeys, tagsKeys } from '@/lib/queryKeys'
|
import { postsKeys, tagsKeys } from '@/lib/queryKeys'
|
||||||
import { fetchTag } from '@/lib/tags'
|
import { fetchExternalTag, fetchTag } from '@/lib/tags'
|
||||||
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'
|
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'
|
||||||
import { cn, dateString, originalCreatedAtString } from '@/lib/utils'
|
import { cn, dateString, originalCreatedAtString } from '@/lib/utils'
|
||||||
|
|
||||||
@@ -64,6 +64,12 @@ const PostHistoryPage: FC = () => {
|
|||||||
queryKey: tagsKeys.show (tagQueryId),
|
queryKey: tagsKeys.show (tagQueryId),
|
||||||
queryFn: () => fetchTag (tagQueryId) })
|
queryFn: () => fetchTag (tagQueryId) })
|
||||||
|
|
||||||
|
const externalTagQueryId = externalTagId ?? ''
|
||||||
|
const { data: externalTag } = useQuery ({
|
||||||
|
enabled: Boolean (externalTagId),
|
||||||
|
queryKey: tagsKeys.externalShow (externalTagQueryId),
|
||||||
|
queryFn: () => fetchExternalTag (externalTagQueryId) })
|
||||||
|
|
||||||
const { data, isLoading: loading } = useQuery ({
|
const { data, isLoading: loading } = useQuery ({
|
||||||
queryKey: postsKeys.changes ({ ...(id && { post: id }),
|
queryKey: postsKeys.changes ({ ...(id && { post: id }),
|
||||||
...(tagId && { tag: tagId }),
|
...(tagId && { tag: tagId }),
|
||||||
@@ -76,6 +82,9 @@ const PostHistoryPage: FC = () => {
|
|||||||
page, limit }) })
|
page, limit }) })
|
||||||
const changes = data?.versions ?? []
|
const changes = data?.versions ?? []
|
||||||
const totalPages = data ? Math.ceil (data.count / limit) : 0
|
const totalPages = data ? Math.ceil (data.count / limit) : 0
|
||||||
|
const displayedTag = externalTag ?? tag
|
||||||
|
const pageTitleLabel = `耕作履歴${ id ? `: 投稿 #${ id }` : '' }${
|
||||||
|
displayedTag ? `(${ displayedTag.name })` : '' }`
|
||||||
|
|
||||||
const qc = useQueryClient ()
|
const qc = useQueryClient ()
|
||||||
|
|
||||||
@@ -138,10 +147,14 @@ const PostHistoryPage: FC = () => {
|
|||||||
<title>{`耕作履歴 | ${ SITE_TITLE }`}</title>
|
<title>{`耕作履歴 | ${ SITE_TITLE }`}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<PageTitle>
|
<PageTitle aria-label={pageTitleLabel}>
|
||||||
耕作履歴
|
耕作履歴
|
||||||
{id && <>: 投稿 {<PrefetchLink to={`/posts/${ id }`}>#{id}</PrefetchLink>}</>}
|
{id && <>: 投稿 {<PrefetchLink to={`/posts/${ id }`}>#{id}</PrefetchLink>}</>}
|
||||||
{tag && <>(<TagLink tag={tag} withWiki={false} withCount={false}/>)</>}
|
{displayedTag && (
|
||||||
|
<>(<TagLink
|
||||||
|
tag={displayedTag}
|
||||||
|
withWiki={false}
|
||||||
|
withCount={false}/>)</>)}
|
||||||
</PageTitle>
|
</PageTitle>
|
||||||
|
|
||||||
{loading ? 'Loading...' : (
|
{loading ? 'Loading...' : (
|
||||||
|
|||||||
新しいイシューから参照
ユーザーをブロックする