UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

110 lines (101 loc) 4.29 kB
import { isCrossDatasetReference, isCrossDatasetReferenceSchemaType, isReferenceSchemaType, type PrepareViewOptions, } from '@sanity/types' import {isPlainObject} from 'lodash' import {type Observable, of as observableOf} from 'rxjs' import {map, switchMap} from 'rxjs/operators' import { type ApiConfig, type PreparedSnapshot, type Previewable, type PreviewableType, type PreviewPath, } from './types' import {getPreviewPaths} from './utils/getPreviewPaths' import {invokePrepare, prepareForPreview} from './utils/prepareForPreview' function isRecord(value: unknown): value is Record<string, unknown> { return isPlainObject(value) } function isReference(value: unknown): value is {_ref: string} { return isPlainObject(value) } // Takes a value and its type and prepares a snapshot for it that can be passed to a preview component export function createPreviewObserver(context: { observeDocumentTypeFromId: (id: string, apiConfig?: ApiConfig) => Observable<string | undefined> observePaths: (value: Previewable, paths: PreviewPath[], apiConfig?: ApiConfig) => any }): ( value: Previewable, type: PreviewableType, viewOptions?: PrepareViewOptions, apiConfig?: ApiConfig, ) => Observable<PreparedSnapshot> { const {observeDocumentTypeFromId, observePaths} = context return function observeForPreview( value: Previewable, type: PreviewableType, viewOptions?: PrepareViewOptions, apiConfig?: ApiConfig, ): Observable<PreparedSnapshot> { if (isCrossDatasetReferenceSchemaType(type)) { // if the value is of type crossDatasetReference, but has no _ref property, we cannot prepare any value for the preview // and the most appropriate thing to do is to return `undefined` for snapshot if (!isCrossDatasetReference(value)) { return observableOf({snapshot: undefined}) } const refApiConfig = {projectId: value._projectId, dataset: value._dataset} return observeDocumentTypeFromId(value._ref, refApiConfig).pipe( switchMap((typeName) => { if (typeName) { const refType = type.to.find((toType) => toType.type === typeName) return observeForPreview(value, refType as any, {}, refApiConfig) } return observableOf({snapshot: undefined}) }), ) } if (isReferenceSchemaType(type)) { // if the value is of type reference, but has no _ref property, we cannot prepare any value for the preview // and the most appropriate thing to do is to return `undefined` for snapshot if (!isReference(value)) { return observableOf({snapshot: undefined}) } // Previewing references actually means getting the referenced value, // and preview using the preview config of its type // todo: We need a way of knowing the type of the referenced value by looking at the reference record alone return observeDocumentTypeFromId(value._ref).pipe( switchMap((typeName) => { if (typeName) { const refType = type.to.find((toType) => toType.name === typeName) return observeForPreview(value, refType as any) } // todo: in case we can't read the document type, we can figure out the reason why e.g. whether it's because // the document doesn't exist or it's not readable due to lack of permission. // We can use the "observeDocumentAvailability" function // for this, but currently not sure if needed return observableOf({snapshot: undefined}) }), ) } const paths = getPreviewPaths(type.preview) if (paths) { return observePaths(value, paths, apiConfig).pipe( map((snapshot) => ({ type: type, snapshot: snapshot && prepareForPreview(snapshot, type as any, viewOptions), })), ) } // Note: this case is typically rare (or non-existent) and occurs only if // the SchemaType doesn't have a `select` field. The schema compiler // provides a default `preview` implementation for `object`s, `image`s, // `file`s, and `document`s return observableOf({ type, snapshot: value && isRecord(value) ? invokePrepare(type, value, viewOptions).returnValue : null, }) } }