Skip to content

Commit

Permalink
[desk-tool] Prevent publish action component from publishing before s…
Browse files Browse the repository at this point in the history
…ync/validation has completed
  • Loading branch information
bjoerge committed Feb 19, 2020
1 parent f952dad commit 8690d43
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 14 deletions.
75 changes: 61 additions & 14 deletions packages/@sanity/desk-tool/src/actions/PublishAction.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import * as React from 'react'
import {useDocumentOperation, useValidationStatus} from '@sanity/react-hooks'
import TimeAgo from '../components/TimeAgo'
import {useSyncState} from '@sanity/react-hooks'
import Spinner from 'part:@sanity/components/loading/spinner'

const DISABLED_REASON_TITLE = {
LIVE_EDIT_ENABLED: 'Cannot publish since liveEdit is enabled for this document type',
ALREADY_PUBLISHED: 'Already published',
NO_CHANGES: 'No unpublished changes'
}

const InlineSpinner = () => <Spinner inline />
const Checkmark = () => '✓ '

function getDisabledReason(reason, publishedAt) {
if (reason === 'ALREADY_PUBLISHED' && publishedAt) {
return (
Expand All @@ -20,7 +25,7 @@ function getDisabledReason(reason, publishedAt) {
}

export function PublishAction(props) {
const {id, type, liveEdit} = props
const {id, type, liveEdit, draft, published} = props

if (liveEdit) {
return {
Expand All @@ -31,39 +36,81 @@ export function PublishAction(props) {
}
}

const [publishStatus, setPublishStatus] = React.useState<'publishing' | 'published' | null>(null)
const [publishState, setPublishState] = React.useState<'publishing' | 'published' | null>(null)

const {publish}: any = useDocumentOperation(id, type)
const validationStatus = useValidationStatus(id, type)
const syncState = useSyncState(id, type)

const hasValidationErrors = validationStatus.markers.length > 0

// we use this to "schedule" publish after pending tasks (e.g. validation and sync) has completed
const [publishScheduled, setPublishScheduled] = React.useState<boolean>(false)

const doPublish = React.useCallback(() => {
publish.execute()
setPublishState('publishing')
}, [publish])

React.useEffect(() => {
if (publishScheduled && !syncState.isSyncing && !validationStatus.isValidating) {
if (!hasValidationErrors) {
doPublish()
}
setPublishScheduled(false)
}
}, [!syncState.isSyncing && !validationStatus.isValidating])

const title = publish.disabled
? getDisabledReason(publish.disabled, (props.published || {})._updatedAt) || ''
? getDisabledReason(publish.disabled, (published || {})._updatedAt) || ''
: hasValidationErrors
? 'There are validation errors that needs to be fixed before this document can be published'
: ''

React.useEffect(() => {
const delay = 4000
const didPublish = publishState === 'publishing' && !draft
const nextState = didPublish ? 'published' : null
const delay = didPublish ? 200 : 4000
const timer = setTimeout(() => {
setPublishStatus(null)
setPublishState(nextState)
}, delay)
return () => clearTimeout(timer)
}, [publishStatus])
}, [publishState, Boolean(draft)])

const disabled = Boolean(validationStatus.isValidating || hasValidationErrors || publish.disabled)
const disabled = Boolean(
publishScheduled ||
publishState === 'publishing' ||
publishState === 'published' ||
hasValidationErrors ||
publish.disabled
)

const didPublish = !props.draft && publishStatus === 'published'
return {
disabled,
label: didPublish ? 'Published' : 'Publish',
icon: didPublish ? () => '✓ ' : null,
title: didPublish ? null : title,
shortcut: disabled ? null : 'Ctrl+Alt+P',
label:
publishState === 'published'
? 'Published'
: publishScheduled || publishState === 'publishing'
? 'Publishing…'
: 'Publish',
icon:
publishState === 'published'
? Checkmark
: publishScheduled || publishState === 'publishing'
? InlineSpinner
: null,
title: publishScheduled
? 'Waiting for tasks to finish before publishing'
: publishState === 'published' || publishState === 'publishing'
? null
: title,
shortcut: disabled || publishScheduled ? null : 'Ctrl+Alt+P',
onHandle: () => {
publish.execute()
setPublishStatus('published')
if (syncState.isSyncing || validationStatus.isValidating) {
setPublishScheduled(true)
} else {
doPublish()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function DocumentStatusBarActionsInner(props: Props) {
show={firstActionState.title || firstActionState.shortcut}
arrow
theme="light"
hideOnClick={false}
disabled={TOUCH_SUPPORT}
className={styles.tooltip}
html={
Expand Down

0 comments on commit 8690d43

Please sign in to comment.