このコミットが含まれているのは:
2026-07-12 00:54:21 +09:00
コミット 440a6c9961
3個のファイルの変更51行の追加3行の削除
+28 -2
ファイルの表示
@@ -32,6 +32,7 @@ type ImportRow = {
status: 'ready' | 'warning' | 'error'
existing: boolean
metadataUrl?: string
createdPostId?: number
importStatus?: 'pending' | 'created' | 'skipped' | 'failed' }
type ParsedImport = { columns: Column[], rows: { sourceRow: number, values: string[] }[] }
type Phase = 'source' | 'mapping' | 'preview' | 'result'
@@ -75,6 +76,10 @@ const PostImportPage: FC<Props> = ({ user }) => {
existing })
setColumns (data.columns)
setParsed (data)
setMappings ({ })
setRows ([])
setResults ([])
setUrlColumn ('')
if (data.columns.length === 1)
setUrlColumn ('0')
else
@@ -175,6 +180,24 @@ const PostImportPage: FC<Props> = ({ user }) => {
}
}
const updateExisting = async (value: 'skip' | 'error') => {
setExisting (value)
const generation = ++validationGeneration.current
setLoading (true)
try
{
const validated = await apiPost<{ rows: ImportRow[] }> ('/posts/import/validate',
{ rows, existing: value, changed_row: -1 })
if (generation === validationGeneration.current)
setRows (validated.rows)
}
finally
{
if (generation === validationGeneration.current)
setLoading (false)
}
}
const submit = async () => {
const targets = rows.filter (row => (row as ImportRow & { importStatus?: string }).importStatus !== 'created')
if (targets.length === 0)
@@ -192,7 +215,9 @@ const PostImportPage: FC<Props> = ({ user }) => {
setResults (result.rows)
setRows (current => current.map (row => {
const resultRow = result.rows.find (_1 => _1.sourceRow === row.sourceRow)
return resultRow ? { ...row, importStatus: resultRow.status } : row
return resultRow ? { ...row, importStatus: resultRow.status,
createdPostId: resultRow.post?.id,
errors: resultRow.errors ?? row.errors } : row
}))
}
catch
@@ -273,7 +298,7 @@ const PostImportPage: FC<Props> = ({ user }) => {
<label>URL <select value={urlColumn} onChange={ev => setUrlColumn (ev.target.value)}>
{columns.map ((column, index) => <option key={column.key} value={index}>{column.label}</option>)}
</select></label>
<label>稿 <select value={existing} onChange={ev => setExisting (ev.target.value as typeof existing)}>
<label>稿 <select value={existing} onChange={ev => updateExisting (ev.target.value as typeof existing)}>
<option value="skip"></option><option value="error"></option>
</select></label>
{['title', 'thumbnail_base', 'original_created_from', 'original_created_before', 'duration', 'tags', 'parent_post_ids'].map (field =>
@@ -290,6 +315,7 @@ const PostImportPage: FC<Props> = ({ user }) => {
<div className="space-y-3"><p></p>
{results.map (result => <div key={result.sourceRow} className="rounded border p-2 dark:border-neutral-700"> {result.sourceRow}{result.status} {result.post && <PrefetchLink to={`/posts/${result.post.id}`}>稿</PrefetchLink>}<FieldError messages={Object.values (result.errors ?? { }).flat ()}/></div>)}
<Button type="button" onClick={() => setPhase ('preview')}></Button>
<Button type="button" variant="outline" onClick={() => setPhase ('preview')}></Button>
<Button type="button" variant="outline" onClick={() => setPhase ('source')}></Button>
</div>)}
</MainArea>)