From eeefb09d0c9bd63c016471b4fc4b9a2018f942dd Mon Sep 17 00:00:00 2001 From: miteruzo Date: Mon, 22 Jun 2026 08:16:29 +0900 Subject: [PATCH] #378 --- .../app/controllers/wiki_pages_controller.rb | 18 +++++++++++------- backend/app/models/wiki_page.rb | 1 + backend/app/representations/wiki_page_repr.rb | 2 +- frontend/src/components/TagLink.test.tsx | 15 +++++++++++++++ frontend/src/components/TagLink.tsx | 2 +- frontend/src/lib/tags.ts | 1 - frontend/src/pages/wiki/WikiDetailPage.tsx | 8 ++++++-- frontend/src/pages/wiki/WikiDiffPage.tsx | 7 +++++-- frontend/src/pages/wiki/WikiHistoryPage.tsx | 1 + .../src/pages/wiki/WikiSearchPage.test.tsx | 13 +++++++++++++ frontend/src/pages/wiki/WikiSearchPage.tsx | 1 + frontend/src/test/factories.ts | 1 + frontend/src/types.ts | 4 +++- 13 files changed, 59 insertions(+), 15 deletions(-) diff --git a/backend/app/controllers/wiki_pages_controller.rb b/backend/app/controllers/wiki_pages_controller.rb index 818ae02..f3ece93 100644 --- a/backend/app/controllers/wiki_pages_controller.rb +++ b/backend/app/controllers/wiki_pages_controller.rb @@ -4,17 +4,18 @@ class WikiPagesController < ApplicationController def index title = params[:title].to_s.strip if title.blank? - return render json: WikiPageRepr.base(WikiPage.joins(:tag_name).includes(:tag_name)) + return render json: WikiPageRepr.base( + WikiPage.joins(:tag_name).includes(tag_name: :tag)) end - q = WikiPage.joins(:tag_name).includes(:tag_name) + q = WikiPage.joins(:tag_name).includes(tag_name: :tag) .where('tag_names.name LIKE ?', "%#{ WikiPage.sanitize_sql_like(title) }%") render json: WikiPageRepr.base(q.limit(20)) end def show page = WikiPage.joins(:tag_name) - .includes(:tag_name) + .includes(tag_name: :tag) .find_by(id: params[:id]) render_wiki_page_or_404 page end @@ -22,7 +23,7 @@ class WikiPagesController < ApplicationController def show_by_title title = params[:title].to_s.strip page = WikiPage.joins(:tag_name) - .includes(:tag_name) + .includes(tag_name: :tag) .find_by(tag_name: { name: title }) render_wiki_page_or_404 page end @@ -51,7 +52,7 @@ class WikiPagesController < ApplicationController from = params[:from].presence to = params[:to].presence - page = WikiPage.joins(:tag_name).includes(:tag_name).find(id) + page = WikiPage.joins(:tag_name).includes(tag_name: :tag).find(id) from_rev = from && page.wiki_revisions.find(from) to_rev = to ? page.wiki_revisions.find(to) : page.current_revision @@ -76,6 +77,7 @@ class WikiPagesController < ApplicationController render json: { wiki_page_id: page.id, title: page.title, + deprecated_at: page.deprecated_at, older_revision_id: from_rev&.id, newer_revision_id: to_rev.id, diff: diff_json } @@ -157,7 +159,7 @@ class WikiPagesController < ApplicationController def changes id = params[:id].presence q = WikiRevision.joins(wiki_page: :tag_name) - .includes(:created_user, wiki_page: :tag_name) + .includes(:created_user, wiki_page: { tag_name: :tag }) .order(id: :desc) q = q.where(wiki_page_id: id) if id @@ -165,7 +167,9 @@ class WikiPagesController < ApplicationController { revision_id: rev.id, pred: rev.base_revision_id, succ: nil, - wiki_page: { id: rev.wiki_page_id, title: rev.wiki_page.title }, + wiki_page: { id: rev.wiki_page_id, + title: rev.wiki_page.title, + deprecated_at: rev.wiki_page.deprecated_at }, user: rev.created_user && { id: rev.created_user.id, name: rev.created_user.name }, kind: rev.kind, message: rev.message, diff --git a/backend/app/models/wiki_page.rb b/backend/app/models/wiki_page.rb index efe7868..68928f1 100644 --- a/backend/app/models/wiki_page.rb +++ b/backend/app/models/wiki_page.rb @@ -22,6 +22,7 @@ class WikiPage < ApplicationRecord validates :body, presence: true def title = tag_name.name + def deprecated_at = tag_name.tag&.deprecated_at def title= val (self.tag_name ||= build_tag_name).name = val diff --git a/backend/app/representations/wiki_page_repr.rb b/backend/app/representations/wiki_page_repr.rb index 3fb712c..ee09de3 100644 --- a/backend/app/representations/wiki_page_repr.rb +++ b/backend/app/representations/wiki_page_repr.rb @@ -2,7 +2,7 @@ module WikiPageRepr - BASE = { methods: [:title] }.freeze + BASE = { methods: [:title, :deprecated_at] }.freeze module_function diff --git a/frontend/src/components/TagLink.test.tsx b/frontend/src/components/TagLink.test.tsx index 3c2a152..e6a073c 100644 --- a/frontend/src/components/TagLink.test.tsx +++ b/frontend/src/components/TagLink.test.tsx @@ -18,6 +18,21 @@ describe ('TagLink', () => { expect (screen.getByText ('4')).toBeInTheDocument () }) + it ('does not append deprecated state to the rendered tag name', () => { + renderWithProviders ( + , + ) + + expect (screen.getByRole ('link', { name: '旧タグ' })).toBeInTheDocument () + expect (screen.queryByText ('(廃止)')).not.toBeInTheDocument () + }) + it ('links wiki markers to the correct detail route', () => { renderWithProviders ( , diff --git a/frontend/src/components/TagLink.tsx b/frontend/src/components/TagLink.tsx index 33bfc40..4abdf1a 100644 --- a/frontend/src/components/TagLink.tsx +++ b/frontend/src/components/TagLink.tsx @@ -128,4 +128,4 @@ const TagLink: FC = ({ tag, ) } -export default TagLink \ No newline at end of file +export default TagLink diff --git a/frontend/src/lib/tags.ts b/frontend/src/lib/tags.ts index 6ec70df..31cad85 100644 --- a/frontend/src/lib/tags.ts +++ b/frontend/src/lib/tags.ts @@ -66,7 +66,6 @@ export const fetchTagByName = async (name: string): Promise => { } } - export const fetchTagChanges = async ( { id, page, limit }: { id?: string diff --git a/frontend/src/pages/wiki/WikiDetailPage.tsx b/frontend/src/pages/wiki/WikiDetailPage.tsx index 249bf84..15b7f93 100644 --- a/frontend/src/pages/wiki/WikiDetailPage.tsx +++ b/frontend/src/pages/wiki/WikiDetailPage.tsx @@ -39,6 +39,7 @@ const WikiDetailPage: FC = () => { queryFn: () => fetchWikiPageByTitle (title, { version }) }) const effectiveTitle = wikiPage?.title ?? title + const deprecated = wikiPage?.deprecatedAt != null const { data: tag } = useQuery ({ enabled: Boolean (effectiveTitle), @@ -88,7 +89,7 @@ const WikiDetailPage: FC = () => { return ( - {`${ title } Wiki | ${ SITE_TITLE }`} + {`${ effectiveTitle }${ deprecated ? '(廃止)' : '' } Wiki | ${ SITE_TITLE }`} {!(wikiPage?.body) && } @@ -110,10 +111,13 @@ const WikiDetailPage: FC = () => {

