@sanity/vision
Version:
Sanity plugin for running/debugging GROQ-queries against Sanity datasets
1,138 lines (1,120 loc) • 87.6 kB
JavaScript
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
import { c } from "react-compiler-runtime";
import { useTranslation, useKeyValueStore, useDateTimeFormat, ContextMenuButton, Translate, usePerspective, useDataset, useClient } from "sanity";
import { Spinner, rem, useTheme, Flex, Box, Card, Label, Text, Tooltip, Stack, useToast, TextInput, MenuButton, Menu, MenuItem, Code, Button, Hotkeys, useClickOutsideEvent, Popover, Inline, Badge, Grid, Select, Container, Heading } from "@sanity/ui";
import { useState, useEffect, forwardRef, useRef, useImperativeHandle, useMemo, useCallback, Fragment, Component } from "react";
import { SplitPane } from "@rexxars/react-split-pane";
import { ErrorOutlineIcon, TrashIcon, AddIcon, SearchIcon, StopIcon, PlayIcon, HelpCircleIcon, CopyIcon, LinkIcon, DocumentSheetIcon, ChevronLeftIcon, ChevronRightIcon } from "@sanity/icons";
import { isHotkey } from "is-hotkey-esm";
import { useEffectEvent } from "use-effect-event";
import CodeMirror, { EditorSelection } from "@uiw/react-codemirror";
import { closeBrackets } from "@codemirror/autocomplete";
import { history, defaultKeymap, historyKeymap } from "@codemirror/commands";
import { javascriptLanguage } from "@codemirror/lang-javascript";
import { indentOnInput, bracketMatching, syntaxHighlighting, defaultHighlightStyle, HighlightStyle } from "@codemirror/language";
import { highlightSelectionMatches } from "@codemirror/search";
import { lineNumbers, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, drawSelection, keymap, EditorView } from "@codemirror/view";
import { tags } from "@lezer/highlight";
import { hues } from "@sanity/color";
import { styled, css } from "styled-components";
import { visionLocaleNamespace } from "./index.mjs";
import debounce from "lodash/debounce.js";
import JSON5 from "json5";
import isEqual from "lodash/isEqual.js";
import { uuid } from "@sanity/uuid";
import { startWith, map } from "rxjs/operators";
import { json2csv } from "json-2-csv";
import { JsonInspector } from "@rexxars/react-json-inspector";
import LRU from "quick-lru";
import { IntentLink } from "sanity/router";
import { useObservable } from "react-rx";
import { of, map as map$1, catchError } from "rxjs";
const API_VERSIONS = ["v1", "vX", "v2021-03-25", "v2021-10-21", "v2022-03-07", "v2025-02-19", `v${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`], [DEFAULT_API_VERSION] = API_VERSIONS.slice(-1);
function DelayedSpinner(props) {
const $ = c(5), [show, setShow] = useState(!1);
let t0, t1;
$[0] !== props.delay ? (t0 = () => {
const timer = setTimeout(() => setShow(!0), props.delay || 500);
return () => clearTimeout(timer);
}, t1 = [props.delay], $[0] = props.delay, $[1] = t0, $[2] = t1) : (t0 = $[1], t1 = $[2]), useEffect(t0, t1);
let t2;
return $[3] !== show ? (t2 = show ? /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }) : null, $[3] = show, $[4] = t2) : t2 = $[4], t2;
}
const codemirrorExtensions = [[javascriptLanguage], lineNumbers(), highlightActiveLine(), highlightActiveLineGutter(), highlightSelectionMatches(), highlightSpecialChars(), indentOnInput(), bracketMatching(), closeBrackets(), history(), drawSelection(), syntaxHighlighting(defaultHighlightStyle, {
fallback: !0
}), keymap.of([
// Override the default keymap for Mod-Enter to not insert a new line, we have a custom event handler for executing queries
{
key: "Mod-Enter",
run: () => !0
},
// Add the default keymap and history keymap
defaultKeymap,
historyKeymap
].flat().filter(Boolean))];
function useCodemirrorTheme(theme) {
const $ = c(7);
let t0, t1;
$[0] !== theme ? (t1 = createTheme(theme), $[0] = theme, $[1] = t1) : t1 = $[1], t0 = t1;
const cmTheme = t0;
let t2, t3;
$[2] !== theme ? (t3 = syntaxHighlighting(createHighlight(theme)), $[2] = theme, $[3] = t3) : t3 = $[3], t2 = t3;
const cmHighlight = t2;
let t4;
return $[4] !== cmHighlight || $[5] !== cmTheme ? (t4 = [cmTheme, cmHighlight], $[4] = cmHighlight, $[5] = cmTheme, $[6] = t4) : t4 = $[6], t4;
}
function createTheme(theme) {
const {
color,
fonts
} = theme.sanity, card = color.card.enabled, cursor = hues.blue[color.dark ? 400 : 500].hex, selection = hues.gray[theme.sanity.color.dark ? 900 : 100].hex;
return EditorView.theme({
"&": {
color: card.fg,
backgroundColor: card.bg
},
".cm-content": {
caretColor: cursor
},
".cm-editor": {
fontFamily: fonts.code.family,
fontSize: rem(fonts.code.sizes[1].fontSize),
lineHeight: "inherit"
},
".cm-cursor, .cm-dropCursor": {
borderLeftColor: cursor
},
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {
backgroundColor: selection
},
".cm-panels": {
backgroundColor: card.bg,
color: card.fg
},
".cm-panels.cm-panels-top": {
borderBottom: `2px solid ${card.border}`
},
".cm-panels.cm-panels-bottom": {
borderTop: `2px solid ${card.border}`
}
}, {
dark: color.dark
});
}
function createHighlight(theme) {
const c2 = theme.sanity.color.base, s = theme.sanity.color.syntax;
return HighlightStyle.define([{
tag: tags.keyword,
color: s.keyword
}, {
tag: [tags.propertyName, tags.name, tags.deleted, tags.character, tags.macroName],
color: s.property
}, {
tag: [tags.function(tags.variableName), tags.labelName],
color: s.function
}, {
tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)],
color: s.variable
}, {
tag: [tags.definition(tags.name), tags.separator],
color: s.constant
}, {
tag: [tags.typeName, tags.className, tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace],
color: s.number
}, {
tag: [tags.operator, tags.operatorKeyword, tags.url, tags.escape, tags.regexp, tags.link, tags.special(tags.string)],
color: s.operator
}, {
tag: [tags.meta, tags.comment],
color: s.comment
}, {
tag: tags.strong,
fontWeight: "bold"
}, {
tag: tags.emphasis,
fontStyle: "italic"
}, {
tag: tags.strikethrough,
textDecoration: "line-through"
}, {
tag: tags.heading,
fontWeight: "bold",
color: s.property
}, {
tag: [tags.atom, tags.bool, tags.special(tags.variableName)],
color: s.boolean
}, {
tag: [tags.processingInstruction, tags.string, tags.inserted],
color: s.string
}, {
tag: tags.invalid,
color: c2.fg
}]);
}
const EditorRoot = styled.div`
width: 100%;
box-sizing: border-box;
height: 100%;
overflow: hidden;
overflow: clip;
position: relative;
display: flex;
& .cm-theme {
width: 100%;
}
& .cm-editor {
height: 100%;
font-size: 16px;
line-height: 21px;
}
& .cm-line {
padding-left: ${({
theme
}) => rem(theme.sanity.space[3])};
}
& .cm-content {
border-right-width: ${({
theme
}) => rem(theme.sanity.space[4])} !important;
padding-top: ${({
theme
}) => rem(theme.sanity.space[5])};
}
`, VisionCodeMirror = forwardRef((props, ref) => {
const $ = c(7), [initialValue] = useState(props.initialValue), sanityTheme = useTheme(), theme = useCodemirrorTheme(sanityTheme), codeMirrorRef = useRef(null);
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = (newContent) => {
const editorView = codeMirrorRef.current?.view;
if (!editorView)
return;
const currentDoc = editorView.state.doc.toString();
newContent !== currentDoc && editorView.dispatch({
changes: {
from: 0,
to: currentDoc.length,
insert: newContent
},
selection: EditorSelection.cursor(newContent.length)
});
}, $[0] = t0) : t0 = $[0];
const resetEditorContent = t0;
let t1, t2;
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => ({
resetEditorContent
}), t2 = [resetEditorContent], $[1] = t1, $[2] = t2) : (t1 = $[1], t2 = $[2]), useImperativeHandle(ref, t1, t2);
let t3;
return $[3] !== initialValue || $[4] !== props.onChange || $[5] !== theme ? (t3 = /* @__PURE__ */ jsx(EditorRoot, { children: /* @__PURE__ */ jsx(CodeMirror, { ref: codeMirrorRef, basicSetup: !1, theme, extensions: codemirrorExtensions, value: initialValue, onChange: props.onChange }) }), $[3] = initialValue, $[4] = props.onChange, $[5] = theme, $[6] = t3) : t3 = $[6], t3;
});
VisionCodeMirror.displayName = "VisionCodeMirror";
const SUPPORTED_PERSPECTIVES = ["pinnedRelease", "raw", "published", "drafts"], VIRTUAL_PERSPECTIVES = ["pinnedRelease"];
function isSupportedPerspective(p) {
return SUPPORTED_PERSPECTIVES.includes(p);
}
function isVirtualPerspective(maybeVirtualPerspective) {
return typeof maybeVirtualPerspective == "string" && VIRTUAL_PERSPECTIVES.includes(maybeVirtualPerspective);
}
function hasPinnedPerspective({
selectedPerspectiveName
}) {
return typeof selectedPerspectiveName < "u";
}
function getActivePerspective({
visionPerspective,
perspectiveStack
}) {
return visionPerspective !== "pinnedRelease" ? visionPerspective : perspectiveStack;
}
function encodeQueryString(query, params = {}, options = {}) {
const searchParams = new URLSearchParams();
searchParams.set("query", query);
for (const [key, value] of Object.entries(params))
searchParams.set(`$${key}`, JSON.stringify(value));
for (const [key, value] of Object.entries(options))
value && searchParams.set(key, `${value}`);
return `?${searchParams}`;
}
function isPlainObject(obj) {
return !!obj && typeof obj == "object" && Object.prototype.toString.call(obj) === "[object Object]";
}
const hasLocalStorage = supportsLocalStorage(), keyPrefix = "sanityVision:";
function clearLocalStorage() {
if (hasLocalStorage)
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
key?.startsWith(keyPrefix) && localStorage.removeItem(key);
}
}
function getLocalStorage(namespace) {
const storageKey = `${keyPrefix}${namespace}`;
let loadedState = null;
return {
get,
set,
merge
};
function get(key, defaultVal) {
const state = ensureState();
return typeof state[key] > "u" ? defaultVal : state[key];
}
function set(key, value) {
const state = ensureState();
return state[key] = value, localStorage.setItem(storageKey, JSON.stringify(loadedState)), value;
}
function merge(props) {
const state = {
...ensureState(),
...props
};
return localStorage.setItem(storageKey, JSON.stringify(state)), state;
}
function ensureState() {
return loadedState === null && (loadedState = loadState()), loadedState;
}
function loadState() {
if (!hasLocalStorage)
return {};
try {
const stored = JSON.parse(localStorage.getItem(storageKey) || "{}");
return isPlainObject(stored) ? stored : {};
} catch {
return {};
}
}
}
function supportsLocalStorage() {
const mod = "lsCheck";
try {
return localStorage.setItem(mod, mod), localStorage.removeItem(mod), !0;
} catch {
return !1;
}
}
function parseApiQueryString(qs) {
const params = {}, options = {};
for (const [key, value] of qs.entries()) {
if (key[0] === "$") {
params[key.slice(1)] = JSON.parse(value);
continue;
}
if (key === "perspective") {
options[key] = value;
continue;
}
}
return {
query: qs.get("query") || "",
params,
options
};
}
function prefixApiVersion(version) {
return version[0] !== "v" && version !== "other" ? `v${version}` : version;
}
function validateApiVersion(apiVersion) {
const parseableApiVersion = apiVersion.replace(/^v/, "").trim().toUpperCase();
return parseableApiVersion.length > 0 && (parseableApiVersion === "X" || parseableApiVersion === "1" || /^\d{4}-\d{2}-\d{2}$/.test(parseableApiVersion) && !isNaN(Date.parse(parseableApiVersion)));
}
function tryParseParams(val, t) {
try {
const parsed = val ? JSON5.parse(val) : {};
return typeof parsed == "object" && parsed && !Array.isArray(parsed) ? parsed : {};
} catch (err) {
return err.message = `${t("params.error.params-invalid-json")}:
${err.message.replace("JSON5:", "")}`, err;
}
}
const Root = styled(Flex)`
.sidebarPanes .Pane {
overflow-y: auto;
overflow-x: hidden;
}
& .Resizer {
background: var(--card-border-color);
opacity: 1;
z-index: 1;
box-sizing: border-box;
background-clip: padding-box;
border: solid transparent;
}
& .Resizer:hover {
border-color: var(--card-shadow-ambient-color);
}
& .Resizer.horizontal {
height: 11px;
margin: -5px 0;
border-width: 5px 0;
cursor: row-resize;
width: 100%;
z-index: 4;
}
& .Resizer.vertical {
width: 11px;
margin: 0 -5px;
border-width: 0 5px;
cursor: col-resize;
z-index: 2; /* To prevent the resizer from being hidden behind CodeMirror scroll area */
}
.Resizer.disabled {
cursor: not-allowed;
}
.Resizer.disabled:hover {
border-color: transparent;
}
`;
Root.displayName = "Root";
const Header = styled(Card)`
border-bottom: 1px solid var(--card-border-color);
`, StyledLabel = styled(Label)`
flex: 1;
`, SplitpaneContainer = styled(Box)`
position: relative;
`, QueryCopyLink = styled.a`
cursor: pointer;
margin-right: auto;
`, InputBackgroundContainer = styled(Box)`
position: absolute;
top: 1rem;
left: 0;
padding: 0;
margin: 0;
z-index: 10;
right: 0;
${StyledLabel} {
user-select: none;
}
`, InputBackgroundContainerLeft = styled(InputBackgroundContainer)`
// This is so its aligned with the gutters of CodeMirror
left: 33px;
`, InputContainer = styled(Card)`
width: 100%;
height: 100%;
position: relative;
flex-direction: column;
`, ResultOuterContainer = styled(Flex)`
height: 100%;
`, ResultInnerContainer = styled(Box)`
position: relative;
`, ResultContainer = styled(Card)`
height: 100%;
width: 100%;
position: absolute;
max-width: 100%;
${({
$isInvalid
}) => $isInvalid && css`
&:after {
background-color: var(--card-bg-color);
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
}
`}
`, Result = styled(Box)`
position: relative;
width: 100%;
height: 100%;
z-index: 20;
`, ResultFooter = styled(Flex)`
border-top: 1px solid var(--card-border-color);
`, TimingsCard = styled(Card)`
position: relative;
`;
styled(Box)`
width: 100%;
height: 100%;
`;
const TimingsTextContainer = styled(Flex)`
height: 100%;
min-height: ${({
theme
}) => rem(theme.sanity.space[3] * 2 + theme.sanity.fonts.text.sizes[2].lineHeight - theme.sanity.fonts.text.sizes[2].ascenderHeight - theme.sanity.fonts.text.sizes[2].descenderHeight)};
`, DownloadsCard = styled(Card)`
position: relative;
`, SaveResultLabel = styled(Text)`
transform: initial;
&:before,
&:after {
content: none;
}
> span {
display: flex !important;
gap: ${({
theme
}) => rem(theme.sanity.space[3])};
align-items: center;
}
`, ControlsContainer = styled(Box)`
border-top: 1px solid var(--card-border-color);
`, defaultValue$1 = `{
}`;
function ParamsEditor(props) {
const $ = c(33), {
onChange,
paramsError,
hasValidParams,
editorRef
} = props, {
t
} = useTranslation(visionLocaleNamespace);
let t0;
$[0] !== props.value || $[1] !== t ? (t0 = parseParams(props.value, t), $[0] = props.value, $[1] = t, $[2] = t0) : t0 = $[2];
const {
raw: value,
error,
parsed,
valid
} = t0, [isValid, setValid] = useState(valid), [init, setInit] = useState(!1);
let t1, t2;
$[3] !== error || $[4] !== init || $[5] !== isValid || $[6] !== onChange || $[7] !== parsed || $[8] !== value ? (t1 = () => {
init || (onChange({
parsed,
raw: value,
valid: isValid,
error
}), setInit(!0));
}, t2 = [error, init, isValid, onChange, parsed, value], $[3] = error, $[4] = init, $[5] = isValid, $[6] = onChange, $[7] = parsed, $[8] = value, $[9] = t1, $[10] = t2) : (t1 = $[9], t2 = $[10]), useEffect(t1, t2);
let t3;
$[11] !== onChange || $[12] !== t ? (t3 = (newValue) => {
const event = parseParams(newValue, t);
setValid(event.valid), onChange(event);
}, $[11] = onChange, $[12] = t, $[13] = t3) : t3 = $[13];
const handleChangeRaw = t3;
let t4, t5;
$[14] !== handleChangeRaw ? (t5 = debounce(handleChangeRaw, 333), $[14] = handleChangeRaw, $[15] = t5) : t5 = $[15], t4 = t5;
const handleChange = t4, t6 = hasValidParams ? "default" : "critical";
let t7;
$[16] !== t ? (t7 = t("params.label"), $[16] = t, $[17] = t7) : t7 = $[17];
let t8;
$[18] !== t7 ? (t8 = /* @__PURE__ */ jsx(StyledLabel, { muted: !0, children: t7 }), $[18] = t7, $[19] = t8) : t8 = $[19];
let t9;
$[20] !== paramsError ? (t9 = paramsError && /* @__PURE__ */ jsx(Tooltip, { animate: !0, placement: "top", portal: !0, content: /* @__PURE__ */ jsx(Text, { size: 1, children: paramsError }), children: /* @__PURE__ */ jsx(Box, { padding: 1, marginX: 2, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }) }) }), $[20] = paramsError, $[21] = t9) : t9 = $[21];
let t10;
$[22] !== t8 || $[23] !== t9 ? (t10 = /* @__PURE__ */ jsx(InputBackgroundContainerLeft, { children: /* @__PURE__ */ jsxs(Flex, { children: [
t8,
t9
] }) }), $[22] = t8, $[23] = t9, $[24] = t10) : t10 = $[24];
const t11 = props.value || defaultValue$1;
let t12;
$[25] !== editorRef || $[26] !== handleChange || $[27] !== t11 ? (t12 = /* @__PURE__ */ jsx(VisionCodeMirror, { ref: editorRef, initialValue: t11, onChange: handleChange }), $[25] = editorRef, $[26] = handleChange, $[27] = t11, $[28] = t12) : t12 = $[28];
let t13;
return $[29] !== t10 || $[30] !== t12 || $[31] !== t6 ? (t13 = /* @__PURE__ */ jsxs(Card, { flex: 1, tone: t6, "data-testid": "params-editor", children: [
t10,
t12
] }), $[29] = t10, $[30] = t12, $[31] = t6, $[32] = t13) : t13 = $[32], t13;
}
function parseParams(value, t) {
const parsedParams = tryParseParams(value, t), params = parsedParams instanceof Error ? {} : parsedParams, validationError = parsedParams instanceof Error ? parsedParams.message : void 0;
return {
parsed: params,
raw: value,
valid: !validationError,
error: validationError
};
}
const STORED_QUERIES_NAMESPACE = "studio.vision-tool.saved-queries", defaultValue = {
queries: []
}, keyValueStoreKey = STORED_QUERIES_NAMESPACE;
function useSavedQueries() {
const keyValueStore = useKeyValueStore(), [value, setValue] = useState(defaultValue), [saving, setSaving] = useState(!1), [deleting, setDeleting] = useState([]), [saveQueryError, setSaveQueryError] = useState(), [deleteQueryError, setDeleteQueryError] = useState(), [error, setError] = useState(), queries = useMemo(() => keyValueStore.getKey(keyValueStoreKey), [keyValueStore]);
useEffect(() => {
const sub = queries.pipe(startWith(defaultValue), map((data) => data || defaultValue)).subscribe({
next: setValue,
error: (err) => setError(err)
});
return () => sub?.unsubscribe();
}, [queries, keyValueStore]);
const saveQuery = useCallback((query) => {
setSaving(!0), setSaveQueryError(void 0);
try {
const newQueries = [{
...query,
_key: uuid()
}, ...value.queries];
setValue({
queries: newQueries
}), keyValueStore.setKey(keyValueStoreKey, {
queries: newQueries
});
} catch (err_0) {
setSaveQueryError(err_0);
} finally {
setSaving(!1);
}
}, [keyValueStore, value.queries]), updateQuery = useCallback((query_0) => {
setSaving(!0), setSaveQueryError(void 0);
try {
const updatedQueries = value.queries.map((q) => q._key === query_0._key ? {
...q,
...query_0
} : q);
setValue({
queries: updatedQueries
}), keyValueStore.setKey(keyValueStoreKey, {
queries: updatedQueries
});
} catch (err_1) {
setSaveQueryError(err_1);
} finally {
setSaving(!1);
}
}, [keyValueStore, value.queries]), deleteQuery = useCallback((key) => {
setDeleting((prev) => [...prev, key]), setDeleteQueryError(void 0);
try {
const filteredQueries = value.queries.filter((q_0) => q_0._key !== key);
setValue({
queries: filteredQueries
}), keyValueStore.setKey(keyValueStoreKey, {
queries: filteredQueries
});
} catch (err_2) {
setDeleteQueryError(err_2);
} finally {
setDeleting((prev) => prev.filter((k) => k !== key));
}
}, [keyValueStore, value.queries]);
return {
queries: value.queries,
saveQuery,
updateQuery,
deleteQuery,
saving,
deleting,
saveQueryError,
deleteQueryError,
error
};
}
const FixedHeader = styled(Stack)`
position: sticky;
top: 0;
background: ${({
theme
}) => theme.sanity.color.base.bg};
z-index: 1;
`, ScrollContainer = styled(Box)`
height: 100%;
overflow-y: auto;
overflow-x: hidden;
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: ${({
theme
}) => theme.sanity.color.base.border};
border-radius: 4px;
}
`;
function QueryRecall(t0) {
const $ = c(80), {
url,
getStateFromUrl,
setStateFromParsedUrl,
currentQuery,
currentParams,
generateUrl
} = t0, toast = useToast(), {
saveQuery,
updateQuery,
queries,
deleteQuery,
saving,
saveQueryError
} = useSavedQueries(), {
t
} = useTranslation(visionLocaleNamespace);
let t1;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
hour12: !0
}, $[0] = t1) : t1 = $[0];
const formatDate = useDateTimeFormat(t1), [editingKey, setEditingKey] = useState(null), [editingTitle, setEditingTitle] = useState("");
let t2;
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {}, $[1] = t2) : t2 = $[1];
const [optimisticTitles, setOptimisticTitles] = useState(t2), [searchQuery, setSearchQuery] = useState(""), [selectedUrl, setSelectedUrl] = useState(url);
let t3;
$[2] !== currentParams || $[3] !== currentQuery || $[4] !== formatDate || $[5] !== generateUrl || $[6] !== getStateFromUrl || $[7] !== queries || $[8] !== saveQuery || $[9] !== saveQueryError || $[10] !== t || $[11] !== toast ? (t3 = async () => {
const newUrl = generateUrl(currentQuery, currentParams);
if (queries?.some((q) => {
const savedQueryObj = getStateFromUrl(q.url);
return savedQueryObj && savedQueryObj.query === currentQuery && isEqual(savedQueryObj.params, currentParams);
})) {
const duplicateQuery = queries?.find((q_0) => {
const savedQueryObj_0 = getStateFromUrl(q_0.url);
return savedQueryObj_0 && savedQueryObj_0.query === currentQuery && isEqual(savedQueryObj_0.params, currentParams);
});
toast.push({
closable: !0,
status: "warning",
title: t("save-query.already-saved"),
description: `${duplicateQuery?.title} - ${formatDate.format(new Date(duplicateQuery?.savedAt || ""))}`
});
return;
}
newUrl && (await saveQuery({
url: newUrl,
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
title: "Untitled"
}), setSelectedUrl(newUrl)), saveQueryError ? toast.push({
closable: !0,
status: "error",
title: t("save-query.error"),
description: saveQueryError.message
}) : toast.push({
closable: !0,
status: "success",
title: t("save-query.success")
});
}, $[2] = currentParams, $[3] = currentQuery, $[4] = formatDate, $[5] = generateUrl, $[6] = getStateFromUrl, $[7] = queries, $[8] = saveQuery, $[9] = saveQueryError, $[10] = t, $[11] = toast, $[12] = t3) : t3 = $[12];
const handleSave = t3;
let t4;
$[13] !== t || $[14] !== toast || $[15] !== updateQuery ? (t4 = async (query, newTitle) => {
setEditingKey(null), setOptimisticTitles((prev) => ({
...prev,
[query._key]: newTitle
}));
try {
await updateQuery({
...query,
title: newTitle
}), setOptimisticTitles((prev_1) => {
const next_0 = {
...prev_1
};
return delete next_0[query._key], next_0;
});
} catch (t52) {
const err = t52;
setOptimisticTitles((prev_0) => {
const next = {
...prev_0
};
return delete next[query._key], next;
}), toast.push({
closable: !0,
status: "error",
title: t("save-query.error"),
description: err.message
});
}
}, $[13] = t, $[14] = toast, $[15] = updateQuery, $[16] = t4) : t4 = $[16];
const handleTitleSave = t4;
let t5;
$[17] !== currentParams || $[18] !== currentQuery || $[19] !== formatDate || $[20] !== generateUrl || $[21] !== getStateFromUrl || $[22] !== queries || $[23] !== t || $[24] !== toast || $[25] !== updateQuery ? (t5 = async (query_0) => {
const newUrl_0 = generateUrl(currentQuery, currentParams);
if (queries?.some((q_1) => {
if (q_1._key === query_0._key)
return !1;
const savedQueryObj_1 = getStateFromUrl(q_1.url);
return savedQueryObj_1 && savedQueryObj_1.query === currentQuery && isEqual(savedQueryObj_1.params, currentParams);
})) {
const duplicateQuery_0 = queries?.find((q_2) => {
if (q_2._key === query_0._key)
return !1;
const savedQueryObj_2 = getStateFromUrl(q_2.url);
return savedQueryObj_2 && savedQueryObj_2.query === currentQuery && isEqual(savedQueryObj_2.params, currentParams);
});
toast.push({
closable: !0,
status: "warning",
title: t("save-query.already-saved"),
description: `${duplicateQuery_0?.title} - ${formatDate.format(new Date(duplicateQuery_0?.savedAt || ""))}`
});
return;
}
try {
await updateQuery({
...query_0,
url: newUrl_0,
savedAt: (/* @__PURE__ */ new Date()).toISOString()
}), setSelectedUrl(newUrl_0), toast.push({
closable: !0,
status: "success",
title: t("save-query.success")
});
} catch (t62) {
const err_0 = t62;
toast.push({
closable: !0,
status: "error",
title: t("save-query.error"),
description: err_0.message
});
}
}, $[17] = currentParams, $[18] = currentQuery, $[19] = formatDate, $[20] = generateUrl, $[21] = getStateFromUrl, $[22] = queries, $[23] = t, $[24] = toast, $[25] = updateQuery, $[26] = t5) : t5 = $[26];
const handleUpdate = t5;
let T0, T1, t6, t7, t8;
if ($[27] !== currentParams || $[28] !== currentQuery || $[29] !== deleteQuery || $[30] !== editingKey || $[31] !== editingTitle || $[32] !== formatDate || $[33] !== getStateFromUrl || $[34] !== handleSave || $[35] !== handleTitleSave || $[36] !== handleUpdate || $[37] !== optimisticTitles || $[38] !== queries || $[39] !== saving || $[40] !== searchQuery || $[41] !== selectedUrl || $[42] !== setStateFromParsedUrl || $[43] !== t) {
const filteredQueries = queries?.filter((q_3) => q_3?.title?.toLowerCase().includes(searchQuery.toLowerCase()));
T1 = ScrollContainer;
let t92;
$[49] === Symbol.for("react.memo_cache_sentinel") ? (t92 = {
textTransform: "capitalize"
}, $[49] = t92) : t92 = $[49];
let t102;
$[50] !== t ? (t102 = t("label.saved-queries"), $[50] = t, $[51] = t102) : t102 = $[51];
let t11;
$[52] !== t102 ? (t11 = /* @__PURE__ */ jsx(Text, { weight: "semibold", style: t92, size: 4, children: t102 }), $[52] = t102, $[53] = t11) : t11 = $[53];
let t12;
$[54] !== t ? (t12 = t("action.save-query"), $[54] = t, $[55] = t12) : t12 = $[55];
let t13;
$[56] !== handleSave || $[57] !== saving || $[58] !== t12 ? (t13 = /* @__PURE__ */ jsx(Button, { label: t12, icon: AddIcon, disabled: saving, onClick: handleSave, mode: "bleed" }), $[56] = handleSave, $[57] = saving, $[58] = t12, $[59] = t13) : t13 = $[59];
let t14;
$[60] !== t11 || $[61] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Flex, { padding: 3, paddingTop: 4, paddingBottom: 0, justify: "space-between", align: "center", children: [
t11,
t13
] }), $[60] = t11, $[61] = t13, $[62] = t14) : t14 = $[62];
let t15;
$[63] !== t ? (t15 = t("label.search-queries"), $[63] = t, $[64] = t15) : t15 = $[64];
let t16;
$[65] === Symbol.for("react.memo_cache_sentinel") ? (t16 = (event) => setSearchQuery(event.currentTarget.value), $[65] = t16) : t16 = $[65];
let t17;
$[66] !== searchQuery || $[67] !== t15 ? (t17 = /* @__PURE__ */ jsx(Box, { padding: 3, paddingTop: 0, children: /* @__PURE__ */ jsx(TextInput, { placeholder: t15, icon: SearchIcon, value: searchQuery, onChange: t16 }) }), $[66] = searchQuery, $[67] = t15, $[68] = t17) : t17 = $[68], $[69] !== t14 || $[70] !== t17 ? (t8 = /* @__PURE__ */ jsxs(FixedHeader, { space: 3, children: [
t14,
t17
] }), $[69] = t14, $[70] = t17, $[71] = t8) : t8 = $[71], T0 = Stack, t6 = 3, t7 = filteredQueries?.map((q_4) => {
const queryObj = getStateFromUrl(q_4.url), isSelected = selectedUrl === q_4.url, areQueriesEqual = queryObj && currentQuery === queryObj.query && isEqual(currentParams, queryObj.params), isEdited = isSelected && !areQueriesEqual;
return /* @__PURE__ */ jsx(Card, { width: "fill", padding: 4, border: !0, tone: isSelected ? "positive" : "default", onClick: () => {
setSelectedUrl(q_4.url);
const parsedUrl = getStateFromUrl(q_4.url);
parsedUrl && setStateFromParsedUrl(parsedUrl);
}, style: {
position: "relative"
}, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, paddingRight: 1, children: [
editingKey === q_4._key ? /* @__PURE__ */ jsx(TextInput, { value: editingTitle, onChange: (event_0) => setEditingTitle(event_0.currentTarget.value), onKeyDown: (event_1) => {
event_1.key === "Enter" ? handleTitleSave(q_4, editingTitle) : event_1.key === "Escape" && setEditingKey(null);
}, onBlur: () => handleTitleSave(q_4, editingTitle), autoFocus: !0, style: {
maxWidth: "170px",
height: "24px"
} }) : /* @__PURE__ */ jsx(Text, { weight: "bold", size: 3, textOverflow: "ellipsis", style: {
maxWidth: "170px",
cursor: "pointer",
padding: "4px 0"
}, title: optimisticTitles[q_4._key] || q_4.title || q_4._key.slice(q_4._key.length - 5, q_4._key.length), onClick: () => {
setEditingKey(q_4._key), setEditingTitle(q_4.title || q_4._key.slice(0, 5));
}, children: optimisticTitles[q_4._key] || q_4.title || q_4._key.slice(q_4._key.length - 5, q_4._key.length) }),
isEdited && /* @__PURE__ */ jsx(Box, { style: {
width: "6px",
height: "6px",
borderRadius: "50%",
backgroundColor: "var(--card-focus-ring-color)"
} })
] }),
/* @__PURE__ */ jsx(MenuButton, { button: /* @__PURE__ */ jsx(ContextMenuButton, {}), id: `${q_4._key}-menu`, menu: /* @__PURE__ */ jsx(Menu, { children: /* @__PURE__ */ jsx(MenuItem, { tone: "critical", padding: 3, icon: TrashIcon, text: t("action.delete"), onClick: (event_2) => {
event_2.stopPropagation(), deleteQuery(q_4._key);
} }) }), popover: {
portal: !0,
placement: "bottom-end",
tone: "default"
} })
] }),
/* @__PURE__ */ jsx(Code, { muted: !0, children: queryObj?.query.split("{")[0] }),
/* @__PURE__ */ jsx(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: formatDate.format(new Date(q_4.savedAt || "")) }) }),
isEdited && /* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "default", size: 1, padding: 2, style: {
height: "24px",
position: "absolute",
right: "16px",
bottom: "16px",
fontSize: "12px"
}, text: t("action.update"), onClick: (e) => {
e.stopPropagation(), handleUpdate(q_4);
} })
] }) }, q_4._key);
}), $[27] = currentParams, $[28] = currentQuery, $[29] = deleteQuery, $[30] = editingKey, $[31] = editingTitle, $[32] = formatDate, $[33] = getStateFromUrl, $[34] = handleSave, $[35] = handleTitleSave, $[36] = handleUpdate, $[37] = optimisticTitles, $[38] = queries, $[39] = saving, $[40] = searchQuery, $[41] = selectedUrl, $[42] = setStateFromParsedUrl, $[43] = t, $[44] = T0, $[45] = T1, $[46] = t6, $[47] = t7, $[48] = t8;
} else
T0 = $[44], T1 = $[45], t6 = $[46], t7 = $[47], t8 = $[48];
let t9;
$[72] !== T0 || $[73] !== t6 || $[74] !== t7 ? (t9 = /* @__PURE__ */ jsx(T0, { paddingY: t6, children: t7 }), $[72] = T0, $[73] = t6, $[74] = t7, $[75] = t9) : t9 = $[75];
let t10;
return $[76] !== T1 || $[77] !== t8 || $[78] !== t9 ? (t10 = /* @__PURE__ */ jsxs(T1, { children: [
t8,
t9
] }), $[76] = T1, $[77] = t8, $[78] = t9, $[79] = t10) : t10 = $[79], t10;
}
function narrowBreakpoint() {
return typeof window < "u" && window.innerWidth > 600;
}
function calculatePaneSizeOptions(height) {
let rootHeight = height;
return rootHeight || (rootHeight = typeof window < "u" && typeof document < "u" ? document.body.getBoundingClientRect().height - 60 : 0), {
defaultSize: rootHeight / (narrowBreakpoint() ? 2 : 1),
size: rootHeight > 550 ? void 0 : rootHeight * 0.4,
allowResize: rootHeight > 550,
minSize: Math.min(170, Math.max(170, rootHeight / 2)),
maxSize: rootHeight > 650 ? rootHeight * 0.7 : rootHeight * 0.6
};
}
function usePaneSize(t0) {
const $ = c(7), {
visionRootRef
} = t0, [isNarrowBreakpoint, setIsNarrowBreakpoint] = useState(_temp$3), [paneSizeOptions, setPaneSizeOptions] = useState(_temp2$2);
let t1;
$[0] !== visionRootRef.current ? (t1 = () => {
if (!visionRootRef.current)
return;
const handleResize = (entries) => {
setIsNarrowBreakpoint(narrowBreakpoint());
const entry = entries?.[0];
entry && setPaneSizeOptions(calculatePaneSizeOptions(entry.contentRect.height));
}, resizeObserver = new ResizeObserver(handleResize);
return resizeObserver.observe(visionRootRef.current), () => {
resizeObserver.disconnect();
};
}, $[0] = visionRootRef.current, $[1] = t1) : t1 = $[1];
let t2;
$[2] !== visionRootRef ? (t2 = [visionRootRef], $[2] = visionRootRef, $[3] = t2) : t2 = $[3], useEffect(t1, t2);
let t3;
return $[4] !== isNarrowBreakpoint || $[5] !== paneSizeOptions ? (t3 = {
paneSizeOptions,
isNarrowBreakpoint
}, $[4] = isNarrowBreakpoint, $[5] = paneSizeOptions, $[6] = t3) : t3 = $[6], t3;
}
function _temp2$2() {
return calculatePaneSizeOptions(void 0);
}
function _temp$3() {
return narrowBreakpoint();
}
function VisionGuiControls(t0) {
const $ = c(30), {
hasValidParams,
listenInProgress,
queryInProgress,
onQueryExecution,
onListenExecution
} = t0, {
t
} = useTranslation(visionLocaleNamespace);
let t1;
$[0] !== t ? (t1 = t("params.error.params-invalid-json"), $[0] = t, $[1] = t1) : t1 = $[1];
let t2;
$[2] !== t1 ? (t2 = /* @__PURE__ */ jsx(Card, { radius: 4, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: t1 }) }), $[2] = t1, $[3] = t2) : t2 = $[3];
let t3;
$[4] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Card, { radius: 4, children: /* @__PURE__ */ jsx(Hotkeys, { keys: ["Ctrl", "Enter"] }) }), $[4] = t3) : t3 = $[4];
const t4 = queryInProgress ? StopIcon : PlayIcon, t5 = listenInProgress || !hasValidParams, t6 = queryInProgress ? "positive" : "primary";
let t7;
$[5] !== queryInProgress || $[6] !== t ? (t7 = t(queryInProgress ? "action.query-cancel" : "action.query-execute"), $[5] = queryInProgress, $[6] = t, $[7] = t7) : t7 = $[7];
let t8;
$[8] !== onQueryExecution || $[9] !== t4 || $[10] !== t5 || $[11] !== t6 || $[12] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(Tooltip, { content: t3, placement: "top", portal: !0, children: /* @__PURE__ */ jsx(Button, { width: "fill", onClick: onQueryExecution, type: "button", icon: t4, disabled: t5, tone: t6, text: t7 }) }) }), $[8] = onQueryExecution, $[9] = t4, $[10] = t5, $[11] = t6, $[12] = t7, $[13] = t8) : t8 = $[13];
const t9 = listenInProgress ? StopIcon : PlayIcon;
let t10;
$[14] !== listenInProgress || $[15] !== t ? (t10 = t(listenInProgress ? "action.listen-cancel" : "action.listen-execute"), $[14] = listenInProgress, $[15] = t, $[16] = t10) : t10 = $[16];
const t11 = !hasValidParams, t12 = listenInProgress ? "positive" : "default";
let t13;
$[17] !== onListenExecution || $[18] !== t10 || $[19] !== t11 || $[20] !== t12 || $[21] !== t9 ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1, marginLeft: 3, children: /* @__PURE__ */ jsx(Button, { width: "fill", onClick: onListenExecution, type: "button", icon: t9, text: t10, mode: "ghost", disabled: t11, tone: t12 }) }), $[17] = onListenExecution, $[18] = t10, $[19] = t11, $[20] = t12, $[21] = t9, $[22] = t13) : t13 = $[22];
let t14;
$[23] !== t13 || $[24] !== t8 ? (t14 = /* @__PURE__ */ jsxs(Flex, { justify: "space-evenly", children: [
t8,
t13
] }), $[23] = t13, $[24] = t8, $[25] = t14) : t14 = $[25];
let t15;
return $[26] !== hasValidParams || $[27] !== t14 || $[28] !== t2 ? (t15 = /* @__PURE__ */ jsx(ControlsContainer, { children: /* @__PURE__ */ jsx(Card, { padding: 3, paddingX: 3, children: /* @__PURE__ */ jsx(Tooltip, { content: t2, placement: "top", disabled: hasValidParams, portal: !0, children: t14 }) }) }), $[26] = hasValidParams, $[27] = t14, $[28] = t2, $[29] = t15) : t15 = $[29], t15;
}
const PerspectivePopoverContent = styled(Box)`
/* This limits the width of the popover content */
max-width: 240px;
`, PerspectivePopoverLink = styled.a`
cursor: pointer;
margin-right: auto;
`, Dot = styled.div`
width: 4px;
height: 4px;
border-radius: 3px;
box-shadow: 0 0 0 1px var(--card-bg-color);
background-color: ${({
$tone
}) => `var(--card-badge-${$tone}-dot-color)`};
`;
function PerspectivePopover() {
const $ = c(39), [open, setOpen] = useState(!1), buttonRef = useRef(null), popoverRef = useRef(null);
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => setOpen(_temp$2), $[0] = t0) : t0 = $[0];
const handleClick = t0, {
t
} = useTranslation(visionLocaleNamespace);
let t1, t2;
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => setOpen(!1), t2 = () => [buttonRef.current, popoverRef.current], $[1] = t1, $[2] = t2) : (t1 = $[1], t2 = $[2]), useClickOutsideEvent(t1, t2);
let t3;
$[3] !== t ? (t3 = t("settings.perspectives.title"), $[3] = t, $[4] = t3) : t3 = $[4];
let t4;
$[5] !== t3 ? (t4 = /* @__PURE__ */ jsx(Inline, { space: 2, children: /* @__PURE__ */ jsx(Text, { weight: "medium", children: t3 }) }), $[5] = t3, $[6] = t4) : t4 = $[6];
let t5;
$[7] !== t ? (t5 = t("settings.perspectives.description"), $[7] = t, $[8] = t5) : t5 = $[8];
let t6;
$[9] !== t5 ? (t6 = /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Text, { muted: !0, children: t5 }) }), $[9] = t5, $[10] = t6) : t6 = $[10];
let t7;
$[11] !== t ? (t7 = t("label.new"), $[11] = t, $[12] = t7) : t7 = $[12];
let t8;
$[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Badge, { tone: "primary", children: t7 }) }), $[13] = t7, $[14] = t8) : t8 = $[14];
let t9;
$[15] !== t ? (t9 = /* @__PURE__ */ jsx(Text, { muted: !0, children: /* @__PURE__ */ jsx(Translate, { t, i18nKey: "settings.perspective.preview-drafts-renamed-to-drafts.description" }) }), $[15] = t, $[16] = t9) : t9 = $[16];
let t10;
$[17] !== t8 || $[18] !== t9 ? (t10 = /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
t8,
t9
] }) }), $[17] = t8, $[18] = t9, $[19] = t10) : t10 = $[19];
let t11;
$[20] !== t ? (t11 = null, $[20] = t, $[21] = t11) : t11 = $[21];
let t12;
$[22] !== t ? (t12 = t("settings.perspectives.action.docs-link"), $[22] = t, $[23] = t12) : t12 = $[23];
let t13;
$[24] !== t12 ? (t13 = /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsxs(PerspectivePopoverLink, { href: "https://sanity.io/docs/perspectives", target: "_blank", children: [
t12,
" \u2192"
] }) }) }), $[24] = t12, $[25] = t13) : t13 = $[25];
let t14;
$[26] !== t10 || $[27] !== t11 || $[28] !== t13 || $[29] !== t4 || $[30] !== t6 ? (t14 = /* @__PURE__ */ jsx(PerspectivePopoverContent, { children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
t4,
t6,
t10,
t11,
t13
] }) }), $[26] = t10, $[27] = t11, $[28] = t13, $[29] = t4, $[30] = t6, $[31] = t14) : t14 = $[31];
let t15;
$[32] === Symbol.for("react.memo_cache_sentinel") ? (t15 = /* @__PURE__ */ jsx(Dot, { $tone: "primary" }), $[32] = t15) : t15 = $[32];
let t16;
$[33] !== open ? (t16 = /* @__PURE__ */ jsx(Button, { icon: HelpCircleIcon, mode: "bleed", padding: 2, paddingRight: 1, tone: "primary", fontSize: 1, ref: buttonRef, onClick: handleClick, selected: open, children: t15 }), $[33] = open, $[34] = t16) : t16 = $[34];
let t17;
return $[35] !== open || $[36] !== t14 || $[37] !== t16 ? (t17 = /* @__PURE__ */ jsx(Popover, { content: t14, placement: "bottom-start", portal: !0, padding: 3, ref: popoverRef, open, children: t16 }), $[35] = open, $[36] = t14, $[37] = t16, $[38] = t17) : t17 = $[38], t17;
}
function _temp$2(o) {
return !o;
}
const PinnedReleasePerspectiveOption = (t0) => {
const $ = c(9), {
pinnedPerspective,
t
} = t0, name = typeof pinnedPerspective.selectedPerspective == "object" ? pinnedPerspective.selectedPerspective.metadata.title : pinnedPerspective.selectedPerspectiveName;
let t1;
$[0] !== pinnedPerspective || $[1] !== t ? (t1 = hasPinnedPerspective(pinnedPerspective) ? `(${t("settings.perspectives.pinned-release-label")})` : t("settings.perspectives.pinned-release-label"), $[0] = pinnedPerspective, $[1] = t, $[2] = t1) : t1 = $[2];
const label = t1;
let t2, t3;
$[3] !== label || $[4] !== name ? (t3 = [name, label].filter(_temp$1), $[3] = label, $[4] = name, $[5] = t3) : t3 = $[5], t2 = t3.join(" ");
const text = t2, t4 = !hasPinnedPerspective(pinnedPerspective);
let t5;
return $[6] !== t4 || $[7] !== text ? (t5 = /* @__PURE__ */ jsx("option", { value: "pinnedRelease", disabled: t4, children: text }), $[6] = t4, $[7] = text, $[8] = t5) : t5 = $[8], t5;
};
function VisionGuiHeader(t0) {
const $ = c(64), {
onChangeDataset,
dataset,
customApiVersion,
apiVersion,
onChangeApiVersion,
datasets,
customApiVersionElementRef,
onCustomApiVersionChange,
isValidApiVersion,
onChangePerspective,
url,
perspective
} = t0, pinnedPerspective = usePerspective(), {
t
} = useTranslation(visionLocaleNamespace), operationUrlElement = useRef(null);
let t1;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
const el = operationUrlElement.current;
if (el)
try {
el.select(), document.execCommand("copy");
} catch {
console.error("Unable to copy to clipboard :(");
}
}, $[0] = t1) : t1 = $[0];
const handleCopyUrl = t1;
let t2;
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t2 = [1, 4, 8, 12], $[1] = t2) : t2 = $[1];
let t3;
$[2] !== t ? (t3 = t("settings.dataset-label"), $[2] = t, $[3] = t3) : t3 = $[3];
let t4;
$[4] !== t3 ? (t4 = /* @__PURE__ */ jsx(Card, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsx(StyledLabel, { children: t3 }) }), $[4] = t3, $[5] = t4) : t4 = $[5];
let t5;
$[6] !== datasets ? (t5 = datasets.map(_temp2$1), $[6] = datasets, $[7] = t5) : t5 = $[7];
let t6;
$[8] !== dataset || $[9] !== onChangeDataset || $[10] !== t5 ? (t6 = /* @__PURE__ */ jsx(Select, { value: dataset, onChange: onChangeDataset, children: t5 }), $[8] = dataset, $[9] = onChangeDataset, $[10] = t5, $[11] = t6) : t6 = $[11];
let t7;
$[12] !== t4 || $[13] !== t6 ? (t7 = /* @__PURE__ */ jsx(Box, { padding: 1, column: 2, children: /* @__PURE__ */ jsxs(Stack, { children: [
t4,
t6
] }) }), $[12] = t4, $[13] = t6, $[14] = t7) : t7 = $[14];
let t8;
$[15] !== t ? (t8 = t("settings.api-version-label"), $[15] = t, $[16] = t8) : t8 = $[16];
let t9;
$[17] !== t8 ? (t9 = /* @__PURE__ */ jsx(Card, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsx(StyledLabel, { children: t8 }) }), $[17] = t8, $[18] = t9) : t9 = $[18];
const t10 = customApiVersion === !1 ? apiVersion : "other";
let t11;
$[19] === Symbol.for("react.memo_cache_sentinel") ? (t11 = API_VERSIONS.map(_temp3$1), $[19] = t11) : t11 = $[19];
let t12;
$[20] !== t ? (t12 = t("settings.other-api-version-label"), $[20] = t, $[21] = t12) : t12 = $[21];
let t13;
$[22] !== t12 ? (t13 = /* @__PURE__ */ jsx("option", { value: "other", children: t12 }, "other"), $[22] = t12, $[23] = t13) : t13 = $[23];
let t14;
$[24] !== onChangeApiVersion || $[25] !== t10 || $[26] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Select, { "data-testid": "api-version-selector", value: t10, onChange: onChangeApiVersion, children: [
t11,
t13
] }), $[24] = onChangeApiVersion, $[25] = t10, $[26] = t13, $[27] = t14) : t14 = $[27];
let t15;
$[28] !== t14 || $[29] !== t9 ? (t15 = /* @__PURE__ */ jsx(Box, { padding: 1, column: 2, children: /* @__PURE__ */ jsxs(Stack, { children: [
t9,
t14
] }) }), $[28] = t14, $[29] = t9, $[30] = t15) : t15 = $[30];
let t16;
$[31] !== customApiVersion || $[32] !== customApiVersionElementRef || $[33] !== isValidApiVersion || $[34] !== onCustomApiVersionChange || $[35] !== t ? (t16 = customApiVersion !== !1 && /* @__PURE__ */ jsx(Box, { padding: 1, column: 2, children: /* @__PURE__ */ jsxs(Stack, { children: [
/* @__PURE__ */ jsx(Card, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsx(StyledLabel, { textOverflow: "ellipsis", children: t("settings.custom-api-version-label") }) }),
/* @__PURE__ */ jsx(TextInput, { ref: customApiVersionElementRef, value: customApiVersion, onChange: onCustomApiVersionChange, customValidity: isValidApiVersion ? void 0 : t("settings.error.invalid-api-version"), maxLength: 11 })
] }) }), $[31] = customApiVersion, $[32] = customApiVersionElementRef, $[33] = isValidApiVersion, $[34] = onCustomApiVersionChange, $[35] = t, $[36] = t16) : t16 = $[36];
let t17;
$[37] !== t ? (t17 = t("settings.perspective-label"), $[37] = t, $[38] = t17) : t17 = $[38];
let t18;
$[39] !== t17 ? (t18 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StyledLabel, { children: t17 }) }), $[39] = t17, $[40] = t18) : t18 = $[40];
let t19;
$[41] === Symbol.for("react.memo_cache_sentinel") ? (t19 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(PerspectivePopover, {}) }), $[41] = t19) : t19 = $[41];
let t20;
$[42] !== t18 ? (t20 = /* @__PURE__ */ jsx(Card, { paddingBottom: 1, children: /* @__PURE__ */ jsxs(Inline, { space: 1, children: [
t18,
t19
] }) }), $[42] = t18, $[43] = t20) : t20 = $[43];
const t21 = perspective || "default";
let t22;
$[44] !== pinnedPerspective || $[45] !== t ? (t22 = SUPPORTED_PERSPECTIVES.map((perspectiveName) => perspectiveName === "pinnedRelease" ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PinnedReleasePerspectiveOption, { pinnedPerspective, t }),
/* @__PURE__ */ jsx("option", { value: "default", children: t("settings.perspectives.default") }, "default"),
/* @__PURE__ */ jsx("hr", {})
] }, "pinnedRelease") : /* @__PURE__ */ jsx("option", { children: perspectiveName }, perspectiveName)), $[44] = pinnedPerspective, $[45] = t, $[46] = t22) : t22 = $[46];
let t23;
$[47] !== onChangePerspective || $[48] !== t21 || $[49] !== t22 ? (t23 = /* @__PURE__ */ jsx(Select, { value: t21, onChange: onChangePerspective, children: t22 }), $[47] = onChangePerspective, $[48] = t21, $[49] = t22, $[50] = t23) : t23 = $[50];
let t24;
$[51] !== t20 || $[52] !== t23 ? (t24 = /* @__PURE__ */ jsx(Box, { padding: 1, column: 2, children: /* @__PURE__ */ jsxs(Stack, { children: [
t20,
t23
] }) }), $[51] = t20, $[52] = t23, $[53] = t24) : t24 = $[53];
let t25;
$[54] !== customApiVersion || $[55] !== t || $[56] !== url ? (t25 = typeof url == "string" ? /* @__PURE__ */ jsx(Box, { padding: 1, flex: 1, column: customApiVersion === !1 ? 6 : 4, children: /* @__PURE__ */ jsxs(Stack, { children: [
/* @__PURE__ */ jsx(Card, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(StyledLabel, { children: [
t("query.url"),
"\xA0",
/* @__PURE__ */ jsxs(QueryCopyLink, { onClick: handleCopyUrl, children: [
"[",
t("action.copy-url-to-clipboard"),
"]"
] })
] }) }),
/* @__PURE__ */ jsxs(Flex, { flex: 1, gap: 1, children: [
/* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(TextInput, { readOnly: !0, type: "url", ref: operationUrlElement, value: url }) }),
/* @__PURE__ */ jsx(Tooltip, { content: t("action.copy-url-to-clipboard"), children: /* @__PURE__ */ jsx(Button, { "aria-label": t("action.copy-url-to-clipboard"), type: "button", mode: "ghost", icon: CopyIcon, onClick: handleCopyUrl }) })
] })
] }) }) : /* @__PURE__ */ jsx(Box, { flex: 1 }), $[54] = customApiVersion, $[55] = t, $[56] = url, $[57] = t25) : t25 = $[57];
let t26;
return $[58] !== t15 || $[59] !== t16 || $[60] !== t24 || $[61] !== t25 || $[62] !== t7 ? (t26 = /* @__PURE__