From a62ffd9b381a30b5514bbc3dadc8899105c3c4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rge=20N=C3=A6ss?= Date: Tue, 17 Dec 2024 13:14:51 +0100 Subject: [PATCH] feat(sanity): export useReferringDocuments and mark as beta --- .../components/WithReferringDocuments.tsx | 4 +- .../assetSource/shared/AssetDeleteDialog.tsx | 4 +- .../assetSource/shared/AssetUsageDialog.tsx | 4 +- packages/sanity/src/core/hooks/index.ts | 1 + .../src/core/hooks/useReferringDocuments.ts | 56 ++++++++++++++++--- .../sanity/src/structure/useStructureTool.ts | 1 - 6 files changed, 55 insertions(+), 15 deletions(-) diff --git a/packages/sanity/src/core/components/WithReferringDocuments.tsx b/packages/sanity/src/core/components/WithReferringDocuments.tsx index 3deee5990afb..ef784d2c6a32 100644 --- a/packages/sanity/src/core/components/WithReferringDocuments.tsx +++ b/packages/sanity/src/core/components/WithReferringDocuments.tsx @@ -4,6 +4,8 @@ import {type ReactElement} from 'react' import {useReferringDocuments} from '../hooks/useReferringDocuments' import {type DocumentStore} from '../store' +const EMPTY: never[] = [] + /** * @internal * @deprecated - Will be removed in 4.0.0, use the `useReferringDocuments()` hook instead @@ -19,5 +21,5 @@ export function WithReferringDocuments({ documentStore?: DocumentStore id: string }) { - return children(useReferringDocuments(id)) + return children(useReferringDocuments(id, EMPTY)) } diff --git a/packages/sanity/src/core/form/studio/assetSource/shared/AssetDeleteDialog.tsx b/packages/sanity/src/core/form/studio/assetSource/shared/AssetDeleteDialog.tsx index a85e03fbb446..e81a4750a3df 100644 --- a/packages/sanity/src/core/form/studio/assetSource/shared/AssetDeleteDialog.tsx +++ b/packages/sanity/src/core/form/studio/assetSource/shared/AssetDeleteDialog.tsx @@ -5,7 +5,7 @@ import {useMemo} from 'react' import {Dialog} from '../../../../../ui-components' import {LoadingBlock} from '../../../../components/loadingBlock' -import {useReferringDocuments} from '../../../../hooks/useReferringDocuments' +import {useLegacyReferringDocuments} from '../../../../hooks/useReferringDocuments' import {useTranslation} from '../../../../i18n' import {AssetUsageList} from './AssetUsageList' import {ConfirmMessage} from './ConfirmMessage' @@ -25,7 +25,7 @@ export function AssetDeleteDialog({ onClose, onDelete, }: UsageDialogProps) { - const {isLoading, referringDocuments} = useReferringDocuments(asset._id) + const {isLoading, referringDocuments} = useLegacyReferringDocuments(asset._id) const publishedDocuments = useMemo(() => { const drafts = referringDocuments.reduce( diff --git a/packages/sanity/src/core/form/studio/assetSource/shared/AssetUsageDialog.tsx b/packages/sanity/src/core/form/studio/assetSource/shared/AssetUsageDialog.tsx index 6c925afe2a65..829d77209283 100644 --- a/packages/sanity/src/core/form/studio/assetSource/shared/AssetUsageDialog.tsx +++ b/packages/sanity/src/core/form/studio/assetSource/shared/AssetUsageDialog.tsx @@ -3,7 +3,7 @@ import {useMemo} from 'react' import {Dialog} from '../../../../../ui-components' import {LoadingBlock} from '../../../../components/loadingBlock' -import {useReferringDocuments} from '../../../../hooks/useReferringDocuments' +import {useLegacyReferringDocuments} from '../../../../hooks/useReferringDocuments' import {useTranslation} from '../../../../i18n' import {AssetUsageList} from './AssetUsageList' @@ -14,7 +14,7 @@ export interface UsageDialogProps { } export function AssetUsageDialog({asset, assetType, onClose}: UsageDialogProps) { - const {isLoading, referringDocuments} = useReferringDocuments(asset._id) + const {isLoading, referringDocuments} = useLegacyReferringDocuments(asset._id) const publishedDocuments = useMemo(() => { const drafts = referringDocuments.reduce( diff --git a/packages/sanity/src/core/hooks/index.ts b/packages/sanity/src/core/hooks/index.ts index 2632e9e0d001..f519f320d2e2 100644 --- a/packages/sanity/src/core/hooks/index.ts +++ b/packages/sanity/src/core/hooks/index.ts @@ -11,6 +11,7 @@ export * from './useGlobalCopyPasteElementHandler' export * from './useListFormat' export * from './useNumberFormat' export * from './useProjectId' +export {type DocumentField, useReferringDocuments} from './useReferringDocuments' export * from './useRelativeTime' export * from './useSchema' export * from './useSyncState' diff --git a/packages/sanity/src/core/hooks/useReferringDocuments.ts b/packages/sanity/src/core/hooks/useReferringDocuments.ts index 42fd48b9eb21..bf89292e9a5d 100644 --- a/packages/sanity/src/core/hooks/useReferringDocuments.ts +++ b/packages/sanity/src/core/hooks/useReferringDocuments.ts @@ -5,37 +5,75 @@ import {map, startWith} from 'rxjs/operators' import {useDocumentStore} from '../store' -interface ReferringDocumentsState { +interface ReferringDocumentsState { isLoading: boolean - referringDocuments: SanityDocument[] + referringDocuments: Doc[] } +/** @beta */ +export type DocumentField = Exclude -const INITIAL_STATE: ReferringDocumentsState = {referringDocuments: [], isLoading: true} +const INITIAL_STATE: ReferringDocumentsState = {referringDocuments: [], isLoading: true} +const DEFAULT_FIELDS: DocumentField[] = ['_id', '_type'] /** - * @internal - * @param id - the id to search for referring documents for + * @beta + * Subscribe to a live-updating list document referring to the document of the passed ID + * A new list of document will be emitted every time a document refers or no longer refers to the document of the given ID + * + * ## Gotcha + * The returned list of referring documents is not extensive, will only return the 101 first documents. + * + * ## Gotcha + * For every component that calls this hook, a new listener connection will be made to the backed. + * + * Make sure call this hook sparingly + * @param id - id of document to search for referring documents for + * @param fields - which fields to return for each document (defaults to _id and _type). Pass an empty array to return full documents */ -export function useReferringDocuments(id: string): ReferringDocumentsState { +export function useReferringDocuments( + id: string, + fields: DocumentField[] = DEFAULT_FIELDS, +) { const documentStore = useDocumentStore() + + const projection = useMemo(() => { + return fields.length === 0 ? '' : fields.join(',') + }, [fields]) + const observable = useMemo( () => documentStore .listenQuery( - '*[references($docId)] [0...101]', + `*[references($docId)] [0...101]${projection}`, {docId: id}, {tag: 'use-referring-documents'}, ) .pipe( map( - (docs: SanityDocument[]): ReferringDocumentsState => ({ + (docs: DocumentType[]): ReferringDocumentsState => ({ referringDocuments: docs, isLoading: false, }), ), startWith(INITIAL_STATE), ), - [documentStore, id], + [documentStore, id, projection], ) return useObservable(observable, INITIAL_STATE) } + +const EMPTY_FIELDS: never[] = [] +/** + * Kept for backwards compat + * - useReferringDocuments(id) will select `{_id, _type}` from returned documents, + * - while this hook will return full documents + * + * Internal callers of this hook should migrate over to useReferringDocuments + * @deprecated - replaced by useReferringDocuments(id) but kept for backwards compatibility + * @internal + * @param id - id of document to search for referring documents for + */ +// eslint-disable-next-line camelcase +export function useLegacyReferringDocuments(id: string): ReferringDocumentsState { + return useReferringDocuments(id, EMPTY_FIELDS) +} diff --git a/packages/sanity/src/structure/useStructureTool.ts b/packages/sanity/src/structure/useStructureTool.ts index 07a411582d85..a13ac1505d9c 100644 --- a/packages/sanity/src/structure/useStructureTool.ts +++ b/packages/sanity/src/structure/useStructureTool.ts @@ -6,7 +6,6 @@ import {type StructureToolContextValue} from './types' /** @internal */ export function useStructureTool(): StructureToolContextValue { const structureTool = useContext(StructureToolContext) - if (!structureTool) throw new Error(`StructureTool: missing context value`) return structureTool