Skip to content

Commit

Permalink
fix(desk-tool): make sure validation result is about current revision…
Browse files Browse the repository at this point in the history
… before publishing
  • Loading branch information
bjoerge committed Sep 26, 2022
1 parent 44adf9c commit 6d38e04
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ import {editState} from './editState'
export interface ValidationStatus {
isValidating: boolean
validation: ValidationMarker[]
revision?: string
}

const INITIAL_VALIDATION_STATUS: ValidationStatus = {isValidating: true, validation: []}
const INITIAL_VALIDATION_STATUS: ValidationStatus = {
isValidating: true,
validation: [],
}

function findReferenceIds(obj: any): Set<string> {
return reduceJSON(
Expand Down Expand Up @@ -150,7 +154,7 @@ export const validation = memoize(
return of({validation: EMPTY_VALIDATION, isValidating: false})
}
return concat(
of({isValidating: true}),
of({isValidating: true, revision: document._rev}),
validateDocumentObservable(ctx.getClient, document, ctx.schema, {
getDocumentExists,
}).pipe(
Expand Down
51 changes: 40 additions & 11 deletions packages/sanity/src/desk/actions/documentActions/PublishAction.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {CheckmarkIcon, PublishIcon} from '@sanity/icons'
import React, {useCallback, useEffect, useState} from 'react'
import {isValidationErrorMarker} from '@sanity/types'
import {useSyncState, useDocumentOperation, useValidationStatus} from '../../../hooks'
import {useDocumentOperation, useEditState, useSyncState, useValidationStatus} from '../../../hooks'
import {DocumentActionComponent} from '../types'
import {InsufficientPermissionsMessage} from '../../../components/InsufficientPermissionsMessage'
import {TimeAgo} from '../../components'
Expand Down Expand Up @@ -38,11 +38,16 @@ export const PublishAction: DocumentActionComponent = (props) => {
const {publish} = useDocumentOperation(id, type)
const validationStatus = useValidationStatus(id, type)
const syncState = useSyncState(id, type)
const {changesOpen, editState, onHistoryOpen} = useDocumentPane()
const {changesOpen, onHistoryOpen, documentId, documentType} = useDocumentPane()
const editState = useEditState(documentId, documentType)

const revision = (editState?.draft || editState?.published || {})._rev

const hasValidationErrors = validationStatus.validation.some(isValidationErrorMarker)
// we use this to "schedule" publish after pending tasks (e.g. validation and sync) has completed
const [publishScheduled, setPublishScheduled] = useState<boolean>(false)
const isNeitherSyncingNorValidating = !syncState.isSyncing && !validationStatus.isValidating
const isSyncing = syncState.isSyncing
const isValidating = validationStatus.isValidating
const [permissions, isPermissionsLoading] = useDocumentPairPermissions({
id,
type,
Expand All @@ -66,14 +71,28 @@ export const PublishAction: DocumentActionComponent = (props) => {
}, [publish])

useEffect(() => {
if (publishScheduled && isNeitherSyncingNorValidating) {
if (!hasValidationErrors) {
doPublish()
}
// make sure the validation status is about the current revision and not an earlier one
const validationComplete =
validationStatus.isValidating === false && validationStatus.revision !== revision

setPublishScheduled(false)
if (!publishScheduled || isSyncing || !validationComplete) {
return
}

if (!hasValidationErrors) {
doPublish()
}
}, [isNeitherSyncingNorValidating, doPublish, hasValidationErrors, publishScheduled])
setPublishScheduled(false)
}, [
isSyncing,
doPublish,
hasValidationErrors,
publishScheduled,
validationStatus.revision,
revision,
isValidating,
validationStatus.isValidating,
])

useEffect(() => {
const didPublish = publishState === 'publishing' && !hasDraft
Expand All @@ -92,12 +111,22 @@ export const PublishAction: DocumentActionComponent = (props) => {
}, [changesOpen, publishState, hasDraft, onHistoryOpen])

const handle = useCallback(() => {
if (syncState.isSyncing || validationStatus.isValidating) {
if (
syncState.isSyncing ||
validationStatus.isValidating ||
validationStatus.revision !== revision
) {
setPublishScheduled(true)
} else {
doPublish()
}
}, [syncState.isSyncing, validationStatus.isValidating, doPublish])
}, [
syncState.isSyncing,
validationStatus.isValidating,
validationStatus.revision,
revision,
doPublish,
])

if (liveEdit) {
return {
Expand Down
1 change: 1 addition & 0 deletions packages/sanity/src/hooks/useValidationStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {useDocumentStore} from '../datastores'
export interface ValidationStatus {
isValidating: boolean
validation: ValidationMarker[]
revision?: string
}

const INITIAL: ValidationStatus = {validation: [], isValidating: false}
Expand Down

0 comments on commit 6d38e04

Please sign in to comment.