Skip to content

Commit

Permalink
fix(core): add retry to image observer and loading state (#6709)
Browse files Browse the repository at this point in the history
* fix(core): add retry to image observer and loading state

* fix(core): add comment on the observeAssetDoc change
  • Loading branch information
pedrobonamin committed May 22, 2024
1 parent 1587dfe commit 0f51f9d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {CropIcon} from '@sanity/icons'
import {Inline, Menu, useClickOutside, useGlobalKeyDown} from '@sanity/ui'
import {Inline, Menu, Skeleton, useClickOutside, useGlobalKeyDown} from '@sanity/ui'
import {type MouseEventHandler, type ReactNode, useCallback, useEffect, useState} from 'react'
import {styled} from 'styled-components'

Expand All @@ -13,6 +13,12 @@ export const MenuActionsWrapper = styled(Inline)`
right: 0;
`

export const ImageActionsMenuWaitPlaceholder = () => (
<MenuActionsWrapper padding={2}>
<Skeleton style={{width: '25px', height: '25px'}} animated />
</MenuActionsWrapper>
)

interface ImageActionsMenuProps {
children: ReactNode
onEdit: MouseEventHandler<HTMLButtonElement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {UploadProgress} from '../common/UploadProgress'
import {UploadWarning} from '../common/UploadWarning'
import {ImageToolInput} from '../ImageToolInput'
import {type ImageUrlBuilder} from '../types'
import {ImageActionsMenu} from './ImageActionsMenu'
import {ImageActionsMenu, ImageActionsMenuWaitPlaceholder} from './ImageActionsMenu'
import {ImagePreview} from './ImagePreview'
import {InvalidImageWarning} from './InvalidImageWarning'

Expand Down Expand Up @@ -510,7 +510,11 @@ export class BaseImageInput extends PureComponent<BaseImageInputProps, BaseImage
}

return (
<WithReferencedAsset observeAsset={observeAsset} reference={asset}>
<WithReferencedAsset
observeAsset={observeAsset}
reference={asset}
waitPlaceholder={<ImageActionsMenuWaitPlaceholder />}
>
{({_id, originalFilename, extension}) => {
let copyUrl: string | undefined
let downloadUrl: string | undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {type ProgressEvent, type SanityAssetDocument, type SanityClient} from '@sanity/client'
import {type FileAsset, type ImageAsset} from '@sanity/types'
import {Observable, of as observableOf} from 'rxjs'
import {catchError, map, mergeMap} from 'rxjs/operators'
import {Observable, of as observableOf, of} from 'rxjs'
import {catchError, map, mergeMap, retry, switchMap} from 'rxjs/operators'

import {type DocumentPreviewStore} from '../../../../preview'
import {type UploadOptions} from '../../uploads/types'
Expand Down Expand Up @@ -78,19 +78,49 @@ export const uploadImageAsset = (
export const uploadFileAsset = (client: SanityClient, file: File | Blob, options?: UploadOptions) =>
uploadAsset(client, 'file', file, options)

/**
*
*
*/
// note: there's currently 100% overlap between the ImageAsset document and the FileAsset documents as per interface required by the image and file input
function observeAssetDoc(documentPreviewStore: DocumentPreviewStore, id: string) {
return documentPreviewStore.observePaths({_type: 'reference', _ref: id}, [
'originalFilename',
'url',
'metadata',
'label',
'title',
'description',
'creditLine',
'source',
'size',
])
return documentPreviewStore
.observePaths({_type: 'reference', _ref: id}, [
'originalFilename',
'url',
'metadata',
'label',
'title',
'description',
'creditLine',
'source',
'size',
])
.pipe(
/**
* In some cases when uploading large media file we are getting an stale `null` response from content lake when fetching the reference that was just uploaded,
* making the UI not to react as it should.
* This retry logic is added to handle the case where the asset is not found in the initial fetch to the documentPreviewStore but it will eventually be found,
* because the asset has been just added.
* It has the downside that if this is being used to check if an asset exists, it will retry 5 times before returning null.
*/
switchMap((result) => {
// If the result is null, throw an error to trigger retry
if (result === null) {
throw new Error(`No asset found in documentPreviewStore with id: ${id}`)
}
// If the result is not null, return the result
return of(result)
}),
retry({
count: 5,
delay: 1000,
}),
catchError((err) => {
console.error('Final error after retries, asset not found in documentPreviewStore:', err)
return of(null) // Return null if the asset is not found
}),
)
}

export function observeImageAsset(documentPreviewStore: DocumentPreviewStore, id: string) {
Expand Down

0 comments on commit 0f51f9d

Please sign in to comment.