このコミットが含まれているのは:
@@ -26,22 +26,26 @@ describe ('post import row state', () => {
|
||||
sourceRow: 2,
|
||||
skipReason: 'existing',
|
||||
existingPostId: 20 })
|
||||
const invalid = buildPostImportRow ({
|
||||
const manual = buildPostImportRow ({
|
||||
sourceRow: 3,
|
||||
skipReason: 'manual' })
|
||||
const invalid = buildPostImportRow ({
|
||||
sourceRow: 4,
|
||||
status: 'error',
|
||||
validationErrors: { url: ['invalid'] } })
|
||||
const created = buildPostImportRow ({
|
||||
sourceRow: 4,
|
||||
sourceRow: 5,
|
||||
importStatus: 'created',
|
||||
createdPostId: 40 })
|
||||
const rows = [ready, existing, invalid, created]
|
||||
const rows = [ready, existing, manual, invalid, created]
|
||||
|
||||
expect (processableImportRows (rows)).toEqual ([ready, existing])
|
||||
expect (processableImportRows (rows)).toEqual ([ready])
|
||||
expect (creatableImportRows (rows)).toEqual ([ready])
|
||||
expect (reviewSummaryCounts (rows)).toEqual ({
|
||||
total: 4,
|
||||
submittable: 1,
|
||||
skipPlanned: 1 })
|
||||
creatable: 1,
|
||||
manualSkipped: 1,
|
||||
existingSkipped: 1,
|
||||
pendingOrError: 1 })
|
||||
})
|
||||
|
||||
it ('preserves terminal rows while merging validation results', () => {
|
||||
|
||||
@@ -2,9 +2,17 @@ import type { PostImportEditableDraft,
|
||||
PostImportResultRow,
|
||||
PostImportRow } from '@/lib/postImportTypes'
|
||||
|
||||
const hasSkipReason = (row: PostImportRow): boolean =>
|
||||
export const isExistingSkipRow = (row: PostImportRow): boolean =>
|
||||
row.skipReason === 'existing'
|
||||
|
||||
|
||||
export const isManualSkipRow = (row: PostImportRow): boolean =>
|
||||
row.skipReason === 'manual'
|
||||
|
||||
|
||||
const hasSkipReason = (row: PostImportRow): boolean =>
|
||||
row.skipReason != null
|
||||
|
||||
const hasValidationErrors = (row: PostImportRow): boolean =>
|
||||
Object.keys (row.validationErrors ?? { }).length > 0
|
||||
|
||||
@@ -15,6 +23,26 @@ const isRepairableImportStatus = (row: PostImportRow): boolean =>
|
||||
isRecoverableRow (row)
|
||||
&& (row.importStatus === 'failed' || row.importStatus === 'pending')
|
||||
|
||||
|
||||
export const isNonRecoverableFailedRow = (row: PostImportRow): boolean =>
|
||||
row.importStatus === 'failed' && row.recoverable !== true
|
||||
|
||||
|
||||
export const isTerminalRow = (row: PostImportRow): boolean =>
|
||||
row.importStatus === 'created'
|
||||
|| row.importStatus === 'skipped'
|
||||
|| isNonRecoverableFailedRow (row)
|
||||
|
||||
|
||||
export const isCompletedReviewRow = (row: PostImportRow): boolean =>
|
||||
row.importStatus === 'created'
|
||||
|| row.importStatus === 'skipped'
|
||||
|| hasSkipReason (row)
|
||||
|
||||
|
||||
export const validatableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
rows.filter (row => !(hasSkipReason (row)) && !(isTerminalRow (row)))
|
||||
|
||||
const buildResetSnapshot = (row: PostImportRow) => ({
|
||||
url: row.url,
|
||||
attributes: { ...row.attributes },
|
||||
@@ -29,7 +57,7 @@ const buildResetSnapshot = (row: PostImportRow) => ({
|
||||
|
||||
|
||||
export const processableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
rows.filter (row => {
|
||||
validatableImportRows (rows).filter (row => {
|
||||
if (row.importStatus === 'created')
|
||||
return false
|
||||
if (row.importStatus === 'skipped')
|
||||
@@ -46,13 +74,12 @@ export const creatableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
|
||||
|
||||
export const reviewSummaryCounts = (rows: PostImportRow[]) => ({
|
||||
total: rows.length,
|
||||
submittable: rows.filter (row =>
|
||||
creatableImportRows ([row]).length > 0
|
||||
&& !(hasValidationErrors (row))).length,
|
||||
skipPlanned: rows.filter (row =>
|
||||
processableImportRows ([row]).length > 0
|
||||
&& hasSkipReason (row)).length })
|
||||
creatable: rows.filter (row => creatableImportRows ([row]).length > 0).length,
|
||||
manualSkipped: rows.filter (row => isManualSkipRow (row)).length,
|
||||
existingSkipped: rows.filter (row => isExistingSkipRow (row)).length,
|
||||
pendingOrError: rows.filter (row =>
|
||||
!(isCompletedReviewRow (row))
|
||||
&& creatableImportRows ([row]).length === 0).length })
|
||||
|
||||
|
||||
export const resultSummaryCounts = (rows: PostImportRow[]) =>
|
||||
@@ -85,19 +112,22 @@ export const resultRepairMode = (
|
||||
|
||||
|
||||
export const canEditReviewRow = (row: PostImportRow): boolean =>
|
||||
!(row.importStatus === 'created'
|
||||
!(hasSkipReason (row)
|
||||
|| row.importStatus === 'created'
|
||||
|| row.importStatus === 'skipped'
|
||||
|| (row.importStatus === 'failed' && row.recoverable !== true))
|
||||
|
||||
|
||||
export const canEditResultRow = (row: PostImportRow): boolean =>
|
||||
row.recoverable === true
|
||||
row.skipReason == null
|
||||
&& row.recoverable === true
|
||||
&& (row.importStatus === 'failed'
|
||||
|| (row.importStatus === 'pending' && hasValidationErrors (row)))
|
||||
|
||||
|
||||
export const canRetryResultRow = (row: PostImportRow): boolean =>
|
||||
row.recoverable === true
|
||||
row.skipReason == null
|
||||
&& row.recoverable === true
|
||||
&& (row.importStatus === 'failed'
|
||||
|| (row.importStatus === 'pending' && !(hasValidationErrors (row))))
|
||||
|
||||
|
||||
@@ -24,10 +24,13 @@ describe ('post import storage', () => {
|
||||
importStatus: 'skipped',
|
||||
skipReason: 'existing',
|
||||
existingPostId: 10 })
|
||||
const manual = buildPostImportRow ({
|
||||
sourceRow: 3,
|
||||
skipReason: 'manual' })
|
||||
|
||||
expect (savePostImportSession ({
|
||||
source: skipped.url,
|
||||
rows: [row, skipped],
|
||||
rows: [row, skipped, manual],
|
||||
repairMode: 'all' })).toBe (true)
|
||||
expect (loadPostImportSession ()).toMatchObject ({
|
||||
version: 2,
|
||||
@@ -39,7 +42,9 @@ describe ('post import storage', () => {
|
||||
{
|
||||
importStatus: 'skipped',
|
||||
skipReason: 'existing',
|
||||
existingPostId: 10 }] })
|
||||
existingPostId: 10 },
|
||||
{
|
||||
skipReason: 'manual' }] })
|
||||
|
||||
expect (savePostImportSourceDraft ('https://example.com')).toBe (true)
|
||||
expect (loadPostImportSourceDraft ()).toEqual ({ source: 'https://example.com' })
|
||||
|
||||
@@ -129,7 +129,7 @@ const isValidOrigin = (
|
||||
const isValidSkipReason = (
|
||||
value: unknown,
|
||||
): value is PostImportSkipReason =>
|
||||
value === 'existing'
|
||||
value === 'existing' || value === 'manual'
|
||||
|
||||
const isPositiveInteger = (value: unknown): value is number =>
|
||||
Number.isInteger (value) && Number (value) > 0
|
||||
|
||||
@@ -5,7 +5,7 @@ export type PostImportStatus =
|
||||
| 'created'
|
||||
| 'skipped'
|
||||
| 'failed'
|
||||
export type PostImportSkipReason = 'existing'
|
||||
export type PostImportSkipReason = 'existing' | 'manual'
|
||||
export type PostImportResultStatus = 'created' | 'skipped' | 'failed'
|
||||
export type PostImportAttributeValue = string | number
|
||||
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする