UNPKG

@sanity/desk-tool

Version:

Tool for managing all sorts of content in a structured manner

151 lines (147 loc) • 8.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useReferringDocuments = useReferringDocuments; var _react = require("react"); var _document = _interopRequireDefault(require("part:@sanity/base/datastore/document")); var _client = _interopRequireDefault(require("part:@sanity/base/client")); var _internal = require("@sanity/base/_internal"); var _rxjs = require("rxjs"); var _operators = require("rxjs/operators"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // this is used in place of `instanceof` so the matching can be more robust and // won't have any issues with dual packages etc // https://nodejs.org/api/packages.html#dual-package-hazard function isClientError(e) { if (typeof e !== 'object') return false; if (!e) return false; return 'statusCode' in e && 'response' in e; } var versionedClient = _client.default.withConfig({ apiVersion: '2022-03-07' }); var DEFAULT_POLL_INTERVAL = 5000; // only fetches when the document is visible var createVisiblePoll = interval => (0, _rxjs.fromEvent)(document, 'visibilitychange').pipe( // add empty emission to have this fire on creation (0, _operators.startWith)(null), (0, _operators.map)(() => document.visibilityState === 'visible'), (0, _operators.distinctUntilChanged)(), (0, _operators.switchMap)(visible => visible ? // using timer instead of interval since timer will emit on creation (0, _rxjs.timer)(0, interval || DEFAULT_POLL_INTERVAL) : _rxjs.EMPTY), (0, _operators.shareReplay)({ refCount: true, bufferSize: 1 })); function getDocumentExistence(documentId) { var draftId = (0, _internal.getDraftId)(documentId); var publishedId = (0, _internal.getPublishedId)(documentId); var requestOptions = { uri: versionedClient.getDataUrl('doc', "".concat(draftId, ",").concat(publishedId)), json: true, query: { excludeContent: 'true' }, tag: 'use-referring-documents.document-existence' }; return versionedClient.observable.request(requestOptions).pipe((0, _operators.map)(_ref => { var omitted = _ref.omitted; var nonExistant = omitted.filter(doc => doc.reason === 'existence'); if (nonExistant.length === 2) { // None of the documents exist return undefined; } if (nonExistant.length === 0) { // Both exist, so use the published one return publishedId; } // If the draft does not exist, use the published ID, and vice versa return nonExistant.some(doc => doc.id === draftId) ? publishedId : draftId; })); } /** * fetches the cross-dataset references using the client observable.request * method (for that requests can be automatically cancelled) */ function fetchCrossDatasetReferences(documentId, visiblePoll$) { return visiblePoll$.pipe((0, _operators.switchMap)(() => getDocumentExistence(documentId)), (0, _operators.switchMap)(checkDocumentId => { if (!checkDocumentId) { return (0, _rxjs.of)({ totalCount: 0, references: [] }); } var currentDataset = _client.default.config().dataset; return versionedClient.observable.request({ url: "/data/references/".concat(currentDataset, "/documents/").concat(checkDocumentId, "/to?excludeInternalReferences=true&excludePaths=true"), tag: 'use-referring-documents.external' }).pipe((0, _operators.catchError)(e => { // it's possible that referencing document doesn't exist yet so the // API will return a 404. In those cases, we want to catch and return // a response with no references if (isClientError(e) && e.statusCode === 404) { return (0, _rxjs.of)({ totalCount: 0, references: [] }); } throw e; })); })); } var useInternalReferences = (0, _internal.createHookFromObservableFactory)(documentId => { var referencesClause = '*[references($documentId)][0...100]{_id,_type}'; var totalClause = 'count(*[references($documentId)])'; var fetchQuery = "{\"references\":".concat(referencesClause, ",\"totalCount\":").concat(totalClause, "}"); var listenQuery = '*[references($documentId)]'; return _document.default.listenQuery({ fetch: fetchQuery, listen: listenQuery }, { documentId }, { tag: 'use-referring-documents', transitions: ['appear', 'disappear'], throttleTime: 5000 }); }); var useCrossDatasetReferences = (0, _internal.createHookFromObservableFactory)((documentId, interval) => { var visiblePoll$ = createVisiblePoll(interval); return visiblePoll$.pipe((0, _operators.switchMap)(() => fetchCrossDatasetReferences(documentId, visiblePoll$))); }); function useReferringDocuments(documentId) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var publishedId = (0, _internal.getPublishedId)(documentId); var _useInternalReference = useInternalReferences(publishedId), _useInternalReference2 = _slicedToArray(_useInternalReference, 2), internalReferences = _useInternalReference2[0], isInternalReferencesLoading = _useInternalReference2[1]; var _useCrossDatasetRefer = useCrossDatasetReferences(publishedId, options.externalPollInterval), _useCrossDatasetRefer2 = _slicedToArray(_useCrossDatasetRefer, 2), crossDatasetReferences = _useCrossDatasetRefer2[0], isCrossDatasetReferencesLoading = _useCrossDatasetRefer2[1]; var projectIds = (0, _react.useMemo)(() => { return Array.from(new Set(crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references.map(crossDatasetReference => crossDatasetReference.projectId).filter(Boolean))).sort(); }, [crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references]); var datasetNames = (0, _react.useMemo)(() => { return Array.from(new Set(crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references // .filter((name) => typeof name === 'string') .map(crossDatasetReference => (crossDatasetReference === null || crossDatasetReference === void 0 ? void 0 : crossDatasetReference.datasetName) || '').filter(datasetName => Boolean(datasetName) && datasetName !== ''))).sort(); }, [crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references]); var hasUnknownDatasetNames = (0, _react.useMemo)(() => { return Boolean(crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references.some(crossDatasetReference => typeof crossDatasetReference.datasetName !== 'string')); }, [crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.references]); return { totalCount: ((internalReferences === null || internalReferences === void 0 ? void 0 : internalReferences.totalCount) || 0) + ((crossDatasetReferences === null || crossDatasetReferences === void 0 ? void 0 : crossDatasetReferences.totalCount) || 0), projectIds, datasetNames, hasUnknownDatasetNames, internalReferences, crossDatasetReferences, isLoading: isInternalReferencesLoading || isCrossDatasetReferencesLoading }; }