Skip to content

Commit

Permalink
fix(core): fix various issues with previews
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoerge committed Nov 23, 2022
1 parent 73782f4 commit 3143386
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 136 deletions.
Expand Up @@ -102,8 +102,7 @@ export default function guessPreviewFields(rawObjectTypeDef) {
{
title: titleField,
description: descField,
imageUrl: !mediaField && imageAssetPath ? `${imageAssetPath}.url` : undefined,
media: mediaField ? mediaField.name : undefined,
media: mediaField ? mediaField.name : imageAssetPath,
},
isUndefined
)
Expand Down
9 changes: 7 additions & 2 deletions packages/@sanity/types/src/upload/uploadState.ts
@@ -1,8 +1,13 @@
/** @internal */
export interface UploadState {
progress: number
initiated: string
updated: string
/** @deprecated use createdAt instead */
initiated?: string
/** @deprecated use updatedAt instead */
updated?: string

createdAt: string
updatedAt: string
file: {name: string; type: string}
previewImage?: string
}
Expand Up @@ -21,10 +21,10 @@ export function UploadProgress({uploadState, onCancel, onStale, height}: Props)
const filename = uploadState.file.name

useEffect(() => {
if (elapsedMs(uploadState.updated) > STALE_UPLOAD_MS) {
if (elapsedMs(uploadState.updatedAt) > STALE_UPLOAD_MS) {
onStale?.()
}
}, [uploadState.updated, onStale])
}, [uploadState.updatedAt, onStale])

