groqd-playground
Version:
Groqd Playground is a plugin for Sanity Studio for testing [groqd](https://formidable.com/open-source/groqd/) queries, featuring:
909 lines (889 loc) • 36.4 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/util/useDatasets.ts
var React, useDatasets;
var init_useDatasets = __esm({
"src/util/useDatasets.ts"() {
"use strict";
React = __toESM(require("react"));
useDatasets = (client) => {
const [datasets, setDatasets] = React.useState([]);
React.useEffect(() => {
const datasets$ = client.observable.datasets.list().subscribe({
next: (result) => setDatasets(result.map((ds) => ds.name))
});
return () => datasets$.unsubscribe();
}, []);
return datasets;
};
}
});
// src/consts.ts
var STORAGE_KEYS, API_VERSIONS, DEFAULT_API_VERSION;
var init_consts = __esm({
"src/consts.ts"() {
"use strict";
STORAGE_KEYS = {
DATASET: "__groqd_playground_dataset",
API_VERSION: "__groqd_playground_api_version",
CODE: "__groqd_playground_code",
EDITOR_WIDTH: "__groqd_playground_editor_width"
};
API_VERSIONS = ["v1", "vX", "v2021-03-25", "v2021-10-21"];
DEFAULT_API_VERSION = API_VERSIONS.at(-1);
}
});
// src/util/copyDataToClipboard.ts
var React2, import_ui, useCopyDataAndNotify;
var init_copyDataToClipboard = __esm({
"src/util/copyDataToClipboard.ts"() {
"use strict";
React2 = __toESM(require("react"));
import_ui = require("@sanity/ui");
useCopyDataAndNotify = (message) => {
const toast = (0, import_ui.useToast)();
return React2.useCallback(
(url2) => {
navigator.clipboard.writeText(url2).then(() => {
toast.push({ title: message });
});
},
[message]
);
};
}
});
// src/components/ShareUrlField.tsx
var React3, import_ui2, import_icons, ShareUrlField;
var init_ShareUrlField = __esm({
"src/components/ShareUrlField.tsx"() {
"use strict";
React3 = __toESM(require("react"));
import_ui2 = require("@sanity/ui");
import_icons = require("@sanity/icons");
init_copyDataToClipboard();
ShareUrlField = ({
title,
url: url2,
column = 4,
notificationMessage = "Copied URL to clipboard!"
}) => {
const copyUrl = useCopyDataAndNotify(notificationMessage);
const handleCopyUrl = () => copyUrl(url2);
return /* @__PURE__ */ React3.createElement(import_ui2.Box, { padding: 1, flex: 1, column }, /* @__PURE__ */ React3.createElement(import_ui2.Stack, null, /* @__PURE__ */ React3.createElement(import_ui2.Card, { paddingY: 2 }, /* @__PURE__ */ React3.createElement(import_ui2.Label, { muted: true }, title)), /* @__PURE__ */ React3.createElement(import_ui2.Flex, { flex: 1, gap: 1 }, /* @__PURE__ */ React3.createElement(import_ui2.Box, { flex: 1 }, /* @__PURE__ */ React3.createElement(import_ui2.TextInput, { readOnly: true, type: "url", value: url2 })), /* @__PURE__ */ React3.createElement(
import_ui2.Tooltip,
{
content: /* @__PURE__ */ React3.createElement(import_ui2.Box, { padding: 2 }, /* @__PURE__ */ React3.createElement(import_ui2.Text, null, "Copy to clipboard"))
},
/* @__PURE__ */ React3.createElement(
import_ui2.Button,
{
"aria-label": "Copy to clipboard",
type: "button",
mode: "ghost",
icon: import_icons.CopyIcon,
onClick: handleCopyUrl
}
)
))));
};
}
});
// src/util/messaging.ts
var emitReset, emitInit;
var init_messaging = __esm({
"src/util/messaging.ts"() {
"use strict";
emitReset = (iframe, target) => {
var _a2;
(_a2 = iframe.contentWindow) == null ? void 0 : _a2.postMessage(
JSON.stringify({ event: "RESET_CODE" }),
target
);
};
emitInit = (source, target, payload) => {
source.postMessage(JSON.stringify(__spreadValues({ event: "INIT" }, payload)), {
targetOrigin: target
});
};
}
});
// src/components/JSONExplorer.styled.tsx
var import_styled_components, import_ui3, Root, Label2, Key, Value, LineItem, CollapsibleContainer, ErrorMessageText, DEPTH_SC;
var init_JSONExplorer_styled = __esm({
"src/components/JSONExplorer.styled.tsx"() {
"use strict";
import_styled_components = __toESM(require("styled-components"));
import_ui3 = require("@sanity/ui");
Root = (0, import_styled_components.default)(import_ui3.Box)`
font-family: Menlo, monospace;
font-size: 0.9em;
position: relative;
height: 100%;
--border-radius: 4px;
--error-bg-color: #ffe5ea;
--item-hover-color: #e7e7e7;
@media (prefers-color-scheme: dark) {
--error-bg-color: #470417;
--item-hover-color: #505050;
}
`;
Label2 = import_styled_components.default.span`
color: #9d1fcd;
@media (prefers-color-scheme: dark) {
color: #d05afc;
}
`;
Key = import_styled_components.default.span`
color: #1e61cd;
@media (prefers-color-scheme: dark) {
color: #5998fc;
}
`;
Value = import_styled_components.default.span`
color: #967e1c;
@media (prefers-color-scheme: dark) {
color: #dbb931;
}
`;
LineItem = (0, import_styled_components.default)(import_ui3.Box)`
padding-left: ${({ depth }) => depth * DEPTH_SC}px;
border-radius: var(--border-radius);
cursor: ${({ pointer }) => pointer ? "pointer" : "initial"};
background-color: ${({ hasError }) => hasError ? "var(--error-bg-color)" : "initial"};
&:hover {
background-color: ${({ hasError }) => hasError ? void 0 : "var(--item-hover-color)"};
}
`;
CollapsibleContainer = (0, import_styled_components.default)(import_ui3.Stack)`
border-radius: var(--border-radius);
background-color: ${({ hasError }) => hasError ? "var(--error-bg-color)" : "initial"};
`;
ErrorMessageText = import_styled_components.default.div`
font-weight: 400;
`;
DEPTH_SC = 15;
}
});
// ../../shared/util/jsonExplorerUtils.ts
var formatPrimitiveData, isObject, addToPath;
var init_jsonExplorerUtils = __esm({
"../../shared/util/jsonExplorerUtils.ts"() {
"use strict";
formatPrimitiveData = (data) => {
if (typeof data === "string")
return `"${data}"`;
if (data instanceof Date)
return `(Date) ${data}`;
return String(data);
};
isObject = (data) => typeof data === "object" && data !== null && !Array.isArray(data) && !(data instanceof Date);
addToPath = (existingPath, newSegment) => existingPath ? `${existingPath}.${newSegment}` : newSegment;
}
});
// src/components/JSONExplorer.tsx
var React4, import_ui4, import_icons2, JSONExplorer, JSONExplorerDisplay, Collapsible;
var init_JSONExplorer = __esm({
"src/components/JSONExplorer.tsx"() {
"use strict";
React4 = __toESM(require("react"));
import_ui4 = require("@sanity/ui");
init_JSONExplorer_styled();
import_icons2 = require("@sanity/icons");
init_copyDataToClipboard();
init_jsonExplorerUtils();
JSONExplorer = (props) => {
const copyUrl = useCopyDataAndNotify("Copied JSON to clipboard!");
const handleCopy = () => {
try {
copyUrl(JSON.stringify(props.data, null, 2));
} catch (e) {
}
};
return /* @__PURE__ */ React4.createElement(Root, { flex: 1 }, /* @__PURE__ */ React4.createElement(
import_ui4.Box,
{
padding: 3,
style: { position: "absolute", inset: 0 },
overflow: "auto"
},
/* @__PURE__ */ React4.createElement(JSONExplorerDisplay, __spreadValues({}, props))
), /* @__PURE__ */ React4.createElement(import_ui4.Box, { style: { position: "absolute", bottom: 0, right: 0 }, padding: 3 }, /* @__PURE__ */ React4.createElement(
import_ui4.Button,
{
"aria-label": "Copy to clipboard",
type: "button",
mode: "ghost",
icon: import_icons2.CopyIcon,
text: "Copy to clipboard",
onClick: handleCopy
}
)));
};
JSONExplorerDisplay = ({
data,
prefix,
highlightedPaths,
currentPath = ""
}) => {
const prefixDisplay = prefix !== void 0 ? /* @__PURE__ */ React4.createElement(Key, null, prefix, ": ") : null;
const errorMessage = highlightedPaths && highlightedPaths.get(currentPath);
const depth = currentPath === "" ? 0 : (currentPath == null ? void 0 : currentPath.split(".").length) || 0;
if (Array.isArray(data)) {
return /* @__PURE__ */ React4.createElement(
Collapsible,
{
depth,
title: /* @__PURE__ */ React4.createElement(React4.Fragment, null, prefixDisplay, /* @__PURE__ */ React4.createElement(Label2, null, "[...] ", data.length, " items")),
errorMessage,
id: `json-item-${currentPath}`
},
/* @__PURE__ */ React4.createElement(import_ui4.Stack, { space: 2 }, data.map((dat, i) => /* @__PURE__ */ React4.createElement(
JSONExplorerDisplay,
{
data: dat,
key: i,
prefix: String(i),
currentPath: addToPath(currentPath, String(i)),
highlightedPaths
}
)))
);
}
if (isObject(data)) {
return /* @__PURE__ */ React4.createElement(
Collapsible,
{
depth,
title: /* @__PURE__ */ React4.createElement(React4.Fragment, null, prefixDisplay, /* @__PURE__ */ React4.createElement(Label2, null, `{...}`, " ", Object.keys(data).length, " properties")),
errorMessage,
id: `json-item-${currentPath}`
},
/* @__PURE__ */ React4.createElement(import_ui4.Stack, { space: 2 }, Object.entries(data).map(([key, dat]) => /* @__PURE__ */ React4.createElement(
JSONExplorerDisplay,
{
data: dat,
key,
prefix: key,
currentPath: addToPath(currentPath, key),
highlightedPaths
}
)))
);
}
return /* @__PURE__ */ React4.createElement(
LineItem,
{
paddingY: 1,
depth,
hasError: !!errorMessage,
id: `json-item-${currentPath}`
},
/* @__PURE__ */ React4.createElement(import_ui4.Stack, { space: 1 }, errorMessage && /* @__PURE__ */ React4.createElement(ErrorMessageText, null, errorMessage), /* @__PURE__ */ React4.createElement("div", null, prefixDisplay, /* @__PURE__ */ React4.createElement(Value, null, formatPrimitiveData(data)), " "))
);
};
Collapsible = ({
title,
depth,
children,
errorMessage,
id
}) => {
const [isExpanded, setIsExpanded] = React4.useState(true);
return /* @__PURE__ */ React4.createElement(CollapsibleContainer, { space: 2, id, hasError: !!errorMessage }, /* @__PURE__ */ React4.createElement(
LineItem,
{
paddingY: 1,
depth,
onClick: () => setIsExpanded((v) => !v),
pointer: true
},
/* @__PURE__ */ React4.createElement(import_ui4.Stack, { space: 1 }, errorMessage && /* @__PURE__ */ React4.createElement(ErrorMessageText, null, errorMessage), /* @__PURE__ */ React4.createElement(import_ui4.Box, null, title))
), /* @__PURE__ */ React4.createElement("div", { style: { height: isExpanded ? "auto" : 0, overflow: "hidden" } }, children));
};
}
});
// src/components/Playground.styled.tsx
var import_styled_components2, import_ui5, ErrorLineItem, CopyQueryButton;
var init_Playground_styled = __esm({
"src/components/Playground.styled.tsx"() {
"use strict";
import_styled_components2 = __toESM(require("styled-components"));
import_ui5 = require("@sanity/ui");
ErrorLineItem = (0, import_styled_components2.default)(import_ui5.Box)`
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: #e7e7e7;
}
@media (prefers-color-scheme: dark) {
&:hover {
background-color: #505050;
}
}
`;
CopyQueryButton = import_styled_components2.default.button`
all: unset;
cursor: pointer;
&:focus {
box-shadow: inset 0 0 0 1px var(--card-border-color), 0 0 0 1px #fff,
0 0 0 3px var(--card-focus-ring-color);
border-radius: 0.1875rem;
}
`;
}
});
// ../../shared/util/formatErrorPath.ts
var formatErrorPath, NumReg;
var init_formatErrorPath = __esm({
"../../shared/util/formatErrorPath.ts"() {
"use strict";
formatErrorPath = (path) => path.split(".").reduce((acc, el) => {
if (!NumReg.test(el)) {
return `${acc}.${el}`;
}
return `${acc}[${el}]`;
}, "");
NumReg = /\d+/;
}
});
// src/components/Playground.tsx
function GroqdPlayground({ tool }) {
var _a2;
const [
{
query,
params,
parsedResponse,
fetchParseError,
rawResponse,
activeDataset,
activeAPIVersion,
queryUrl,
isFetching,
rawExecutionTime,
errorPaths
},
dispatch
] = React5.useReducer(reducer, null, () => {
var _a3, _b;
const activeDataset2 = localStorage.getItem(STORAGE_KEYS.DATASET) || ((_a3 = tool.options) == null ? void 0 : _a3.defaultDataset) || "production";
const activeAPIVersion2 = localStorage.getItem(STORAGE_KEYS.API_VERSION) || ((_b = tool.options) == null ? void 0 : _b.defaultApiVersion) || DEFAULT_API_VERSION;
return {
query: q.q(""),
activeDataset: activeDataset2,
activeAPIVersion: activeAPIVersion2,
isFetching: false
};
});
const iframeRef = React5.useRef(null);
const editorContainer = React5.useRef(null);
const editorInitialWidth = React5.useMemo(
() => +(localStorage.getItem(STORAGE_KEYS.EDITOR_WIDTH) || 0) || EDITOR_INITIAL_WIDTH,
[]
);
const copyShareUrl = useCopyDataAndNotify("Copied share URL to clipboard!");
const copyQueryUrl = useCopyDataAndNotify("Copied Query to clipboard!");
const windowHref = window.location.href;
const _client = (0, import_sanity.useClient)({
apiVersion: ((_a2 = tool.options) == null ? void 0 : _a2.defaultApiVersion) || "v2021-10-21"
});
const client = React5.useMemo(
() => _client.withConfig({
dataset: activeDataset,
apiVersion: activeAPIVersion
}),
[_client, activeDataset, activeAPIVersion]
);
const datasets = useDatasets(_client);
const generateQueryUrl = (query2, params2) => {
const searchParams = new URLSearchParams();
searchParams.append("query", query2.query);
if (params2) {
for (const [key, value] of Object.entries(params2))
searchParams.append(key, String(value));
}
return client.getUrl(
client.getDataUrl("query", "?" + searchParams.toString())
);
};
React5.useEffect(() => {
if (datasets[0] && !datasets.includes(activeDataset))
handleDatasetChange(datasets[0]);
}, [datasets]);
const runQuery = React5.useMemo(
() => q.makeSafeQueryRunner(
(query2, params2) => new Promise((resolve, reject) => {
client.observable.fetch(query2, params2, { filterResponse: false }).subscribe({
next: (res) => {
dispatch({
type: "RAW_RESPONSE_RECEIVED",
payload: { rawResponse: res.result, execTime: res.ms }
});
resolve(res.result);
},
error: (err) => {
reject(err);
}
});
})
),
[client]
);
const handleRun = (query2, params2) => __async(this, null, function* () {
dispatch({
type: "MAKE_FETCH_REQUEST",
payload: { queryUrl: generateQueryUrl(query2, params2) }
});
try {
const data = yield runQuery(query2, params2);
dispatch({
type: "FETCH_RESPONSE_PARSED",
payload: { parsedResponse: data }
});
} catch (err) {
let errorPaths2;
if (err instanceof q.GroqdParseError) {
errorPaths2 = /* @__PURE__ */ new Map();
for (const e of err.zodError.errors) {
if (e.message === "Required" && !(0, import_lodash.default)(err.rawResponse, e.path)) {
errorPaths2.set(
e.path.slice(0, -1).map((v) => String(v)).join("."),
`Field "${e.path.at(-1)}" is Required`
);
} else {
errorPaths2.set(e.path.map((v) => String(v)).join("."), e.message);
}
}
}
dispatch({
type: "FETCH_PARSE_FAILURE",
payload: { fetchParseError: err, errorPaths: errorPaths2 }
});
}
});
React5.useEffect(() => {
const handleMessage = (message) => {
if (message.origin !== EDITOR_ORIGIN)
return;
try {
const payload = messageSchema.parse(JSON.parse(message.data));
if (payload.event === "READY") {
const storedCode = new URL(window.location.href).searchParams.get("code") || localStorage.getItem(STORAGE_KEYS.CODE);
message.source && emitInit(message.source, EDITOR_ORIGIN, {
code: storedCode || void 0,
origin: window.location.origin
});
} else if (payload.event === "INPUT") {
localStorage.setItem(STORAGE_KEYS.CODE, payload.compressedRawCode);
setQP("code", payload.compressedRawCode);
if (payload.requestShareCopy) {
copyShareUrl(window.location.href);
}
let playgroundRunQueryCount = 0;
const libs = {
groqd: q,
playground: {
runQuery: (query2, params2) => {
playgroundRunQueryCount++;
if (playgroundRunQueryCount > 1)
return;
try {
if (query2 instanceof q.BaseQuery) {
dispatch({
type: "INPUT_EVAL_SUCCESS",
payload: { query: query2, params: params2 }
});
if (payload.requestImmediateFetch) {
handleRun(query2, params2);
}
}
} catch (e) {
}
}
}
};
const scope = {
exports: {},
require: (name) => libs[name]
};
const keys = Object.keys(scope);
new Function(...keys, payload.code)(
...keys.map((key) => scope[key])
);
} else if (payload.event === "ERROR") {
console.error(payload.message);
}
} catch (e) {
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, []);
const handleDatasetChange = (datasetName) => {
dispatch({ type: "SET_ACTIVE_DATASET", payload: { dataset: datasetName } });
};
const handleAPIVersionChange = (apiVersion) => {
dispatch({ type: "SET_ACTIVE_API_VERSION", payload: { apiVersion } });
};
const handleReset = () => {
iframeRef.current && emitReset(iframeRef.current, EDITOR_ORIGIN);
};
const handleCopyQuery = () => query.query && copyQueryUrl(query.query);
const handleEditorResize = () => {
const container = editorContainer.current;
if (!container)
return;
localStorage.setItem(
STORAGE_KEYS.EDITOR_WIDTH,
String(container.clientWidth)
);
};
const responseView = (() => {
if (isFetching) {
return /* @__PURE__ */ React5.createElement(import_ui6.Flex, { justify: "center", flex: 1, align: "center" }, /* @__PURE__ */ React5.createElement(import_ui6.Spinner, { muted: true }));
}
const execTimeDisplay = rawExecutionTime && /* @__PURE__ */ React5.createElement(
import_ui6.Tooltip,
{
placement: "right-end",
content: /* @__PURE__ */ React5.createElement(import_ui6.Box, { padding: 2 }, /* @__PURE__ */ React5.createElement(import_ui6.Text, null, "Raw execution time of query"))
},
/* @__PURE__ */ React5.createElement("span", null, " (", rawExecutionTime, "ms)")
);
if (fetchParseError || (errorPaths == null ? void 0 : errorPaths.size)) {
let errorView = null;
const scrollToError = (path) => {
const lineEl = document.getElementById(`json-item-${path}`);
if (lineEl instanceof HTMLElement)
lineEl.scrollIntoView({ behavior: "smooth", block: "start" });
};
if (errorPaths) {
errorView = /* @__PURE__ */ React5.createElement(import_ui6.Stack, { space: 2, flex: 1, paddingX: 3, paddingY: 1 }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { marginBottom: 1 }, /* @__PURE__ */ React5.createElement(import_ui6.Text, { weight: "semibold", size: 1 }, "Error parsing:")), [...errorPaths.entries()].map(([path, message]) => /* @__PURE__ */ React5.createElement(
ErrorLineItem,
{
key: path,
onClick: () => scrollToError(path),
padding: 1
},
/* @__PURE__ */ React5.createElement(import_ui6.Text, { size: 2 }, "`result", formatErrorPath(path), "`: ", message)
)));
} else if (fetchParseError instanceof Error) {
errorView = /* @__PURE__ */ React5.createElement("pre", null, fetchParseError.message);
} else {
errorView = /* @__PURE__ */ React5.createElement("span", null, "Something went wrong...");
}
return /* @__PURE__ */ React5.createElement(import_ui6.Flex, { flex: 1, direction: "column" }, /* @__PURE__ */ React5.createElement(import_react_split.default, { mode: "vertical" }, /* @__PURE__ */ React5.createElement(import_ui6.Flex, { direction: "column", style: { maxHeight: 400 } }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { marginY: 3, paddingX: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "\u2757Error")), /* @__PURE__ */ React5.createElement(import_ui6.Box, { flex: 1, overflow: "auto" }, errorView)), /* @__PURE__ */ React5.createElement(import_ui6.Flex, { flex: 1, direction: "column" }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { paddingX: 3, marginY: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "Raw Response ", execTimeDisplay)), /* @__PURE__ */ React5.createElement(import_ui6.Box, { flex: 1, style: { height: "100%" } }, /* @__PURE__ */ React5.createElement(
JSONExplorer,
{
data: rawResponse,
highlightedPaths: errorPaths
}
)))));
}
return /* @__PURE__ */ React5.createElement(import_ui6.Flex, { flex: 1, direction: "column", style: { maxHeight: "100%" } }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { padding: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "Query Response ", execTimeDisplay)), parsedResponse ? /* @__PURE__ */ React5.createElement(JSONExplorer, { data: parsedResponse }) : null);
})();
return /* @__PURE__ */ React5.createElement(import_ui6.Flex, { style: { height: "100%" }, direction: "column" }, /* @__PURE__ */ React5.createElement(import_ui6.Card, { paddingX: 3, paddingY: 2, borderBottom: true }, /* @__PURE__ */ React5.createElement(import_ui6.Grid, { columns: [6, 6, 12] }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { padding: 1, column: 2 }, /* @__PURE__ */ React5.createElement(import_ui6.Stack, null, /* @__PURE__ */ React5.createElement(import_ui6.Card, { paddingY: 2 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "Dataset")), /* @__PURE__ */ React5.createElement(
import_ui6.Select,
{
value: activeDataset,
onChange: (e) => handleDatasetChange(e.currentTarget.value)
},
datasets.map((ds) => /* @__PURE__ */ React5.createElement("option", { key: ds }, ds))
))), /* @__PURE__ */ React5.createElement(import_ui6.Box, { padding: 1, column: 2 }, /* @__PURE__ */ React5.createElement(import_ui6.Stack, null, /* @__PURE__ */ React5.createElement(import_ui6.Card, { paddingY: 2 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "API Version")), /* @__PURE__ */ React5.createElement(
import_ui6.Select,
{
value: activeAPIVersion,
onChange: (e) => handleAPIVersionChange(e.currentTarget.value)
},
API_VERSIONS.map((v) => /* @__PURE__ */ React5.createElement("option", { key: v }, v))
))), /* @__PURE__ */ React5.createElement(
ShareUrlField,
{
url: windowHref,
title: "Share URL",
column: queryUrl ? 4 : 8,
notificationMessage: "Copied share URL to clipboard!"
}
), queryUrl && /* @__PURE__ */ React5.createElement(
ShareUrlField,
{
url: queryUrl,
title: "Raw Query URL",
notificationMessage: "Copied raw query URL to clipboard!"
}
))), /* @__PURE__ */ React5.createElement(import_ui6.Box, { flex: 1 }, /* @__PURE__ */ React5.createElement(
import_react_split.default,
{
style: { width: "100%", height: "100%", overflow: "hidden" },
onDragEnd: handleEditorResize
},
/* @__PURE__ */ React5.createElement(
"div",
{
style: {
width: editorInitialWidth,
minWidth: 200,
height: "100%",
display: "flex",
flexDirection: "column"
},
ref: editorContainer
},
/* @__PURE__ */ React5.createElement("div", { style: { flex: 1, position: "relative" } }, /* @__PURE__ */ React5.createElement(
"iframe",
{
src: EDITOR_URL,
width: "100%",
height: "100%",
style: { border: "none" },
ref: iframeRef
}
), /* @__PURE__ */ React5.createElement("div", { style: { position: "absolute", bottom: 12, left: 12 } }, /* @__PURE__ */ React5.createElement(
import_ui6.Button,
{
icon: import_icons3.ResetIcon,
text: "Reset",
mode: "ghost",
onClick: handleReset
}
))),
/* @__PURE__ */ React5.createElement(import_ui6.Card, { paddingTop: 3, paddingBottom: 3, borderTop: true }, /* @__PURE__ */ React5.createElement(import_ui6.Stack, { space: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Box, null, /* @__PURE__ */ React5.createElement(import_ui6.Box, { paddingX: 3, marginBottom: 1 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "Query", " ", query.query && /* @__PURE__ */ React5.createElement(CopyQueryButton, { onClick: handleCopyQuery, tabIndex: 0 }, "(Copy to clipboard)"))), /* @__PURE__ */ React5.createElement(import_ui6.Flex, { padding: 3, paddingBottom: 4, overflow: "auto" }, /* @__PURE__ */ React5.createElement(import_ui6.Code, { language: "text" }, query.query), /* @__PURE__ */ React5.createElement(import_ui6.Box, { width: 3 }))), params && Object.keys(params).length > 0 ? /* @__PURE__ */ React5.createElement(import_ui6.Box, { paddingX: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Box, { marginBottom: 3 }, /* @__PURE__ */ React5.createElement(import_ui6.Label, { muted: true }, "Params")), /* @__PURE__ */ React5.createElement(import_ui6.Stack, { space: 3, marginLeft: 3 }, Object.entries(params).map(([key, value]) => /* @__PURE__ */ React5.createElement(import_ui6.Text, { key, size: 2, muted: true }, "$", key, ": ", value)))) : null)),
/* @__PURE__ */ React5.createElement(import_ui6.Card, { padding: 3, borderTop: true }, /* @__PURE__ */ React5.createElement(
import_ui6.Button,
{
tone: "primary",
icon: import_icons3.PlayIcon,
text: "Fetch",
fontSize: [2],
padding: [3],
style: { width: "100%" },
onClick: () => handleRun(query, params),
disabled: !query.query
}
))
),
/* @__PURE__ */ React5.createElement(
import_ui6.Box,
{
style: {
width: `calc(100% - ${editorInitialWidth}px)`,
minWidth: 100,
display: "flex",
flexDirection: "column"
}
},
/* @__PURE__ */ React5.createElement(import_ui6.Flex, { flex: 1, direction: "column", overflow: "hidden" }, responseView)
)
)));
}
var React5, import_sanity, import_ui6, import_zod, q, import_lodash, import_react_split, import_icons3, _a, EDITOR_URL, EDITOR_ORIGIN, reducer, EDITOR_INITIAL_WIDTH, readySchema, inputSchema, errorSchema, messageSchema, url, setQP;
var init_Playground = __esm({
"src/components/Playground.tsx"() {
"use strict";
React5 = __toESM(require("react"));
import_sanity = require("sanity");
import_ui6 = require("@sanity/ui");
import_zod = require("zod");
q = __toESM(require("groqd"));
import_lodash = __toESM(require("lodash.has"));
import_react_split = __toESM(require("@uiw/react-split"));
import_icons3 = require("@sanity/icons");
init_useDatasets();
init_consts();
init_ShareUrlField();
init_copyDataToClipboard();
init_messaging();
init_JSONExplorer();
init_Playground_styled();
init_formatErrorPath();
EDITOR_URL = typeof process !== "undefined" && ((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.SANITY_STUDIO_GROQD_PLAYGROUND_ENV) === "development" ? "http://localhost:3069" : "https://unpkg.com/groqd-playground-editor@0.0.6/build/index.html";
EDITOR_ORIGIN = new URL(EDITOR_URL).origin;
reducer = (state, action) => {
switch (action.type) {
case "INPUT_EVAL_SUCCESS":
return __spreadProps(__spreadValues({}, state), {
query: action.payload.query,
params: action.payload.params,
inputParseError: void 0
});
case "INPUT_PARSE_FAILURE":
return __spreadProps(__spreadValues({}, state), {
inputParseError: action.payload.inputParseError
});
case "MAKE_FETCH_REQUEST":
return __spreadProps(__spreadValues({}, state), {
isFetching: true,
queryUrl: action.payload.queryUrl
});
case "RAW_RESPONSE_RECEIVED":
return __spreadProps(__spreadValues({}, state), {
isFetching: false,
rawResponse: action.payload.rawResponse,
rawExecutionTime: action.payload.execTime
});
case "FETCH_RESPONSE_PARSED":
return __spreadProps(__spreadValues({}, state), {
parsedResponse: action.payload.parsedResponse,
fetchParseError: void 0,
errorPaths: void 0
});
case "FETCH_PARSE_FAILURE":
return __spreadProps(__spreadValues({}, state), {
isFetching: false,
fetchParseError: action.payload.fetchParseError,
errorPaths: action.payload.errorPaths
});
case "SET_ACTIVE_API_VERSION":
localStorage.setItem(STORAGE_KEYS.API_VERSION, action.payload.apiVersion);
return __spreadProps(__spreadValues({}, state), { activeAPIVersion: action.payload.apiVersion });
case "SET_ACTIVE_DATASET":
localStorage.setItem(STORAGE_KEYS.DATASET, action.payload.dataset);
return __spreadProps(__spreadValues({}, state), { activeDataset: action.payload.dataset });
default:
return state;
}
};
EDITOR_INITIAL_WIDTH = 500;
readySchema = import_zod.z.object({
event: import_zod.z.literal("READY")
});
inputSchema = import_zod.z.object({
event: import_zod.z.literal("INPUT"),
compressedRawCode: import_zod.z.string(),
code: import_zod.z.string(),
requestImmediateFetch: import_zod.z.boolean().optional().default(false),
requestShareCopy: import_zod.z.boolean().optional().default(false)
});
errorSchema = import_zod.z.object({
event: import_zod.z.literal("ERROR"),
message: import_zod.z.string()
});
messageSchema = import_zod.z.union([inputSchema, errorSchema, readySchema]);
url = new URL(window.location.href);
setQP = (key, value) => {
url.searchParams.set(key, value);
window.history.replaceState(null, "", url);
};
}
});
// src/PlaygroundWrapper.tsx
var PlaygroundWrapper_exports = {};
__export(PlaygroundWrapper_exports, {
default: () => GroqdPlaygroundWrapper
});
function GroqdPlaygroundWrapper(props) {
return /* @__PURE__ */ React6.createElement(import_ui7.ToastProvider, null, /* @__PURE__ */ React6.createElement(GroqdPlayground, __spreadValues({}, props)));
}
var React6, import_ui7;
var init_PlaygroundWrapper = __esm({
"src/PlaygroundWrapper.tsx"() {
"use strict";
React6 = __toESM(require("react"));
import_ui7 = require("@sanity/ui");
init_Playground();
}
});
// src/index.ts
var src_exports = {};
__export(src_exports, {
groqdPlaygroundTool: () => groqdPlaygroundTool
});
module.exports = __toCommonJS(src_exports);
var import_sanity2 = require("sanity");
var import_react = require("react");
var import_router = require("sanity/router");
var import_icons4 = require("@sanity/icons");
var groqdPlaygroundTool = (0, import_sanity2.definePlugin)(
({ name, title, icon, defaultApiVersion, defaultDataset } = {}) => {
return {
name: "groqd-playground",
tools: [
{
name: name || "groqd-playground",
title: title || "GROQD",
icon: import_icons4.CodeIcon || icon,
component: (0, import_react.lazy)(() => Promise.resolve().then(() => (init_PlaygroundWrapper(), PlaygroundWrapper_exports))),
options: {
defaultApiVersion: defaultApiVersion || "v2021-10-21",
defaultDataset: defaultDataset || "production"
},
router: import_router.route.create("/*")
}
]
};
}
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
groqdPlaygroundTool
});
//# sourceMappingURL=index.js.map