datajunction-ui
Version:
DataJunction UI
1,243 lines (1,242 loc) โข 77.6 kB
JavaScript
import { jsxs as i, jsx as t, Fragment as Re } from "react/jsx-runtime";
import { useState as b, useRef as ee, useEffect as Q, useMemo as de, useCallback as L, memo as Tt, useContext as jt, Suspense as zt, lazy as Kt } from "react";
import { useLocation as Bt, useNavigate as qt } from "react-router-dom";
import { ac as Wt, aP as Ut, ag as St, cd as It, D as Ot } from "./index-n79cxNwC.js";
import { P as Vt, M as Gt, Q as Qt } from "./PreAggDetailsPanel-UslxH4LA.js";
import { R as Dt, c as xt, X as Pt, Y as _t, a as Ht, B as Yt } from "./BarChart-JyKNSAsC.js";
import { a as Xt, L as Jt } from "./LineChart-B9ulwx-b.js";
const Zt = [
{ value: null, label: "Auto" },
{ value: "druid", label: "Druid" },
{ value: "trino", label: "Trino" }
], wt = "application/x-dj-dimension", Lt = (l, d) => (l.trim() ? l.trimEnd() + " AND " : "") + d;
function Ft({ text: l }) {
return /* @__PURE__ */ t("span", { className: "chip-label chip-label-clip", title: l, children: /* @__PURE__ */ t("bdi", { className: "chip-label-inner", children: l }) });
}
function en({
metrics: l,
selectedMetrics: d,
onMetricsChange: N,
dimensions: _,
selectedDimensions: w,
onDimensionsChange: M,
loading: C,
cubes: v = [],
onLoadCubePreset: k,
loadedCubeName: g = null,
// Managed by parent for URL persistence
onClearSelection: E,
filters: h = [],
onFiltersChange: K,
selectedEngine: F = null,
onEngineChange: R,
onRunQuery: $,
canRunQuery: j = !1,
queryLoading: W = !1,
compatibleMetrics: O = null
// Set<string> of compatible metric names, or null if no filter
}) {
const [I, ue] = b(""), [S, Ne] = b(""), [z, ge] = b(/* @__PURE__ */ new Set()), [ze, H] = b(/* @__PURE__ */ new Set()), [Y, oe] = b(/* @__PURE__ */ new Set()), [ke, Ce] = b(!1), [V, Pe] = b(""), [_e, Le] = b(!1), [te, x] = b(!1), [D, B] = b(""), [X, ne] = b(!1), [be, $e] = b(35), [Se, Ae] = b(65), [ae, Te] = b(85), we = ee(""), Ke = ee(null), Be = ee(null), Fe = ee(null), T = ee(null), me = ee(null), he = ee(null), Me = ee({ split1: 35, split2: 65, split3: 85 });
Q(() => {
Me.current = { split1: be, split2: Se, split3: ae };
}, [be, Se, ae]);
const ve = 8, De = de(() => g ? v.find((e) => e.name === g) || { name: g } : null, [g, v]);
Q(() => {
const e = (r) => {
Ke.current && !Ke.current.contains(r.target) && Ce(!1);
};
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
}, []);
const We = de(() => {
const e = V.toLowerCase().trim();
return e ? v.filter((r) => {
const m = r.name || "", f = r.display_name || "";
return m.toLowerCase().includes(e) || f.toLowerCase().includes(e);
}) : v;
}, [v, V]), Ee = (e) => {
const r = e.split(".");
return r[r.length - 1];
}, Xe = (e) => {
const r = e.split(".");
return r.length > 1 ? r.slice(0, -1).join(".") : "default";
}, xe = de(() => {
const e = {};
return l.forEach((r) => {
const m = Xe(r);
e[m] || (e[m] = []), e[m].push(r);
}), e;
}, [l]), { filteredGroups: ye, sortedNamespaces: je } = de(() => {
const e = I.trim().toLowerCase();
if (!e) {
const f = Object.keys(xe).sort();
return { filteredGroups: xe, sortedNamespaces: f };
}
const r = {};
Object.entries(xe).forEach(([f, p]) => {
const s = p.filter((n) => n.toLowerCase().includes(e));
s.length > 0 && (s.sort((n, a) => {
const o = Ee(n).toLowerCase(), c = Ee(a).toLowerCase(), u = o.startsWith(e), A = c.startsWith(e);
return u && !A ? -1 : !u && A ? 1 : o.localeCompare(c);
}), r[f] = s);
});
const m = Object.keys(r).sort((f, p) => {
const s = f.toLowerCase(), n = p.toLowerCase(), a = s.startsWith(e), o = n.startsWith(e);
if (a && !o) return -1;
if (!a && o) return 1;
const c = s.includes(e), u = n.includes(e);
if (c && !u) return -1;
if (!c && u) return 1;
const A = r[f].length, q = r[p].length;
return A !== q ? q - A : s.localeCompare(n);
});
return { filteredGroups: r, sortedNamespaces: m };
}, [xe, I]);
Q(() => {
const e = I.trim(), r = we.current;
e && e !== r && ge(new Set(je)), we.current = e;
}, [I, je]);
const y = de(() => {
const e = /* @__PURE__ */ new Map();
return _.forEach((r) => {
var f, p;
if (!r.name) return;
const m = e.get(r.name);
(!m || (((f = r.path) == null ? void 0 : f.length) || 0) < (((p = m.path) == null ? void 0 : p.length) || 1 / 0)) && e.set(r.name, r);
}), Array.from(e.values());
}, [_]), Je = (e) => {
const r = e.match(/\[([^\]]+)\]$/);
return r ? r[1] : null;
}, J = (e) => e ? "via " + e.replace(/->/g, " โ ") : "direct", pe = (e) => e ? e.split("->").length : 0, U = de(() => {
const e = S.trim().toLowerCase(), r = /* @__PURE__ */ new Map();
y.forEach((f) => {
var o;
if (!f.name) return;
const p = ((o = f.path) == null ? void 0 : o.length) > 0 ? f.path[f.path.length - 1] : f.name.split(".").slice(0, -1).join("."), s = Math.max(0, f.path ? f.path.length - 1 : 0), n = Je(f.name);
r.has(p) || r.set(p, {
nodeKey: p,
minDistance: s,
rolePathMap: /* @__PURE__ */ new Map()
});
const a = r.get(p);
a.minDistance = Math.min(a.minDistance, s), a.rolePathMap.has(n) || a.rolePathMap.set(n, { roleKey: n, dimensions: [] }), a.rolePathMap.get(n).dimensions.push(f);
});
let m = Array.from(r.values()).map((f) => {
const p = Array.from(f.rolePathMap.values()).sort(
(s, n) => pe(s.roleKey) - pe(n.roleKey) || (s.roleKey || "").localeCompare(n.roleKey || "")
);
return p.forEach((s) => {
s.dimensions.sort((n, a) => n.name.localeCompare(a.name));
}), {
nodeKey: f.nodeKey,
minDistance: f.minDistance,
rolePaths: p,
totalCount: p.reduce((s, n) => s + n.dimensions.length, 0)
};
});
return e && (m = m.map((f) => ({
...f,
rolePaths: f.rolePaths.map((p) => ({
...p,
dimensions: p.dimensions.filter((s) => s.name.toLowerCase().includes(e) || s.name.split(".").pop().toLowerCase().includes(e))
})).filter(
(p) => p.dimensions.length > 0 || (p.roleKey || "").toLowerCase().includes(e)
)
})).filter(
(f) => f.rolePaths.length > 0 || f.nodeKey.toLowerCase().includes(e)
).map((f) => ({
...f,
totalCount: f.rolePaths.reduce(
(p, s) => p + s.dimensions.length,
0
)
}))), m.sort(
(f, p) => f.minDistance - p.minDistance || f.nodeKey.localeCompare(p.nodeKey)
), m;
}, [y, S]);
Q(() => {
U.length !== 0 && (S.trim() ? (H(new Set(U.map((e) => e.nodeKey))), oe(
new Set(
U.flatMap(
(e) => e.rolePaths.map((r) => `${e.nodeKey}::${r.roleKey}`)
)
)
)) : (H((e) => e.size > 0 ? e : new Set(
U.filter((r) => r.minDistance === 0).map((r) => r.nodeKey)
)), oe((e) => e.size > 0 ? e : new Set(
U.filter((r) => r.minDistance === 0).map((r) => `${r.nodeKey}::null`)
))));
}, [U, S]);
const se = (e) => (e || "").split(".").slice(-2).join("."), Ze = (e) => {
ge((r) => {
const m = new Set(r);
return m.has(e) ? m.delete(e) : m.add(e), m;
});
}, et = (e) => {
H((r) => {
const m = new Set(r);
return m.has(e) ? m.delete(e) : m.add(e), m;
});
}, tt = (e, r) => {
const m = `${e}::${r}`;
oe((f) => {
const p = new Set(f);
return p.has(m) ? p.delete(m) : p.add(m), p;
});
}, nt = (e) => e.split(".").pop(), qe = L((e, r) => {
e.preventDefault();
const m = r === 1 ? Me.current.split1 : r === 2 ? Me.current.split2 : Me.current.split3;
he.current = { divider: r, startY: e.clientY, startSplit: m };
}, []);
Q(() => {
const e = (m) => {
if (!he.current || !me.current) return;
const f = me.current.getBoundingClientRect().height, p = (m.clientY - he.current.startY) / f * 100, { divider: s, startSplit: n } = he.current, { split1: a, split2: o, split3: c } = Me.current;
s === 1 ? $e(Math.max(10, Math.min(o - 15, n + p))) : s === 2 ? Ae(
Math.max(a + 15, Math.min(c - 10, n + p))
) : Te(Math.max(o + 10, Math.min(95, n + p)));
}, r = () => {
he.current = null;
};
return window.addEventListener("mousemove", e), window.addEventListener("mouseup", r), () => {
window.removeEventListener("mousemove", e), window.removeEventListener("mouseup", r);
};
}, []);
const Oe = (e) => {
d.includes(e) ? N(d.filter((r) => r !== e)) : N([...d, e]);
}, at = (e) => {
N(d.filter((r) => r !== e));
}, st = (e) => {
w.includes(e) ? M(w.filter((r) => r !== e)) : M([...w, e]);
}, rt = (e) => {
M(w.filter((r) => r !== e));
}, lt = (e, r) => {
const m = [.../* @__PURE__ */ new Set([...d, ...r])];
N(m);
}, ot = (e, r) => {
N(d.filter((m) => !r.includes(m)));
}, it = (e) => {
k && k(e.name), Ce(!1), Pe("");
}, ct = () => {
E ? E() : (N([]), M([]));
}, Ve = () => {
const e = D.trim();
e && !h.includes(e) && K && (K([...h, e]), B(""));
}, dt = (e) => {
e.key === "Enter" && (e.preventDefault(), Ve());
}, ut = (e) => {
K && K(h.filter((r) => r !== e));
}, mt = (e) => {
var r;
B((m) => Lt(m, e)), K && K(h.filter((m) => m !== e)), (r = T.current) == null || r.focus();
}, Ge = (e) => {
var r;
B((m) => Lt(m, e + " ")), (r = T.current) == null || r.focus();
}, ht = (e, r) => {
e.preventDefault(), e.stopPropagation(), Ge(r);
}, Qe = (e, r) => {
e.dataTransfer.setData(wt, r), e.dataTransfer.setData("text/plain", r), e.dataTransfer.effectAllowed = "copy";
}, pt = (e) => {
e.dataTransfer.types.includes(wt) && (e.preventDefault(), e.dataTransfer.dropEffect = "copy", X || ne(!0));
}, ft = (e) => {
e.currentTarget.contains(e.relatedTarget) || ne(!1);
}, gt = (e) => {
const r = e.dataTransfer.getData(wt);
r && (e.preventDefault(), Ge(r)), ne(!1);
};
return /* @__PURE__ */ i("div", { className: "selection-panel", children: [
v.length > 0 && /* @__PURE__ */ i("div", { className: "cube-preset-section", ref: Ke, children: [
/* @__PURE__ */ i("div", { className: "preset-row", children: [
/* @__PURE__ */ i(
"button",
{
className: `preset-button ${De ? "has-preset" : ""}`,
onClick: () => Ce(!ke),
children: [
/* @__PURE__ */ t("span", { className: "preset-icon", children: De ? "๐ฆ" : "๐" }),
/* @__PURE__ */ t("span", { className: "preset-label", children: De ? De.display_name || (De.name ? De.name.split(".").pop() : "Cube") : "Load from Cube" }),
/* @__PURE__ */ t("span", { className: "dropdown-arrow", children: ke ? "โฒ" : "โผ" })
]
}
),
(d.length > 0 || w.length > 0) && /* @__PURE__ */ t("button", { className: "clear-all-btn", onClick: ct, children: "Clear" })
] }),
ke && /* @__PURE__ */ i("div", { className: "cube-dropdown", children: [
/* @__PURE__ */ t(
"input",
{
type: "text",
className: "cube-search",
placeholder: "Search cubes...",
value: V,
onChange: (e) => Pe(e.target.value),
autoFocus: !0
}
),
/* @__PURE__ */ t("div", { className: "cube-list", children: We.length === 0 ? /* @__PURE__ */ t("div", { className: "cube-empty", children: V ? "No cubes match your search" : "No cubes available" }) : We.map((e) => /* @__PURE__ */ i(
"button",
{
className: `cube-option ${g === e.name ? "selected" : ""}`,
onClick: () => it(e),
children: [
/* @__PURE__ */ t("span", { className: "cube-name", children: e.display_name || (e.name ? e.name.split(".").pop() : "Unknown") }),
/* @__PURE__ */ t("span", { className: "cube-info", children: e.name }),
g === e.name && /* @__PURE__ */ t("span", { className: "cube-selected-icon", children: "โ" })
]
},
e.name
)) })
] })
] }),
/* @__PURE__ */ i("div", { className: "resizable-sections", ref: me, children: [
/* @__PURE__ */ i("div", { className: "selection-section", style: { flex: be }, children: [
/* @__PURE__ */ i("div", { className: "section-header", children: [
/* @__PURE__ */ t("h3", { children: "Metrics" }),
/* @__PURE__ */ i("span", { className: "selection-count", children: [
d.length,
" selected"
] })
] }),
/* @__PURE__ */ i(
"div",
{
className: "combobox-input",
onClick: () => {
var e;
return (e = Be.current) == null ? void 0 : e.focus();
},
children: [
d.length > 0 && /* @__PURE__ */ t(
"div",
{
className: `combobox-chips ${d.length > ve ? _e ? "expanded" : "collapsed" : ""}`,
children: d.map((e) => /* @__PURE__ */ i("span", { className: "selected-chip metric-chip", children: [
/* @__PURE__ */ t(Ft, { text: Ee(e) }),
/* @__PURE__ */ t(
"button",
{
className: "chip-remove",
onClick: (r) => {
r.stopPropagation(), at(e);
},
title: `Remove ${Ee(e)}`,
children: "ร"
}
)
] }, e))
}
),
/* @__PURE__ */ i("div", { className: "combobox-input-row", children: [
/* @__PURE__ */ t(
"input",
{
ref: Be,
type: "text",
className: "combobox-search",
placeholder: "Search metrics...",
value: I,
onChange: (e) => ue(e.target.value),
onClick: (e) => e.stopPropagation()
}
),
d.length > ve && /* @__PURE__ */ t(
"button",
{
className: "combobox-action",
onClick: (e) => {
e.stopPropagation(), Le(!_e);
},
children: _e ? "Show less" : "Show all"
}
),
d.length > 0 && /* @__PURE__ */ t(
"button",
{
className: "combobox-action",
onClick: (e) => {
e.stopPropagation(), N([]);
},
children: "Clear"
}
)
] })
]
}
),
/* @__PURE__ */ i("div", { className: "selection-list", children: [
je.map((e) => {
const r = ye[e], m = z.has(e), f = r.filter(
(p) => d.includes(p)
).length;
return /* @__PURE__ */ i("div", { className: "namespace-group", children: [
/* @__PURE__ */ i(
"div",
{
className: "namespace-header",
onClick: () => Ze(e),
children: [
/* @__PURE__ */ t("span", { className: "expand-icon", children: m ? "โผ" : "โถ" }),
/* @__PURE__ */ t("span", { className: "namespace-name", children: e }),
/* @__PURE__ */ i("span", { className: "namespace-count", children: [
f > 0 && /* @__PURE__ */ t("span", { className: "selected-badge", children: f }),
r.length
] })
]
}
),
m && /* @__PURE__ */ i("div", { className: "namespace-items", children: [
/* @__PURE__ */ i("div", { className: "namespace-actions", children: [
/* @__PURE__ */ t(
"button",
{
type: "button",
className: "select-all-btn",
onClick: () => lt(e, r),
children: "Select all"
}
),
/* @__PURE__ */ t(
"button",
{
type: "button",
className: "select-all-btn",
onClick: () => ot(e, r),
children: "Clear"
}
)
] }),
r.map((p) => {
const s = O !== null && !O.has(p) && !d.includes(p);
return /* @__PURE__ */ i(
"label",
{
className: `selection-item${s ? " metric-incompatible" : ""}`,
title: s ? "Not compatible with selected dimensions" : p,
children: [
/* @__PURE__ */ t(
"input",
{
type: "checkbox",
checked: d.includes(p),
onChange: () => Oe(p)
}
),
/* @__PURE__ */ t("span", { className: "item-name", children: Ee(p) }),
O !== null && O.has(p) && !d.includes(p) && /* @__PURE__ */ t(
"span",
{
className: "metric-compatible-badge",
title: "Compatible with selected dimensions",
children: "โ"
}
)
]
},
p
);
})
] })
] }, e);
}),
je.length === 0 && /* @__PURE__ */ t("div", { className: "empty-list", children: I ? "No metrics match your search" : "No metrics available" })
] })
] }),
/* @__PURE__ */ t(
"div",
{
className: "section-divider draggable-divider",
onMouseDown: (e) => qe(e, 1)
}
),
/* @__PURE__ */ i("div", { className: "selection-section", style: { flex: Se - be }, children: [
/* @__PURE__ */ i("div", { className: "section-header", children: [
/* @__PURE__ */ t("h3", { children: "Dimensions" }),
/* @__PURE__ */ i("span", { className: "selection-count", children: [
w.length,
" selected",
_.length > 0 && ` / ${_.length} available`
] })
] }),
d.length === 0 ? /* @__PURE__ */ t("div", { className: "empty-list hint", children: "Select metrics to see available dimensions" }) : C ? /* @__PURE__ */ t("div", { className: "empty-list", children: "Loading dimensions..." }) : /* @__PURE__ */ i(Re, { children: [
/* @__PURE__ */ i(
"div",
{
className: "combobox-input",
onClick: () => {
var e;
return (e = Fe.current) == null ? void 0 : e.focus();
},
children: [
w.length > 0 && /* @__PURE__ */ t(
"div",
{
className: `combobox-chips ${w.length > ve ? te ? "expanded" : "collapsed" : ""}`,
children: w.map((e) => /* @__PURE__ */ i(
"span",
{
className: "selected-chip dimension-chip draggable-dim",
title: `${e} โ drag to Filters to filter on it`,
draggable: !0,
onDragStart: (r) => Qe(r, e),
children: [
/* @__PURE__ */ t(Ft, { text: se(e) }),
/* @__PURE__ */ t(
"button",
{
className: "chip-remove",
onClick: (r) => {
r.stopPropagation(), rt(e);
},
title: `Remove ${se(e)}`,
children: "ร"
}
)
]
},
e
))
}
),
/* @__PURE__ */ i("div", { className: "combobox-input-row", children: [
/* @__PURE__ */ t(
"input",
{
ref: Fe,
type: "text",
className: "combobox-search",
placeholder: "Search dimensions...",
value: S,
onChange: (e) => Ne(e.target.value),
onClick: (e) => e.stopPropagation()
}
),
w.length > ve && /* @__PURE__ */ t(
"button",
{
className: "combobox-action",
onClick: (e) => {
e.stopPropagation(), x(!te);
},
children: te ? "Show less" : "Show all"
}
),
w.length > 0 && /* @__PURE__ */ t(
"button",
{
className: "combobox-action",
onClick: (e) => {
e.stopPropagation(), M([]);
},
children: "Clear"
}
)
] })
]
}
),
/* @__PURE__ */ i("div", { className: "selection-list dimensions-list", children: [
U.map((e) => {
const r = ze.has(e.nodeKey);
return /* @__PURE__ */ i("div", { className: "dim-group", children: [
/* @__PURE__ */ i(
"div",
{
className: "dim-group-header",
onClick: () => et(e.nodeKey),
title: e.nodeKey,
children: [
/* @__PURE__ */ t("span", { className: "expand-icon", children: r ? "โผ" : "โถ" }),
/* @__PURE__ */ t("span", { className: "dim-group-name", children: nt(e.nodeKey) }),
/* @__PURE__ */ t("span", { className: "dim-group-count", children: e.totalCount })
]
}
),
r && e.rolePaths.map((m) => {
const f = `${e.nodeKey}::${m.roleKey}`, p = Y.has(f), s = pe(m.roleKey), n = s === 0 ? "direct" : `${s} hop${s > 1 ? "s" : ""}`;
return /* @__PURE__ */ i("div", { className: "dim-role-group", children: [
/* @__PURE__ */ i(
"div",
{
className: "dim-role-header",
onClick: () => tt(e.nodeKey, m.roleKey),
children: [
/* @__PURE__ */ t("span", { className: "expand-icon", children: p ? "โผ" : "โถ" }),
/* @__PURE__ */ t("span", { className: "dim-role-label", children: J(m.roleKey) }),
/* @__PURE__ */ t("span", { className: "dim-group-meta", children: n }),
/* @__PURE__ */ t("span", { className: "dim-group-count", children: m.dimensions.length })
]
}
),
p && m.dimensions.map((a) => /* @__PURE__ */ i(
"label",
{
className: "selection-item dimension-item dim-role-item draggable-dim",
title: `${a.name} โ drag to Filters to filter on it`,
draggable: !0,
onDragStart: (o) => Qe(o, a.name),
children: [
/* @__PURE__ */ t(
"input",
{
type: "checkbox",
checked: w.includes(
a.name
),
onChange: () => st(a.name)
}
),
/* @__PURE__ */ t("div", { className: "dimension-info", children: /* @__PURE__ */ t("span", { className: "item-name", children: se(
a.name.replace(/\[[^\]]*\]$/, "")
) }) }),
/* @__PURE__ */ t(
"button",
{
className: "dim-filter-btn",
title: `Add "${a.name}" to filters`,
onClick: (o) => ht(o, a.name),
children: "+ filter"
}
)
]
},
a.name
))
] }, f);
})
] }, e.nodeKey);
}),
U.length === 0 && /* @__PURE__ */ t("div", { className: "empty-list", children: S ? "No dimensions match your search" : "No shared dimensions" })
] })
] })
] }),
/* @__PURE__ */ t(
"div",
{
className: "section-divider draggable-divider",
onMouseDown: (e) => qe(e, 2)
}
),
/* @__PURE__ */ i(
"div",
{
className: `selection-section filters-section${X ? " drop-active" : ""}`,
style: { flex: ae - Se },
onDragOver: pt,
onDragLeave: ft,
onDrop: gt,
children: [
/* @__PURE__ */ i("div", { className: "section-header", children: [
/* @__PURE__ */ t("h3", { children: "Filters" }),
/* @__PURE__ */ i("span", { className: "selection-count", children: [
h.length,
" applied"
] })
] }),
X && /* @__PURE__ */ t("div", { className: "filter-drop-hint", children: "Drop to filter on this dimension" }),
h.length > 0 && /* @__PURE__ */ t("div", { className: "filter-chips-container", children: h.map((e, r) => /* @__PURE__ */ i("span", { className: "filter-chip", children: [
/* @__PURE__ */ t(
"button",
{
type: "button",
className: "filter-chip-text filter-chip-edit",
onClick: () => mt(e),
title: `${e} โ click to edit`,
children: e
}
),
/* @__PURE__ */ t(
"button",
{
className: "filter-chip-remove",
onClick: () => ut(e),
title: "Remove filter",
children: "ร"
}
)
] }, r)) }),
/* @__PURE__ */ i("div", { className: "filter-input-container", children: [
/* @__PURE__ */ t(
"input",
{
ref: T,
type: "text",
className: "filter-input",
placeholder: "e.g. v3.date.date_id >= '2024-01-01'",
value: D,
onChange: (e) => B(e.target.value),
onKeyDown: dt
}
),
/* @__PURE__ */ t(
"button",
{
className: "filter-add-btn",
onClick: Ve,
disabled: !D.trim(),
children: "Add"
}
)
] })
]
}
),
/* @__PURE__ */ t(
"div",
{
className: "section-divider draggable-divider",
onMouseDown: (e) => qe(e, 3)
}
),
/* @__PURE__ */ i(
"div",
{
className: "selection-section engine-run-section",
style: { flex: 100 - ae },
children: [
/* @__PURE__ */ i("div", { className: "engine-section", children: [
/* @__PURE__ */ t("span", { className: "engine-label", children: "Engine" }),
/* @__PURE__ */ t("div", { className: "engine-pills", children: Zt.map(({ value: e, label: r }) => /* @__PURE__ */ t(
"button",
{
className: `engine-pill${F === e ? " active" : ""}`,
onClick: () => R && R(e),
children: r
},
r
)) })
] }),
/* @__PURE__ */ i("div", { className: "run-query-section", children: [
/* @__PURE__ */ t(
"button",
{
className: "run-query-btn",
onClick: $,
disabled: !j || W,
children: W ? /* @__PURE__ */ i(Re, { children: [
/* @__PURE__ */ t("span", { className: "spinner small" }),
"Running..."
] }) : /* @__PURE__ */ i(Re, { children: [
/* @__PURE__ */ t("span", { className: "run-icon", children: "โถ" }),
"Run Query"
] })
}
),
!j && /* @__PURE__ */ t("span", { className: "run-hint", children: "Select at least one metric to run a query" })
] })
]
}
)
] })
] });
}
Wt.registerLanguage("sql", It);
const yt = [
"#60a5fa",
"#34d399",
"#fbbf24",
"#f87171",
"#a78bfa",
"#22d3ee",
"#fb923c"
], tn = 2;
function Mt(l) {
const d = l.name.toLowerCase(), N = (l.type || "").toLowerCase();
return N.includes("date") || N.includes("timestamp") || N.includes("time") || d === "date" || d === "day" || d === "week" || d === "month" || d === "year" || d === "quarter" || d.endsWith("_date") || d.endsWith("_day") || d.endsWith("_week") || d.endsWith("_month") || d.endsWith("_year") || d.endsWith("_at") || d.startsWith("date") || d.startsWith("ds");
}
function Et(l) {
const d = (l.type || "").toLowerCase();
return d.includes("int") || d.includes("float") || d.includes("double") || d.includes("decimal") || d.includes("numeric") || d.includes("real") || d.includes("number");
}
function nn(l, d) {
if (!l.length || !d.length) return null;
const N = l.map((v, k) => ({ ...v, idx: k })), _ = N.filter((v) => Mt(v)), w = N.filter((v) => Et(v)), C = N.filter((v) => !Et(v)).filter((v) => !Mt(v));
if (_.length > 0) {
const v = _[0], k = w.filter((g) => g.idx !== v.idx);
if (k.length > 0)
return C.length === 1 ? {
type: "line",
xCol: v,
groupByCol: C[0],
metricCols: k
} : { type: "line", xCol: v, metricCols: k };
}
if (C.length > 0 && w.length > 0)
return C.length === 1 ? { type: "bar", xCol: C[0], metricCols: w } : C.length === 2 ? {
type: "bar",
xCol: C[0],
groupByCol: C[1],
metricCols: w
} : { type: "bar", xCol: C[0], metricCols: w };
if (w.length > 1) {
const v = w[0], k = w.slice(1);
return { type: "line", xCol: v, metricCols: k };
}
return w.length > 0 ? { type: "kpi", metricCols: w } : null;
}
const an = 50;
function sn(l, d, N, _, w) {
const M = N.idx, C = _.idx, v = w.map((R) => R.idx), k = {};
for (const R of l) {
const $ = String(R[C] ?? "(null)");
k[$] = (k[$] || 0) + (Number(R[v[0]]) || 0);
}
const g = Object.entries(k).sort((R, $) => $[1] - R[1]).slice(0, an).map(([R]) => R), E = new Set(g), h = w.map(() => ({}));
for (const R of l) {
const $ = String(R[C] ?? "(null)");
if (!E.has($)) continue;
const j = R[M], W = String(j ?? "(null)");
for (let O = 0; O < w.length; O++) {
const I = h[O];
I[W] || (I[W] = { [N.name]: j }), I[W][$] = R[v[O]];
}
}
const K = (R, $) => {
const j = R[N.name], W = $[N.name];
return j === null && W === null ? 0 : j === null ? 1 : W === null ? -1 : typeof j == "number" && typeof W == "number" ? j - W : String(j).localeCompare(String(W));
};
return { pivotedByMetric: w.map((R, $) => {
const j = Object.values(h[$]);
return j.sort(K), { col: R, data: j };
}), groupValues: g };
}
function rn(l, d, N) {
const _ = d.map((M) => {
const C = {};
return l.forEach((v, k) => {
C[v.name] = M[k];
}), C;
}), w = N.name;
return _.sort((M, C) => {
const v = M[w], k = C[w];
return v === null && k === null ? 0 : v === null ? 1 : k === null ? -1 : typeof v == "number" && typeof k == "number" ? v - k : String(v).localeCompare(String(k));
}), _;
}
function Rt(l) {
return Math.abs(l) >= 1e9 ? (l / 1e9).toFixed(1) + "B" : Math.abs(l) >= 1e6 ? (l / 1e6).toFixed(1) + "M" : Math.abs(l) >= 1e3 ? (l / 1e3).toFixed(1) + "K" : l;
}
function ln({ rows: l, metricCols: d }) {
const N = l[0] || [];
return /* @__PURE__ */ t("div", { className: "kpi-cards", children: d.map((_) => {
const w = N[_.idx], M = w == null ? "โ" : typeof w == "number" ? w.toLocaleString(void 0, { maximumFractionDigits: 4 }) : String(w);
return /* @__PURE__ */ i("div", { className: "kpi-card", children: [
/* @__PURE__ */ t("div", { className: "kpi-label", children: _.name }),
/* @__PURE__ */ t("div", { className: "kpi-value", children: M }),
_.type && /* @__PURE__ */ t("div", { className: "kpi-type", children: _.type })
] }, _.idx);
}) });
}
const $t = { top: 8, right: 24, left: 8, bottom: 40 }, He = { fontSize: 11, fill: "#64748b" }, At = { fontSize: 12, border: "1px solid #e2e8f0" }, on = { zIndex: 9999 }, Ye = Tt(function({
type: d,
xCol: N,
metricCols: _,
seriesKeys: w,
chartData: M,
seriesColors: C = yt
}) {
const v = M.length <= 60, k = w || _.map((E) => E.name), g = d === "line" ? "preserveStartEnd" : Math.max(0, Math.ceil(M.length / 20) - 1);
return d === "line" ? /* @__PURE__ */ t(Dt, { width: "100%", height: "100%", children: /* @__PURE__ */ i(Xt, { data: M, margin: $t, children: [
/* @__PURE__ */ t(xt, { strokeDasharray: "3 3", stroke: "#e2e8f0" }),
/* @__PURE__ */ t(
Pt,
{
dataKey: N.name,
tick: He,
angle: -35,
textAnchor: "end",
interval: g
}
),
/* @__PURE__ */ t(_t, { tickFormatter: Rt, tick: He, width: 60 }),
/* @__PURE__ */ t(
St,
{
contentStyle: At,
wrapperStyle: on
}
),
k.map((E, h) => /* @__PURE__ */ t(
Jt,
{
type: "monotone",
dataKey: E,
stroke: C[h % C.length],
dot: v,
strokeWidth: 2,
isAnimationActive: !1
},
E
))
] }) }) : /* @__PURE__ */ t(Dt, { width: "100%", height: "100%", children: /* @__PURE__ */ i(Ht, { data: M, margin: $t, children: [
/* @__PURE__ */ t(xt, { strokeDasharray: "3 3", stroke: "#e2e8f0" }),
/* @__PURE__ */ t(
Pt,
{
dataKey: N.name,
tick: He,
angle: -35,
textAnchor: "end",
interval: g
}
),
/* @__PURE__ */ t(_t, { tickFormatter: Rt, tick: He, width: 60 }),
/* @__PURE__ */ t(St, { contentStyle: At }),
k.map((E, h) => /* @__PURE__ */ t(
Yt,
{
dataKey: E,
fill: C[h % C.length],
isAnimationActive: !1
},
E
))
] }) });
}), cn = Tt(function({
chartConfig: d,
chartData: N,
pivotedByMetric: _,
groupValues: w,
rows: M,
columns: C
}) {
if (!d)
return /* @__PURE__ */ t("div", { className: "chart-no-data", children: "No chartable data detected" });
if (d.type === "kpi")
return /* @__PURE__ */ t(ln, { rows: M, metricCols: d.metricCols });
const { type: v, xCol: k, metricCols: g } = d;
return _ && _.length > 1 ? /* @__PURE__ */ t("div", { className: "small-multiples", children: _.map(({ col: E, data: h }) => /* @__PURE__ */ i("div", { className: "small-multiple", children: [
/* @__PURE__ */ t("div", { className: "small-multiple-label", children: E.name }),
/* @__PURE__ */ t("div", { className: "small-multiple-chart", children: /* @__PURE__ */ t(
Ye,
{
type: v,
xCol: k,
metricCols: [E],
seriesKeys: w,
chartData: h
}
) })
] }, E.idx)) }) : w ? /* @__PURE__ */ t(
Ye,
{
type: v,
xCol: k,
metricCols: g,
seriesKeys: w,
chartData: N
}
) : g.length > tn ? /* @__PURE__ */ t("div", { className: "small-multiples", children: g.map((E, h) => /* @__PURE__ */ i("div", { className: "small-multiple", children: [
/* @__PURE__ */ t("div", { className: "small-multiple-label", children: E.name }),
/* @__PURE__ */ t("div", { className: "small-multiple-chart", children: /* @__PURE__ */ t(
Ye,
{
type: v,
xCol: k,
metricCols: [E],
chartData: N,
seriesColors: [yt[h % yt.length]]
}
) })
] }, E.idx)) }) : /* @__PURE__ */ t(
Ye,
{
type: v,
xCol: k,
metricCols: g,
chartData: N
}
);
});
function dn({
sql: l,
results: d,
loading: N,
error: _,
elapsedTime: w,
onBackToPlan: M,
selectedMetrics: C,
selectedDimensions: v,
filters: k,
dialect: g,
cubeName: E,
availability: h,
links: K
}) {
const [F, R] = b(!1), [$, j] = b(null), [W, O] = b("asc"), [I, ue] = b("table"), [S, Ne] = b(null), z = ee(null), ge = L(
(x) => {
x.preventDefault();
const D = z.current;
if (!D) return;
const B = x.clientY, X = S ?? D.offsetHeight * 0.333, ne = ($e) => {
const Se = $e.clientY - B, Ae = Math.max(
80,
Math.min(D.offsetHeight * 0.8, X + Se)
);
Ne(Ae);
}, be = () => {
document.removeEventListener("mousemove", ne), document.removeEventListener("mouseup", be);
};
document.addEventListener("mousemove", ne), document.addEventListener("mouseup", be);
},
[S]
), ze = L(() => {
l && (navigator.clipboard.writeText(l), R(!0), setTimeout(() => R(!1), 2e3));
}, [l]), H = de(
() => {
var x, D;
return ((D = (x = d == null ? void 0 : d.results) == null ? void 0 : x[0]) == null ? void 0 : D.columns) || [];
},
[d]
), Y = de(() => {
var x, D;
return ((D = (x = d == null ? void 0 : d.results) == null ? void 0 : x[0]) == null ? void 0 : D.rows) || [];
}, [d]), oe = Y.length, ke = L(
(x) => {
$ === x ? O((D) => D === "asc" ? "desc" : "asc") : (j(x), O("asc"));
},
[$]
), Ce = de(() => $ === null ? Y : [...Y].sort((x, D) => {
const B = x[$], X = D[$];
if (B === null && X === null) return 0;
if (B === null) return 1;
if (X === null) return -1;
let ne;
return typeof B == "number" && typeof X == "number" ? ne = B - X : ne = String(B).localeCompare(String(X)), W === "asc" ? ne : -ne;
}), [Y, $, W]), V = de(
() => nn(H, Y),
[H, Y]
), { chartData: Pe, pivotedByMetric: _e, groupValues: Le } = de(() => {
if (!V || !V.xCol)
return { chartData: [], pivotedByMetric: null, groupValues: null };
if (V.groupByCol) {
const { pivotedByMetric: x, groupValues: D } = sn(
Y,
H,
V.xCol,
V.groupByCol,
V.metricCols
);
return {
chartData: x[0].data,
pivotedByMetric: x,
groupValues: D
};
}
return {
chartData: rn(H, Y, V.xCol),
pivotedByMetric: null,
groupValues: null
};
}, [H, Y, V]), te = oe > 0;
return Q(() => {
!te && I === "chart" && ue("table");
}, [te, I]), /* @__PURE__ */ i("div", { className: "results-view", children: [
/* @__PURE__ */ i("div", { className: "results-header", children: [
/* @__PURE__ */ i("button", { className: "back-to-plan-btn", onClick: M, children: [
/* @__PURE__ */ t("span", { className: "back-arrow", children: "โ" }),
/* @__PURE__ */ t("span", { children: "Back to Plan" })
] }),
/* @__PURE__ */ t("div", { className: "results-summary", children: N ? /* @__PURE__ */ t("span", { className: "results-loading-text", children: "Running query..." }) : _ ? /* @__PURE__ */ t("span", { className: "results-error-text", children: "Query failed" }) : /* @__PURE__ */ i(Re, { children: [
/* @__PURE__ */ i("span", { className: "results-count", children: [
oe.toLocaleString(),
" rows"
] }),
w != null && /* @__PURE__ */ i("span", { className: "results-time", children: [
w.toFixed(2),
"s"
] })
] }) })
] }),
/* @__PURE__ */ i("div", { className: "results-panes", ref: z, children: [
/* @__PURE__ */ i(
"div",
{
className: "sql-pane",
style: S != null ? { flex: `0 0 ${S}px`, maxHeight: S } : void 0,
children: [
/* @__PURE__ */ i("div", { className: "sql-pane-header", children: [
/* @__PURE__ */ t("span", { className: "sql-pane-title", children: "SQL Query" }),
E && /* @__PURE__ */ i(
"span",
{
className: "sql-pane-info",
title: h ? `Querying materialized dataset ${[
h.catalog,
h.schema_,
h.table
].filter(Boolean).join(".")}, last refreshed for data through ${new Date(
h.validThroughTs
).toLocaleDateString()}` : void 0,
children: [
/* @__PURE__ */ i("span", { className: "info-materialized", children: [
/* @__PURE__ */ t("span", { style: { fontFamily: "sans-serif" }, children: "โก" }),
" Using materialized cube"
] }),
(h == null ? void 0 : h.validThroughTs) && /* @__PURE__ */ i(Re, { children: [
" ยท Valid thru ",
new Date(h.validThroughTs).toLocaleDateString()
] })
]
}
),
/* @__PURE__ */ t(
"button",
{
className: `copy-btn ${F ? "copied" : ""}`,
onClick: ze,
disabled: !l,
children: F ? "โ Copied" : "Copy"
}
)
] }),
/* @__PURE__ */ t("div", { className: "sql-pane-content", children: l ? /* @__PURE__ */ t(
Wt,
{
language: "sql",
style: Ut,
wrapLongLines: !0,
customStyle: {
margin: 0,
padding: "12px 16px",
background: "#f8fafc",
fontSize: "12px",
height: "100%",
overflow: "auto"
},
children: l
}
) : /* @__PURE__ */ t("div", { className: "sql-pane-empty", children: "Generating SQL..." }) })
]
}
),
/* @__PURE__ */ t(
"div",
{
className: "horizontal-resizer",
onMouseDown: ge,
title: "Drag to resize"
}
),
/* @__PURE__ */ t("div", { className: "results-pane", children: N ? /* @__PURE__ */ i("div", { className: "results-loading", children: [
/* @__PURE__ */ t("div", { className: "loading-spinner large" }),
/* @__PURE__ */ t("span", { children: "Executing query..." }),
/* @__PURE__ */ i("span", { className: "loading-hint", children: [
"Querying ",
C.length,
" metric(s) with",
" ",
v.length,
" dimension(s)"
] }),
K && K.length > 0 && /* @__PURE__ */ t("span", { className: "results-links", children: K.map((x, D) => /* @__PURE__ */ t(
"a",
{
href: x,
target: "_blank",
rel: "noopener noreferrer",
className: "results-link",
children: "View query โ"
},
D
)) })
] }) : _ ? /* @__PURE__ */ i("div", { className: "results-error", children: [
/* @__PURE__ */ t("div", { className: "error-icon", children: "โ " }),
/* @__PURE__ */ t("h3", { children: "Query Failed" }),
/* @__PURE__ */ t("p", { className: "error-message", children: _ }),
/* @__PURE__ */ t(
"button",
{
className: "action-btn action-btn-primary",
onClick: M,
children: "Back to Plan"
}
)
] }) : /* @__PURE__ */ i("div", { className: "results-table-section", children: [
/* @__PURE__ */ i("div", { className: "results-tabs-bar", children: [
/* @__PURE__ */ i("div", { className: "results-tabs", children: [
/* @__PURE__ */ t(
"button",
{
className: `results-tab ${I === "table" ? "active" : ""}`,
onClick: () => ue("table"),
children: "Table"
}
),
/* @__PURE__ */ t(
"button",
{
className: `results-tab ${I === "chart" ? "active" : ""} ${te ? "" : "disabled"}`,
onClick: () => te && ue("chart"),
title: te ? void 0 : "No chartable data (need at least one numeric column)",
children: "Chart"
}
)
] }),
/* @__PURE__ */ i("div", { className: "results-tabs-meta", children: [
/* @__PURE__ */ i("span", { className: "table-count", children: [
oe.toLocaleString(),
" rows"
] }),
k && k.length > 0 && /* @__PURE__ */ t("div", { className: "table-filters", children: k.map((x, D) => /* @__PURE__ */ t("span", { className: "filter-chip small", children: x }, D)) })
] })
] }),
I === "table" ? /* @__PURE__ */ t("div", { className: "results-table-wrapper", children: oe === 0 ? /* @__PURE__ */ t("div", { className: "table-empty", children: /* @__PURE__ */ t("p", { children: "No results returned" }) }) : /* @__PURE__ */ i("table", { className: "results-table", children: [
/* @__PURE__ */ t("thead", { children: /* @__PURE__ */ t("tr", { children: H.map((x, D) => /* @__PURE__ */ i(
"th",
{
title: x.semantic_name || x.name,
onClick: () => ke(D),
className: $ === D ? "sorted" : "",
children: [
/* @__PURE__ */ i("span", { className: "col-header-content", children: [
x.name,
/* @__PURE__ */ i("span", { className: "sort-arrows", children: [
/* @__PURE__ */ t(
"span",
{
className: `sort-arrow up ${$ === D && W === "asc" ? "active" : ""}`,
children: "โฒ"
}
),
/* @__PURE__ */ t(
"span",
{
className: `sort-arrow down ${$ === D && W === "desc" ? "active" : ""}`,
children: "โผ"
}
)
] })
] }),
/* @__PURE__ */ t("span", { className: "col-type", children: x.type })
]
},
D
)) }) }),
/* @__PURE__ */ t("tbody", { children: Ce.map((x, D) => /* @__PURE__ */ t("tr", { children: x.map((B, X) => /* @__PURE__ */ t("td", { children: B === null ? /* @__PURE__ */ t("span", { className: "null-value", children: "NULL" }) : String(B) }, X)) }, D)) })
] }) }) : /* @__PURE__ */ t("div", { className: "results-chart-wrapper", children: te ? /* @__PURE__ */ t(
cn,
{
chartConfig: V,
chartData: Pe,
pivotedByMetric: _e,
groupValues: Le,
rows: Y,
columns: H
}
) : /* @__PURE__ */ t("div", { className: "chart-no-data", children: "No chartable data detected" }) })
] }) })
] })
] });
}
const un = Kt(() => import("./MetricFlowGraph-CgV3lxXj.js"));
function vt(l) {
return (l || []).map((d) => d.split(".").pop()).sort().join(",");
}
function vn() {
var e, r, m, f, p;
const l = jt(Ot).DataJunctionAPI, d = Bt(), N = qt(), [_, w] = b([]), [M, C] = b([]), [v, k] = b([]), [g, E] = b([]), [h, K] = b([]), [F, R] = b(null), $ = ee(!1), j = ee([]), W = ee(null), O = ee([]), [I, ue] = b(null), [S, Ne] = b(null), [z, ge] = b(null), [ze, H] = b(!1), [Y, oe] = b(!1), [ke, Ce] = b(null), [V, Pe] = b(!1), [_e, Le] = b(null), [te, x] = b(!1), [D, B] = b(null), [X, ne] = b(null), [be, $e] = b(null), [Se, Ae] = b([]), [ae, Te] = b([]), [we, Ke] = b(null), [Be, Fe] = b(null), [T, me] = b(null), [he, Me] = b(null), [ve, De] = b(null), We = ee(null), Ee = L(
(s) => {
s.preventDefault();
const n = We.current;
if (!n) return;
const a = s.clientX, o = he ?? n.offsetWidth * 0.2, c = (A) => {
const q = A.clientX - a, P = Math.max(
200,