datajunction-ui
Version:
DataJunction UI
1,230 lines (1,229 loc) • 92.8 kB
JavaScript
import { jsxs as a, jsx as e, Fragment as S } from "react/jsx-runtime";
import { useRef as sa, useEffect as ca, useCallback as M, useState as f } from "react";
import { Link as Qe } from "react-router-dom";
import { ac as Ve, a1 as ra, a2 as oa } from "./index-n79cxNwC.js";
const Re = {
hljs: {
display: "block",
overflowX: "auto",
padding: "0.5em",
color: "#383a42",
background: "#fafafa"
},
"hljs-comment": {
color: "#a0a1a7",
fontStyle: "italic"
},
"hljs-quote": {
color: "#a0a1a7",
fontStyle: "italic"
},
"hljs-doctag": {
color: "#a626a4"
},
"hljs-keyword": {
color: "#a626a4"
},
"hljs-formula": {
color: "#a626a4"
},
"hljs-section": {
color: "#e45649"
},
"hljs-name": {
color: "#e45649"
},
"hljs-selector-tag": {
color: "#e45649"
},
"hljs-deletion": {
color: "#e45649"
},
"hljs-subst": {
color: "#e45649"
},
"hljs-literal": {
color: "#0184bb"
},
"hljs-string": {
color: "#50a14f"
},
"hljs-regexp": {
color: "#50a14f"
},
"hljs-addition": {
color: "#50a14f"
},
"hljs-attribute": {
color: "#50a14f"
},
"hljs-meta-string": {
color: "#50a14f"
},
"hljs-built_in": {
color: "#c18401"
},
"hljs-class .hljs-title": {
color: "#c18401"
},
"hljs-attr": {
color: "#986801"
},
"hljs-variable": {
color: "#986801"
},
"hljs-template-variable": {
color: "#986801"
},
"hljs-type": {
color: "#986801"
},
"hljs-selector-class": {
color: "#986801"
},
"hljs-selector-attr": {
color: "#986801"
},
"hljs-selector-pseudo": {
color: "#986801"
},
"hljs-number": {
color: "#986801"
},
"hljs-symbol": {
color: "#4078f2"
},
"hljs-bullet": {
color: "#4078f2"
},
"hljs-link": {
color: "#4078f2",
textDecoration: "underline"
},
"hljs-meta": {
color: "#4078f2"
},
"hljs-selector-id": {
color: "#4078f2"
},
"hljs-title": {
color: "#4078f2"
},
"hljs-emphasis": {
fontStyle: "italic"
},
"hljs-strong": {
fontWeight: "bold"
}
};
function da(t) {
const u = t.split("[")[0], d = u.split(".");
return d.length > 1 ? d.slice(0, -1).join(".") : u;
}
function ma(t) {
return (t || []).map((u) => u.split(".").pop()).sort().join(",");
}
function Ge(t) {
if (!t) return null;
const u = t.split(" ");
if (u.length < 5) return t;
const [d, p, N, b, v] = u;
if (N === "*" && b === "*" && v === "*") {
const g = parseInt(p, 10), k = parseInt(d, 10);
if (!isNaN(g) && !isNaN(k)) {
const B = g >= 12 ? "pm" : "am", A = g > 12 ? g - 12 : g || 12, U = k.toString().padStart(2, "0");
return `Daily @ ${A}:${U}${B}`;
}
}
if (N === "*" && b === "*" && v !== "*") {
const g = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], k = parseInt(v, 10);
if (!isNaN(k) && k >= 0 && k <= 6)
return `Weekly on ${g[k]}`;
}
return t;
}
function ha(t) {
var u, d, p;
if (!t || ((u = t.workflow_urls) == null ? void 0 : u.length) === 0)
return {
icon: "○",
text: "Not planned",
className: "status-not-planned",
color: "#94a3b8"
};
if (t._isCompatible) {
const N = (d = t.grain_columns) == null ? void 0 : d.map((b) => b.split(".").pop()).join(", ");
return t.availability || t.status === "active" ? {
icon: "✓",
text: `Covered (${N})`,
className: "status-compatible-materialized",
color: "#059669",
isCompatible: !0
} : {
icon: "◐",
text: `Covered (${N})`,
className: "status-compatible",
color: "#d97706",
isCompatible: !0
};
}
return t.status === "running" ? {
icon: "◉",
text: "Running",
className: "status-running",
color: "#2563eb"
} : t.availability || t.status === "active" ? {
icon: "●",
text: "Materialized",
className: "status-materialized",
color: "#059669"
} : t.workflow_status === "active" ? {
icon: "◐",
text: "Workflow Active",
className: "status-workflow-active",
color: "#2563eb"
} : t.workflow_status === "paused" ? {
icon: "◐",
text: "Workflow Paused",
className: "status-workflow-paused",
color: "#94a3b8"
} : ((p = t.workflow_urls) == null ? void 0 : p.length) > 0 ? {
icon: "◐",
text: "Pending",
className: "status-pending",
color: "#d97706"
} : {
icon: "○",
text: "Not planned",
className: "status-not-planned",
color: "#94a3b8"
};
}
function ua(t) {
switch (t == null ? void 0 : t.toUpperCase()) {
case "HOUR":
return { cron: "0 * * * *", label: "Hourly" };
case "DAY":
default:
return { cron: "0 6 * * *", label: "Daily at 6:00 AM" };
}
}
function pa(t) {
for (const u of t || [])
for (const d of u.grain || [])
if (d.split(".").pop().toLowerCase().includes("hour")) return "HOUR";
return "DAY";
}
function Ue(t) {
if (!t || t === 0) return "0 B";
const u = 1024, d = ["B", "KB", "MB", "GB", "TB", "PB"], p = Math.floor(Math.log(t) / Math.log(u));
return Math.round(t / Math.pow(u, p) * 100) / 100 + " " + d[p];
}
function fa(t) {
return t > ra ? "critical" : t > oa ? "warning" : "ok";
}
function ga(t) {
if (!t || !t.sources || t.sources.length === 0)
return null;
const u = t.sources.some(
(N) => N.total_bytes === null || N.total_bytes === void 0
);
let d = "unknown", p = "ℹ️";
return t.total_bytes !== null && t.total_bytes !== void 0 && (d = fa(t.total_bytes), p = d === "critical" ? "⚠️" : d === "warning" ? "⚡" : "✓"), {
icon: p,
level: d,
totalBytes: t.total_bytes,
sources: t.sources || [],
hasMissingData: u
};
}
function Na({ onClose: t, onSubmit: u, loading: d }) {
const p = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], N = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0], [b, v] = f(N), [g, k] = f(p);
return /* @__PURE__ */ e("div", { className: "backfill-modal-overlay", onClick: t, children: /* @__PURE__ */ a("div", { className: "backfill-modal", onClick: (B) => B.stopPropagation(), children: [
/* @__PURE__ */ a("div", { className: "backfill-modal-header", children: [
/* @__PURE__ */ e("h3", { children: "Run Cube Backfill" }),
/* @__PURE__ */ e("button", { className: "modal-close", onClick: t, children: "×" })
] }),
/* @__PURE__ */ a("div", { className: "backfill-modal-body", children: [
/* @__PURE__ */ e("p", { className: "backfill-description", children: "Run a backfill for the specified date range:" }),
/* @__PURE__ */ a("div", { className: "backfill-date-inputs", children: [
/* @__PURE__ */ a("div", { className: "date-input-group", children: [
/* @__PURE__ */ e("label", { htmlFor: "backfill-start", children: "Start Date" }),
/* @__PURE__ */ e(
"input",
{
id: "backfill-start",
type: "date",
value: b,
onChange: (B) => v(B.target.value),
disabled: d
}
)
] }),
/* @__PURE__ */ a("div", { className: "date-input-group", children: [
/* @__PURE__ */ e("label", { htmlFor: "backfill-end", children: "End Date" }),
/* @__PURE__ */ e(
"input",
{
id: "backfill-end",
type: "date",
value: g,
onChange: (B) => k(B.target.value),
disabled: d
}
)
] })
] })
] }),
/* @__PURE__ */ a("div", { className: "backfill-modal-actions", children: [
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-secondary",
onClick: t,
disabled: d,
children: "Cancel"
}
),
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-primary",
disabled: d || !b,
onClick: () => u(b, g || null),
children: d ? /* @__PURE__ */ a(S, { children: [
/* @__PURE__ */ e("span", { className: "spinner" }),
" Starting..."
] }) : "Start Backfill"
}
)
] })
] }) });
}
function Ca({
measuresResult: t,
metricsResult: u,
selectedMetrics: d,
selectedDimensions: p,
plannedPreaggs: N = {},
onPlanMaterialization: b,
onUpdateConfig: v,
onCreateWorkflow: g,
onRunBackfill: k,
onRunAdhoc: B,
onFetchRawSql: A,
onSetPartition: U,
onRefreshMeasures: w,
onFetchNodePartitions: P,
materializationError: ee,
onClearError: ae,
workflowUrls: V = [],
onClearWorkflowUrls: ba,
loadedCubeName: J = null,
// Existing cube name if loaded from preset
cubeMaterialization: m = null,
// Full cube materialization info {schedule, strategy, lookbackWindow, ...}
onUpdateCubeConfig: ue,
onRefreshCubeWorkflow: ve,
onRunCubeBackfill: ke,
onDeactivatePreaggWorkflow: we,
onDeactivateCubeWorkflow: Ce
}) {
var Ee, Oe, He;
const _e = M(() => {
if (d && d.length > 0) {
const n = d[0].split(".");
if (n.length > 1)
return n.slice(0, -1).join(".");
}
return "default";
}, [d]), [le, Se] = f({}), [pe, ne] = f(null), [Ye, te] = f(null), [Je, ie] = f(!1), [Ke, fe] = f(!1), [R, K] = f({
strategy: "incremental_time",
schedule: "0 6 * * *",
lookbackWindow: "1 DAY"
}), [De, Te] = f(!1), [Xe, je] = f(!1), [Ze, se] = f({}), [ze, xe] = f(null), [Me, ge] = f({}), [E, Ne] = f({}), [Be, Fe] = f(!1), [s, y] = f({
strategy: "incremental_time",
backfillFrom: "",
backfillTo: "today",
// 'today' or specific date
backfillToDate: "",
continueAfterBackfill: !0,
schedule: "",
scheduleType: "auto",
// 'auto' or 'custom'
lookbackWindow: "1 day",
// Druid cube materialization settings
enableDruidCube: !0,
druidCubeNamespace: "",
// Will be initialized with user's namespace
druidCubeName: ""
// Short name without namespace
}), [ce, re] = f(!1), [D, T] = f(null), [Y, O] = f(null), [Pe, H] = f(null), [oe, ea] = f("optimized"), [Q, aa] = f(null), [We, $e] = f(!1), Le = async (l) => {
if (ea(l), l === "raw" && !Q && A) {
$e(!0);
const n = await A();
aa(n), $e(!1);
}
}, $ = M(() => {
const l = (t == null ? void 0 : t.grain_groups) || [], n = /* @__PURE__ */ new Set();
return l.forEach((c) => {
c.parent_name && n.add(c.parent_name);
}), Array.from(n);
}, [t == null ? void 0 : t.grain_groups]), Ie = M(async () => {
const l = $();
if (l.length === 0 || !P)
return Ne({}), {};
Fe(!0);
try {
const n = {}, c = l.map(async (r) => {
try {
const i = await P(r);
n[r] = i;
} catch (i) {
console.error(`Failed to fetch partitions for ${r}:`, i), n[r] = { columns: [], temporalPartitions: [] };
}
});
return await Promise.all(c), console.log("[fetchAllNodePartitions] results:", n), Ne(n), n;
} catch (n) {
return console.error("Failed to fetch node partitions:", n), Ne({}), {};
} finally {
Fe(!1);
}
}, [$, P]), de = M(() => {
const l = $();
if (l.length === 0) return !1;
const n = l.every((c) => {
var i;
const r = E[c];
return ((i = r == null ? void 0 : r.temporalPartitions) == null ? void 0 : i.length) > 0;
});
return console.log("[hasActualTemporalPartitions]", {
parentNodes: l,
allNodePartitions: E,
allHaveTemporal: n
}), n;
}, [$, E]);
M(() => $().filter((n) => {
var r;
const c = E[n];
return !((r = c == null ? void 0 : c.temporalPartitions) != null && r.length);
}), [$, E]);
const la = async () => {
const l = (t == null ? void 0 : t.grain_groups) || [], n = pa(l), c = ua(n), r = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0], i = await Ie(), j = $(), L = j.every(
(C) => {
var o, x;
return ((x = (o = i[C]) == null ? void 0 : o.temporalPartitions) == null ? void 0 : x.length) > 0;
}
);
console.log(
"[openConfigForm] allHaveTemporal:",
L,
"partitionResults:",
i
);
const W = /date|time|day|month|year|hour|ds|dt|dateint|timestamp/i, I = {};
j.forEach((C) => {
var x, X;
const o = i[C];
if (!((x = o == null ? void 0 : o.temporalPartitions) != null && x.length)) {
const he = [...((o == null ? void 0 : o.columns) || []).filter((G) => !G.partition)].sort((G, Z) => {
const z = W.test(G.name), h = W.test(Z.name);
return z && !h ? -1 : !z && h ? 1 : G.name.localeCompare(Z.name);
});
I[C] = {
column: ((X = he[0]) == null ? void 0 : X.name) || "",
granularity: "day",
format: "yyyyMMdd"
};
}
}), se(I), ge({}), y({
strategy: L ? "incremental_time" : "full",
runBackfill: !0,
// Option to skip backfill
backfillFrom: r,
backfillTo: "today",
backfillToDate: "",
continueAfterBackfill: !0,
schedule: c.cron,
scheduleType: "auto",
lookbackWindow: "1 day",
_recommendedSchedule: c,
// Store for display
_granularity: n,
// Druid cube settings
enableDruidCube: !0,
druidCubeNamespace: _e(),
// Default to first metric's namespace
druidCubeName: ""
// Short name without namespace
}), ne("__all__");
}, na = (l, n) => {
y({
strategy: n.strategy || "incremental_time",
backfillFrom: "",
backfillTo: "today",
backfillToDate: "",
continueAfterBackfill: !0,
schedule: n.schedule || "",
scheduleType: n.schedule ? "custom" : "auto",
lookbackWindow: n.lookback_window || ""
}), te(l);
}, ta = (l) => {
Se((n) => ({
...n,
[l]: !n[l]
}));
};
if (!(d != null && d.length) || !(p != null && p.length))
return /* @__PURE__ */ e("div", { className: "details-panel details-panel-empty", children: /* @__PURE__ */ a("div", { className: "empty-hint", children: [
/* @__PURE__ */ e("div", { className: "empty-icon", children: "⊞" }),
/* @__PURE__ */ e("h4", { children: "Query Planner" }),
/* @__PURE__ */ e("p", { children: "Select metrics and dimensions from the left panel to see the generated SQL and pre-aggregation plan" })
] }) });
if (!t || !u)
return /* @__PURE__ */ e("div", { className: "details-panel details-panel-empty", children: /* @__PURE__ */ a("div", { className: "empty-hint", children: [
/* @__PURE__ */ e("div", { className: "loading-spinner" }),
/* @__PURE__ */ e("p", { children: "Building query plan..." })
] }) });
const me = t.grain_groups || [], be = t.metric_formulas || [], qe = u.sql || "", Ae = V.length > 0 || Object.values(N).some((l) => {
var n;
return ((n = l == null ? void 0 : l.workflow_urls) == null ? void 0 : n.length) > 0;
});
return /* @__PURE__ */ a("div", { className: "details-panel", children: [
/* @__PURE__ */ a("div", { className: "details-header", children: [
/* @__PURE__ */ e("h2", { className: "details-title", children: "Query Plan" }),
/* @__PURE__ */ a("p", { className: "details-full-name", children: [
d.length,
" metric",
d.length !== 1 ? "s" : "",
" ×",
" ",
p.length,
" dimension",
p.length !== 1 ? "s" : ""
] })
] }),
ee && /* @__PURE__ */ a("div", { className: "materialization-error global-error", children: [
/* @__PURE__ */ a("div", { className: "error-content", children: [
/* @__PURE__ */ e("span", { className: "error-icon", children: "⚠" }),
/* @__PURE__ */ e("span", { className: "error-message", children: ee })
] }),
/* @__PURE__ */ e(
"button",
{
className: "error-dismiss",
onClick: ae,
"aria-label": "Dismiss error",
children: "×"
}
)
] }),
me.length > 0 && b && (!Ae || pe === "__all__") && /* @__PURE__ */ a("div", { className: "details-section", children: [
!Ae && pe !== "__all__" && /* @__PURE__ */ a("div", { className: "plan-materialization-cta", children: [
/* @__PURE__ */ a("div", { className: "cta-content", children: [
/* @__PURE__ */ e("div", { className: "cta-icon", children: "⚡" }),
/* @__PURE__ */ a("div", { className: "cta-text", children: [
/* @__PURE__ */ e("strong", { children: "Ready to materialize?" }),
/* @__PURE__ */ e("span", { children: "Configure scheduled materialization for faster queries" })
] })
] }),
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-primary",
type: "button",
onClick: la,
children: "Configure"
}
)
] }),
pe === "__all__" && /* @__PURE__ */ a("div", { className: "materialization-config-form section-level-config", children: [
/* @__PURE__ */ a("div", { className: "config-form-header", children: [
/* @__PURE__ */ e("span", { children: "Configure Materialization" }),
/* @__PURE__ */ e(
"button",
{
className: "config-close-btn",
type: "button",
onClick: () => ne(null),
children: "×"
}
)
] }),
/* @__PURE__ */ a("div", { className: "config-form-body", children: [
/* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Strategy" }),
/* @__PURE__ */ a("div", { className: "config-form-options", children: [
/* @__PURE__ */ a("label", { className: "radio-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "radio",
name: "strategy-all",
value: "full",
checked: s.strategy === "full",
onChange: (l) => y((n) => ({
...n,
strategy: l.target.value
}))
}
),
/* @__PURE__ */ e("span", { children: "Full" })
] }),
/* @__PURE__ */ a("label", { className: "radio-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "radio",
name: "strategy-all",
value: "incremental_time",
checked: s.strategy === "incremental_time",
onChange: (l) => {
y((n) => ({
...n,
strategy: l.target.value
})), !de() && !Be && je(!0);
}
}
),
/* @__PURE__ */ e("span", { children: "Incremental" }),
s.strategy === "incremental_time" && (Be ? /* @__PURE__ */ e("span", { className: "option-hint", children: "(checking...)" }) : de() ? /* @__PURE__ */ e("span", { className: "partition-badge", children: $().map(
(l) => {
var n, c, r;
return (r = (c = (n = E[l]) == null ? void 0 : n.temporalPartitions) == null ? void 0 : c[0]) == null ? void 0 : r.name;
}
).filter(Boolean).join(", ") }) : null)
] })
] })
] }),
Xe && s.strategy === "incremental_time" && !de() && /* @__PURE__ */ a("div", { className: "partition-setup-form", children: [
/* @__PURE__ */ a("div", { className: "partition-setup-header", children: [
/* @__PURE__ */ e("span", { className: "partition-setup-icon", children: "⚠️" }),
/* @__PURE__ */ e("span", { children: "Set up temporal partitions for incremental builds" })
] }),
/* @__PURE__ */ e("div", { className: "partition-setup-body", children: $().map((l) => {
var W, I;
const n = E[l], c = ((W = n == null ? void 0 : n.temporalPartitions) == null ? void 0 : W.length) > 0, r = Ze[l] || {
column: "",
granularity: "day",
format: "yyyyMMdd"
}, i = Me[l], j = ze === l, L = l.split(".").pop();
return c ? /* @__PURE__ */ a(
"div",
{
className: "partition-node-section partition-node-done",
children: [
/* @__PURE__ */ e("div", { className: "partition-node-header", children: /* @__PURE__ */ a("span", { className: "partition-node-name", children: [
/* @__PURE__ */ e("span", { className: "partition-node-icon", children: "✓" }),
L
] }) }),
/* @__PURE__ */ e("div", { className: "partition-node-status", children: /* @__PURE__ */ e("span", { className: "partition-badge", children: (I = n.temporalPartitions[0]) == null ? void 0 : I.name }) })
]
},
l
) : /* @__PURE__ */ a(
"div",
{
className: "partition-node-section",
children: [
/* @__PURE__ */ e("div", { className: "partition-node-header", children: /* @__PURE__ */ a("span", { className: "partition-node-name", children: [
/* @__PURE__ */ e("span", { className: "partition-node-icon", children: "📦" }),
L
] }) }),
i && /* @__PURE__ */ e("div", { className: "partition-setup-error", children: i }),
/* @__PURE__ */ a("div", { className: "partition-node-form", children: [
/* @__PURE__ */ a("div", { className: "partition-field", children: [
/* @__PURE__ */ e("label", { children: "Column" }),
/* @__PURE__ */ a(
"select",
{
value: r.column,
onChange: (C) => se((o) => ({
...o,
[l]: {
...r,
column: C.target.value
}
})),
children: [
/* @__PURE__ */ e("option", { value: "", children: "Select..." }),
(() => {
const C = /date|time|day|month|year|hour|ds|dt|dateint|timestamp/i;
return ((n == null ? void 0 : n.columns) || []).filter((o) => !o.partition).map((o) => ({
...o,
isDateLike: C.test(
o.name
)
})).sort((o, x) => o.isDateLike && !x.isDateLike ? -1 : !o.isDateLike && x.isDateLike ? 1 : o.name.localeCompare(x.name)).map((o) => /* @__PURE__ */ a(
"option",
{
value: o.name,
children: [
o.name,
o.isDateLike ? " ★" : ""
]
},
o.name
));
})()
]
}
)
] }),
/* @__PURE__ */ a("div", { className: "partition-field partition-field-small", children: [
/* @__PURE__ */ e("label", { children: "Granularity" }),
/* @__PURE__ */ a(
"select",
{
value: r.granularity,
onChange: (C) => se((o) => ({
...o,
[l]: {
...r,
granularity: C.target.value
}
})),
children: [
/* @__PURE__ */ e("option", { value: "day", children: "Day" }),
/* @__PURE__ */ e("option", { value: "hour", children: "Hour" }),
/* @__PURE__ */ e("option", { value: "month", children: "Month" })
]
}
)
] }),
/* @__PURE__ */ a("div", { className: "partition-field partition-field-small", children: [
/* @__PURE__ */ e("label", { children: "Format" }),
/* @__PURE__ */ e(
"input",
{
type: "text",
placeholder: "yyyyMMdd",
value: r.format,
onChange: (C) => se((o) => ({
...o,
[l]: {
...r,
format: C.target.value
}
}))
}
)
] }),
/* @__PURE__ */ e(
"button",
{
type: "button",
className: "partition-set-btn",
disabled: !r.column || j,
onClick: async () => {
var C;
if (r.column) {
xe(l), ge((o) => ({
...o,
[l]: null
}));
try {
const o = await U(
l,
r.column,
"temporal",
r.format || "yyyyMMdd",
r.granularity
);
if ((o == null ? void 0 : o.status) >= 400)
throw new Error(
((C = o.json) == null ? void 0 : C.message) || "Failed to set partition"
);
await Ie(), de() && je(!1);
} catch (o) {
ge((x) => ({
...x,
[l]: o.message || "Failed to set partition"
}));
} finally {
xe(null);
}
}
},
children: j ? "..." : "Set"
}
)
] })
]
},
l
);
}) })
] }),
s.strategy === "incremental_time" && /* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ a("label", { className: "checkbox-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "checkbox",
checked: s.runBackfill,
onChange: (l) => y((n) => ({
...n,
runBackfill: l.target.checked
}))
}
),
/* @__PURE__ */ e("span", { children: "Run initial backfill" })
] }),
/* @__PURE__ */ e("span", { className: "config-form-hint", children: "Populate historical data. Uncheck to only set up ongoing materialization." })
] }),
s.strategy === "incremental_time" && s.runBackfill && /* @__PURE__ */ a("div", { className: "config-form-section", children: [
/* @__PURE__ */ e("label", { className: "config-form-section-label", children: "Backfill Date Range" }),
/* @__PURE__ */ a("div", { className: "backfill-range", children: [
/* @__PURE__ */ a("div", { className: "backfill-field", children: [
/* @__PURE__ */ e("label", { children: "From" }),
/* @__PURE__ */ e(
"input",
{
type: "date",
value: s.backfillFrom,
onChange: (l) => y((n) => ({
...n,
backfillFrom: l.target.value
}))
}
)
] }),
/* @__PURE__ */ a("div", { className: "backfill-field", children: [
/* @__PURE__ */ e("label", { children: "To" }),
/* @__PURE__ */ a(
"select",
{
value: s.backfillTo,
onChange: (l) => y((n) => ({
...n,
backfillTo: l.target.value
})),
children: [
/* @__PURE__ */ e("option", { value: "today", children: "Today" }),
/* @__PURE__ */ e("option", { value: "specific", children: "Specific date" })
]
}
),
s.backfillTo === "specific" && /* @__PURE__ */ e(
"input",
{
type: "date",
value: s.backfillToDate,
onChange: (l) => y((n) => ({
...n,
backfillToDate: l.target.value
})),
style: { marginTop: "6px" }
}
)
] })
] })
] }),
/* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Schedule" }),
/* @__PURE__ */ a(
"select",
{
className: "config-form-select",
value: s.scheduleType,
onChange: (l) => {
const n = l.target.value;
y((c) => {
var r;
return {
...c,
scheduleType: n,
schedule: n === "auto" ? ((r = c._recommendedSchedule) == null ? void 0 : r.cron) || "0 6 * * *" : c.schedule
};
});
},
children: [
/* @__PURE__ */ a("option", { value: "auto", children: [
((Ee = s._recommendedSchedule) == null ? void 0 : Ee.label) || "Daily at 6:00 AM",
" ",
"(recommended)"
] }),
/* @__PURE__ */ e("option", { value: "hourly", children: "Hourly" }),
/* @__PURE__ */ e("option", { value: "custom", children: "Custom cron..." })
]
}
),
s.scheduleType === "custom" && /* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input",
placeholder: "0 6 * * *",
value: s.schedule,
onChange: (l) => y((n) => ({
...n,
schedule: l.target.value
})),
style: { marginTop: "6px" }
}
),
s.scheduleType === "auto" && /* @__PURE__ */ a("span", { className: "config-form-hint", children: [
"Based on",
" ",
((Oe = s._granularity) == null ? void 0 : Oe.toLowerCase()) || "daily",
" ",
"partition granularity"
] })
] }),
s.strategy === "incremental_time" && /* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Lookback Window" }),
/* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input",
placeholder: "1 day",
value: s.lookbackWindow,
onChange: (l) => y((n) => ({
...n,
lookbackWindow: l.target.value
}))
}
),
/* @__PURE__ */ e("span", { className: "config-form-hint", children: 'For late-arriving data (e.g., "1 day", "3 days")' })
] }),
/* @__PURE__ */ e("div", { className: "config-form-divider", children: /* @__PURE__ */ e("span", { children: "Cube Materialization (Druid)" }) }),
/* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ a("label", { className: "checkbox-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "checkbox",
checked: s.enableDruidCube,
onChange: (l) => y((n) => ({
...n,
enableDruidCube: l.target.checked
}))
}
),
"Enable Druid cube materialization"
] }),
/* @__PURE__ */ e("span", { className: "config-form-hint", children: "Combines pre-aggs into a single Druid datasource for fast interactive queries" })
] }),
s.enableDruidCube && !J && /* @__PURE__ */ a("div", { className: "config-form-section druid-cube-config", children: [
J ? /* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Using Cube" }),
/* @__PURE__ */ a("div", { className: "existing-cube-name", children: [
/* @__PURE__ */ e("span", { className: "cube-badge", children: "📦" }),
/* @__PURE__ */ e("code", { children: J })
] }),
/* @__PURE__ */ e("span", { className: "config-form-hint", children: "Materialization will be added to this existing cube" })
] }) : /* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Cube Name" }),
/* @__PURE__ */ a("div", { className: "cube-name-input-group", children: [
/* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input namespace-input",
placeholder: "users.myname",
value: s.druidCubeNamespace,
onChange: (l) => y((n) => ({
...n,
druidCubeNamespace: l.target.value
}))
}
),
/* @__PURE__ */ e("span", { className: "namespace-separator", children: "." }),
/* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input name-input",
placeholder: "my_cube",
value: s.druidCubeName,
onChange: (l) => y((n) => ({
...n,
druidCubeName: l.target.value
}))
}
)
] }),
/* @__PURE__ */ a("span", { className: "config-form-hint", children: [
"Full name:",
" ",
/* @__PURE__ */ a("code", { children: [
s.druidCubeNamespace,
".",
s.druidCubeName || "my_cube"
] })
] })
] }),
/* @__PURE__ */ a("div", { className: "druid-cube-preview", children: [
/* @__PURE__ */ e("div", { className: "preview-label", children: "Pre-aggregations to combine:" }),
/* @__PURE__ */ e("div", { className: "preview-list", children: ((t == null ? void 0 : t.grain_groups) || []).map((l, n) => {
var c;
return /* @__PURE__ */ a("div", { className: "preview-item", children: [
/* @__PURE__ */ e("span", { className: "preview-source", children: (c = l.parent_name) == null ? void 0 : c.split(".").pop() }),
/* @__PURE__ */ a("span", { className: "preview-grain", children: [
"(",
(l.grain || []).map((r) => r.split(".").pop()).join(", "),
")"
] })
] }, n);
}) }),
/* @__PURE__ */ a("div", { className: "preview-info", children: [
/* @__PURE__ */ e("span", { className: "info-icon", children: "ℹ️" }),
"Pre-aggs will be combined with FULL OUTER JOIN on shared dimensions and ingested to Druid"
] })
] })
] })
] }),
/* @__PURE__ */ a("div", { className: "config-form-actions", children: [
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-secondary",
type: "button",
onClick: () => ne(null),
children: "Cancel"
}
),
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-primary",
type: "button",
disabled: ce,
onClick: async () => {
var l;
re(!0);
try {
let n = s.schedule;
s.scheduleType === "auto" ? n = ((l = s._recommendedSchedule) == null ? void 0 : l.cron) || "0 6 * * *" : s.scheduleType === "hourly" && (n = "0 * * * *");
let c = null;
s.strategy === "incremental_time" && (c = s.backfillTo === "today" ? (/* @__PURE__ */ new Date()).toISOString().split("T")[0] : s.backfillToDate);
const r = {
strategy: s.strategy,
schedule: n,
// Always set - we always create workflows
lookbackWindow: s.strategy === "incremental_time" ? s.lookbackWindow : null,
// Backfill info (only for incremental + runBackfill checked)
runBackfill: s.runBackfill,
backfillFrom: s.strategy === "incremental_time" && s.runBackfill ? s.backfillFrom : null,
backfillTo: s.strategy === "incremental_time" && s.runBackfill ? c : null,
// Druid cube config
enableDruidCube: s.enableDruidCube,
// Only send cube name if creating a new cube (no existing cube loaded)
// Combine namespace and name: "users.myname.my_cube"
druidCubeName: s.enableDruidCube && s.druidCubeName ? `${s.druidCubeNamespace}.${s.druidCubeName}` : null
};
await b(null, r), ne(null), y({
strategy: "incremental_time",
runBackfill: !0,
backfillFrom: "",
backfillTo: "today",
backfillToDate: "",
continueAfterBackfill: !0,
schedule: "",
scheduleType: "auto",
lookbackWindow: "1 day",
enableDruidCube: !0,
druidCubeNamespace: _e(),
druidCubeName: ""
});
} catch (n) {
console.error("Failed to plan:", n);
}
re(!1);
},
children: ce ? /* @__PURE__ */ a(S, { children: [
/* @__PURE__ */ e("span", { className: "spinner" }),
" Creating..."
] }) : s.enableDruidCube ? "Create Pre-Agg Workflows & Schedule Cube" : s.strategy === "incremental_time" && s.runBackfill ? "Create Workflow & Start Backfill" : "Create Workflow"
}
)
] })
] })
] }),
V.length > 0 && /* @__PURE__ */ a("div", { className: "details-section", children: [
/* @__PURE__ */ e("div", { className: "section-header-row", children: /* @__PURE__ */ a("h3", { className: "section-title", children: [
/* @__PURE__ */ e("span", { className: "section-icon cube-icon", children: "◆" }),
"Druid Cube"
] }) }),
/* @__PURE__ */ e("div", { className: "preagg-summary-card cube-card", children: Je ? (
/* Edit Cube Config Form - matches pre-agg edit form exactly */
/* @__PURE__ */ a("div", { className: "materialization-config-form", children: [
/* @__PURE__ */ a("div", { className: "config-form-header", children: [
/* @__PURE__ */ e("span", { children: "Edit Materialization Config" }),
/* @__PURE__ */ e(
"button",
{
className: "config-close-btn",
type: "button",
onClick: () => ie(!1),
children: "×"
}
)
] }),
/* @__PURE__ */ a("div", { className: "config-form-body", children: [
/* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Strategy" }),
/* @__PURE__ */ a("div", { className: "config-form-options", children: [
/* @__PURE__ */ a("label", { className: "radio-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "radio",
name: "cube-strategy",
value: "full",
checked: R.strategy === "full",
onChange: (l) => K((n) => ({
...n,
strategy: l.target.value
}))
}
),
/* @__PURE__ */ e("span", { children: "Full" })
] }),
/* @__PURE__ */ a("label", { className: "radio-option", children: [
/* @__PURE__ */ e(
"input",
{
type: "radio",
name: "cube-strategy",
value: "incremental_time",
checked: R.strategy === "incremental_time",
onChange: (l) => K((n) => ({
...n,
strategy: l.target.value
}))
}
),
/* @__PURE__ */ e("span", { children: "Incremental (Time)" })
] })
] })
] }),
/* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Schedule (cron)" }),
/* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input",
placeholder: "0 6 * * * (daily at 6am)",
value: R.schedule,
onChange: (l) => K((n) => ({
...n,
schedule: l.target.value
}))
}
)
] }),
R.strategy === "incremental_time" && /* @__PURE__ */ a("div", { className: "config-form-row", children: [
/* @__PURE__ */ e("label", { className: "config-form-label", children: "Lookback Window" }),
/* @__PURE__ */ e(
"input",
{
type: "text",
className: "config-form-input",
placeholder: "3 days",
value: R.lookbackWindow,
onChange: (l) => K((n) => ({
...n,
lookbackWindow: l.target.value
}))
}
)
] })
] }),
/* @__PURE__ */ a("div", { className: "config-form-actions", children: [
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-secondary",
type: "button",
onClick: () => ie(!1),
children: "Cancel"
}
),
/* @__PURE__ */ e(
"button",
{
className: "action-btn action-btn-primary",
type: "button",
disabled: De,
onClick: async () => {
Te(!0);
try {
ue && await ue(R), ie(!1);
} catch (l) {
console.error("Failed to save cube config:", l);
}
Te(!1);
},
children: De ? /* @__PURE__ */ a(S, { children: [
/* @__PURE__ */ e("span", { className: "spinner" }),
" Saving..."
] }) : "Save"
}
)
] })
] })
) : (
/* Cube Summary View - matches pre-agg expandable pattern */
/* @__PURE__ */ a(S, { children: [
/* @__PURE__ */ a("div", { className: "preagg-summary-header", children: [
/* @__PURE__ */ e("span", { className: "preagg-summary-name cube-name", children: (m == null ? void 0 : m.druidDatasource) || (J ? `dj__${J.replace(/\./g, "_")}` : "dj__cube") }),
/* @__PURE__ */ e("span", { className: "status-pill status-active", children: "● Active" })
] }),
/* @__PURE__ */ a(
"div",
{
className: "materialization-header clickable",
onClick: () => Se((l) => ({ ...l, cube: !l.cube })),
children: [
/* @__PURE__ */ a("div", { className: "materialization-status", children: [
/* @__PURE__ */ e(
"span",
{
className: "status-indicator status-materialized",
style: { color: "#059669" },
children: "●"
}
),
/* @__PURE__ */ e("span", { className: "status-text", children: "Workflow active" }),
(m == null ? void 0 : m.schedule) && /* @__PURE__ */ a(S, { children: [
/* @__PURE__ */ e("span", { className: "status-separator", children: "|" }),
/* @__PURE__ */ e("span", { className: "schedule-summary", children: Ge(m.schedule) })
] })
] }),
/* @__PURE__ */ e(
"button",
{
className: "expand-toggle",
type: "button",
"aria-label": le.cube ? "Collapse" : "Expand",
children: le.cube ? "▲" : "▼"
}
)
]
}
),
le.cube && /* @__PURE__ */ a("div", { className: "materialization-details", children: [
/* @__PURE__ */ a("div", { className: "materialization-config", children: [
/* @__PURE__ */ a("div", { className: "config-row", children: [
/* @__PURE__ */ e("span", { className: "config-label", children: "Strategy:" }),
/* @__PURE__ */ e("span", { className: "config-value", children: (m == null ? void 0 : m.strategy) === "incremental_time" ? "Incremental (Time-based)" : (m == null ? void 0 : m.strategy) === "full" ? "Full" : (m == null ? void 0 : m.strategy) || "Not set" })
] }),
(m == null ? void 0 : m.schedule) && /* @__PURE__ */ a("div", { className: "config-row", children: [
/* @__PURE__ */ e("span", { className: "config-label", children: "Schedule:" }),
/* @__PURE__ */ e("span", { className: "config-value config-mono", children: m.schedule })
] }),
(m == null ? void 0 : m.lookbackWindow) && /* @__PURE__ */ a("div", { className: "config-row", children: [
/* @__PURE__ */ e("span", { className: "config-label", children: "Lookback:" }),
/* @__PURE__ */ e("span", { className: "config-value", children: m.lookbackWindow })
] }),
/* @__PURE__ */ a("div", { className: "config-row", children: [
/* @__PURE__ */ e("span", { className: "config-label", children: "Dependencies:" }),
/* @__PURE__ */ a("span", { className: "config-value", children: [
((He = m == null ? void 0 : m.preaggTables) == null ? void 0 : He.length) || Object.keys(N).length || me.length,
" ",
"pre-agg(s)"
] })