UNPKG

@sanity/desk-tool

Version:

Tool for managing all sorts of content in a structured manner

167 lines (163 loc) • 9.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReferenceChangedBanner = void 0; var _react = _interopRequireWildcard(require("react")); var _ui = require("@sanity/ui"); var _icons = require("@sanity/icons"); var _styledComponents = _interopRequireDefault(require("styled-components")); var _paths = require("@sanity/util/paths"); var _operators = require("rxjs/operators"); var _internal = require("@sanity/base/_internal"); var _rxjs = require("rxjs"); var _reactRx = require("react-rx"); var _paneRouter = require("../../../contexts/paneRouter"); var _templateObject, _templateObject2; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } var Root = (0, _styledComponents.default)(_ui.Card)(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: relative;\n z-index: 50;\n"]))); var TextOneLine = (0, _styledComponents.default)(_ui.Text)(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n & > * {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n"]))); var ReferenceChangedBanner = /*#__PURE__*/(0, _react.memo)(() => { var _routerPanesState$gro, _parentSibling$params, _referenceInfo$result2, _referenceInfo$result3, _referenceInfo$result4, _referenceInfo$result5; var _usePaneRouter = (0, _paneRouter.usePaneRouter)(), params = _usePaneRouter.params, groupIndex = _usePaneRouter.groupIndex, routerPanesState = _usePaneRouter.routerPanesState, replaceCurrent = _usePaneRouter.replaceCurrent, BackLink = _usePaneRouter.BackLink; var routerReferenceId = (_routerPanesState$gro = routerPanesState[groupIndex]) === null || _routerPanesState$gro === void 0 ? void 0 : _routerPanesState$gro[0].id; var parentGroup = routerPanesState[groupIndex - 1]; var parentSibling = parentGroup === null || parentGroup === void 0 ? void 0 : parentGroup[0]; var parentId = parentSibling === null || parentSibling === void 0 ? void 0 : parentSibling.id; var hasHistoryOpen = Boolean(parentSibling === null || parentSibling === void 0 || (_parentSibling$params = parentSibling.params) === null || _parentSibling$params === void 0 ? void 0 : _parentSibling$params.rev); var parentRefPath = (0, _react.useMemo)(() => { return (params === null || params === void 0 ? void 0 : params.parentRefPath) && (0, _paths.fromString)(params.parentRefPath) || null; }, [params === null || params === void 0 ? void 0 : params.parentRefPath]); /** * Loads information regarding the reference field of the parent pane. This * is only applicable to child references (aka references-in-place). * * It utilizes the pane ID of the parent pane (which is a document ID) along * with the `parentRefPath` router param on the current pane to find the * current value of the reference field on the parent document. * * This is used to compare with the current pane's document ID. If the IDs * don't match then this banner should reveal itself */ var referenceInfo = (0, _reactRx.useMemoObservable)(() => { var parentRefPathSegment = parentRefPath === null || parentRefPath === void 0 ? void 0 : parentRefPath[0]; // short-circuit: this document pane is not a child reference pane if (!parentId || !parentRefPathSegment || !parentRefPath) { return (0, _rxjs.of)({ loading: false }); } var publishedId = (0, _internal.getPublishedId)(parentId); var path = (0, _paths.fromString)(parentRefPathSegment); // note: observePaths doesn't support keyed path segments, so we need to select the nearest parent var keyedSegmentIndex = path.findIndex(p => typeof p == 'object' && '_key' in p); return (0, _rxjs.concat)( // emit a loading state instantly (0, _rxjs.of)({ loading: true }), // then emit the values from watching the published ID's path (0, _internal.unstable_observePathsDocumentPair)(publishedId, keyedSegmentIndex === -1 ? path : path.slice(0, keyedSegmentIndex)).pipe( // this debounce time is needed to prevent flashing banners due to // the router state updating faster than the content-lake state. we // debounce to wait for more emissions because the value pulled // initially could be stale. (0, _operators.debounceTime)(750), (0, _operators.map)(_ref => { var _pathGet; var draft = _ref.draft, published = _ref.published; return { loading: false, result: { availability: { draft: draft.availability, published: published.availability }, refValue: (_pathGet = (0, _paths.get)(draft.snapshot || published.snapshot, parentRefPath)) === null || _pathGet === void 0 ? void 0 : _pathGet._ref } }; }))); }, [parentId, parentRefPath], { loading: true }); var handleReloadReference = (0, _react.useCallback)(() => { var _referenceInfo$result; if (referenceInfo.loading) return; if ((_referenceInfo$result = referenceInfo.result) !== null && _referenceInfo$result !== void 0 && _referenceInfo$result.refValue) { replaceCurrent({ id: referenceInfo.result.refValue, params: params }); } }, [referenceInfo.loading, referenceInfo.result, replaceCurrent, params]); var shouldHide = // if `parentId` or `parentRefPath` is not present then this banner is n/a !parentId || !parentRefPath || // if viewing this pane via history, then hide hasHistoryOpen || // if loading, hide referenceInfo.loading || // if the parent document is not available (e.g. due to permission denied or // not found) we don't want to display a warning here, but instead rely on the // parent view to display the appropriate message !((_referenceInfo$result2 = referenceInfo.result) !== null && _referenceInfo$result2 !== void 0 && _referenceInfo$result2.availability.draft.available) && !((_referenceInfo$result3 = referenceInfo.result) !== null && _referenceInfo$result3 !== void 0 && _referenceInfo$result3.availability.published.available) || // if the references are the same, then hide the reference changed banner ((_referenceInfo$result4 = referenceInfo.result) === null || _referenceInfo$result4 === void 0 ? void 0 : _referenceInfo$result4.refValue) === routerReferenceId; if (shouldHide) return null; return /*#__PURE__*/_react.default.createElement(Root, { shadow: 1, tone: "caution", "data-testid": "reference-changed-banner" }, /*#__PURE__*/_react.default.createElement(_ui.Container, { paddingX: 4, paddingY: 2, sizing: "border", width: 1 }, /*#__PURE__*/_react.default.createElement(_ui.Flex, { align: "center" }, /*#__PURE__*/_react.default.createElement(_ui.Text, { size: 1 }, /*#__PURE__*/_react.default.createElement(_icons.WarningOutlineIcon, null)), (_referenceInfo$result5 = referenceInfo.result) !== null && _referenceInfo$result5 !== void 0 && _referenceInfo$result5.refValue ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_ui.Box, { flex: 1, marginLeft: 3 }, /*#__PURE__*/_react.default.createElement(TextOneLine, { title: "This reference has changed since you opened it.", size: 1 }, "This reference has changed since you opened it.")), /*#__PURE__*/_react.default.createElement(_ui.Box, { marginLeft: 3 }, /*#__PURE__*/_react.default.createElement(_ui.Button, { onClick: handleReloadReference, icon: _icons.SyncIcon, fontSize: 1, mode: "ghost", padding: 2, space: 2, text: "Reload reference" }))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_ui.Box, { flex: 1, marginLeft: 3 }, /*#__PURE__*/_react.default.createElement(TextOneLine, { title: "This reference has been removed since you opened it.", size: 1 }, "This reference has been removed since you opened it.")), /*#__PURE__*/_react.default.createElement(_ui.Box, { marginLeft: 3 }, /*#__PURE__*/_react.default.createElement(_ui.Button, { as: BackLink, icon: _icons.CloseIcon, fontSize: 1, mode: "ghost", padding: 2, space: 2, text: "Close reference" })))))); }); exports.ReferenceChangedBanner = ReferenceChangedBanner; ReferenceChangedBanner.displayName = 'ReferenceChangedBanner';