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
1,050 lines (1,049 loc) • 661 kB
JavaScript
"use strict";
var jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), React = require("react"), icons = require("@sanity/icons"), sanity = require("sanity"), uuid = require("@sanity/uuid"), framerMotion = require("framer-motion"), styled = require("styled-components"), getJsonStream = require("./getJsonStream.js"), router$1 = require("sanity/router"), orderBy = require("lodash/orderBy.js"), isEqual = require("lodash/isEqual.js"), react$1 = require("@sanity/telemetry/react"), template = require("lodash/template.js"), react = require("@portabletext/react"), color = require("@sanity/color"), types = require("@sanity/types"), reactI18next = require("react-i18next"), portableTextEditor = require("@sanity/portable-text-editor"), schema$1 = require("@sanity/schema"), theme = require("@sanity/ui/theme"), deburr = require("lodash/deburr.js"), reactRx = require("react-rx"), rxjs = require("rxjs"), CopyToClipboard = require("react-copy-to-clipboard"), isNumber = require("lodash/isNumber.js"), isString = require("lodash/isString.js"), PathUtils = require("@sanity/util/paths"), omit = require("lodash/omit.js"), operators = require("rxjs/operators"), uniqBy = require("lodash/uniqBy.js"), negate = require("lodash/negate.js"), throttle = require("lodash/throttle.js"), scrollIntoView = require("scroll-into-view-if-needed"), findIndex = require("lodash/findIndex.js"), diffMatchPatch = require("@sanity/diff-match-patch"), isHotkey = require("is-hotkey"), JSONInspector = require("@rexxars/react-json-inspector"), HLRU = require("hashlru"), telemetry = require("@sanity/telemetry"), _internal = require("@sanity/schema/_internal"), shallowEquals = require("shallow-equals"), _internalBrowser = require("sanity/_internalBrowser"), rxjsExhaustmapWithTrailing = require("rxjs-exhaustmap-with-trailing"), camelCase = require("lodash/camelCase.js"), speakingurl = require("speakingurl"), uniqueId = require("lodash/uniqueId.js"), reactIs = require("react-is"), uniq = require("lodash/uniq.js"), kebabCase = require("lodash/kebabCase.js"), generateHelpUrl = require("@sanity/generate-help-url"), find = require("lodash/find.js"), startCase = require("lodash/startCase.js"), legacyDateFormat = require("@sanity/util/legacyDateFormat"), FocusLock = require("react-focus-lock"), mendoza = require("mendoza"), assetUtils = require("@sanity/asset-utils"), imageUrlBuilder = require("@sanity/image-url"), deepCompare = require("react-fast-compare"), dateFns = require("date-fns"), debounce = require("lodash/debounce.js");
function _interopDefaultCompat(e) {
return e && typeof e == "object" && "default" in e ? e : { default: e };
}
function _interopNamespaceCompat(e) {
if (e && typeof e == "object" && "default" in e)
return e;
var n = /* @__PURE__ */ Object.create(null);
return e && Object.keys(e).forEach(function(k) {
if (k !== "default") {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: !0,
get: function() {
return e[k];
}
});
}
}), n.default = e, Object.freeze(n);
}
var React__namespace = /* @__PURE__ */ _interopNamespaceCompat(React), styled__default = /* @__PURE__ */ _interopDefaultCompat(styled), orderBy__default = /* @__PURE__ */ _interopDefaultCompat(orderBy), isEqual__default = /* @__PURE__ */ _interopDefaultCompat(isEqual), template__default = /* @__PURE__ */ _interopDefaultCompat(template), deburr__default = /* @__PURE__ */ _interopDefaultCompat(deburr), CopyToClipboard__default = /* @__PURE__ */ _interopDefaultCompat(CopyToClipboard), isNumber__default = /* @__PURE__ */ _interopDefaultCompat(isNumber), isString__default = /* @__PURE__ */ _interopDefaultCompat(isString), PathUtils__namespace = /* @__PURE__ */ _interopNamespaceCompat(PathUtils), omit__default = /* @__PURE__ */ _interopDefaultCompat(omit), uniqBy__default = /* @__PURE__ */ _interopDefaultCompat(uniqBy), negate__default = /* @__PURE__ */ _interopDefaultCompat(negate), throttle__default = /* @__PURE__ */ _interopDefaultCompat(throttle), scrollIntoView__default = /* @__PURE__ */ _interopDefaultCompat(scrollIntoView), findIndex__default = /* @__PURE__ */ _interopDefaultCompat(findIndex), isHotkey__default = /* @__PURE__ */ _interopDefaultCompat(isHotkey), JSONInspector__default = /* @__PURE__ */ _interopDefaultCompat(JSONInspector), HLRU__default = /* @__PURE__ */ _interopDefaultCompat(HLRU), shallowEquals__default = /* @__PURE__ */ _interopDefaultCompat(shallowEquals), camelCase__default = /* @__PURE__ */ _interopDefaultCompat(camelCase), speakingurl__default = /* @__PURE__ */ _interopDefaultCompat(speakingurl), uniqueId__default = /* @__PURE__ */ _interopDefaultCompat(uniqueId), uniq__default = /* @__PURE__ */ _interopDefaultCompat(uniq), kebabCase__default = /* @__PURE__ */ _interopDefaultCompat(kebabCase), find__default = /* @__PURE__ */ _interopDefaultCompat(find), startCase__default = /* @__PURE__ */ _interopDefaultCompat(startCase), FocusLock__default = /* @__PURE__ */ _interopDefaultCompat(FocusLock), imageUrlBuilder__default = /* @__PURE__ */ _interopDefaultCompat(imageUrlBuilder), deepCompare__default = /* @__PURE__ */ _interopDefaultCompat(deepCompare), debounce__default = /* @__PURE__ */ _interopDefaultCompat(debounce);
const commentsLocaleNamespace = "comments", commentsUsEnglishLocaleBundle = sanity.defineLocaleResourceBundle({
locale: "en-US",
namespace: commentsLocaleNamespace,
resources: () => Promise.resolve().then(function() {
return require("./resources.js");
})
}), DOCUMENT_PANEL_MIN_WIDTH = 320, DOCUMENT_PANEL_INITIAL_MIN_WIDTH = 600, DOCUMENT_INSPECTOR_MIN_WIDTH = 320, DOCUMENT_INSPECTOR_MAX_WIDTH = 540, EMPTY_PARAMS$2 = {}, INSPECT_ACTION_PREFIX = "inspect:", DEFAULT_MENU_ITEM_GROUPS = [{ id: "inspectors" }, { id: "links" }], HISTORY_INSPECTOR_NAME = "sanity/structure/history", VALIDATION_INSPECTOR_NAME = "sanity/structure/validation", COMMENTS_INSPECTOR_NAME = "sanity/structure/comments", separator = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, children: /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronRightIcon, {}) }), renderItem = (item, index) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { as: "li", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { textOverflow: "ellipsis", size: 1, weight: "medium", children: item }) }, `${item}-${index}`);
function CommentBreadcrumbs(props) {
const { titlePath, maxLength } = props, items = React.useMemo(() => {
const len = titlePath.length, beforeLength = Math.ceil(maxLength / 2), afterLength = Math.floor(maxLength / 2);
return maxLength && len > maxLength ? [
...titlePath.slice(0, beforeLength - 1),
titlePath.slice(beforeLength - 1, len - afterLength),
...titlePath.slice(len - afterLength)
] : titlePath;
}, [maxLength, titlePath]), nodes = React.useMemo(() => items.map((item, index) => {
const key = `${item}-${index}`, showSeparator = index < items.length - 1;
return Array.isArray(item) ? /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
getJsonStream.Tooltip,
{
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, padding: 2, children: item.map(renderItem) }),
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: renderItem("...", index) })
}
),
showSeparator && separator
] }, key) : /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
renderItem(item, index),
showSeparator && separator
] }, key);
}), [items]);
return /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", as: "ol", gap: 2, children: nodes });
}
function getDialogCopy(t) {
return {
thread: {
title: t("delete-thread.title"),
body: t("delete-thread.body"),
confirmButtonText: t("delete-thread.confirm")
},
comment: {
title: t("delete-comment.title"),
body: t("delete-comment.body"),
confirmButtonText: t("delete-comment.confirm")
}
};
}
function CommentDeleteDialog(props) {
const { isParent, onClose, commentId, onConfirm, loading, error } = props, { t } = sanity.useTranslation(commentsLocaleNamespace), dialogCopy = getDialogCopy(t), { title, body, confirmButtonText } = dialogCopy[isParent ? "thread" : "comment"], handleDelete = React.useCallback(() => {
onConfirm(commentId);
}, [commentId, onConfirm]);
return /* @__PURE__ */ jsxRuntime.jsx(
getJsonStream.Dialog,
{
footer: {
cancelButton: {
onClick: onClose
},
confirmButton: {
loading,
onClick: handleDelete,
text: confirmButtonText,
tone: "critical"
}
},
header: title,
id: "delete-comment-dialog",
onClose,
width: 0,
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 4, children: [
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: body }),
error && /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, { tone: "critical", children: t("delete-dialog.error") })
] })
}
);
}
const CommentDisabledIcon = React.forwardRef(function(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsxs(
"svg",
{
"data-sanity-icon": "comment-disabled",
width: "1em",
height: "1em",
ref,
viewBox: "0 0 25 25",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
...props,
children: [
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M5.92627 14.5381H7.92627V18.5381L11.9263 14.5381H15.9263C17.0308 14.5381 17.9263 13.6427 17.9263 12.5381V6.53809C17.9263 5.43352 17.0308 4.53809 15.9263 4.53809H5.92627C4.8217 4.53809 3.92627 5.43352 3.92627 6.53809V12.5381C3.92627 13.6427 4.8217 14.5381 5.92627 14.5381Z",
stroke: "currentColor",
strokeWidth: "1.2",
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M2.77256 2.66835C2.54413 2.51319 2.23317 2.57259 2.07802 2.80103L1.40378 3.7937C1.32927 3.9034 1.30139 4.0382 1.32627 4.16845C1.35115 4.29871 1.42676 4.41374 1.53646 4.48825L19.5861 16.7479C19.8146 16.903 20.1255 16.8436 20.2807 16.6152L20.9549 15.6225C21.0294 15.5128 21.0573 15.378 21.0324 15.2478C21.0076 15.1175 20.9319 15.0025 20.8222 14.928L2.77256 2.66835Z",
fill: "currentColor",
strokeLinejoin: "round"
}
)
]
}
);
}), CommentIcon = React.forwardRef(function(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
"data-sanity-icon": "comment",
width: "1em",
height: "1em",
ref,
viewBox: "0 0 25 25",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
...props,
children: /* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M7.5 15.5H9.5V19.5L13.5 15.5H17.5C18.6046 15.5 19.5 14.6046 19.5 13.5V7.5C19.5 6.39543 18.6046 5.5 17.5 5.5H7.5C6.39543 5.5 5.5 6.39543 5.5 7.5V13.5C5.5 14.6046 6.39543 15.5 7.5 15.5Z",
stroke: "currentColor",
strokeLinejoin: "round",
strokeWidth: "1.2"
}
)
}
);
}), MentionIcon = React.forwardRef(function(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsxs(
"svg",
{
"data-sanity-icon": "mention",
fill: "none",
height: "1em",
ref,
viewBox: "0 0 25 25",
width: "1em",
xmlns: "http://www.w3.org/2000/svg",
...props,
children: [
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M16.6633 18.9383C15.539 19.6562 14.2034 20.0723 12.7705 20.0723C8.77022 20.0723 5.52734 16.8294 5.52734 12.8291C5.52734 8.82881 8.77022 5.58594 12.7705 5.58594C16.7708 5.58594 20.0137 8.82881 20.0137 12.8291C20.0137 13.6623 19.8249 14.7093 19.6141 15.2077C19.5578 15.3408 19.479 15.4845 19.3936 15.6238C19.0955 16.1106 18.5507 16.3721 17.9807 16.4018V16.4018C16.8271 16.462 15.8588 15.5428 15.8588 14.3877V9.27302",
stroke: "currentColor",
strokeWidth: 1.2,
strokeLinejoin: "round"
}
),
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12.5732", cy: "12.8291", r: "3.08691", stroke: "currentColor", strokeWidth: 1.2 })
]
}
);
}), ReactionIcon = React.forwardRef(function(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsxs(
"svg",
{
"data-sanity-icon": "add-reaction",
fill: "none",
height: "1em",
ref,
viewBox: "0 0 25 25",
width: "1em",
xmlns: "http://www.w3.org/2000/svg",
...props,
children: [
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M10.1044 10.4011L10.1044 10.9972",
stroke: "currentColor",
strokeWidth: 1.2,
strokeLinecap: "square"
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M14.2393 10.4011L14.2393 10.9972",
stroke: "currentColor",
strokeWidth: 1.2,
strokeLinecap: "square"
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M7.12128 14.1151C7.70803 15.0226 9.66113 16.8377 11.7735 16.8377C13.8859 16.8377 15.6713 15.0226 16.4257 14.1151",
stroke: "currentColor",
strokeWidth: 1.2,
strokeLinecap: "square"
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
d: "M16.703 6.43905C15.3486 5.36511 13.6357 4.72374 11.773 4.72374C7.38731 4.72374 3.83203 8.27902 3.83203 12.6647C3.83203 17.0503 7.38731 20.6056 11.773 20.6056C16.0995 20.6056 19.618 17.1455 19.712 12.8415",
stroke: "currentColor",
strokeWidth: 1.2
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"path",
{
fillRule: "evenodd",
clipRule: "evenodd",
d: "M19.1135 9.03425L19.1135 11.4903L20.3135 11.4903L20.3135 9.03425L22.7693 9.03425L22.7693 7.83425L20.3135 7.83425L20.3135 5.37941L19.1135 5.37941L19.1135 7.83425L16.6584 7.83425L16.6584 9.03425L19.1135 9.03425Z",
fill: "currentColor"
}
)
]
}
);
}), SendIcon = React.forwardRef(function(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
"data-sanity-icon": "send",
fill: "none",
height: "1em",
ref,
viewBox: "0 0 25 25",
width: "1em",
xmlns: "http://www.w3.org/2000/svg",
...props,
children: /* @__PURE__ */ jsxRuntime.jsx(
"path",
{
clipRule: "evenodd",
d: "M21.1602 12.5L7.16016 19.5V14.8765L13.6656 12.4989L7.16016 9.97149L7.16016 5.5L21.1602 12.5Z",
stroke: "currentColor",
strokeWidth: 1.2,
strokeLinejoin: "round"
}
)
}
);
}), CommentsAuthoringPathContext = React.createContext(
null
);
function CommentsAuthoringPathProvider(props) {
const { children } = props, [authoringPath, setAuthoringPath] = React.useState(null), handleSetAuthoringPath = React.useCallback((nextAuthoringPath) => {
setAuthoringPath(nextAuthoringPath);
}, []), value = React.useMemo(
() => ({
authoringPath,
setAuthoringPath: handleSetAuthoringPath
}),
[authoringPath, handleSetAuthoringPath]
);
return /* @__PURE__ */ jsxRuntime.jsx(CommentsAuthoringPathContext.Provider, { value, children });
}
const CommentsContext = React.createContext(null);
function getSchemaField(schemaType, fieldPath) {
var _a;
const paths = PathUtils__namespace.fromString(fieldPath), firstPath = paths[0];
if (firstPath && types.isObjectSchemaType(schemaType)) {
const field = (_a = schemaType == null ? void 0 : schemaType.fields) == null ? void 0 : _a.find((f) => f.name === firstPath);
if (field) {
const nextPath = PathUtils__namespace.toString(paths.slice(1));
return nextPath ? getSchemaField(field.type, nextPath) : field;
}
}
}
function findArrayItemIndex(array, pathSegment) {
if (typeof pathSegment == "number")
return pathSegment;
const index = findIndex__default.default(array, pathSegment);
return index === -1 ? !1 : index;
}
function buildCommentBreadcrumbs(props) {
const { currentUser, schemaType, fieldPath, documentValue } = props, paths = PathUtils__namespace.fromString(fieldPath), fieldPaths = [];
let currentSchemaType = null;
return paths.forEach((seg, index) => {
var _a, _b, _c, _d, _e;
const currentPath = paths.slice(0, index + 1), previousPath = paths.slice(0, index), field = getSchemaField(schemaType, PathUtils__namespace.toString(currentPath)), isKeySegment = seg.hasOwnProperty("_key"), parentValue = sanity.getValueAtPath(documentValue, previousPath), currentValue = sanity.getValueAtPath(documentValue, currentPath), conditionalContext = {
document: documentValue,
currentUser,
parent: parentValue,
value: currentValue
};
if (isKeySegment && Array.isArray(parentValue)) {
const arrayItemIndex = findArrayItemIndex(parentValue, seg), isNumber2 = typeof arrayItemIndex == "number";
fieldPaths.push({
invalid: arrayItemIndex === !1,
isArrayItem: !0,
title: isNumber2 ? `#${Number(arrayItemIndex) + 1}` : "Unknown array item"
});
return;
}
if (field != null && field.type) {
const hidden = sanity.resolveConditionalProperty(field.type.hidden, conditionalContext);
fieldPaths.push({
invalid: hidden,
isArrayItem: !1,
title: sanity.getSchemaTypeTitle(field.type)
}), currentSchemaType = field.type;
return;
}
if (types.isArraySchemaType(currentSchemaType)) {
const arrayValue = sanity.getValueAtPath(documentValue, previousPath), objectType = arrayValue == null ? void 0 : arrayValue._type, objectField = (_a = currentSchemaType == null ? void 0 : currentSchemaType.of) == null ? void 0 : _a.find(
(type) => type.name === objectType
), currentField = (_b = objectField == null ? void 0 : objectField.fields) == null ? void 0 : _b.find(
(f) => f.name === seg
);
if (!objectType && currentValue) {
const allCurrentFields = (_c = currentSchemaType == null ? void 0 : currentSchemaType.of) == null ? void 0 : _c.map((o) => o == null ? void 0 : o.fields).filter(Boolean).flat(), anonymousField = allCurrentFields == null ? void 0 : allCurrentFields.find((f) => (f == null ? void 0 : f.name) === seg), hidden = sanity.resolveConditionalProperty((_d = anonymousField == null ? void 0 : anonymousField.type) == null ? void 0 : _d.hidden, conditionalContext);
anonymousField && (fieldPaths.push({
invalid: hidden,
isArrayItem: !1,
title: sanity.getSchemaTypeTitle(anonymousField == null ? void 0 : anonymousField.type)
}), currentSchemaType = anonymousField == null ? void 0 : anonymousField.type);
return;
}
if (!currentField) {
fieldPaths.push({
invalid: !0,
isArrayItem: !1,
title: "Unknown field"
});
return;
}
const currentTitle = sanity.getSchemaTypeTitle(currentField == null ? void 0 : currentField.type), objectFieldHidden = sanity.resolveConditionalProperty(
(_e = objectField == null ? void 0 : objectField.type) == null ? void 0 : _e.hidden,
conditionalContext
), currentFieldHidden = sanity.resolveConditionalProperty(
currentField == null ? void 0 : currentField.type.hidden,
conditionalContext
), isHidden = objectFieldHidden || currentFieldHidden;
fieldPaths.push({
invalid: isHidden,
isArrayItem: !1,
title: currentTitle
}), currentSchemaType = currentField == null ? void 0 : currentField.type;
return;
}
fieldPaths.push({
invalid: !0,
isArrayItem: !1,
title: "Unknown field"
});
}), fieldPaths;
}
function useCommentHasChanged(message) {
const prevMessage = React.useRef(message);
return React.useMemo(() => !isEqual__default.default(prevMessage.current, message), [message]);
}
function hasCommentMessageValue(value) {
return value ? value == null ? void 0 : value.some(
(block) => {
var _a;
return sanity.isPortableTextTextBlock(block) && ((_a = (block == null ? void 0 : block.children) || []) == null ? void 0 : _a.some((c) => sanity.isPortableTextSpan(c) ? c.text : c.userId));
}
) : !1;
}
function commentIntentIfDiffers(parent, comment) {
var _a, _b;
const parentIntent = (_a = parent == null ? void 0 : parent.context) == null ? void 0 : _a.intent, intent = (_b = comment == null ? void 0 : comment.context) == null ? void 0 : _b.intent;
if (intent && (!parentIntent || "preview" in intent.params && "preview" in parentIntent.params && intent.params.preview !== parentIntent.params.preview))
return intent;
}
function isTextSelectionComment(comment) {
var _a, _b, _c, _d, _e, _f;
return comment ? !!(((_c = (_b = (_a = comment == null ? void 0 : comment.target) == null ? void 0 : _a.path) == null ? void 0 : _b.selection) == null ? void 0 : _c.type) === "text" && (_f = (_e = (_d = comment == null ? void 0 : comment.target) == null ? void 0 : _d.path) == null ? void 0 : _e.selection) != null && _f.value) : !1;
}
const EMPTY_ARRAY$j = [];
function buildCommentThreadItems(props) {
const { comments: comments2, currentUser, documentValue, schemaType, type } = props, parentComments = comments2 == null ? void 0 : comments2.filter((c) => !c.parentCommentId);
return type === "task" ? parentComments.map((parentComment) => {
const replies = comments2 == null ? void 0 : comments2.filter((r) => r.parentCommentId === parentComment._id);
return {
commentsCount: [parentComment, ...replies].length,
parentComment,
replies,
threadId: parentComment.threadId,
hasReferencedValue: !1,
breadcrumbs: EMPTY_ARRAY$j,
fieldPath: ""
};
}) : type === "field" ? parentComments.map((parentComment) => {
var _a, _b, _c;
const crumbs = buildCommentBreadcrumbs({
currentUser,
documentValue,
fieldPath: ((_a = parentComment.target.path) == null ? void 0 : _a.field) || "",
schemaType
});
let hasTextSelection = !1;
if (isTextSelectionComment(parentComment) && (hasTextSelection = !!((_b = parentComment.target.path) != null && _b.selection && parentComment.target.path.selection.value.some((v) => v.text))), crumbs.some((bc) => bc.invalid))
return;
const replies = comments2 == null ? void 0 : comments2.filter((r) => r.parentCommentId === parentComment._id), commentsCount = [parentComment, ...replies].length, hasReferencedValue = hasTextSelection;
return {
breadcrumbs: crumbs,
commentsCount,
fieldPath: ((_c = parentComment.target.path) == null ? void 0 : _c.field) || "",
parentComment,
replies,
threadId: parentComment.threadId,
hasReferencedValue
};
}).filter(Boolean) : EMPTY_ARRAY$j;
}
const DMP_MARGIN = 15;
function diffText(current, next) {
const diff = diffMatchPatch.makeDiff(current, next), diffs = diffMatchPatch.cleanupEfficiency(diff), levenshtein = diffsLevenshtein(diffs);
return { patches: diffMatchPatch.makePatches(current, diffs, { margin: DMP_MARGIN }), levenshtein };
}
function diffApply(current, patches) {
return diffMatchPatch.applyPatches(patches, current, {
allowExceedingIndices: !0,
margin: DMP_MARGIN
})[0];
}
const CHILD_SYMBOL = "\uF0D0";
function toPlainTextWithChildSeparators(inputBlock) {
return inputBlock.children.map((child) => types.isPortableTextSpan(child) ? child.text.replaceAll(CHILD_SYMBOL, " ") : "").join(CHILD_SYMBOL);
}
const COMMENT_INDICATORS = ["\uF000", "\uF001"], COMMENT_INDICATORS_REGEX = new RegExp(`[${COMMENT_INDICATORS.join("")}]`, "g"), EMPTY_ARRAY$i = [];
function buildRangeDecorationSelectionsFromComments(props) {
const { value, comments: comments2 } = props;
if (!value || value.length === 0)
return EMPTY_ARRAY$i;
const textSelections = comments2.filter(isTextSelectionComment), decorators = [];
return textSelections.forEach((comment) => {
var _a, _b;
(_b = (_a = comment.target.path) == null ? void 0 : _a.selection) == null || _b.value.forEach((selectionMember) => {
const matchedBlock = value.find((block) => block._key === selectionMember._key);
if (!matchedBlock || !types.isPortableTextTextBlock(matchedBlock))
return;
const selectionText = selectionMember.text.replaceAll(COMMENT_INDICATORS_REGEX, ""), textWithChildSeparators = toPlainTextWithChildSeparators(matchedBlock), { patches } = diffText(selectionText, selectionMember.text), diffedText = diffApply(textWithChildSeparators, patches), startIndex = diffedText.indexOf(COMMENT_INDICATORS[0]), endIndex = diffedText.replaceAll(COMMENT_INDICATORS[0], "").indexOf(COMMENT_INDICATORS[1]), textWithoutCommentTags = diffedText.replaceAll(COMMENT_INDICATORS_REGEX, ""), oldCommentedText = selectionMember.text.substring(
selectionMember.text.indexOf(COMMENT_INDICATORS[0]) + 1,
selectionMember.text.indexOf(COMMENT_INDICATORS[1])
), newCommentedText = textWithoutCommentTags.substring(startIndex, endIndex), { levenshtein } = diffText(newCommentedText, oldCommentedText), threshold = Math.round(newCommentedText.length + oldCommentedText.length / 2);
let nullSelection = !1;
if (newCommentedText.length === 0 && (nullSelection = !0), levenshtein > threshold && (nullSelection = !0), startIndex + 1 === endIndex && (nullSelection = !0), startIndex !== -1 && endIndex !== -1) {
let childIndexAnchor = 0, anchorOffset = 0, childIndexFocus = 0, focusOffset = 0;
for (let i = 0; i < textWithoutCommentTags.length && (textWithoutCommentTags[i] === CHILD_SYMBOL && (i <= startIndex && (anchorOffset = -1, childIndexAnchor++), focusOffset = -1, childIndexFocus++), i < startIndex && anchorOffset++, i < startIndex + newCommentedText.length && focusOffset++, i !== startIndex + newCommentedText.length); i++)
;
decorators.push({
selection: {
anchor: {
path: [
{ _key: matchedBlock._key },
"children",
{ _key: matchedBlock.children[childIndexAnchor]._key }
],
offset: anchorOffset
},
focus: {
path: [
{ _key: matchedBlock._key },
"children",
{ _key: matchedBlock.children[childIndexFocus]._key }
],
offset: focusOffset
}
},
comment,
range: { _key: matchedBlock._key, text: nullSelection ? "" : diffedText }
});
}
});
}), decorators.length === 0 ? EMPTY_ARRAY$i : decorators;
}
function diffsLevenshtein(diffs) {
let levenshtein = 0, insertions = 0, deletions = 0;
for (let x = 0; x < diffs.length; x++) {
const op = diffs[x][0], data = diffs[x][1];
switch (op) {
case diffMatchPatch.DIFF_INSERT:
insertions += data.length;
break;
case diffMatchPatch.DIFF_DELETE:
deletions += data.length;
break;
case diffMatchPatch.DIFF_EQUAL:
levenshtein += Math.max(insertions, deletions), insertions = 0, deletions = 0;
break;
}
}
return levenshtein += Math.max(insertions, deletions), levenshtein;
}
const CommentRangeDecoration = React.memo(function(props) {
const {
children,
commentId,
currentHoveredCommentId,
onClick,
onHoverEnd,
onHoverStart,
selectedThreadId,
threadId
} = props, decoratorRef = React.useRef(null), isNestedRef = React.useRef(!1), parentCommentId = React.useRef(null);
React.useEffect(() => {
var _a, _b;
const prevEl = (_a = decoratorRef.current) == null ? void 0 : _a.previousSibling, nextEl = (_b = decoratorRef.current) == null ? void 0 : _b.nextSibling;
if (!prevEl || !nextEl) {
isNestedRef.current = !1;
return;
}
const [key] = Object.keys(applyInlineCommentIdAttr("")), prevId = prevEl.getAttribute(key), nextId = nextEl.getAttribute(key), isNestedDecorator = !!(prevId && nextId && prevId === nextId);
parentCommentId.current = isNestedDecorator ? prevId : null, isNestedRef.current = isNestedDecorator;
}, []);
const handleMouseEnter = React.useCallback(() => onHoverStart(commentId), [commentId, onHoverStart]), handleMouseLeave = React.useCallback(() => onHoverEnd(null), [onHoverEnd]), handleClick = React.useCallback(() => onClick(commentId), [commentId, onClick]), hovered = currentHoveredCommentId === commentId || currentHoveredCommentId === parentCommentId.current && isNestedRef.current;
return /* @__PURE__ */ jsxRuntime.jsx(
CommentInlineHighlightSpan,
{
isAdded: !0,
isHovered: hovered || selectedThreadId === threadId,
isNested: isNestedRef.current,
onClick: handleClick,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
ref: decoratorRef,
...applyInlineCommentIdAttr(threadId),
children
}
);
});
function buildRangeDecorations(props) {
const {
comments: comments2,
currentHoveredCommentId,
onDecorationClick,
onDecorationHoverEnd,
onDecorationHoverStart,
onDecorationMoved,
selectedThreadId,
value
} = props;
return buildRangeDecorationSelectionsFromComments({ comments: comments2, value }).map(({ selection, comment, range }) => ({
component: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
CommentRangeDecoration,
{
commentId: comment._id,
currentHoveredCommentId,
onClick: onDecorationClick,
onHoverEnd: onDecorationHoverEnd,
onHoverStart: onDecorationHoverStart,
selectedThreadId,
threadId: comment.threadId,
children
}
),
onMoved: onDecorationMoved,
selection,
payload: {
commentId: comment._id,
range
}
}));
}
function buildTextSelectionFromFragment(props) {
const { fragment, value, selection } = props;
if (!selection)
throw new Error("Selection is required");
const normalizedSelection = selection.backward ? { backward: !1, anchor: selection.focus, focus: selection.anchor } : selection;
return {
type: "text",
value: fragment.map((fragmentBlock) => {
const originalBlock = value.find((b) => b._key === fragmentBlock._key);
if (!types.isPortableTextTextBlock(originalBlock))
return {
_key: fragmentBlock._key,
text: ""
};
const anchorBlockKey = types.isKeySegment(normalizedSelection.anchor.path[0]) && normalizedSelection.anchor.path[0]._key, focusBlockKey = types.isKeySegment(normalizedSelection.focus.path[0]) && normalizedSelection.focus.path[0]._key, fragmentBlockText = react.toPlainText([fragmentBlock]), fragmentStartSpan = types.isPortableTextTextBlock(fragmentBlock) ? fragmentBlock.children[0] : void 0, fragmentEndSpan = types.isPortableTextTextBlock(fragmentBlock) ? fragmentBlock.children[fragmentBlock.children.length - 1] : void 0;
let originalTextBeforeSelection = "", startChildIndex = -1;
if (anchorBlockKey === originalBlock._key)
for (const child of originalBlock.children) {
if (startChildIndex++, child._key === (fragmentStartSpan == null ? void 0 : fragmentStartSpan._key)) {
originalTextBeforeSelection += types.isPortableTextSpan(child) && child.text.substring(0, normalizedSelection.anchor.offset) || "";
break;
}
originalTextBeforeSelection += child.text;
}
let originalTextAfterSelection = "";
if (focusBlockKey === originalBlock._key)
for (const child of originalBlock.children.slice(startChildIndex).reverse()) {
if (child._key === (fragmentEndSpan == null ? void 0 : fragmentEndSpan._key)) {
originalTextAfterSelection = (types.isPortableTextSpan(child) && child.text.substring(normalizedSelection.focus.offset, child.text.length) || "") + originalTextAfterSelection;
break;
}
originalTextAfterSelection = child.text + originalTextAfterSelection;
}
return {
_key: originalBlock._key,
text: `${originalTextBeforeSelection}${COMMENT_INDICATORS[0]}${fragmentBlockText}${COMMENT_INDICATORS[1]}${originalTextAfterSelection}`
};
})
};
}
function mergeCommentReactions(reactionsA, reactionsB) {
const mergedReactions = {};
for (const reaction of reactionsA)
mergedReactions[reaction._key] = { ...reaction };
for (const reaction of reactionsB)
mergedReactions[reaction._key] = { ...mergedReactions[reaction._key], ...reaction };
return Object.values(mergedReactions);
}
function createCommentsSet(comments2) {
return comments2.reduce((acc, comment) => ({ ...acc, [comment._id]: comment }), {});
}
function commentsReducer(state2, action) {
var _a;
switch (action.type) {
case "COMMENTS_SET": {
const commentsById = createCommentsSet(action.comments);
return {
...state2,
comments: commentsById
};
}
case "COMMENT_ADDED": {
const nextCommentResult = action.payload, nextCommentValue = nextCommentResult, nextComment = {
[nextCommentResult._id]: {
...state2.comments[nextCommentResult._id],
...nextCommentValue,
_state: nextCommentResult._state || void 0,
// If the comment is created optimistically, it won't have a createdAt date as this is set on the server.
// However, we need to set a createdAt date to be able to sort the comments correctly.
// Therefore, we set the createdAt date to the current date here if it's missing while creating the comment.
// Once the comment is created and received from the server, the createdAt date will be updated to the correct value.
_createdAt: nextCommentResult._createdAt || (/* @__PURE__ */ new Date()).toISOString()
}
};
return {
...state2,
comments: {
...state2.comments,
...nextComment
}
};
}
case "COMMENT_RECEIVED": {
const nextCommentResult = action.payload;
return {
...state2,
comments: {
...state2.comments,
[nextCommentResult._id]: nextCommentResult
}
};
}
case "COMMENT_DELETED": {
const { [action.id]: _, ...restComments } = state2.comments;
return Object.keys(restComments).forEach((commentId) => {
restComments[commentId].parentCommentId === action.id && delete restComments[commentId];
}), {
...state2,
comments: restComments
};
}
case "COMMENT_UPDATED": {
const updatedComment = action.payload, id = updatedComment._id, comment = state2.comments[id], optimisticReactions = ((_a = comment == null ? void 0 : comment.reactions) == null ? void 0 : _a.filter((v) => v == null ? void 0 : v._optimisticState)) || [], incomingReactions = updatedComment.reactions || [], nextReactions = mergeCommentReactions(optimisticReactions, incomingReactions), nextComment = {
// Add existing comment data
...comment,
// Add incoming comment data
...updatedComment,
// Add reactions merged with optimistic reactions
reactions: nextReactions
};
return {
...state2,
comments: {
...state2.comments,
[id]: nextComment
}
};
}
default:
return state2;
}
}
const INITIAL_STATE$2 = {
comments: {}
}, LISTEN_OPTIONS$1 = {
events: ["welcome", "mutation", "reconnect"],
includeResult: !0,
visibility: "query"
}, SORT_FIELD$1 = "_createdAt", SORT_ORDER$1 = "desc", QUERY_FILTERS$1 = ['_type == "comment"', "target.document._ref == $documentId"], QUERY_PROJECTION$1 = `{
_createdAt,
_id,
authorId,
contentSnapshot,
context,
lastEditedAt,
message,
parentCommentId,
reactions,
status,
target,
threadId
}`, QUERY_SORT_ORDER$1 = `order(${SORT_FIELD$1} ${SORT_ORDER$1})`, QUERY$1 = `*[${QUERY_FILTERS$1.join(" && ")}] ${QUERY_PROJECTION$1} | ${QUERY_SORT_ORDER$1}`;
function useCommentsStore(opts) {
const { client, documentId, onLatestTransactionIdReceived, transactionsIdMap } = opts, [state2, dispatch] = React.useReducer(commentsReducer, INITIAL_STATE$2), [loading, setLoading] = React.useState(client !== null), [error, setError] = React.useState(null), didInitialFetch = React.useRef(!1), params = React.useMemo(() => ({ documentId: sanity.getPublishedId(documentId) }), [documentId]), initialFetch = React.useCallback(async () => {
if (!client) {
setLoading(!1);
return;
}
try {
const res = await client.fetch(QUERY$1, params);
dispatch({ type: "COMMENTS_SET", comments: res }), setLoading(!1);
} catch (err) {
setError(err);
}
}, [client, params]), handleListenerEvent = React.useCallback(
async (event) => {
var _a;
if (event.type === "welcome" && !didInitialFetch.current && (setLoading(!0), await initialFetch(), setLoading(!1), didInitialFetch.current = !0), event.type === "reconnect" && (setLoading(!0), didInitialFetch.current = !1), event.type === "mutation") {
if (event.transition === "appear") {
const nextComment = event.result;
nextComment && dispatch({
type: "COMMENT_RECEIVED",
payload: nextComment
});
}
if (event.transition === "disappear" && dispatch({ type: "COMMENT_DELETED", id: event.documentId }), event.transition === "update") {
const updatedComment = event.result, id = ((_a = event.result) == null ? void 0 : _a._id) || "", transactionId = event.transactionId, latestTransactionId = transactionsIdMap.get(id), isLatestTransaction = transactionId === latestTransactionId;
if (!isLatestTransaction && latestTransactionId)
return;
updatedComment && (dispatch({
type: "COMMENT_UPDATED",
payload: updatedComment
}), isLatestTransaction && onLatestTransactionIdReceived(id));
}
}
},
[initialFetch, onLatestTransactionIdReceived, transactionsIdMap]
), listener$ = React.useMemo(() => client ? client.observable.listen(QUERY$1, params, LISTEN_OPTIONS$1).pipe(
rxjs.catchError((err) => (setError(err), rxjs.of(err)))
) : rxjs.of(), [client, params]);
return React.useEffect(() => {
const sub = listener$.subscribe(handleListenerEvent);
return () => {
sub == null || sub.unsubscribe();
};
}, [handleListenerEvent, listener$]), {
data: React.useMemo(() => Object.values(state2.comments), [state2.comments]),
dispatch,
error,
loading
};
}
const EMPTY_ARRAY$h = [], EMPTY_COMMENTS_DATA = {
open: EMPTY_ARRAY$h,
resolved: EMPTY_ARRAY$h
}, CommentsProvider = React.memo(function(props) {
const { children, documentId, documentType, isCommentsOpen, onCommentsOpen, sortOrder, type } = props, commentsEnabled = useCommentsEnabled(), [status, setStatus] = React.useState("open"), { client, createAddonDataset, isCreatingDataset } = sanity.useAddonDataset(), publishedId = sanity.getPublishedId(documentId), editState = sanity.useEditState(publishedId, documentType, "low"), schemaType = sanity.useSchema().get(documentType), currentUser = sanity.useCurrentUser(), { name: workspaceName, dataset, projectId } = sanity.useWorkspace(), documentValue = React.useMemo(() => editState.draft || editState.published, [editState.draft, editState.published]), documentRevisionId = React.useMemo(() => documentValue == null ? void 0 : documentValue._rev, [documentValue]), transactionsIdMap = React.useMemo(() => /* @__PURE__ */ new Map(), []), handleOnLatestTransactionIdReceived = React.useCallback(
(commentDocumentId) => {
transactionsIdMap.delete(commentDocumentId);
},
[transactionsIdMap]
), {
dispatch,
data = EMPTY_ARRAY$h,
error,
loading
} = useCommentsStore({
documentId: publishedId,
client,
transactionsIdMap,
onLatestTransactionIdReceived: handleOnLatestTransactionIdReceived
}), handleOnTransactionStart = React.useCallback(
(commentDocumentId, transactionId) => {
transactionsIdMap.set(commentDocumentId, transactionId);
},
[transactionsIdMap]
), handleSetStatus = React.useCallback(
(newStatus) => commentsEnabled.mode === "upsell" && newStatus === "resolved" ? null : setStatus(newStatus),
[setStatus, commentsEnabled]
), mentionOptions = sanity.useUserListWithPermissions(
React.useMemo(() => ({ documentValue, permission: "read" }), [documentValue])
), threadItemsByStatus = React.useMemo(() => {
if (!schemaType || !currentUser)
return EMPTY_COMMENTS_DATA;
const sorted = orderBy__default.default(data, ["_createdAt"], [sortOrder]), items = buildCommentThreadItems({
comments: sorted,
currentUser,
documentValue,
schemaType,
type
});
return {
open: items.filter((item) => item.parentComment.status === "open"),
resolved: items.filter((item) => item.parentComment.status === "resolved")
};
}, [currentUser, data, documentValue, schemaType, sortOrder, type]), getThreadLength = React.useCallback(
(threadId) => threadItemsByStatus.open.filter((item) => item.threadId === threadId).length,
[threadItemsByStatus.open]
), getComment = React.useCallback((id) => data == null ? void 0 : data.find((c) => c._id === id), [data]), handleOnCreate = React.useCallback(
(payload) => {
var _a, _b;
const hasError = ((_b = (_a = data == null ? void 0 : data.find((c) => c._id === payload._id)) == null ? void 0 : _a._state) == null ? void 0 : _b.type) === "createError";
dispatch({
type: "COMMENT_ADDED",
payload: {
...payload,
_state: hasError ? { type: "createRetrying" } : void 0
}
});
},
[data, dispatch]
), handleOnUpdate = React.useCallback(
(id, payload) => {
dispatch({
type: "COMMENT_UPDATED",
payload: {
_id: id,
...payload
}
});
},
[dispatch]
), handleOnCreateError = React.useCallback(
(id, err) => {
dispatch({
type: "COMMENT_UPDATED",
payload: {
_id: id,
_state: {
error: err,
type: "createError"
}
}
});
},
[dispatch]
), { operation } = useCommentOperations(
React.useMemo(
() => ({
client,
currentUser,
dataset,
documentId: publishedId,
documentRevisionId,
documentType,
getComment,
getThreadLength,
projectId,
schemaType,
workspace: workspaceName,
// This function runs when the first comment creation is executed.
// It is used to create the addon dataset and configure a client for
// the addon dataset.
createAddonDataset,
// The following callbacks runs when the comment operation are executed.
// They are used to update the local state of the comments immediately after
// a comment operation has been executed. This is done to avoid waiting for
// the real time listener to update the comments and make the UI feel more
// responsive. The comment will be updated again when we receive an mutation
// event from the real time listener.
onCreate: handleOnCreate,
onCreateError: handleOnCreateError,
onUpdate: handleOnUpdate,
onTransactionStart: handleOnTransactionStart
}),
[
client,
currentUser,
dataset,
documentRevisionId,
documentType,
getComment,
createAddonDataset,
getThreadLength,
handleOnCreate,
handleOnCreateError,
handleOnTransactionStart,
handleOnUpdate,
projectId,
publishedId,
schemaType,
workspaceName
]
)
), ctxValue = React.useMemo(
() => ({
isCreatingDataset,
status,
setStatus: handleSetStatus,
getComment,
isCommentsOpen,
onCommentsOpen,
comments: {
data: threadItemsByStatus,
error,
loading: loading || isCreatingDataset
},
operation: {
create: operation.create,
react: operation.react,
remove: operation.remove,
update: operation.update
},
mentionOptions
}),
[
isCreatingDataset,
status,
handleSetStatus,
getComment,
isCommentsOpen,
onCommentsOpen,
threadItemsByStatus,
error,
loading,
operation.create,
operation.react,
operation.remove,
operation.update,
mentionOptions
]
);
return /* @__PURE__ */ jsxRuntime.jsx(CommentsContext.Provider, { value: ctxValue, children });
}), CommentsEnabledContext = React.createContext(null), CommentsEnabledProvider = React__namespace.memo(function(props) {
const { children, documentId, documentType } = props, value = useResolveCommentsEnabled(documentId, documentType);
return /* @__PURE__ */ jsxRuntime.jsx(CommentsEnabledContext.Provider, { value, children });
}), CommentsIntentContext = React.createContext(
void 0
), CommentsIntentProvider = React.memo(function(props) {
const { children, getIntent: getIntent2 } = props;
return /* @__PURE__ */ jsxRuntime.jsx(CommentsIntentContext.Provider, { value: getIntent2, children });
}), CommentsOnboardingContext = React.createContext(null), VERSION = 1, LOCAL_STORAGE_KEY = `sanityStudio:comments:inspector:onboarding:dismissed:v${VERSION}`, setLocalStorage = (value) => {
try {
window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(value));
} catch {
}
}, getLocalStorage = () => {
try {
const value = window.localStorage.getItem(LOCAL_STORAGE_KEY);
return value ? JSON.parse(value) : !1;
} catch {
return !1;
}
};
function CommentsOnboardingProvider(props) {
const { children } = props, [dismissed, setDismissed] = React.useState(getLocalStorage()), handleDismiss = React.useCallback(() => {
setDismissed(!0), setLocalStorage(!0);
}, [setDismissed]), ctxValue = React.useMemo(
() => ({
setDismissed: handleDismiss,
isDismissed: dismissed
}),
[handleDismiss, dismissed]
);
return /* @__PURE__ */ jsxRuntime.jsx(CommentsOnboardingContext.Provider, { value: ctxValue, children });
}
const CommentsSelectedPathContext = React.createContext(
null
), CommentsSelectedPathProvider = React__namespace.default.memo(function(props) {
const { children } = props, [selectedPath, setSelectedPath] = React.useState(null), handleSelectPath = React.useCallback(
(nextPath) => {
isEqual__default.default(selectedPath, nextPath) || setSelectedPath(nextPath);
},
[selectedPath]
), ctxValue = React.useMemo(
() => ({
selectedPath,
setSelectedPath: handleSelectPath
}),
[selectedPath, handleSelectPath]
);
return /* @__PURE__ */ jsxRuntime.jsx(CommentsSelectedPathContext.Provider, { value: ctxValue, children });
}), CommentsUpsellContext = React.createContext(null), UPSELL_CLIENT_OPTIONS = {
apiVersion: "2023-12-11",
useProjectHostname: !1,
withCredentials: !1,
useCdn: !0
}, FEATURE = "comments", TEMPLATE_OPTIONS = { interpolate: /{{([\s\S]+?)}}/g }, BASE_URL = "www.sanity.io";
function CommentsUpsellProvider(props) {
const [upsellDialogOpen, setUpsellDialogOpen] = React.useState(!1), [upsellData, setUpsellData] = React.useState(null), projectId = sanity.useProjectId(), telemetry2 = react$1.useTelemetry(), client = sanity.useClient(sanity.DEFAULT_STUDIO_CLIENT_OPTIONS), telemetryLogs = React.useMemo(
() => ({
dialogSecondaryClicked: () => telemetry2.log(sanity.UpsellDialogLearnMoreCtaClicked, {
feature: FEATURE,
type: "modal"
}),
dialogPrimaryClicked: () => telemetry2.log(sanity.UpsellDialogUpgradeCtaClicked, {
feature: FEATURE,
type: "modal"
}),
panelViewed: (source) => telemetry2.log(sanity.UpsellDialogViewed, {
feature: FEATURE,
type: "inspector",
source
}),
panelDismissed: () => telemetry2.log(sanity.UpsellDialogDismissed, {
feature: FEATURE,
type: "inspector"
}),
panelPrimaryClicked: () => telemetry2.log(sanity.UpsellDialogUpgradeCtaClicked, {
feature: FEATURE,
type: "inspector"
}),
panelSecondaryClicked: () => telemetry2.log(sanity.UpsellDialogLearnMoreCtaClicked, {
feature: FEATURE,
type: "inspector"
})
}),
[telemetry2]
), handlePrimaryButtonClick = React.useCallback(() => {
telemetryLogs.dialogPrimaryClicked();
}, [telemetryLogs]), handleSecondaryButtonClick = React.useCallback(() => {
telemetryLogs.dialogSecondaryClicked();
}, [telemetryLogs]), handleClose = React.useCallback(() => {
setUpsellDialogOpen(!1), telemetry2.log(sanity.UpsellDialogDismissed, {
feature: FEATURE,
type: "modal"
});
}, [telemetry2]);
React.useEffect(() => {
const sub = client.withConfig(UPSELL_CLIENT_OPTIONS).observable.request({
uri: "/journey/comments"
}).subscribe({
next: (data) => {
if (data)
try {
const ctaUrl = template__default.default(data.ctaButton.url, TEMPLATE_OPTIONS);
data.ctaButton.url = ctaUrl({ baseUrl: BASE_URL, projectId });
const secondaryUrl = template__default.default(data.secondaryButton.url, TEMPLATE_OPTIONS);
data.secondaryButton.url = secondaryUrl({ baseUrl: BASE_URL, projectId }), setUpsellData(data);
} catch {