このコミットが含まれているのは:
2026-07-16 23:12:14 +09:00
コミット 3f75994bd4
14個のファイルの変更592行の追加404行の削除
+84 -15
ファイルの表示
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useNavigate } from 'react-router-dom'
import { useLocation, useNavigate } from 'react-router-dom'
import PageTitle from '@/components/common/PageTitle'
import MainArea from '@/components/layout/MainArea'
@@ -11,9 +11,8 @@ import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { apiPost } from '@/lib/api'
import useDialogue from '@/lib/dialogues/useDialogue'
import { clearPostImportSession,
clearPostImportSourceDraft,
loadPostImportSession,
import { parsePostNewState, serialisePostNewState } from '@/lib/postNewQueryState'
import { clearPostImportSourceDraft,
buildNextEditedRow,
canEditReviewRow,
canRetryResultRow,
@@ -31,7 +30,6 @@ import { clearPostImportSession,
resultRowMessages,
reviewSummaryCounts,
retryImportRow,
savePostImportSession,
validatableImportRows } from '@/lib/postImportSession'
import { canEditContent } from '@/lib/users'
import Forbidden from '@/pages/Forbidden'
@@ -56,6 +54,7 @@ const isRepairRow = (row: PostImportRow): boolean =>
const PostImportReviewPage: FC<Props> = ({ user }) => {
const editable = canEditContent (user)
const dialogue = useDialogue ()
const location = useLocation ()
const navigate = useNavigate ()
const [session, setSession] = useState<PostImportSession | null> (null)
@@ -64,17 +63,84 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
const [editingRow, setEditingRow] = useState<PostImportRow | null> (null)
const [showExistingRows, setShowExistingRows] = useState (false)
const sessionRef = useRef<PostImportSession | null> (null)
const persistedSearchRef = useRef<string | null> (null)
useEffect (() => {
const loaded = loadPostImportSession (message =>
toast ({ title: '取込状態を復元できませんでした', description: message }))
if (loaded == null)
if (sessionRef.current != null && persistedSearchRef.current === location.search)
return
const parsed = parsePostNewState (location.search)
if (parsed == null)
{
navigate ('/posts/new', { replace: true })
return
}
const loaded = {
version: 2,
savedAt: new Date ().toISOString (),
source: parsed.source,
rows: parsed.rows,
repairMode: parsed.repairMode }
persistedSearchRef.current = location.search
sessionRef.current = loaded
setSession (loaded)
}, [navigate])
const hydrate = async () => {
if (parsed.shortcut)
{
try
{
const preview = await apiPost<{ rows: PostImportRow[] }> ('/posts/import/preview', {
source: parsed.source })
const rows = initialisePreviewRows (preview.rows)
const nextSession = {
...loaded,
source: parsed.source,
rows,
repairMode: resultRepairMode (rows) }
persistSession (nextSession)
}
catch
{
navigate ('/posts/new', { replace: true })
}
return
}
const requestedRows = validatableImportRows (parsed.rows)
if (requestedRows.length === 0)
return
try
{
const validated = await apiPost<{ rows: PostImportRow[] }> ('/posts/import/validate', {
rows: requestedRows.map (row => ({
sourceRow: row.sourceRow,
url: row.url,
attributes: row.attributes,
provenance: row.provenance,
tagSources: row.tagSources,
metadataUrl: row.metadataUrl })),
changed_row: 'all' })
const validatedRows = initialisePreviewRows (validated.rows)
if (!(hasExactSourceRows (requestedRows.map (row => row.sourceRow), validatedRows)))
return
const latest = sessionRef.current ?? loaded
const rows = mergeValidatedImportRows (latest.rows, validatedRows)
const nextSession = {
...latest,
rows,
repairMode: resultRepairMode (rows) }
sessionRef.current = nextSession
setSession (nextSession)
}
catch
{
}
}
void hydrate ()
}, [location.search, navigate])
useEffect (() => {
sessionRef.current = session
@@ -96,15 +162,18 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
const busy = loading || loadingRow != null
const persistSession = (nextSession: PostImportSession) => {
sessionRef.current = nextSession
setSession (nextSession)
savePostImportSession (nextSession, message =>
toast ({ title: '取込状態を保存できませんでした', description: message }))
const source = nextSession.rows.map (row => row.url).join ('\n')
const persistedSession = {
...nextSession,
source }
const nextPath = serialisePostNewState (persistedSession.rows)
persistedSearchRef.current = nextPath.replace ('/posts/new', '')
sessionRef.current = persistedSession
setSession (persistedSession)
navigate (nextPath, { replace: true })
}
const finishImport = () => {
clearPostImportSession (message =>
toast ({ title: '取込状態を削除できませんでした', description: message }))
clearPostImportSourceDraft (message =>
toast ({ title: '入力内容を削除できませんでした', description: message }))
navigate ('/posts')