UNPKG

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
"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