return (
<CardWrapper tone="primary" padding={4} border style={{height: `${height}px`}}>
Expand Down
@@ -1,16 +1,25 @@
import {ArraySchemaType, SchemaType} from '@sanity/types'
import {ArraySchemaType, Path, SchemaType} from '@sanity/types'
import {concat, defer, EMPTY, from, Observable, of} from 'rxjs'
import {catchError, map, mergeMap} from 'rxjs/operators'
import {catchError, filter, map, mergeMap} from 'rxjs/operators'
import {resolveTypeName} from '@sanity/util/content'
import {FormPatch, set, unset} from '../../patch'
import {ObjectItem} from '../../types'
import {isEmptyItem} from '../../store/utils/isEmptyItem'
import {isNonNullable} from '../../../util'

const getMemberTypeOfItem = (schemaType: ArraySchemaType, item: any): SchemaType | undefined => {
const itemTypeName = resolveTypeName(item)
return schemaType.of.find((memberType) => memberType.name === itemTypeName)
}

/**
* Create patches that shallow merges keys from the given value
* Used by initial value resolver to retain any properties already added on the item when initial value is done resolving
* */
function assign(values: Record<string, unknown>, path: Path) {
return Object.entries(values).map(([key, value]) => set(value, [...path, key]))
}

export function resolveInitialArrayValues<T extends ObjectItem>(
items: T[],
schemaType: ArraySchemaType,
Expand All @@ -21,25 +30,32 @@ export function resolveInitialArrayValues<T extends ObjectItem>(
> {
return from(items).pipe(
mergeMap((item) => {
const itemKey = {_key: item._key}
const itemPathSegment = {_key: item._key}
return of(getMemberTypeOfItem(schemaType, item)).pipe(
mergeMap((memberType) => (memberType ? of(memberType) : EMPTY)),
mergeMap((memberType) => {
if (!isEmptyItem(item) || !resolver) {
return EMPTY
}
return concat(
of({type: 'patch' as const, patches: [set(true, [itemKey, '_resolvingInitialValue'])]}),
of({
type: 'patch' as const,
patches: [set(true, [itemPathSegment, '_resolvingInitialValue'])],
}),
defer(() => resolver(memberType, item)).pipe(
filter(isNonNullable),
map((initial) => ({
type: 'patch' as const,
patches: [set({...item, ...initial}, [itemKey])],
patches: assign(initial, [itemPathSegment]),
})),
catchError((error) =>
of({type: 'error' as const, error, item, schemaType: memberType})
)
),
of({type: 'patch' as const, patches: [unset([itemKey, '_resolvingInitialValue'])]})
of({
type: 'patch' as const,
patches: [unset([itemPathSegment, '_resolvingInitialValue'])],
})
)
})
)
Expand Down
9 changes: 3 additions & 6 deletions packages/sanity/src/core/form/studio/uploads/uploadFile.ts
@@ -1,5 +1,5 @@
import {of as observableOf, Observable} from 'rxjs'
import {map, concat} from 'rxjs/operators'
import {of, concat, Observable} from 'rxjs'
import {map} from 'rxjs/operators'
import {SanityClient} from '@sanity/client'
import {set} from '../../patch'
import {uploadFileAsset} from '../inputs/client-adapters/assets'
Expand Down Expand Up @@ -28,8 +28,5 @@ export function uploadFile(
})
)

return observableOf(createInitialUploadEvent(file)).pipe(
concat(upload$),
concat(observableOf(CLEANUP_EVENT))
)
return concat(of(createInitialUploadEvent(file)), upload$, of(CLEANUP_EVENT))
}
22 changes: 11 additions & 11 deletions packages/sanity/src/core/form/studio/uploads/uploadImage.ts
@@ -1,12 +1,12 @@
import {from as observableFrom, of as observableOf, Observable} from 'rxjs'
import {catchError, concat, filter, map, merge, mergeMap} from 'rxjs/operators'
import {concat, merge, Observable, of} from 'rxjs'
import {catchError, filter, map, mergeMap} from 'rxjs/operators'
import type {SanityClient} from '@sanity/client'
import {set} from '../../patch'
import {uploadImageAsset} from '../inputs/client-adapters/assets'
import {readExif} from './image/readExif'
import {rotateImage} from './image/rotateImage'
import {DEFAULT_ORIENTATION, Orientation} from './image/orient'
import {UploadProgressEvent, UploadOptions} from './types'
import {UploadOptions, UploadProgressEvent} from './types'
import {UPLOAD_STATUS_KEY} from './constants'
import {CLEANUP_EVENT, createInitialUploadEvent, createUploadEvent} from './utils'

Expand All @@ -26,17 +26,17 @@ export function uploadImage(
progress: 2 + (event.percent / 100) * 98,
})),

map((event: any) => {
map((event) => {
if (event.type === 'complete') {
return createUploadEvent([
set({_type: 'reference', _ref: event.asset._id}, ['asset']),
set(100, [UPLOAD_STATUS_KEY, 'progress']),
set(new Date().toISOString(), [UPLOAD_STATUS_KEY, 'updated']),
set(new Date().toISOString(), [UPLOAD_STATUS_KEY, 'updatedAt']),
])
}
return createUploadEvent([
set(event.percent, [UPLOAD_STATUS_KEY, 'progress']),
set(new Date().toISOString(), [UPLOAD_STATUS_KEY, 'updated']),
set(new Date().toISOString(), [UPLOAD_STATUS_KEY, 'updatedAt']),
])
})
)
Expand All @@ -45,7 +45,6 @@ export function uploadImage(
mergeMap((exifData: unknown) =>
rotateImage(file, (exifData as Exif).orientation || DEFAULT_ORIENTATION)
),

catchError((error) => {
// eslint-disable-next-line no-console
console.warn(
Expand All @@ -55,14 +54,15 @@ export function uploadImage(
)

// something went wrong, but continue still
return observableOf(null)
return of(null)
}),
filter(Boolean),
map((imageUrl) => createUploadEvent([set(imageUrl, [UPLOAD_STATUS_KEY, 'previewImage'])]))
)

return observableOf(createInitialUploadEvent(file)).pipe(
concat(observableFrom(upload$).pipe(merge(setPreviewUrl$))),
concat(observableOf(CLEANUP_EVENT))
return concat(
of(createInitialUploadEvent(file)),
merge(upload$, setPreviewUrl$),
of(CLEANUP_EVENT)
)
}
11 changes: 4 additions & 7 deletions packages/sanity/src/core/form/studio/uploads/utils.ts
@@ -1,4 +1,4 @@
import {FormPatch, set, setIfMissing, unset} from '../../patch'
import {FormPatch, set, unset} from '../../patch'
import {UploadProgressEvent} from './types'
import {UPLOAD_STATUS_KEY} from './constants'

Expand All @@ -17,13 +17,10 @@ export function createInitialUploadEvent(file: File) {
const now = new Date().toISOString()
const value = {
progress: 2,
initiated: now,
updated: now,
createdAt: now,
updatedAt: now,
file: {name: file.name, type: file.type},
}

return createUploadEvent([
setIfMissing({[UPLOAD_STATUS_KEY]: value}, []),
set(value, [UPLOAD_STATUS_KEY]),
])
return createUploadEvent([set(value, [UPLOAD_STATUS_KEY])])
}
@@ -1,6 +1,6 @@
import {DocumentIcon} from '@sanity/icons'
import imageUrlBuilder from '@sanity/image-url'
import {ImageUrlFitMode, isImage, isReference} from '@sanity/types'
import {ImageUrlFitMode} from '@sanity/types'
import React, {
ComponentType,
createElement,
Expand All @@ -11,6 +11,8 @@ import React, {
useMemo,
} from 'react'
import {isValidElementType} from 'react-is'
import {SanityImageSource} from '@sanity/image-url/lib/types/types'
import {isImageSource} from '@sanity/asset-utils'
import {PreviewProps} from '../../components/previews'
import {useClient} from '../../hooks'
import {DEFAULT_STUDIO_CLIENT_OPTIONS} from '../../studioClient'
Expand All @@ -29,6 +31,7 @@ export interface SanityDefaultPreviewProps
}

/**
* Used in cases where no custom preview component is provided
* @internal
* */
export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactElement {
Expand All @@ -37,18 +40,12 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle
const client = useClient(DEFAULT_STUDIO_CLIENT_OPTIONS)
const imageBuilder = useMemo(() => imageUrlBuilder(client), [client])

const component = _previewComponents[layout || 'default'] || _previewComponents.default

// NOTE: This function exists because the previews provides options
// for the rendering of the media (dimensions)
const renderMedia = useCallback(
(options: {
dimensions: {width?: number; height?: number; fit: ImageUrlFitMode; dpr?: number}
}) => {
if (!isImage(mediaProp)) {
return null
}

const {dimensions} = options

// Handle sanity image
Expand All @@ -58,7 +55,9 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle
referrerPolicy="strict-origin-when-cross-origin"
src={
imageBuilder
.image(mediaProp)
.image(
mediaProp as SanityImageSource /*will only enter this code path if it's compatible*/
)
.width(dimensions.width || 100)
.height(dimensions.height || 100)
.fit(dimensions.fit)
Expand Down Expand Up @@ -89,13 +88,7 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle
return mediaProp
}

// If the asset is on media
if (isReference(mediaProp) && mediaProp._type === 'reference') {
return renderMedia
}

// Handle sanity image
if (isImage(mediaProp)) {
if (isImageSource(mediaProp)) {
return renderMedia
}

Expand All @@ -112,7 +105,7 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle

// Render fallback icon
return renderIcon
}, [icon, imageUrl, mediaProp, renderIcon, renderMedia])
}, [icon, imageUrl, mediaProp, renderIcon, renderMedia, title])

const previewProps: Omit<PreviewProps, 'renderDefault'> = useMemo(
() => ({
Expand All @@ -123,8 +116,11 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle
}),
[media, restProps, title]
)

const layoutComponent = _previewComponents[layout || 'default']

return createElement(
component as ComponentType<Omit<PreviewProps, 'renderDefault'>>,
layoutComponent as ComponentType<Omit<PreviewProps, 'renderDefault'>>,
previewProps
)
}

0 comments on commit 3143386

Please sign in to comment.