UNPKG

mongoku

Version:

[![CI](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml/badge.svg)](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml)

671 lines (668 loc) 37.5 kB
import './async-DUoD1OpG.js'; import { i as await_block, e as escape_html, a as attr, j as bind_props, c as attr_class, k as attr_style, s as stringify, d as derived, f as clsx, b as ensure_array_like } from './root-otUAnOAR.js'; import { l as loadDocuments, c as countDocuments, e as explainQuery, d as deleteDocument, u as updateDocument } from './servers.remote-CGenkEHX.js'; import './utils-BQzn9ikS.js'; import { r as resolve } from './server2-D_y4YbpC.js'; import './exports-B5ORJhfK.js'; import './state.svelte-Bj5yxNNk.js'; import { J as JsonValue_1 } from './JsonValue-CGVfzyTL.js'; import { M as Modal } from './Modal-D2E5OLRi.js'; import { P as Panel } from './Panel-C6VWd6JD.js'; import { P as PrettyJson } from './PrettyJson-Bo4UtQ1o.js'; import './client-COtw9Xqw.js'; import 'esprima'; import { n as notificationStore } from './notifications.svelte-CIqkoPWX.js'; import { a as formatNumber } from './filters-B3U8Nh9P.js'; import { p as parseJSON } from './jsonParser-C3QUcODD.js'; import { a as SvelteURLSearchParams } from './index-server-Bf-hP5gL.js'; import './shared-server-BmU87nph.js'; import './shared-DlqhoNLb.js'; import './index-NcxaM188.js'; import './JsonEncoder-Dgtqxb_U.js'; import 'mongodb'; import './logger-PfH_grbh.js'; import 'async_hooks'; import 'node:util'; import './mongo-B92d7zNj.js'; import 'dns/promises'; import 'url'; import 'node:fs'; import 'node:os'; import 'node:path'; import './schema-BZonjzNJ.js'; import 'zod'; import './server-Crjo4w1q.js'; import './routing-EDfUNu8L.js'; import './Tooltip-OVylvwfb.js'; import './client2-BIa3wTXU.js'; import './index-CtYzvcG6.js'; function ExplainPanel($$renderer, $$props) { $$renderer.component(($$renderer2) => { let { data, show, onclose } = $$props; function findIndexInPlan(plan) { if (!plan) { return null; } if (plan.indexName) { return String(plan.indexName); } if (plan.stage === "IXSCAN" && plan.indexName) { return String(plan.indexName); } if (plan.inputStage) { const result = findIndexInPlan(plan.inputStage); if (result) { return result; } } if (Array.isArray(plan.inputStages)) { for (const stage of plan.inputStages) { const result = findIndexInPlan(stage); if (result) { return result; } } } if (plan.queryPlan) { const result = findIndexInPlan(plan.queryPlan); if (result) { return result; } } return null; } function hasCollScan(plan) { if (!plan) { return false; } if (plan.stage === "COLLSCAN") { return true; } if (plan.inputStage) { if (hasCollScan(plan.inputStage)) { return true; } } if (Array.isArray(plan.inputStages)) { for (const stage of plan.inputStages) { if (hasCollScan(stage)) { return true; } } } if (plan.queryPlan) { if (hasCollScan(plan.queryPlan)) { return true; } } return false; } const metrics = derived(() => { if (!data || typeof data !== "object") { return null; } const d = data; const execStats = d.executionStats; const queryPlanner = d.queryPlanner; const winningPlan = queryPlanner?.winningPlan; const indexName = findIndexInPlan(winningPlan); const isCollScan = hasCollScan(winningPlan); let indexUsed; if (indexName) { indexUsed = indexName; } else if (isCollScan) { indexUsed = "COLLSCAN"; } else { indexUsed = "N/A"; } const stage = winningPlan?.stage ?? "N/A"; return { executionTimeMs: execStats?.executionTimeMillis ?? "N/A", docsExamined: execStats?.totalDocsExamined ?? "N/A", keysExamined: execStats?.totalKeysExamined ?? "N/A", nReturned: execStats?.nReturned ?? "N/A", indexUsed, stage }; }); const efficiency = derived(() => { if (!metrics()) { return null; } const keysExamined = Number(metrics().keysExamined); const returned = Number(metrics().nReturned); if (keysExamined > 0) { return (returned / keysExamined * 100).toFixed(1); } return "0.0"; }); const efficiencyLabel = derived(() => { if (!metrics()) { return ""; } const keysExamined = Number(metrics().keysExamined); const docsExamined = Number(metrics().docsExamined); const returned = Number(metrics().nReturned); if (keysExamined > 0) { return `${returned} / ${keysExamined} keys to docs`; } return `${keysExamined} keys / ${docsExamined} docs`; }); const isEfficient = derived(() => { if (!metrics()) { return null; } if (metrics().indexUsed === "COLLSCAN" || metrics().indexUsed === "N/A") { return false; } return true; }); { let footer = function($$renderer3) { $$renderer3.push(`<button class="btn btn-default btn-sm">Close</button>`); }; Modal($$renderer2, { show, onclose, title: "Execution Stats", wide: true, footer, children: ($$renderer3) => { if (metrics()) { $$renderer3.push("<!--[0-->"); $$renderer3.push(`<div class="grid grid-cols-2 md:grid-cols-3 gap-4 mb-6"><div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Execution Time</span> <span class="metric-value svelte-10vh4gh">${escape_html(metrics().executionTimeMs)}ms</span></div> <div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Documents Returned</span> <span class="metric-value svelte-10vh4gh">${escape_html(typeof metrics().nReturned === "number" ? metrics().nReturned.toLocaleString() : metrics().nReturned)}</span></div> <div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Documents Examined</span> <span class="metric-value svelte-10vh4gh">${escape_html(typeof metrics().docsExamined === "number" ? metrics().docsExamined.toLocaleString() : metrics().docsExamined)}</span></div> <div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Keys Examined</span> <span class="metric-value svelte-10vh4gh">${escape_html(typeof metrics().keysExamined === "number" ? metrics().keysExamined.toLocaleString() : metrics().keysExamined)}</span></div> <div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Index Used</span> <span${attr_class("metric-value svelte-10vh4gh", void 0, { "warning": metrics().indexUsed === "COLLSCAN", "good": metrics().indexUsed !== "COLLSCAN" })}>${escape_html(metrics().indexUsed)}</span></div> <div class="metric-card svelte-10vh4gh"><span class="metric-label svelte-10vh4gh">Query Stage</span> <span class="metric-value svelte-10vh4gh">${escape_html(metrics().stage)}</span></div></div> `); if (efficiency() !== null) { $$renderer3.push("<!--[0-->"); $$renderer3.push(`<div class="efficiency-bar mb-6"><div class="flex justify-between items-center mb-2"><span class="text-sm font-semibold" style="color: var(--text);">Efficiency</span> <span class="text-sm font-mono" style="color: var(--text-secondary);">${escape_html(efficiencyLabel())} (${escape_html(efficiency())}%)</span></div> <div class="h-2 rounded-full bg-[var(--color-3)] overflow-hidden"><div${attr_class("h-full rounded-full transition-all duration-300", void 0, { "bg-green-500": isEfficient() && Number(efficiency()) >= 70, "bg-yellow-500": isEfficient() && Number(efficiency()) >= 30 && Number(efficiency()) < 70, "bg-red-500": !isEfficient() || Number(efficiency()) < 30 })}${attr_style(`width: ${stringify(isEfficient() ? Math.min(Number(efficiency()), 100) : 100)}%`)}></div></div> `); if (isEfficient() === false) { $$renderer3.push("<!--[0-->"); $$renderer3.push(`<p class="text-xs mt-2" style="color: var(--error);">⚠️ This query is using a collection scan (COLLSCAN). Consider adding an index for better performance.</p>`); } else { $$renderer3.push("<!--[-1-->"); } $$renderer3.push(`<!--]--></div>`); } else { $$renderer3.push("<!--[-1-->"); } $$renderer3.push(`<!--]-->`); } else { $$renderer3.push("<!--[-1-->"); } $$renderer3.push(`<!--]--> <details class="mt-4"><summary class="cursor-pointer text-sm font-semibold mb-3" style="color: var(--link);">View full explain output</summary> <div class="p-4 rounded-xl bg-[var(--color-3)] font-mono text-sm overflow-auto max-h-[400px] border border-[var(--border-color)]">`); JsonValue_1($$renderer3, { value: data, collapsed: false }); $$renderer3.push(`<!----></div></details>`); } }); } }); } function IconChevronDown($$renderer, $$props) { let { class: className = "w-4 h-4" } = $$props; $$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(className))}><path d="m6 9 6 6 6-6"></path></svg>`); } function IconEdit($$renderer, $$props) { let { class: className = "w-4 h-4" } = $$props; $$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(className))}><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"></path><path d="m15 5 4 4"></path></svg>`); } function SearchBox($$renderer, $$props) { $$renderer.component(($$renderer2) => { let { params = void 0, editMode = false, readonly = false, explainLoading = false, onexplain, onsearch, server, database, collection } = $$props; let showOptionalFields = params.sort !== "{}" || params.project !== "{}" || params.skip !== 0 || params.limit !== 20; let counter = Math.random(); let queryMultiline = derived(() => params.query?.includes("\n") ?? false); const TIME_RANGES = [ { label: "Last 24 hours", days: 1 }, { label: "Last 7 days", days: 7 }, { label: "Last 30 days", days: 30 }, { label: "Last 90 days", days: 90 }, { label: "Last 180 days", days: 180 } ]; TIME_RANGES.map((r) => ({ ...r, count: null, error: null, loading: false })); $$renderer2.push(`<div class="rounded-2xl border border-[var(--border-color)] bg-[var(--light-background)]/70 shadow-sm p-3 sm:p-4"><form class="flex flex-col gap-3" method="GET" action="?"><div class="flex items-stretch gap-2"><div class="flex-1 flex items-stretch rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50"><button type="button" class="h-full px-3 flex items-center gap-1 text-[13px] border-r border-[var(--border-color)] hover:bg-[var(--color-3)] transition cursor-pointer" style="color: var(--text-secondary);"><span class="capitalize">${escape_html(params.mode)}</span> `); IconChevronDown($$renderer2, { class: "w-3 h-3" }); $$renderer2.push(`<!----></button> `); if (params.mode === "aggregation") { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<textarea placeholder="[]" name="query" rows="5" class="w-full px-3 py-2 bg-transparent outline-none font-mono text-[13px] resize-y svelte-1o0c7a1" style="color: var(--text);">`); const $$body = escape_html(params.query); if ($$body) { $$renderer2.push(`${$$body}`); } $$renderer2.push(`</textarea>`); } else if (params.mode === "distinct") { $$renderer2.push("<!--[1-->"); $$renderer2.push(`<input type="text"${attr("value", params.field)} name="field" placeholder="field name" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/>`); } else if (queryMultiline()) { $$renderer2.push("<!--[2-->"); $$renderer2.push(`<textarea placeholder="{}" name="query" rows="5" class="w-full px-3 py-2 bg-transparent outline-none font-mono text-[13px] resize-y svelte-1o0c7a1" style="color: var(--text);">`); const $$body_1 = escape_html(params.query); if ($$body_1) { $$renderer2.push(`${$$body_1}`); } $$renderer2.push(`</textarea>`); } else { $$renderer2.push("<!--[-1-->"); $$renderer2.push(`<input type="text"${attr("value", params.query)} placeholder="{}" name="query" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/>`); } $$renderer2.push(`<!--]--></div> <input type="hidden"${attr("value", params.mode)} name="mode"/> <input type="hidden"${attr("value", counter)} name="v"/> <div class="flex items-center gap-2">`); if (server && database && collection) { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<button type="button" class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] transition cursor-pointer text-[13px] font-medium flex items-center gap-1" style="color: var(--text-secondary);" title="Filter by document creation time"><span>📊</span> `); IconChevronDown($$renderer2, { class: "w-3 h-3" }); $$renderer2.push(`<!----></button>`); } else { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]--> <button type="button" class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[15px] font-semibold leading-none transition cursor-pointer" style="color: var(--text);" title="Toggle optional fields">${escape_html(showOptionalFields ? "−" : "+")}</button> `); if (!readonly) { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<button type="button" class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] transition disabled:opacity-50 cursor-pointer" style="color: var(--text);"${attr("title", params.mode !== "query" ? "Update not available in this mode" : "Update multiple documents")}${attr("disabled", params.mode !== "query", true)}>`); IconEdit($$renderer2, { class: "w-4 h-4" }); $$renderer2.push(`<!----></button>`); } else { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]--> `); if (onexplain) { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<button type="button" class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] transition disabled:opacity-50 cursor-pointer text-[13px] font-medium" style="color: var(--link);"${attr("title", params.mode === "distinct" ? "Explain not available for distinct queries" : "Show query execution plan")}${attr("disabled", params.mode === "distinct" || explainLoading, true)}>${escape_html(explainLoading ? "..." : "Explain")}</button>`); } else { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]--> <button type="submit" class="h-9 px-4 py-0 rounded-xl btn btn-success text-lg font-semibold transition">Go</button></div></div> `); if (showOptionalFields) { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<div class="grid gap-2 sm:grid-cols-2">`); if (params.mode === "distinct") { $$renderer2.push("<!--[0-->"); $$renderer2.push(`<div class="rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50 sm:col-span-2"><div class="px-3 py-1.5 text-[12px] border-b border-[var(--border-color)]" style="color: var(--text-secondary);">Filter (optional)</div> <input type="text"${attr("value", params.query)} name="query" placeholder="{}" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/></div>`); } else { $$renderer2.push("<!--[-1-->"); $$renderer2.push(`<div class="rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50"><div class="px-3 py-1.5 text-[12px] border-b border-[var(--border-color)]" style="color: var(--text-secondary);">Sort</div> <input type="text"${attr("value", params.sort)} name="sort" placeholder="{}" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/></div> <div class="rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50"><div class="px-3 py-1.5 text-[12px] border-b border-[var(--border-color)]" style="color: var(--text-secondary);">Project</div> <input type="text"${attr("value", params.project)} name="project" placeholder="{}" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/></div>`); } $$renderer2.push(`<!--]--> <div class="rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50"><div class="px-3 py-1.5 text-[12px] border-b border-[var(--border-color)]" style="color: var(--text-secondary);">Skip</div> <input type="number"${attr("value", params.skip)} name="skip" min="0" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/></div> <div class="rounded-xl border border-[var(--border-color)] overflow-hidden bg-[var(--color-3)]/50"><div class="px-3 py-1.5 text-[12px] border-b border-[var(--border-color)]" style="color: var(--text-secondary);">Limit</div> <input type="number"${attr("value", params.limit)} name="limit" min="1" class="w-full h-9 px-3 bg-transparent outline-none font-mono text-[13px] border-0 !rounded-none svelte-1o0c7a1" style="color: var(--text);"/></div></div>`); } else { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]--></form></div> `); { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]--> `); { $$renderer2.push("<!--[-1-->"); } $$renderer2.push(`<!--]-->`); bind_props($$props, { params, editMode, readonly }); }); } function IconCopy($$renderer, $$props) { let { class: className = "w-4 h-4" } = $$props; $$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(className))}><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>`); } function IconPlus($$renderer, $$props) { let { class: className = "w-4 h-4" } = $$props; $$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(className))}><path d="M12 5v14M5 12h14"></path></svg>`); } function IconSortReverse($$renderer, $$props) { let { class: className = "w-4 h-4" } = $$props; $$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(className))}><path d="M3 6h18"></path><path d="M7 12h10"></path><path d="M10 18h4"></path><path d="m7 16 3 3 3-3"></path></svg>`); } function previousButton($$renderer, url, onClick) { $$renderer.push(`<a${attr("href", resolve(url))} class="px-3 py-1 rounded-lg border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[13px] transition no-underline -my-2" style="color: var(--text);">Previous</a>`); } function nextButton($$renderer, url, onClick) { $$renderer.push(`<a${attr("href", resolve(url))} class="px-3 py-1 rounded-lg border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[13px] transition no-underline" style="color: var(--text);">Next</a>`); } function _page($$renderer, $$props) { $$renderer.component(($$renderer2) => { let { data } = $$props; let params = { ...data.params }; let dataPromise = derived(() => data.results); let editMode = false; let updateQuery = "{}"; let isUpdating = false; let explainLoading = false; let explainData = null; let showExplain = false; let deleteState = { isCounting: false }; let modifiedItems = null; let items = derived(() => modifiedItems ? { data: modifiedItems, error: null } : dataPromise()); async function editDocument(_id, json, items2) { const partial = Boolean(params.project && params.project !== "{}" && Object.keys(parseJSON(params.project)).length > 0); const newId = json?._id?.$value; const oldId = _id?.$value; if (newId !== oldId) { notificationStore.notifyError("ObjectId changed. This is not supported, update canceled."); return; } if (!oldId) { return; } try { const result = await updateDocument({ server: data.server, database: data.database, collection: data.collection, document: oldId, value: json, partial }); if (result.ok) { notificationStore.notifySuccess("Document updated successfully"); const index = items2.findIndex((item) => item._id?.$value === oldId); if (index !== -1) { items2[index] = result.update; } modifiedItems = items2; } } catch (error) { console.error(error); notificationStore.notifyError(error, "Failed to update document"); } } async function removeDocument(_id, items2) { const documentId = _id?.$value ?? _id; if (!documentId || typeof documentId !== "string") { return; } try { await deleteDocument({ server: data.server, database: data.database, collection: data.collection, document: documentId }); notificationStore.notifySuccess("Document removed successfully"); modifiedItems = items2.filter((item) => (item._id?.$value ?? item._id) !== documentId); } catch (error) { notificationStore.notifyError(error, "Failed to remove document"); } } function buildUrl(skip) { const queryParams = new SvelteURLSearchParams(); queryParams.set("query", params.query || "{}"); queryParams.set("sort", params.sort || ""); queryParams.set("project", params.project || ""); queryParams.set("skip", String(skip)); queryParams.set("limit", String(params.limit)); return `/servers/${encodeURIComponent(data.server)}/databases/${encodeURIComponent(data.database)}/collections/${encodeURIComponent(data.collection)}/documents?${queryParams.toString()}`; } const nextUrl = derived(() => buildUrl(params.skip + params.limit)); const previousUrl = derived(() => buildUrl(Math.max(0, params.skip - params.limit))); async function handleExplain() { explainLoading = true; try { const result = await explainQuery({ server: data.server, database: data.database, collection: data.collection, query: params.query || "{}", sort: params.sort || "{}", project: params.project || "{}", skip: params.skip, limit: params.limit, mode: params.mode === "aggregation" ? "aggregation" : "query", verbosity: "executionStats" }); if (result.error) { notificationStore.notifyError(result.error); } else { explainData = result.data; showExplain = true; } } catch (error) { console.error(error); notificationStore.notifyError(error, "Failed to explain query"); } finally { explainLoading = false; } } function handleSearch(searchParams) { const normalizedParams = { ...searchParams, field: searchParams.field ?? "" }; data.params = normalizedParams; params = normalizedParams; dataPromise(loadDocuments({ server: data.server, database: data.database, collection: data.collection, query: normalizedParams.query, sort: normalizedParams.sort, project: normalizedParams.project, skip: normalizedParams.skip, limit: normalizedParams.limit, mode: normalizedParams.mode, field: normalizedParams.field })); data.count = countDocuments({ server: data.server, database: data.database, collection: data.collection, filter: normalizedParams.query }); } function sortButton($$renderer3) { $$renderer3.push(`<button class="px-3 py-1 rounded-lg border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[13px] transition" style="color: var(--text); cursor: pointer;" title="Reverse sort order">`); IconSortReverse($$renderer3, { class: "w-4 h-4" }); $$renderer3.push(`<!----></button>`); } function copyButton($$renderer3, items2) { $$renderer3.push(`<button class="px-3 py-1 rounded-lg border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[13px] transition" style="color: var(--text); cursor: pointer;" title="Copy distinct values">`); IconCopy($$renderer3, { class: "w-4 h-4" }); $$renderer3.push(`<!----></button>`); } let $$settled = true; let $$inner_renderer; function $$render_inner($$renderer3) { SearchBox($$renderer3, { readonly: data.readOnly, explainLoading, onexplain: handleExplain, onsearch: handleSearch, server: data.server, database: data.database, collection: data.collection, get params() { return params; }, set params($$value) { params = $$value; $$settled = false; }, get editMode() { return editMode; }, set editMode($$value) { editMode = $$value; $$settled = false; } }); $$renderer3.push(`<!----> `); ExplainPanel($$renderer3, { data: explainData, show: showExplain, onclose: () => showExplain = false }); $$renderer3.push(`<!----> `); if (editMode) { $$renderer3.push("<!--[0-->"); Panel($$renderer3, { title: "Edit Mode", children: ($$renderer4) => { $$renderer4.push(`<div class="p-4 sm:p-6 space-y-6"><div class="rounded-xl bg-[var(--color-3)]/30 p-4 border border-[var(--border-color)]"><h3 class="text-lg font-semibold mb-3" style="color: var(--text);">Insert New Document</h3> `); { $$renderer4.push("<!--[0-->"); $$renderer4.push(`<button class="btn btn-success">`); IconPlus($$renderer4, { class: "w-4 h-4 inline mr-2" }); $$renderer4.push(`<!----> Insert Document</button>`); } $$renderer4.push(`<!--]--></div> <div class="rounded-xl bg-[var(--color-3)]/30 p-4 border border-[var(--border-color)]"><h3 class="text-lg font-semibold mb-3" style="color: var(--text);">Update Multiple Documents</h3> <div class="space-y-4"><div><label for="update-filter" class="block text-sm font-semibold mb-2" style="color: var(--text);">Filter (which documents to update):</label> <input type="text" id="update-filter"${attr("value", params.query || "{}")} readonly="" class="w-full p-3 rounded-xl border border-[var(--border-color)] bg-[var(--color-3)] font-mono text-sm opacity-75 cursor-not-allowed" style="color: var(--text);"/> <p class="text-xs mt-2" style="color: var(--text-secondary);">This filter is taken from the query above. Modify the query to change which documents will be updated.</p></div> <div><label for="update-operation" class="block text-sm font-semibold mb-2" style="color: var(--text);">Update Operation (e.g., $set, $inc, $unset):</label> <textarea placeholder="Update operation" rows="4" class="w-full p-3 rounded-xl border border-[var(--border-color)] bg-[var(--color-3)] font-mono text-sm focus:outline-none focus:ring-2" style="color: var(--text); --tw-ring-color: var(--link);">`); const $$body_1 = escape_html(updateQuery); if ($$body_1) { $$renderer4.push(`${$$body_1}`); } $$renderer4.push(`</textarea></div> <div class="flex gap-3"><button class="btn btn-success hover:bg-[var(--button-success-l)]"${attr("disabled", isUpdating, true)}>${escape_html("Execute Update")}</button></div></div></div> <div class="rounded-xl bg-[var(--color-3)]/30 p-4 border border-[var(--border-color)]"><h3 class="text-lg font-semibold mb-3" style="color: var(--text);">Delete Multiple Documents</h3> <div class="space-y-4"><div><label for="delete-filter" class="block text-sm font-semibold mb-2" style="color: var(--text);">Filter (which documents to delete):</label> <input type="text" id="delete-filter"${attr("value", params.query || "{}")} readonly="" class="w-full p-3 rounded-xl border border-[var(--border-color)] bg-[var(--color-3)] font-mono text-sm opacity-75 cursor-not-allowed" style="color: var(--text);"/> <p class="text-xs mt-2" style="color: var(--text-secondary);">This filter is taken from the query above. Modify the query to change which documents will be deleted.</p></div> `); { $$renderer4.push("<!--[0-->"); $$renderer4.push(`<div class="flex gap-3"><button class="btn btn-default"${attr("disabled", deleteState.isCounting, true)}>${escape_html("Check Document Count")}</button></div>`); } $$renderer4.push(`<!--]--></div></div> <div class="flex justify-end"><button class="btn btn-default hover:bg-[var(--color-3)]">Close Edit Mode</button></div> <div class="text-sm rounded-xl bg-[var(--color-3)]/50 p-4 border border-[var(--border-color)]" style="color: var(--text-secondary);"><p class="mb-2 font-semibold" style="color: var(--text);">Update Operation Examples:</p> <p class="mb-2">• Set a field: <code class="bg-[var(--light-background)] px-2 py-1 rounded border border-[var(--border-color)] font-mono text-xs">{"$set": {"status": "active"}}</code></p> <p class="mb-2">• Increment a value: <code class="bg-[var(--light-background)] px-2 py-1 rounded border border-[var(--border-color)] font-mono text-xs">{"$inc": {"count": 1}}</code></p> <p class="mb-2">• Unset a field: <code class="bg-[var(--light-background)] px-2 py-1 rounded border border-[var(--border-color)] font-mono text-xs">{"$unset": {"oldField": ""}}</code></p> <p>• Pipeline (compute from existing fields): <code class="bg-[var(--light-background)] px-2 py-1 rounded border border-[var(--border-color)] font-mono text-xs">[{"$set": {"fullName": {"$concat": ["$firstName", " ", "$lastName"]}}}]</code></p></div></div>`); }, $$slots: { default: true } }); } else { $$renderer3.push("<!--[-1-->"); } $$renderer3.push(`<!--]--> `); await_block( $$renderer3, items(), () => { { let actions = function($$renderer4) { { $$renderer4.push("<!--[-1-->"); } $$renderer4.push(`<!--]-->`); }; Panel($$renderer3, { title: data.params.mode === "distinct" ? "Loading distinct values..." : "Loading documents...", titleClass: "py-1", actions, $$slots: { actions: true } }); } }, (resultsData) => { const items2 = resultsData?.data ?? []; await_block( $$renderer3, data.count, () => { { let actions = function($$renderer4) { if (data.params.skip > 0) { $$renderer4.push("<!--[0-->"); previousButton($$renderer4, previousUrl()); } else { $$renderer4.push("<!--[-1-->"); } $$renderer4.push(`<!--]--> `); if (items2.length >= data.params.limit) { $$renderer4.push("<!--[0-->"); nextButton($$renderer4, nextUrl()); } else { $$renderer4.push("<!--[-1-->"); } $$renderer4.push(`<!--]--> `); if (data.params.mode === "distinct") { $$renderer4.push("<!--[0-->"); copyButton($$renderer4); } else { $$renderer4.push("<!--[-1-->"); sortButton($$renderer4); } $$renderer4.push(`<!--]-->`); }; Panel($$renderer3, { titleClass: "py-1", title: items2.length > 0 ? data.params.mode === "distinct" ? `${formatNumber(items2.length)} distinct value${items2.length === 1 ? "" : "s"} (counting...)` : `${formatNumber(data.params.skip + 1)} - ${formatNumber(data.params.skip + items2.length)} Documents (counting...)` : data.params.mode === "distinct" ? "No distinct values" : "No documents", actions, $$slots: { actions: true } }); } }, (countData) => { if (data.params) { $$renderer3.push("<!--[0-->"); const count = countData.data; const hasNext = countData.error ? items2.length >= data.params.limit : data.params.skip + items2.length < count; const hasPrevious = data.params.skip > 0; const isTimeout = countData.error?.includes("operation exceeded time limit"); { let actions = function($$renderer4) { if (hasPrevious) { $$renderer4.push("<!--[0-->"); previousButton($$renderer4, previousUrl()); } else { $$renderer4.push("<!--[-1-->"); } $$renderer4.push(`<!--]--> `); if (hasNext) { $$renderer4.push("<!--[0-->"); nextButton($$renderer4, nextUrl()); } else { $$renderer4.push("<!--[-1-->"); } $$renderer4.push(`<!--]--> `); if (data.params.mode === "distinct") { $$renderer4.push("<!--[0-->"); copyButton($$renderer4); } else { $$renderer4.push("<!--[-1-->"); sortButton($$renderer4); } $$renderer4.push(`<!--]-->`); }; Panel($$renderer3, { title: items2.length > 0 ? data.params.mode === "distinct" ? `${formatNumber(count)} distinct value${count === 1 ? "" : "s"}` : count > 0 ? `${formatNumber(data.params.skip + 1)} - ${formatNumber(data.params.skip + items2.length)} of ${formatNumber(count)} documents` : `${formatNumber(data.params.skip + 1)} - ${formatNumber(data.params.skip + items2.length)} documents (count ${isTimeout ? "timeout" : "unavailable"})` : data.params.mode === "distinct" ? "No distinct values" : "No documents", titleClass: "py-1", actions, $$slots: { actions: true } }); } } else { $$renderer3.push("<!--[-1-->"); } $$renderer3.push(`<!--]-->`); } ); $$renderer3.push(`<!--]--> <!--[-->`); const each_array = ensure_array_like(items2); for (let index = 0, $$length = each_array.length; index < $$length; index++) { let item = each_array[index]; PrettyJson($$renderer3, { json: item, autoCollapse: true, onedit: data.params.mode === "aggregation" || data.params.mode === "distinct" || data.readOnly ? void 0 : (json) => editDocument(item._id, json, items2), onremove: data.params.mode === "aggregation" || data.params.mode === "distinct" || data.readOnly ? void 0 : () => removeDocument(item._id, items2), server: data.server, database: data.database, collection: data.collection, mappings: data.mappings }); } $$renderer3.push(`<!--]-->`); } ); $$renderer3.push(`<!--]-->`); } do { $$settled = true; $$inner_renderer = $$renderer2.copy(); $$render_inner($$inner_renderer); } while (!$$settled); $$renderer2.subsume($$inner_renderer); }); } export { _page as default }; //# sourceMappingURL=_page.svelte-C_GX0K8M.js.map