- + {deprecated && (廃止)}

{loading ?
Loading...
: } diff --git a/frontend/src/pages/wiki/WikiDiffPage.tsx b/frontend/src/pages/wiki/WikiDiffPage.tsx index 3a1d0dd..5206f2e 100644 --- a/frontend/src/pages/wiki/WikiDiffPage.tsx +++ b/frontend/src/pages/wiki/WikiDiffPage.tsx @@ -23,6 +23,9 @@ const WikiDiffPage: FC = () => { const query = new URLSearchParams (location.search) const from = query.get ('from') const to = query.get ('to') + const displayTitle = diff + ? `${ diff.title }${ diff.deprecatedAt != null ? '(廃止)' : '' }` + : '' useEffect (() => { void (async () => { @@ -33,9 +36,9 @@ const WikiDiffPage: FC = () => { return ( - {`Wiki 差分: ${ diff?.title } | ${ SITE_TITLE }`} + {`Wiki 差分: ${ displayTitle } | ${ SITE_TITLE }`} - {diff?.title} + {displayTitle}
{diff ? ( diff --git a/frontend/src/pages/wiki/WikiHistoryPage.tsx b/frontend/src/pages/wiki/WikiHistoryPage.tsx index 973a812..0affe21 100644 --- a/frontend/src/pages/wiki/WikiHistoryPage.tsx +++ b/frontend/src/pages/wiki/WikiHistoryPage.tsx @@ -59,6 +59,7 @@ const WikiHistoryPage: FC = () => { to={`/wiki/${ encodeURIComponent (change.wikiPage.title) }?version=${ change.revisionId }`}> {change.wikiPage.title} + {change.wikiPage.deprecatedAt != null && (廃止)} {change.pred == null ? '新規' : '更新'} diff --git a/frontend/src/pages/wiki/WikiSearchPage.test.tsx b/frontend/src/pages/wiki/WikiSearchPage.test.tsx index 82213ca..fd87e1b 100644 --- a/frontend/src/pages/wiki/WikiSearchPage.test.tsx +++ b/frontend/src/pages/wiki/WikiSearchPage.test.tsx @@ -42,4 +42,17 @@ describe ('WikiSearchPage', () => { }) expect (await screen.findByRole ('link', { name: '検索結果' })).toBeInTheDocument () }) + + it ('marks deprecated wiki tags in the result title', async () => { + api.apiGet.mockResolvedValueOnce ([ + buildWikiPage ({ + title: '旧タグ', + deprecatedAt: '2026-06-01T00:00:00.000Z', + }), + ]) + + renderWithProviders () + + expect (await screen.findByRole ('link', { name: '旧タグ(廃止)' })).toBeInTheDocument () + }) }) diff --git a/frontend/src/pages/wiki/WikiSearchPage.tsx b/frontend/src/pages/wiki/WikiSearchPage.tsx index 07d651d..b7b671d 100644 --- a/frontend/src/pages/wiki/WikiSearchPage.tsx +++ b/frontend/src/pages/wiki/WikiSearchPage.tsx @@ -86,6 +86,7 @@ const WikiSearchPage: FC = () => { {page.title} + {page.deprecatedAt != null && (廃止)} {dateString (page.updatedAt)} diff --git a/frontend/src/test/factories.ts b/frontend/src/test/factories.ts index 9ae62df..6ab756d 100644 --- a/frontend/src/test/factories.ts +++ b/frontend/src/test/factories.ts @@ -58,6 +58,7 @@ export const buildUser = (overrides: Partial = {}): User => ({ export const buildWikiPage = (overrides: Partial = {}): WikiPage => ({ id: 1, title: 'テストWiki', + deprecatedAt: null, createdUserId: 1, updatedUserId: 1, createdAt: '2026-01-02T03:04:05.000Z', diff --git a/frontend/src/types.ts b/frontend/src/types.ts index b156a83..e725e4e 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -299,6 +299,7 @@ export type ViewFlagBehavior = typeof ViewFlagBehavior[keyof typeof ViewFlagBeha export type WikiPage = { id: number title: string + deprecatedAt: string | null createdUserId: number updatedUserId: number createdAt: string @@ -312,7 +313,7 @@ export type WikiPageChange = { revisionId: number pred: number | null succ: null - wikiPage: Pick + wikiPage: Pick user: Pick kind: 'content' | 'redirect' message: string | null @@ -321,6 +322,7 @@ export type WikiPageChange = { export type WikiPageDiff = { wikiPageId: number title: string + deprecatedAt: string | null olderRevisionId: number | null newerRevisionId: number diff: WikiPageDiffDiff[] }