このコミットが含まれているのは:
@@ -29,6 +29,7 @@ import {
|
||||
clearPostImportSession,
|
||||
clearPostImportSourceDraft,
|
||||
generatePostImportSessionId,
|
||||
hasThumbnailBaseValue,
|
||||
initialisePreviewRows,
|
||||
isCompletedReviewRow,
|
||||
isExistingSkipRow,
|
||||
@@ -41,6 +42,7 @@ import {
|
||||
reviewSummaryCounts,
|
||||
retryImportRow,
|
||||
loadPostImportSession,
|
||||
serialisedPostImportRowsEqual,
|
||||
savePostImportSession,
|
||||
} from '@/lib/postImportSession'
|
||||
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'
|
||||
@@ -125,7 +127,7 @@ const buildDryRunFormData = (row: PostImportRow): FormData => {
|
||||
String (row.attributes.originalCreatedBefore ?? ''))
|
||||
formData.append ('video_ms', String (row.attributes.videoMs ?? ''))
|
||||
formData.append ('duration', String (row.attributes.duration ?? ''))
|
||||
if (!(row.attributes.thumbnailBase) && row.thumbnailFile != null)
|
||||
if (!(hasThumbnailBaseValue (row.attributes.thumbnailBase)) && row.thumbnailFile != null)
|
||||
formData.append ('thumbnail', row.thumbnailFile)
|
||||
return formData
|
||||
}
|
||||
@@ -174,6 +176,12 @@ const indexedBulkResults = (
|
||||
): PostImportResultRow[] =>
|
||||
rows.map ((row, index) => {
|
||||
const result = results[index]
|
||||
const errors =
|
||||
result?.baseErrors?.length
|
||||
? {
|
||||
...(result.errors ?? { }),
|
||||
base: [...new Set ([...(result.errors?.base ?? []), ...result.baseErrors])] }
|
||||
: result?.errors
|
||||
if (result?.status === 'created' && result.post != null)
|
||||
{
|
||||
return {
|
||||
@@ -182,7 +190,7 @@ const indexedBulkResults = (
|
||||
post: result.post,
|
||||
fieldWarnings: result.fieldWarnings,
|
||||
baseWarnings: result.baseWarnings,
|
||||
errors: result.errors }
|
||||
errors }
|
||||
}
|
||||
if (result?.status === 'skipped' && result.existingPost != null)
|
||||
{
|
||||
@@ -193,52 +201,28 @@ const indexedBulkResults = (
|
||||
existingPost: result.existingPost,
|
||||
fieldWarnings: result.fieldWarnings,
|
||||
baseWarnings: result.baseWarnings,
|
||||
errors: result.errors }
|
||||
errors }
|
||||
}
|
||||
return {
|
||||
sourceRow: row.sourceRow,
|
||||
status: 'failed',
|
||||
fieldWarnings: result?.fieldWarnings,
|
||||
baseWarnings: result?.baseWarnings,
|
||||
errors: result?.errors,
|
||||
errors,
|
||||
recoverable: result?.recoverable }
|
||||
})
|
||||
|
||||
const serialisableRowJson = (row: PostImportRow): string =>
|
||||
JSON.stringify ({
|
||||
url: row.url,
|
||||
sourceRow: row.sourceRow,
|
||||
attributes: row.attributes,
|
||||
fieldWarnings: row.fieldWarnings,
|
||||
baseWarnings: row.baseWarnings,
|
||||
validationErrors: row.validationErrors,
|
||||
importErrors: row.importErrors,
|
||||
provenance: row.provenance,
|
||||
tagSources: row.tagSources,
|
||||
status: row.status,
|
||||
skipReason: row.skipReason,
|
||||
existingPostId: row.existingPostId,
|
||||
existingPost: row.existingPost,
|
||||
metadataUrl: row.metadataUrl,
|
||||
resetSnapshot: row.resetSnapshot,
|
||||
createdPostId: row.createdPostId,
|
||||
importStatus: row.importStatus,
|
||||
recoverable: row.recoverable })
|
||||
|
||||
const serialisableRowsEqual = (
|
||||
left: PostImportRow[],
|
||||
right: PostImportRow[],
|
||||
): boolean =>
|
||||
left.length === right.length
|
||||
&& left.every ((row, index) =>
|
||||
serialisableRowJson (row) === serialisableRowJson (right[index]))
|
||||
|
||||
const mergePreviewRow = (
|
||||
currentRow: PostImportRow,
|
||||
preview: PreviewResponse,
|
||||
): PostImportRow => {
|
||||
const nextRow: PostImportRow = {
|
||||
...currentRow,
|
||||
attributes: { ...currentRow.attributes },
|
||||
provenance: { ...currentRow.provenance },
|
||||
tagSources: {
|
||||
automatic: currentRow.tagSources?.automatic ?? '',
|
||||
manual: currentRow.tagSources?.manual ?? '' },
|
||||
url: preview.url,
|
||||
fieldWarnings: preview.fieldWarnings ?? { },
|
||||
baseWarnings: preview.baseWarnings ?? [],
|
||||
@@ -267,9 +251,7 @@ const mergePreviewRow = (
|
||||
if (currentRow.provenance.tags !== 'manual')
|
||||
{
|
||||
nextRow.attributes.tags = preview.tags ?? ''
|
||||
nextRow.tagSources = {
|
||||
automatic: preview.tags ?? '',
|
||||
manual: currentRow.tagSources?.manual ?? '' }
|
||||
nextRow.tagSources.automatic = preview.tags ?? ''
|
||||
}
|
||||
if (currentRow.provenance.videoMs !== 'manual')
|
||||
nextRow.attributes.videoMs = preview.videoMs ?? ''
|
||||
@@ -296,7 +278,7 @@ const buildBulkFormData = (rows: PostImportRow[]): FormData => {
|
||||
video_ms: row.attributes.videoMs ?? '',
|
||||
duration: row.attributes.duration ?? '' }))))
|
||||
rows.forEach ((row, index) => {
|
||||
if (!(row.attributes.thumbnailBase) && row.thumbnailFile != null)
|
||||
if (!(hasThumbnailBaseValue (row.attributes.thumbnailBase)) && row.thumbnailFile != null)
|
||||
formData.append (`thumbnails[${ index }]`, row.thumbnailFile)
|
||||
})
|
||||
return formData
|
||||
@@ -380,10 +362,10 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
const canRecoverFromUrlOnly = serialised.complete
|
||||
if (!(canRecoverFromUrlOnly)
|
||||
&& (!(saved))
|
||||
&& !(serialisableRowsEqual (loadedSession?.rows ?? [], nextSession.rows)))
|
||||
&& !(serialisedPostImportRowsEqual (loadedSession?.rows ?? [], nextSession.rows)))
|
||||
return null
|
||||
if (saved
|
||||
&& !(serialisableRowsEqual (loadedSession?.rows ?? [], nextSession.rows)))
|
||||
&& !(serialisedPostImportRowsEqual (loadedSession?.rows ?? [], nextSession.rows)))
|
||||
return null
|
||||
|
||||
const persistedSession = buildSession (nextSession.rows)
|
||||
@@ -425,6 +407,11 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
return
|
||||
|
||||
const baseRow = baseSession.rows[index]
|
||||
if (baseRow.skipReason === 'manual'
|
||||
|| baseRow.importStatus === 'created'
|
||||
|| baseRow.importStatus === 'skipped'
|
||||
|| isNonRecoverableFailedRow (baseRow))
|
||||
continue
|
||||
const controller = new AbortController ()
|
||||
controllers.add (controller)
|
||||
try
|
||||
@@ -441,10 +428,8 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
if (currentRow == null)
|
||||
continue
|
||||
const mergedRow = mergePreviewRow (currentRow, preview)
|
||||
const nextRows = replaceImportRow (latestSession.rows, mergedRow)
|
||||
const nextSession = buildSession (nextRows)
|
||||
sessionRef.current = nextSession
|
||||
setSession (nextSession)
|
||||
await persistSession (buildSession (
|
||||
replaceImportRow (latestSession.rows, mergedRow)))
|
||||
}
|
||||
catch (requestError)
|
||||
{
|
||||
@@ -457,15 +442,6 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
row => row.sourceRow === baseRow.sourceRow)
|
||||
if (currentRow == null)
|
||||
continue
|
||||
const nextRows = replaceImportRow (
|
||||
latestSession.rows,
|
||||
applyThumbnailWarning ({
|
||||
...currentRow,
|
||||
existingPostId: undefined,
|
||||
existingPost: undefined }))
|
||||
const nextSession = buildSession (nextRows)
|
||||
sessionRef.current = nextSession
|
||||
setSession (nextSession)
|
||||
if (!(isApiError (requestError)))
|
||||
continue
|
||||
}
|
||||
@@ -481,24 +457,25 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
}
|
||||
|
||||
const hydrate = async () => {
|
||||
const parsedSessionId = parsePostNewSessionId (location.search)
|
||||
const sessionId = parsedSessionId ?? generatePostImportSessionId ()
|
||||
const loadedSession = loadPostImportSession (sessionId)
|
||||
const parsed = await parsePostNewState (location.search)
|
||||
if (!(active))
|
||||
return
|
||||
if (parsed == null)
|
||||
if (parsed == null && loadedSession == null)
|
||||
{
|
||||
navigate ('/posts/new', { replace: true })
|
||||
return
|
||||
}
|
||||
|
||||
const parsedSessionId = parsePostNewSessionId (location.search)
|
||||
const sessionId = parsedSessionId ?? generatePostImportSessionId ()
|
||||
sessionIdRef.current = sessionId
|
||||
const loaded = loadPostImportSession (sessionId) ?? buildSession (parsed.rows)
|
||||
const loaded = loadedSession ?? buildSession (parsed?.rows ?? [])
|
||||
persistedSearchRef.current = location.search
|
||||
sessionRef.current = loaded
|
||||
setSession (loaded)
|
||||
|
||||
if (parsed.shortcut)
|
||||
if (loadedSession == null && parsed?.shortcut)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -580,7 +557,7 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (parsedSessionId == null)
|
||||
if (loadedSession == null)
|
||||
{
|
||||
await persistSession (loaded)
|
||||
}
|
||||
@@ -672,21 +649,28 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
.map (([key, values]) => [key, [...values]])),
|
||||
baseWarnings: [...row.resetSnapshot.baseWarnings],
|
||||
metadataUrl: row.resetSnapshot.metadataUrl,
|
||||
thumbnailFile: undefined,
|
||||
thumbnailObjectUrl: undefined }
|
||||
thumbnailFile: undefined }
|
||||
: row
|
||||
const urlChanged = draft.url !== baseRow.url
|
||||
const nextRow = buildNextEditedRow (baseRow, draft, urlChanged)
|
||||
let candidateRow = nextRow
|
||||
try
|
||||
{
|
||||
candidateRow =
|
||||
urlChanged
|
||||
? mergePreviewRow (
|
||||
nextRow,
|
||||
await apiGet<PreviewResponse> ('/posts/preview', {
|
||||
params: { url: nextRow.url } }))
|
||||
: nextRow
|
||||
const dryRun = await apiPost<PreviewResponse> (
|
||||
'/posts?dry=1',
|
||||
buildDryRunFormData (nextRow))
|
||||
buildDryRunFormData (candidateRow))
|
||||
const latestSession = sessionRef.current
|
||||
if (latestSession == null)
|
||||
return { saved: false, row: null }
|
||||
|
||||
const mergedRow = mergeDryRunRow (nextRow, dryRun)
|
||||
const mergedRow = mergeDryRunRow (candidateRow, dryRun)
|
||||
const mergedRows = replaceImportRow (latestSession.rows, mergedRow)
|
||||
const nextSession = await persistSession (buildSession (mergedRows))
|
||||
if (nextSession == null)
|
||||
@@ -708,7 +692,7 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
&& requestError.response?.status === 422)
|
||||
{
|
||||
const errorRow = {
|
||||
...nextRow,
|
||||
...candidateRow,
|
||||
validationErrors: requestError.response.data.errors ?? { },
|
||||
baseWarnings: [],
|
||||
fieldWarnings: { },
|
||||
@@ -731,7 +715,6 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
|
||||
|
||||
await dialogue.form ({
|
||||
title: '投稿を編輯',
|
||||
description: `投稿 ${ row.sourceRow } の内容を確認し、必要な項目を編輯してください.`,
|
||||
cancelText: '取消',
|
||||
size: 'large',
|
||||
body: controls => (
|
||||
|
||||
新しい課題から参照
ユーザをブロックする