@sanity/desk-tool
Version:
Tool for managing all sorts of content in a structured manner
167 lines (163 loc) • 9.75 kB
JavaScript
"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';