Skip to content

Commit

Permalink
feat(releases): schedule and unschedule releases
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoerge committed Oct 28, 2024
1 parent 4b81a4c commit bb9a972
Show file tree
Hide file tree
Showing 24 changed files with 588 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ export const PublishedRelease = defineEvent({
description: 'User published a release',
})

/** When a release is successfully scheduled
* @internal
*/
export const ScheduledRelease = defineEvent({
name: 'Schedule release',
version: 1,
description: 'User scheduled a release',
})

/** When a release is successfully scheduled
* @internal
*/
export const UnscheduledRelease = defineEvent({
name: 'Unschedule release',
version: 1,
description: 'User unscheduled a release',
})

/** When a release is successfully archived
* @internal
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ export function ReleaseDetailsDialog(props: ReleaseDetailsDialogProps): JSX.Elem
// TODO MAKE SURE THIS IS HOW WE WANT TO DO THIS
const {setPerspective} = usePerspective()

const submit = useCallback(
(formValue: EditableReleaseDocument) => {
return formAction === 'edit' ? updateRelease(formValue) : createRelease(formValue)
},
[createRelease, formAction, updateRelease],
)

const handleOnSubmit = useCallback(
async (event: FormEvent<HTMLFormElement>) => {
try {
Expand All @@ -67,7 +60,8 @@ export function ReleaseDetailsDialog(props: ReleaseDetailsDialogProps): JSX.Elem
...value,
metadata: {...value.metadata, title: value.metadata?.title?.trim()},
}
await submit(submitValue)
const action = formAction === 'edit' ? updateRelease : createRelease
await action(submitValue)
if (formAction === 'create') {
setPerspective(value._id)
telemetry.log(CreatedRelease, {origin})
Expand All @@ -86,7 +80,17 @@ export function ReleaseDetailsDialog(props: ReleaseDetailsDialogProps): JSX.Elem
onSubmit()
}
},
[value, submit, formAction, setPerspective, telemetry, origin, toast, onSubmit],
[
value,
formAction,
updateRelease,
createRelease,
setPerspective,
telemetry,
origin,
toast,
onSubmit,
],
)

const handleOnChange = useCallback((changedValue: EditableReleaseDocument) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('ReleaseDetailsDialog', () => {
expect(onCancelMock).toHaveBeenCalled()
})

it('should call createRelease, setPerspective, and onCreate when form is submitted with a valid slug', async () => {
it('should call createRelease, setPerspective, and onCreate when form is submitted', async () => {
const value: Partial<ReleaseDocument> = {
metadata: {
title: 'Bundle 1',
Expand All @@ -89,7 +89,7 @@ describe('ReleaseDetailsDialog', () => {

expect(useReleaseOperations().createRelease).toHaveBeenCalledWith(
expect.objectContaining({
_id: expect.stringMatching(/system-tmp-releases\.r\w{8}$/),
_id: expect.stringMatching(/_\.releases\.r\w{8}$/),
...value,
}),
)
Expand All @@ -98,7 +98,7 @@ describe('ReleaseDetailsDialog', () => {
expect(usePerspective().setPerspective).toHaveBeenCalledOnce()

expect(usePerspective().setPerspective).toHaveBeenCalledWith(
expect.stringMatching(/system-tmp-releases\.r\w{8}$/),
expect.stringMatching(/_\.releases\.r\w{8}$/),
)
expect(onSubmitMock).toHaveBeenCalled()
})
Expand All @@ -111,7 +111,7 @@ describe('ReleaseDetailsDialog', () => {
_id: 'existing-release',
name: 'existing',
state: 'active',
_type: 'system-tmp.release',
_type: 'system.release',
_createdAt: '2024-07-02T11:37:51Z',
_updatedAt: '2024-07-12T10:39:32Z',
createdBy: '123',
Expand Down
49 changes: 47 additions & 2 deletions packages/sanity/src/core/releases/i18n/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const releasesLocaleStrings = {
'action.open': 'Open',
/** Action text for publishing a release */
'action.publish': 'Publish',
/** Action text for scheduling a release */
'action.schedule': 'Schedule for publishing',
/** Action text for scheduling a release */
'action.unschedule': 'Unschedule',
/** Action text for publishing all documents in a release (and the release itself) */
'action.publish-all': 'Publish all',
/** Text for the review changes button in release tool */
Expand Down Expand Up @@ -122,6 +126,39 @@ const releasesLocaleStrings = {
/** Label for when documents in release have validation errors */
'publish-dialog.validation.error': 'Some documents have validation errors',

/** Title o unschedule release dialog */
'schedule-button.tooltip': 'Are you sure you want to unschedule the release?',

/** Schedule release button tooltip when validation is loading */
'schedule-button-tooltip.validation.loading': 'Validating documents...',
/** Schedule release button tooltip when there are validation errors */
'schedule-button-tooltip.validation.error': 'Some documents have validation errors',

/** Schedule release button tooltip when the release is already scheduled */
'schedule-button-tooltip.already-scheduled': 'This release is already scheduled',

/** Title for unschedule release dialog */
'schedule-dialog.confirm-title':
'Are you sure you want to schedule the release and all document versions for publishing?',
/** Description shown in unschedule relaease dialog */
'schedule-dialog.confirm-description_one':
"The '<strong>{{title}}</strong>' release and its document will be published on the selected date.",
/** Description for the dialog confirming the publish of a release with multiple documents */
'schedule-dialog.confirm-description_other':
'The <strong>{{title}}</strong> release and its {{count}} document versions will be scheduled for publishing.',

/** Description for the confirm button for scheduling a release */
'schedule-dialog.confirm-button': 'Yes, schedule for publishing',

/** Label for date picker when scheduling a release */
'schedule-dialog.select-publish-date-label': 'Schedule for publishing on',

/** Title for unschedule release dialog */
'unschedule-dialog.confirm-title': 'Are you sure you want to unschedule the release?',
/** Description shown in unschedule relaease dialog */
'unschedule-dialog.confirm-description':
'The release will no longer be published on the scheduled date',

/** Description for the review changes button in release tool */
'review.description': 'Add documents to this release to review changes',
/** Text for when a document is edited */
Expand Down Expand Up @@ -162,9 +199,17 @@ const releasesLocaleStrings = {
/** Header for the document table in the release tool - time */
'table-header.time': 'Time',
/** Text for toast when release failed to publish */
'toast.error': "Failed to publish the '<strong>{{title}}</strong>'",
'toast.publish.error': "Failed to publish '<strong>{{title}}</strong>': {{error}}",
/** Text for toast when release has been published */
'toast.published': "The '<strong>{{title}}</strong>' release was published.",
'toast.publish.success': "The '<strong>{{title}}</strong>' release was published.",
/** Text for toast when release failed to schedule */
'toast.schedule.error': "Failed to schedule '<strong>{{title}}</strong>': {{error}}",
/** Text for toast when release has been scheduled */
'toast.schedule.success': "The '<strong>{{title}}</strong>' release was scheduled.",
/** Text for toast when release failed to unschedule */
'toast.unschedule.error': "Failed to unscheduled '<strong>{{title}}</strong>': {{error}}",
/** Text for toast when release has been unschedule */
'toast.unschedule.success': "The '<strong>{{title}}</strong>' release was unscheduled.",
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('ReleasesNav', () => {
it('should have clear button to unset perspective when a perspective is chosen', async () => {
mockUsePerspective.mockReturnValue({
currentGlobalBundle: {
_id: 'system-tmp-releases.a-release',
_id: '_.releases.a-release',
metadata: {title: 'Test Release'},
},
setPerspective: mockSetPerspective,
Expand All @@ -83,7 +83,7 @@ describe('ReleasesNav', () => {
it('should list the title of the chosen perspective', async () => {
mockUsePerspective.mockReturnValue({
currentGlobalBundle: {
_id: 'system-tmp-releases.a-release',
_id: '_.releases.a-release',
metadata: {
title: 'Test Bundle',
},
Expand All @@ -99,7 +99,7 @@ describe('ReleasesNav', () => {
it('should show release avatar for chosen perspective', async () => {
mockUsePerspective.mockReturnValue({
currentGlobalBundle: {
_id: 'system-tmp-releases.a-release',
_id: '_.releases.a-release',
metadata: {title: 'Test Bundle', releaseType: 'asap'},
},
setPerspective: mockSetPerspective,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import {type ReleaseDocument} from '../../../../store'
import {useReleaseOperations} from '../../../../store/release/useReleaseOperations'
import {PublishedRelease} from '../../../__telemetry__/releases.telemetry'
import {releasesLocaleNamespace} from '../../../i18n'
import {type DocumentInBundleResult} from '../../../tool/detail/useBundleDocuments'
import {type DocumentInRelease} from '../../../tool/detail/useBundleDocuments'
import {useObserveDocumentRevisions} from './useObserveDocumentRevisions'

interface ReleasePublishAllButtonProps {
release: ReleaseDocument
releaseDocuments: DocumentInBundleResult[]
documents: DocumentInRelease[]
disabled?: boolean
}

export const ReleasePublishAllButton = ({
release,
releaseDocuments,
documents,
disabled,
}: ReleasePublishAllButtonProps) => {
const toast = useToast()
Expand All @@ -32,11 +32,11 @@ export const ReleasePublishAllButton = ({
)

const publishedDocumentsRevisions = useObserveDocumentRevisions(
releaseDocuments.map(({document}) => document),
documents.map(({document}) => document),
)

const isValidatingDocuments = releaseDocuments.some(({validation}) => validation.isValidating)
const hasDocumentValidationErrors = releaseDocuments.some(({validation}) => validation.hasError)
const isValidatingDocuments = documents.some(({validation}) => validation.isValidating)
const hasDocumentValidationErrors = documents.some(({validation}) => validation.hasError)

const isPublishButtonDisabled = disabled || isValidatingDocuments || hasDocumentValidationErrors

Expand All @@ -47,7 +47,7 @@ export const ReleasePublishAllButton = ({
setPublishBundleStatus('publishing')
await publishRelease(
release._id,
releaseDocuments.map(({document}) => document),
documents.map(({document}) => document),
publishedDocumentsRevisions,
)
telemetry.log(PublishedRelease)
Expand All @@ -73,7 +73,7 @@ export const ReleasePublishAllButton = ({
} finally {
setPublishBundleStatus('idle')
}
}, [release, releaseDocuments, publishRelease, publishedDocumentsRevisions, t, telemetry, toast])
}, [release, documents, publishRelease, publishedDocumentsRevisions, t, telemetry, toast])

const confirmPublishDialog = useMemo(() => {
if (publishBundleStatus === 'idle') return null
Expand All @@ -100,21 +100,15 @@ export const ReleasePublishAllButton = ({
i18nKey="publish-dialog.confirm-publish-description"
values={{
title: release.metadata.title,
releaseDocumentsLength: releaseDocuments.length,
count: releaseDocuments.length,
releaseDocumentsLength: documents.length,
count: documents.length,
}}
/>
}
</Text>
</Dialog>
)
}, [
release.metadata.title,
releaseDocuments.length,
handleConfirmPublishAll,
publishBundleStatus,
t,
])
}, [release.metadata.title, documents.length, handleConfirmPublishAll, publishBundleStatus, t])

const publishTooltipContent = useMemo(() => {
if (!hasDocumentValidationErrors && !isValidatingDocuments) return null
Expand Down
Loading

0 comments on commit bb9a972

Please sign in to comment.