mongoku
Version:
[](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml)
671 lines (668 loc) • 37.5 kB
JavaScript
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