UNPKG

drizzle-cube

Version:

Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.

1,517 lines (1,515 loc) 758 kB
import { jsxs as E, jsx as u, Fragment as Ee } from "react/jsx-runtime"; import * as qt from "react"; import Q, { createContext as Wc, useContext as Sr, Component as Kx, useRef as ue, useState as Z, useEffect as ce, useLayoutEffect as by, forwardRef as un, useMemo as ke, useImperativeHandle as vy, useCallback as J, memo as Te } from "react"; import { useCubeQuery as Qx, useDebounce as Xx, useFilterValues as Zx, useResponsiveDashboard as Jx } from "../hooks.js"; import { F as Er, I as Pe, d as e0, a as t0, b as r0, c as n0, e as s0, f as a0, g as i0, h as o0, i as l0, j as c0, k as d0, l as u0, m as f0, n as m0, o as h0, p as xy, q as p0, r as g0, s as y0, t as b0, u as v0, v as x0, w as w0, x as N0, y as _0, z as wy, A as Ny, B as en, C as S0, D as E0, E as je, G as Ld, H as gr, J as Wt, K as Nc, L as ze, M as tt, N as C0, O as it, P as _c, Q as Sc, R as k0, S as _y, T as zt, U as $d, V as T0, W as Bt, X as A0, Y as Sy, Z as tn, _ as R0, $ as Vd, a0 as Ec, a1 as M0, a2 as D0, a3 as Cc, a4 as q0, a5 as I0 } from "./icons-a6fQwcor.js"; import { u as ct } from "./providers-DONuYrGH.js"; import { i as St, b as zd, d as O0, e as Bd, t as F0, g as P0, h as L0, j as Dr, l as $0, k as V0, m as Ey, n as z0, p as Hd, C as jd, o as Gd, q as Cy, r as kc, s as Ud, u as zn, v as B0, w as H0, x as j0, D as ky, T as G0, a as U0, R as W0, S as Y0, P as K0, A as Q0, L as X0, B as Z0 } from "./charts-P7xq59Tl.js"; import J0 from "react-grid-layout"; import { createPortal as ew } from "react-dom"; var Tc = /* @__PURE__ */ new Map(), qr = /* @__PURE__ */ new WeakMap(), Wd = 0, tw; function rw(e) { return e ? (qr.has(e) || (Wd += 1, qr.set(e, Wd.toString())), qr.get(e)) : "0"; } function nw(e) { return Object.keys(e).sort().filter( (t) => e[t] !== void 0 ).map((t) => `${t}_${t === "root" ? rw(e.root) : e[t]}`).toString(); } function sw(e) { const t = nw(e); let r = Tc.get(t); if (!r) { const n = /* @__PURE__ */ new Map(); let s; const a = new IntersectionObserver((i) => { i.forEach((o) => { var c; const d = o.isIntersecting && s.some((l) => o.intersectionRatio >= l); e.trackVisibility && typeof o.isVisible > "u" && (o.isVisible = d), (c = n.get(o.target)) == null || c.forEach((l) => { l(d, o); }); }); }, e); s = a.thresholds || (Array.isArray(e.threshold) ? e.threshold : [e.threshold || 0]), r = { id: t, observer: a, elements: n }, Tc.set(t, r); } return r; } function aw(e, t, r = {}, n = tw) { if (typeof window.IntersectionObserver > "u" && n !== void 0) { const c = e.getBoundingClientRect(); return t(n, { isIntersecting: n, target: e, intersectionRatio: typeof r.threshold == "number" ? r.threshold : 0, time: 0, boundingClientRect: c, intersectionRect: c, rootBounds: c }), () => { }; } const { id: s, observer: a, elements: i } = sw(r), o = i.get(e) || []; return i.has(e) || i.set(e, o), o.push(t), a.observe(e), function() { o.splice(o.indexOf(t), 1), o.length === 0 && (i.delete(e), a.unobserve(e)), i.size === 0 && (a.disconnect(), Tc.delete(s)); }; } function iw({ threshold: e, delay: t, trackVisibility: r, rootMargin: n, root: s, triggerOnce: a, skip: i, initialInView: o, fallbackInView: c, onChange: d } = {}) { var l; const [f, m] = qt.useState(null), h = qt.useRef(d), g = qt.useRef(o), [y, p] = qt.useState({ inView: !!o, entry: void 0 }); h.current = d, qt.useEffect( () => { if (g.current === void 0 && (g.current = o), i || !f) return; let N; return N = aw( f, (A, x) => { const k = g.current; g.current = A, !(k === void 0 && !A) && (p({ inView: A, entry: x }), h.current && h.current(A, x), x.isIntersecting && a && N && (N(), N = void 0)); }, { root: s, rootMargin: n, threshold: e, // @ts-expect-error trackVisibility: r, delay: t }, c ), () => { N && N(); }; }, // We break the rule here, because we aren't including the actual `threshold` variable // eslint-disable-next-line react-hooks/exhaustive-deps [ // If the threshold is an array, convert it to a string, so it won't change between renders. Array.isArray(e) ? e.toString() : e, f, s, n, a, i, r, c, t ] ); const b = (l = y.entry) == null ? void 0 : l.target, v = qt.useRef(void 0); !f && b && !a && !i && v.current !== b && (v.current = b, p({ inView: !!o, entry: void 0 }), g.current = o); const _ = [m, y.inView, y.entry]; return _.ref = _[0], _.inView = _[1], _.entry = _[2], _; } const Ty = Wc(null), Ay = Ty.Provider, ow = () => Sr(Ty); class lw extends Kx { constructor(t) { super(t), this.state = { hasError: !1, error: null, errorInfo: null }; } static getDerivedStateFromError(t) { return { hasError: !0, error: t, errorInfo: null }; } componentDidCatch(t, r) { this.setState({ error: t, errorInfo: r.componentStack || null }), console.error("Chart Error Boundary caught a rendering error:", t, r); } handleReset = () => { this.setState({ hasError: !1, error: null, errorInfo: null }); }; render() { return this.state.hasError ? this.props.fallback ? this.props.fallback : /* @__PURE__ */ E( "div", { className: "flex flex-col items-center justify-center w-full h-full p-6 text-center border border-dashed rounded-lg", style: { borderColor: "var(--dc-border)", backgroundColor: "var(--dc-surface)" }, children: [ /* @__PURE__ */ u("div", { className: "h-12 w-12 mb-4 text-dc-text-muted", children: "⚠️" }), /* @__PURE__ */ u("h3", { className: "text-lg font-semibold mb-2 text-dc-text", children: this.props.portletTitle ? `Unable to render ${this.props.portletTitle}` : "Unable to render chart" }), /* @__PURE__ */ u("p", { className: "text-sm text-dc-text-secondary mb-4 max-w-md", children: "There was an error rendering this chart component. The error details are shown below." }), /* @__PURE__ */ u("div", { className: "w-full max-w-2xl mb-4", children: /* @__PURE__ */ E("div", { className: "bg-dc-surface-secondary rounded-lg p-3 text-left", children: [ /* @__PURE__ */ E("div", { className: "text-xs font-mono mb-2 text-dc-text", children: [ /* @__PURE__ */ u("strong", { children: "Error:" }), " ", this.state.error?.message ] }), this.state.error?.name && /* @__PURE__ */ E("div", { className: "text-xs font-mono text-dc-text-secondary mb-2", children: [ /* @__PURE__ */ u("strong", { children: "Type:" }), " ", this.state.error.name ] }), this.props.portletConfig && /* @__PURE__ */ E("details", { className: "text-xs font-mono text-dc-text-secondary mb-2", children: [ /* @__PURE__ */ u("summary", { className: "cursor-pointer", children: "Portlet Configuration" }), /* @__PURE__ */ u( "pre", { className: "mt-2 whitespace-pre-wrap p-2 rounded-sm overflow-auto max-h-32", style: { backgroundColor: "rgba(var(--dc-primary-rgb), 0.1)" }, children: JSON.stringify(this.props.portletConfig, null, 2) } ) ] }), this.props.cubeQuery && /* @__PURE__ */ E("details", { className: "text-xs font-mono text-dc-text-secondary mb-2", children: [ /* @__PURE__ */ u("summary", { className: "cursor-pointer", children: "Cube Query" }), /* @__PURE__ */ u( "pre", { className: "mt-2 whitespace-pre-wrap p-2 rounded-sm overflow-auto max-h-32", style: { backgroundColor: "#d1fae5" }, children: typeof this.props.cubeQuery == "string" ? JSON.stringify(JSON.parse(this.props.cubeQuery), null, 2) : JSON.stringify(this.props.cubeQuery, null, 2) } ) ] }), this.state.errorInfo && /* @__PURE__ */ E("details", { className: "text-xs font-mono text-dc-text-secondary", children: [ /* @__PURE__ */ u("summary", { className: "cursor-pointer", children: "Component Stack" }), /* @__PURE__ */ u("pre", { className: "mt-2 whitespace-pre-wrap", children: this.state.errorInfo }) ] }) ] }) }), /* @__PURE__ */ E( "button", { onClick: this.handleReset, className: "px-3 py-1 text-white rounded-sm text-sm hover:opacity-90 transition-opacity", style: { backgroundColor: "var(--dc-primary)" }, children: [ /* @__PURE__ */ u(Er, { style: { width: "16px", height: "16px", display: "inline", marginRight: "4px" } }), "Try Again" ] } ) ] } ) : this.props.children; } } const cw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: e0, className: e }), description: "Compare values across categories", useCase: "Best for comparing discrete categories, showing rankings, or displaying changes over time", dropZones: [ { key: "xAxis", label: "X-Axis (Categories)", description: "Dimensions and time dimensions for grouping", mandatory: !1, acceptTypes: ["dimension", "timeDimension"], emptyText: "Drop dimensions & time dimensions here" }, { key: "yAxis", label: "Y-Axis (Values)", description: "Measures for bar heights", mandatory: !0, acceptTypes: ["measure"], emptyText: "Drop measures here" }, { key: "series", label: "Series (Split into Multiple Series)", description: "Dimensions to create separate data series", mandatory: !1, acceptTypes: ["dimension"], emptyText: "Drop dimensions here to split data into series" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"], displayOptionsConfig: [ { key: "stackType", label: "Stacking", type: "select", defaultValue: "none", options: [ { value: "none", label: "None" }, { value: "normal", label: "Stacked" }, { value: "percent", label: "Stacked 100%" } ], description: "How to stack multiple bar series" }, { key: "target", label: "Target Values", type: "string", placeholder: "e.g., 100 or 50,75 for spread", description: "Single value or comma-separated values to spread across X-axis" } ] }, dw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: t0, className: e }), description: "Show trends and changes over time", useCase: "Best for continuous data, trends, time series, and showing relationships between multiple series", dropZones: [ { key: "xAxis", label: "X-Axis (Time/Categories)", description: "Time dimensions or dimensions for X-axis", mandatory: !0, acceptTypes: ["dimension", "timeDimension"], emptyText: "Drop time dimensions or dimensions here" }, { key: "yAxis", label: "Y-Axis (Values)", description: "Measures for line values", mandatory: !0, acceptTypes: ["measure"], emptyText: "Drop measures here" }, { key: "series", label: "Series (Multiple Lines)", description: "Dimensions to create separate lines", mandatory: !1, acceptTypes: ["dimension"], emptyText: "Drop dimensions here for multiple lines" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"], displayOptionsConfig: [ { key: "connectNulls", label: "Connect Nulls", type: "boolean", defaultValue: !1, description: "Draw continuous line through missing data points" }, { key: "target", label: "Target Values", type: "string", placeholder: "e.g., 100 or 50,75 for spread", description: "Single value or comma-separated values to spread across X-axis" } ] }, uw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: r0, className: e }), description: "Emphasize magnitude of change over time", useCase: "Best for showing cumulative totals, volume changes, or stacked comparisons over time", dropZones: [ { key: "xAxis", label: "X-Axis (Time/Categories)", description: "Time dimensions or dimensions for X-axis", mandatory: !0, acceptTypes: ["dimension", "timeDimension"], emptyText: "Drop time dimensions or dimensions here" }, { key: "yAxis", label: "Y-Axis (Values)", description: "Measures for area values", mandatory: !0, acceptTypes: ["measure"], emptyText: "Drop measures here" }, { key: "series", label: "Series (Stack Areas)", description: "Dimensions to create stacked areas", mandatory: !1, acceptTypes: ["dimension"], emptyText: "Drop dimensions here for stacked areas" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"], displayOptionsConfig: [ { key: "stackType", label: "Stacking", type: "select", defaultValue: "none", options: [ { value: "none", label: "None" }, { value: "normal", label: "Stacked" }, { value: "percent", label: "Stacked 100%" } ], description: "How to stack multiple area series" }, { key: "connectNulls", label: "Connect Nulls", type: "boolean", defaultValue: !1, description: "Draw continuous line through missing data points" }, { key: "target", label: "Target Values", type: "string", placeholder: "e.g., 100 or 50,75 for spread", description: "Single value or comma-separated values to spread across X-axis" } ] }, fw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: n0, className: e }), description: "Show proportions of a whole", useCase: "Best for showing percentage distribution or composition of a total (limit to 5-7 slices)", dropZones: [ { key: "xAxis", label: "Categories", description: "Dimension for pie slices", mandatory: !0, maxItems: 1, acceptTypes: ["dimension"], emptyText: "Drop a dimension for categories" }, { key: "yAxis", label: "Values", description: "Measure for slice sizes", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for values" } ], displayOptions: ["showLegend", "showTooltip", "hideHeader"] }, mw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: s0, className: e }), description: "Reveal correlations between variables", useCase: "Best for identifying patterns, correlations, outliers, and relationships between two measures", dropZones: [ { key: "xAxis", label: "X-Axis", description: "Measure or dimension for X position", mandatory: !0, maxItems: 1, acceptTypes: ["dimension", "timeDimension", "measure"], emptyText: "Drop a field for X-axis" }, { key: "yAxis", label: "Y-Axis", description: "Measure for Y position", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for Y-axis" }, { key: "series", label: "Series (Color Groups)", description: "Dimension to color points by category", mandatory: !1, maxItems: 1, acceptTypes: ["dimension"], emptyText: "Drop a dimension to color points" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"] }, hw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: a0, className: e }), description: "Compare three dimensions of data", useCase: "Best for showing relationships between three variables (X, Y, and size), market analysis", dropZones: [ { key: "xAxis", label: "X-Axis", description: "Horizontal axis position", mandatory: !0, maxItems: 1, acceptTypes: ["dimension", "timeDimension", "measure"], emptyText: "Drop a field for X-axis position" }, { key: "yAxis", label: "Y-Axis", description: "Vertical axis position", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for Y-axis position" }, { key: "sizeField", label: "Bubble Radius", description: "Size of bubbles based on this measure", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for bubble size" }, { key: "series", label: "Bubble Labels", description: "Field to use for bubble labels and identification", mandatory: !0, maxItems: 1, acceptTypes: ["dimension"], emptyText: "Drop a dimension for bubble labels" }, { key: "colorField", label: "Bubble Colour", description: "Color bubbles by this field (optional)", mandatory: !1, maxItems: 1, acceptTypes: ["dimension", "measure"], emptyText: "Drop a field for bubble color (optional)" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "minBubbleSize", "maxBubbleSize", "bubbleOpacity", "hideHeader"] }, pw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: i0, className: e }), description: "Compare multiple metrics across categories", useCase: "Best for multivariate comparisons, performance metrics, strengths/weaknesses analysis", dropZones: [ { key: "xAxis", label: "Axes (Categories)", description: "Dimensions for radar axes", mandatory: !0, acceptTypes: ["dimension"], emptyText: "Drop dimensions for radar axes" }, { key: "yAxis", label: "Values", description: "Measures for radar values", mandatory: !0, acceptTypes: ["measure"], emptyText: "Drop measures for values" }, { key: "series", label: "Series (Multiple Shapes)", description: "Dimensions to create multiple radar shapes", mandatory: !1, acceptTypes: ["dimension"], emptyText: "Drop dimensions for multiple shapes" } ], displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"] }, gw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: o0, className: e }), description: "Circular progress and KPI visualization", useCase: "Best for showing progress toward goals, KPIs, or comparing percentages in a compact form", dropZones: [ { key: "xAxis", label: "Categories", description: "Dimensions for radial segments", mandatory: !0, acceptTypes: ["dimension"], emptyText: "Drop dimensions for categories" }, { key: "yAxis", label: "Values", description: "Measures for radial bar lengths", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for values" } ], displayOptions: ["showLegend", "showTooltip", "hideHeader"] }, yw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: l0, className: e }), description: "Visualize hierarchical data with nested rectangles", useCase: "Best for showing part-to-whole relationships in hierarchical data, disk usage, budget allocation", dropZones: [ { key: "xAxis", label: "Categories", description: "Dimensions for treemap rectangles", mandatory: !0, acceptTypes: ["dimension"], emptyText: "Drop dimensions for categories" }, { key: "yAxis", label: "Size", description: "Measure for rectangle sizes", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for size" }, { key: "series", label: "Color Groups", description: "Dimension to color rectangles by category", mandatory: !1, maxItems: 1, acceptTypes: ["dimension"], emptyText: "Drop a dimension for color grouping" } ], displayOptions: ["showLegend", "showTooltip", "hideHeader"] }, bw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: c0, className: e }), description: "Display detailed tabular data", useCase: "Best for precise values, detailed analysis, sortable/filterable data exploration", dropZones: [ { key: "xAxis", label: "Columns", description: "All fields to display as columns", mandatory: !1, acceptTypes: ["dimension", "timeDimension", "measure"], emptyText: "Drop fields to display as columns (or leave empty for all)" } ], displayOptions: ["hideHeader"] }, vw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: d0, className: e }), description: "GitHub-style activity grid showing temporal patterns across different time scales", useCase: "Best for visualizing activity patterns over time. Supports hour (3hr blocks × days), day (days × weeks), week (weeks × months), month (months × quarters), and quarter (quarters × years) granularities", dropZones: [ { key: "dateField", label: "Time Dimension", description: "Time field that determines grid structure (granularity affects layout)", mandatory: !0, maxItems: 1, acceptTypes: ["timeDimension"], emptyText: "Drop a time dimension (granularity affects grid structure)" }, { key: "valueField", label: "Activity Measure", description: "Measure used for activity intensity (color coding)", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure for activity intensity" } ], displayOptions: ["showLabels", "showTooltip", "hideHeader"], displayOptionsConfig: [ { key: "fitToWidth", label: "Fit to Width", type: "boolean", defaultValue: !1, description: "Automatically size blocks to fill portlet width and height while maintaining aspect ratio" } ], validate: (e) => { const { dateField: t, valueField: r } = e; return !t || Array.isArray(t) && t.length === 0 ? { isValid: !1, message: "Time dimension is required for activity grid" } : !r || Array.isArray(r) && r.length === 0 ? { isValid: !1, message: "Activity measure is required for intensity mapping" } : { isValid: !0 }; } }, xw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: u0, className: e }), description: "Display key performance indicators as large numbers", useCase: "Perfect for showing important metrics like revenue, user count, or other key business metrics in a prominent, easy-to-read format", dropZones: [ { key: "yAxis", label: "Value", description: "Measure to display as KPI number", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure here" } ], displayOptionsConfig: [ { key: "target", label: "Target Value", type: "string", placeholder: "e.g., 100", description: "Target value to compare against (first value used if multiple provided)" }, { key: "prefix", label: "Prefix", type: "string", placeholder: "e.g., $, €, #", description: "Text to display before the number" }, { key: "suffix", label: "Suffix", type: "string", placeholder: "e.g., %, units, items", description: "Text to display after the number" }, { key: "decimals", label: "Decimal Places", type: "number", defaultValue: 0, min: 0, max: 10, step: 1, description: "Number of decimal places to display" }, { key: "valueColorIndex", label: "Value Color", type: "paletteColor", defaultValue: 0, description: "Color from the dashboard palette for the KPI value text" }, { key: "useLastCompletePeriod", label: "Use Last Complete Period", type: "boolean", defaultValue: !0, description: "Exclude current incomplete period from aggregation (e.g., partial week/month)" }, { key: "skipLastPeriod", label: "Skip Last Period", type: "boolean", defaultValue: !1, description: "Always exclude the last period regardless of completeness" } ], displayOptions: ["hideHeader"] }, ww = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: f0, className: e }), description: "Display change between latest and previous values with trend indicators", useCase: "Perfect for showing performance changes over time, such as revenue growth, user acquisition changes, or other metrics where the trend and delta are more important than the absolute value", dropZones: [ { key: "yAxis", label: "Value", description: "Measure to track changes for", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure here" }, { key: "xAxis", label: "Dimension (optional)", description: "Dimension for ordering data (typically time)", mandatory: !1, maxItems: 1, acceptTypes: ["dimension", "timeDimension"], emptyText: "Drop a dimension for ordering" } ], displayOptionsConfig: [ { key: "prefix", label: "Prefix", type: "string", placeholder: "e.g., $, €, #", description: "Text to display before the number" }, { key: "suffix", label: "Suffix", type: "string", placeholder: "e.g., %, units, items", description: "Text to display after the number" }, { key: "decimals", label: "Decimal Places", type: "number", defaultValue: 1, min: 0, max: 10, step: 1, description: "Number of decimal places to display" }, { key: "positiveColorIndex", label: "Positive Change Color", type: "paletteColor", defaultValue: 2, // Typically green in most palettes description: "Color for positive changes (increases)" }, { key: "negativeColorIndex", label: "Negative Change Color", type: "paletteColor", defaultValue: 3, // Typically red in most palettes description: "Color for negative changes (decreases)" }, { key: "showHistogram", label: "Show Variance Histogram", type: "boolean", defaultValue: !0, description: "Display historical variance chart below the delta" }, { key: "useLastCompletePeriod", label: "Use Last Complete Period", type: "boolean", defaultValue: !0, description: "Exclude current incomplete period from delta calculation (e.g., partial week/month)" }, { key: "skipLastPeriod", label: "Skip Last Period", type: "boolean", defaultValue: !1, description: "Always exclude the last period regardless of completeness" } ], displayOptions: ["hideHeader"], validate: (e) => !e.yAxis || Array.isArray(e.yAxis) && e.yAxis.length === 0 ? { isValid: !1, message: "A measure is required for KPI Delta charts" } : { isValid: !0 } }, Nw = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: m0, className: e }), description: "Display key performance indicators as customizable text", useCase: "Perfect for showing metrics with custom formatting, combining multiple values, or displaying contextual KPI information using templates", dropZones: [ { key: "yAxis", label: "Value", description: "Measure to display in the KPI text template", mandatory: !0, maxItems: 1, acceptTypes: ["measure"], emptyText: "Drop a measure here" } ], displayOptionsConfig: [ { key: "template", label: "Text Template", type: "string", placeholder: "e.g., Total Revenue: ${value}", description: "Template for displaying the text. Use ${value} to insert the measure value." }, { key: "decimals", label: "Decimal Places", type: "number", defaultValue: 0, min: 0, max: 10, step: 1, description: "Number of decimal places to display for numeric values" }, { key: "valueColorIndex", label: "Value Color", type: "paletteColor", defaultValue: 0, description: "Color from the dashboard palette for the KPI value text" } ], displayOptions: ["hideHeader"] }, _w = { icon: ({ className: e }) => /* @__PURE__ */ u(Pe, { icon: h0, className: e }), description: "Display custom markdown content with formatting", useCase: "Perfect for adding documentation, notes, instructions, or formatted text to dashboards", skipQuery: !0, // This chart doesn't require a valid query dropZones: [], // No drop zones needed for markdown content displayOptionsConfig: [ { key: "content", label: "Markdown Content", type: "string", placeholder: `# Welcome Add your **markdown** content here: - Lists with bullets - [Links](https://example.com) - *Italic* and **bold** text`, description: "Enter markdown text. Supports headers (#), bold (**text**), italic (*text*), links ([text](url)), and lists (- item)." }, { key: "accentColorIndex", label: "Accent Color", type: "paletteColor", defaultValue: 0, description: "Color from the dashboard palette for headers, bullets, and links" }, { key: "fontSize", label: "Font Size", type: "select", defaultValue: "medium", options: [ { value: "small", label: "Small" }, { value: "medium", label: "Medium" }, { value: "large", label: "Large" } ], description: "Overall text size for the markdown content" }, { key: "alignment", label: "Text Alignment", type: "select", defaultValue: "left", options: [ { value: "left", label: "Left" }, { value: "center", label: "Center" }, { value: "right", label: "Right" } ], description: "Horizontal alignment of the markdown content" } ], displayOptions: ["hideHeader"] }, yr = { bar: cw, line: dw, area: uw, pie: fw, scatter: mw, bubble: hw, radar: pw, radialBar: gw, treemap: yw, table: bw, activityGrid: vw, kpiNumber: xw, kpiDelta: ww, kpiText: Nw, markdown: _w }, Sw = { dropZones: [ { key: "xAxis", label: "X-Axis (Categories)", description: "Dimensions and time dimensions for grouping", mandatory: !1, acceptTypes: ["dimension", "timeDimension"], emptyText: "Drop dimensions & time dimensions here" }, { key: "yAxis", label: "Y-Axis (Values)", description: "Measures for values or dimensions for series", mandatory: !1, acceptTypes: ["measure", "dimension"], emptyText: "Drop measures or dimensions here" }, { key: "series", label: "Series (Split into Multiple Series)", description: "Dimensions to create separate data series", mandatory: !1, acceptTypes: ["dimension"], emptyText: "Drop dimensions here to split data into series" } ], displayOptions: ["showLegend", "showGrid", "showTooltip"] }; function Yc(e, t) { return t[e] || Sw; } function Yd(e, t) { let r, n; if (t === void 0) for (const s of e) s != null && (r === void 0 ? s >= s && (r = n = s) : (r > s && (r = s), n < s && (n = s))); else { let s = -1; for (let a of e) (a = t(a, ++s, e)) != null && (r === void 0 ? a >= a && (r = n = a) : (r > a && (r = a), n < a && (n = a))); } return [r, n]; } function Ac(e, t) { let r; if (t === void 0) for (const n of e) n != null && (r < n || r === void 0 && n >= n) && (r = n); else { let n = -1; for (let s of e) (s = t(s, ++n, e)) != null && (r < s || r === void 0 && s >= s) && (r = s); } return r; } function Kd(e, t) { let r; if (t === void 0) for (const n of e) n != null && (r > n || r === void 0 && n >= n) && (r = n); else { let n = -1; for (let s of e) (s = t(s, ++n, e)) != null && (r > s || r === void 0 && s >= s) && (r = s); } return r; } function Ew(e) { return e; } var Bn = 1, Hn = 2, Rc = 3, ur = 4, Qd = 1e-6; function Cw(e) { return "translate(" + e + ",0)"; } function kw(e) { return "translate(0," + e + ")"; } function Tw(e) { return (t) => +e(t); } function Aw(e, t) { return t = Math.max(0, e.bandwidth() - t * 2) / 2, e.round() && (t = Math.round(t)), (r) => +e(r) + t; } function Rw() { return !this.__axis; } function Ry(e, t) { var r = [], n = null, s = null, a = 6, i = 6, o = 3, c = typeof window < "u" && window.devicePixelRatio > 1 ? 0 : 0.5, d = e === Bn || e === ur ? -1 : 1, l = e === ur || e === Hn ? "x" : "y", f = e === Bn || e === Rc ? Cw : kw; function m(h) { var g = n ?? (t.ticks ? t.ticks.apply(t, r) : t.domain()), y = s ?? (t.tickFormat ? t.tickFormat.apply(t, r) : Ew), p = Math.max(a, 0) + o, b = t.range(), v = +b[0] + c, _ = +b[b.length - 1] + c, N = (t.bandwidth ? Aw : Tw)(t.copy(), c), A = h.selection ? h.selection() : h, x = A.selectAll(".domain").data([null]), k = A.selectAll(".tick").data(g, t).order(), T = k.exit(), S = k.enter().append("g").attr("class", "tick"), C = k.select("line"), M = k.select("text"); x = x.merge(x.enter().insert("path", ".tick").attr("class", "domain").attr("stroke", "currentColor")), k = k.merge(S), C = C.merge(S.append("line").attr("stroke", "currentColor").attr(l + "2", d * a)), M = M.merge(S.append("text").attr("fill", "currentColor").attr(l, d * p).attr("dy", e === Bn ? "0em" : e === Rc ? "0.71em" : "0.32em")), h !== A && (x = x.transition(h), k = k.transition(h), C = C.transition(h), M = M.transition(h), T = T.transition(h).attr("opacity", Qd).attr("transform", function(F) { return isFinite(F = N(F)) ? f(F + c) : this.getAttribute("transform"); }), S.attr("opacity", Qd).attr("transform", function(F) { var I = this.parentNode.__axis; return f((I && isFinite(I = I(F)) ? I : N(F)) + c); })), T.remove(), x.attr("d", e === ur || e === Hn ? i ? "M" + d * i + "," + v + "H" + c + "V" + _ + "H" + d * i : "M" + c + "," + v + "V" + _ : i ? "M" + v + "," + d * i + "V" + c + "H" + _ + "V" + d * i : "M" + v + "," + c + "H" + _), k.attr("opacity", 1).attr("transform", function(F) { return f(N(F) + c); }), C.attr(l + "2", d * a), M.attr(l, d * p).text(y), A.filter(Rw).attr("fill", "none").attr("font-size", 10).attr("font-family", "sans-serif").attr("text-anchor", e === Hn ? "start" : e === ur ? "end" : "middle"), A.each(function() { this.__axis = N; }); } return m.scale = function(h) { return arguments.length ? (t = h, m) : t; }, m.ticks = function() { return r = Array.from(arguments), m; }, m.tickArguments = function(h) { return arguments.length ? (r = h == null ? [] : Array.from(h), m) : r.slice(); }, m.tickValues = function(h) { return arguments.length ? (n = h == null ? null : Array.from(h), m) : n && n.slice(); }, m.tickFormat = function(h) { return arguments.length ? (s = h, m) : s; }, m.tickSize = function(h) { return arguments.length ? (a = i = +h, m) : a; }, m.tickSizeInner = function(h) { return arguments.length ? (a = +h, m) : a; }, m.tickSizeOuter = function(h) { return arguments.length ? (i = +h, m) : i; }, m.tickPadding = function(h) { return arguments.length ? (o = +h, m) : o; }, m.offset = function(h) { return arguments.length ? (c = +h, m) : c; }, m; } function Xd(e) { return Ry(Rc, e); } function Zd(e) { return Ry(ur, e); } var Mw = { value: () => { } }; function fn() { for (var e = 0, t = arguments.length, r = {}, n; e < t; ++e) { if (!(n = arguments[e] + "") || n in r || /[\s.]/.test(n)) throw new Error("illegal type: " + n); r[n] = []; } return new Wr(r); } function Wr(e) { this._ = e; } function Dw(e, t) { return e.trim().split(/^|\s+/).map(function(r) { var n = "", s = r.indexOf("."); if (s >= 0 && (n = r.slice(s + 1), r = r.slice(0, s)), r && !t.hasOwnProperty(r)) throw new Error("unknown type: " + r); return { type: r, name: n }; }); } Wr.prototype = fn.prototype = { constructor: Wr, on: function(e, t) { var r = this._, n = Dw(e + "", r), s, a = -1, i = n.length; if (arguments.length < 2) { for (; ++a < i; ) if ((s = (e = n[a]).type) && (s = qw(r[s], e.name))) return s; return; } if (t != null && typeof t != "function") throw new Error("invalid callback: " + t); for (; ++a < i; ) if (s = (e = n[a]).type) r[s] = Jd(r[s], e.name, t); else if (t == null) for (s in r) r[s] = Jd(r[s], e.name, null); return this; }, copy: function() { var e = {}, t = this._; for (var r in t) e[r] = t[r].slice(); return new Wr(e); }, call: function(e, t) { if ((s = arguments.length - 2) > 0) for (var r = new Array(s), n = 0, s, a; n < s; ++n) r[n] = arguments[n + 2]; if (!this._.hasOwnProperty(e)) throw new Error("unknown type: " + e); for (a = this._[e], n = 0, s = a.length; n < s; ++n) a[n].value.apply(t, r); }, apply: function(e, t, r) { if (!this._.hasOwnProperty(e)) throw new Error("unknown type: " + e); for (var n = this._[e], s = 0, a = n.length; s < a; ++s) n[s].value.apply(t, r); } }; function qw(e, t) { for (var r = 0, n = e.length, s; r < n; ++r) if ((s = e[r]).name === t) return s.value; } function Jd(e, t, r) { for (var n = 0, s = e.length; n < s; ++n) if (e[n].name === t) { e[n] = Mw, e = e.slice(0, n).concat(e.slice(n + 1)); break; } return r != null && e.push({ name: t, value: r }), e; } var Mc = "http://www.w3.org/1999/xhtml"; const eu = { svg: "http://www.w3.org/2000/svg", xhtml: Mc, xlink: "http://www.w3.org/1999/xlink", xml: "http://www.w3.org/XML/1998/namespace", xmlns: "http://www.w3.org/2000/xmlns/" }; function mn(e) { var t = e += "", r = t.indexOf(":"); return r >= 0 && (t = e.slice(0, r)) !== "xmlns" && (e = e.slice(r + 1)), eu.hasOwnProperty(t) ? { space: eu[t], local: e } : e; } function Iw(e) { return function() { var t = this.ownerDocument, r = this.namespaceURI; return r === Mc && t.documentElement.namespaceURI === Mc ? t.createElement(e) : t.createElementNS(r, e); }; } function Ow(e) { return function() { return this.ownerDocument.createElementNS(e.space, e.local); }; } function My(e) { var t = mn(e); return (t.local ? Ow : Iw)(t); } function Fw() { } function Kc(e) { return e == null ? Fw : function() { return this.querySelector(e); }; } function Pw(e) { typeof e != "function" && (e = Kc(e)); for (var t = this._groups, r = t.length, n = new Array(r), s = 0; s < r; ++s) for (var a = t[s], i = a.length, o = n[s] = new Array(i), c, d, l = 0; l < i; ++l) (c = a[l]) && (d = e.call(c, c.__data__, l, a)) && ("__data__" in c && (d.__data__ = c.__data__), o[l] = d); return new Be(n, this._parents); } function Lw(e) { return e == null ? [] : Array.isArray(e) ? e : Array.from(e); } function $w() { return []; } function Dy(e) { return e == null ? $w : function() { return this.querySelectorAll(e); }; } function Vw(e) { return function() { return Lw(e.apply(this, arguments)); }; } function zw(e) { typeof e == "function" ? e = Vw(e) : e = Dy(e); for (var t = this._groups, r = t.length, n = [], s = [], a = 0; a < r; ++a) for (var i = t[a], o = i.length, c, d = 0; d < o; ++d) (c = i[d]) && (n.push(e.call(c, c.__data__, d, i)), s.push(c)); return new Be(n, s); } function qy(e) { return function() { return this.matches(e); }; } function Iy(e) { return function(t) { return t.matches(e); }; } var Bw = Array.prototype.find; function Hw(e) { return function() { return Bw.call(this.children, e); }; } function jw() { return this.firstElementChild; } function Gw(e) { return this.select(e == null ? jw : Hw(typeof e == "function" ? e : Iy(e))); } var Uw = Array.prototype.filter; function Ww() { return Array.from(this.children); } function Yw(e) { return function() { return Uw.call(this.children, e); }; } function Kw(e) { return this.selectAll(e == null ? Ww : Yw(typeof e == "function" ? e : Iy(e))); } function Qw(e) { typeof e != "function" && (e = qy(e)); for (var t = this._groups, r = t.length, n = new Array(r), s = 0; s < r; ++s) for (var a = t[s], i = a.length, o = n[s] = [], c, d = 0; d < i; ++d) (c = a[d]) && e.call(c, c.__data__, d, a) && o.push(c); return new Be(n, this._parents); } function Oy(e) { return new Array(e.length); } function Xw() { return new Be(this._enter || this._groups.map(Oy), this._parents); } function rn(e, t) { this.ownerDocument = e.ownerDocument, this.namespaceURI = e.namespaceURI, this._next = null, this._parent = e, this.__data__ = t; } rn.prototype = { constructor: rn, appendChild: function(e) { return this._parent.insertBefore(e, this._next); }, insertBefore: function(e, t) { return this._parent.insertBefore(e, t); }, querySelector: function(e) { return this._parent.querySelector(e); }, querySelectorAll: function(e) { return this._parent.querySelectorAll(e); } }; function Zw(e) { return function() { return e; }; } function Jw(e, t, r, n, s, a) { for (var i = 0, o, c = t.length, d = a.length; i < d; ++i) (o = t[i]) ? (o.__data__ = a[i], n[i] = o) : r[i] = new rn(e, a[i]); for (; i < c; ++i) (o = t[i]) && (s[i] = o); } function e1(e, t, r, n, s, a, i) { var o, c, d = /* @__PURE__ */ new Map(), l = t.length, f = a.length, m = new Array(l), h; for (o = 0; o < l; ++o) (c = t[o]) && (m[o] = h = i.call(c, c.__data__, o, t) + "", d.has(h) ? s[o] = c : d.set(h, c)); for (o = 0; o < f; ++o) h = i.call(e, a[o], o, a) + "", (c = d.get(h)) ? (n[o] = c, c.__data__ = a[o], d.delete(h)) : r[o] = new rn(e, a[o]); for (o = 0; o < l; ++o) (c = t[o]) && d.get(m[o]) === c && (s[o] = c); } function t1(e) { return e.__data__; } function r1(e, t) { if (!arguments.length) return Array.from(this, t1); var r = t ? e1 : Jw, n = this._parents, s = this._groups; typeof e != "function" && (e = Zw(e)); for (var a = s.length, i = new Array(a), o = new Array(a), c = new Array(a), d = 0; d < a; ++d) { var l = n[d], f = s[d], m = f.length, h = n1(e.call(l, l && l.__data__, d, n)), g = h.length, y = o[d] = new Array(g), p = i[d] = new Array(g), b = c[d] = new Array(m); r(l, f, y, p, b, h, t); for (var v = 0, _ = 0, N, A; v < g; ++v) if (N = y[v]) { for (v >= _ && (_ = v + 1); !(A = p[_]) && ++_ < g; ) ; N._next = A || null; } } return i = new Be(i, n), i._enter = o, i._exit = c, i; } function n1(e) { return typeof e == "object" && "length" in e ? e : Array.from(e); } function s1() { return new Be(this._exit || this._groups.map(Oy), this._parents); } function a1(e, t, r) { var n = this.enter(), s = this, a = this.exit(); return typeof e == "function" ? (n = e(n), n && (n = n.selection())) : n = n.append(e + ""), t != null && (s = t(s), s && (s = s.selection())), r == null ? a.remove() : r(a), n && s ? n.merge(s).order() : s; } function i1(e) { for (var t = e.selection ? e.selection() : e, r = this._groups, n = t._groups, s = r.length, a = n.length, i = Math.min(s, a), o = new Array(s), c = 0; c < i; ++c) for (var d = r[c], l = n[c], f = d.length, m = o[c] = new Array(f), h, g = 0; g < f; ++g) (h = d[g] || l[g]) && (m[g] = h); for (; c < s; ++c) o[c] = r[c]; return new Be(o, this._parents); } function o1() { for (var e = this._groups, t = -1, r = e.length; ++t < r; ) for (var n = e[t], s = n.length - 1, a = n[s], i; --s >= 0; ) (i = n[s]) && (a && i.compareDocumentPosition(a) ^ 4 && a.parentNode.insertBefore(i, a), a = i); return this; } function l1(e) { e || (e = c1); function t(f, m) { return f && m ? e(f.__data__, m.__data__) : !f - !m; } for (var r = this._groups, n = r.length, s = new Array(n), a = 0; a < n; ++a) { for (var i = r[a], o = i.length, c = s[a] = new Array(o), d, l = 0; l < o; ++l) (d = i[l]) && (c[l] = d); c.sort(t); } return new Be(s, this._parents).order(); } function c1(e, t) { return e < t ? -1 : e > t ? 1 : e >= t ? 0 : NaN; } function d1() { var e = arguments[0]; return arguments[0] = this, e.apply(null, arguments), this; } function u1() { return Array.from(this); } function f1() { for (var e = this._groups, t = 0, r = e.length; t < r; ++t) for (var n = e[t], s = 0, a = n.length; s < a; ++s) { var i = n[s]; if (i) return i; } return null; } function m1() { let e = 0; for (const t of this) ++e; return e; } function h1() { return !this.node(); } function p1(e) { for (var t = this._groups, r = 0, n = t.length; r < n; ++r) for (var s = t[r], a = 0, i = s.length, o; a < i; ++a) (o = s[a]) && e.call(o, o.__data__, a, s); return this; } function g1(e) { return function() { this.removeAttribute(e); }; } function y1(e) { return function() { this.removeAttributeNS(e.space, e.local); }; } function b1(e, t) { return function() { this.setAttribute(e, t); }; } function v1(e, t) { return function() { this.setAttributeNS(e.space, e.local, t); }; } function x1(e, t) { return function() { var r = t.apply(this, arguments); r == null ? this.removeAttribute(e) : this.setAttribute(e, r); }; } function w1(e, t) { return function() { var r = t.apply(this, arguments); r == null ? this.removeAttributeNS(e.space, e.local) : this.setAttributeNS(e.space, e.local, r); }; } function N1(e, t) { var r = mn(e); if (arguments.length < 2) { var n = this.node(); return r.local ? n.getAttributeNS(r.space, r.local) : n.getAttribute(r); } return this.each((t == null ? r.local ? y1 : g1 : typeof t == "function" ? r.local ? w1 : x1 : r.local ? v1 : b1)(r, t)); } function Fy(e) { return e.ownerDocument && e.ownerDocument.defaultView || e.document && e || e.defaultView; } function _1(e) { return function() { this.style.removeProperty(e); }; } function S1(e, t, r) { return function() { this.style.setProperty(e, t, r); }; } function E1(e, t, r) { return function() { var n = t.apply(this, arguments); n == null ? this.style.removeProperty(e) : this.style.setProperty(e, n, r); }; } function C1(e, t, r) { return arguments.length > 1 ? this.each((t == null ? _1 : typeof t == "function" ? E1 : S1)(e, t, r ?? "")) : Yt(this.node(), e); } function Yt(e, t) { return e.style.getPropertyValue(t) || Fy(e).getComputedStyle(e, null).getPropertyValue(t); } function k1(e) { return function() { delete this[e]; }; } function T1(e, t) { return function() { this[e] = t; }; } function A1(e, t) { return function() { var r = t.apply(this, arguments); r == null ? delete this[e] : this[e] = r; }; } function R1(e, t) { return arguments.length > 1 ? this.each((t == null ? k1 : typeof t == "function" ? A1 : T1)(e, t)) : this.node()[e]; } function Py(e) { return e.trim().split(/^|\s+/); } function Qc(e) { return e.classList || new Ly(e); } function Ly(e) { this._node = e, this._names = Py(e.getAttribute("class") || ""); } Ly.prototype = { add: function(e) { var t = this._names.indexOf(e); t < 0 && (this._names.push(e), this._node.setAttribute("class", this._names.join(" "))); }, remove: function(e) { var t = this._names.indexOf(e); t >= 0 && (this._names.splice(t, 1), this._node.setAttribute("class", this._names.join(" "))); }, contains: function(e) { return this._names.indexOf(e) >= 0; } }; function $y(e, t) { for (var r = Qc(e), n = -1, s = t.length; ++n < s; ) r.add(t[n]); } function Vy(e, t) { for (var r = Qc(e), n = -1, s = t.length; ++n < s; ) r.remove(t[n]); } function M1(e) { return function() { $y(this, e); }; } function D1(e) { return function() { Vy(this, e); }; } function q1(e, t) { return function() { (t.apply(this, arguments) ? $y : Vy)(this, e); }; } function I1(e, t) { var r = Py(e + ""); if (arguments.length < 2) { for (var n = Qc(this.node()), s = -1, a = r.length; ++s < a; ) if (!n.contains(r[s])) return !1; return !0; } return this.each((typeof t == "function" ? q1 : t ? M1 : D1)(r, t)); } function O1() { this.textContent = ""; } function F1(e) { return function() { this.textContent = e; }; } function P1(e) { return function() { var t = e.apply(this, arguments); this.textContent = t ?? ""; }; } function L1(e) { return arguments.length ? this.each(e == null ? O1 : (typeof e == "function" ? P1 : F1)(e)) : this.node().textContent; } function $1() { this.innerHTML = ""; } function V1(e) { return function() { this.innerHTML = e; }; } function z1(e) { return function() { var t = e.apply(this, arguments); this.innerHTML = t ?? ""; }; } function B1(e) { return arguments.length ? this.each(e == null ? $1 : (typeof e == "function" ? z1 : V1)(e)) : this.node().innerHTML; } function H1() { this.nextSibling && this.parentNode.appendChild(this); } function j1() { return this.each(H1); } function G1() { this.previousSibling && this.parentNode.insertBefore(this, this.parentNode.firstChild); }