{"version":3,"file":"index-CfXXlICc.cjs","sources":["../src/app/pages/QueryPlannerPage/SelectionPanel.jsx","../src/app/pages/QueryPlannerPage/ResultsView.jsx","../src/app/pages/QueryPlannerPage/index.jsx"],"sourcesContent":["import { useState, useMemo, useEffect, useRef, useCallback } from 'react';\n\nconst ENGINE_OPTIONS = [\n  { value: null, label: 'Auto' },\n  { value: 'druid', label: 'Druid' },\n  { value: 'trino', label: 'Trino' },\n];\n\n// MIME type used to carry a dimension name during drag-to-filter.\nconst DIM_DRAG_MIME = 'application/x-dj-dimension';\n\n// Append a filter expression onto an in-progress one, ANDing if non-empty.\nconst andAppend = (prev, expr) =>\n  (prev.trim() ? prev.trimEnd() + ' AND ' : '') + expr;\n\n/**\n * Label that clips the START under truncation, keeping the END visible:\n * \"…erience_f__cart_initiation\". Metric/dimension names share long common\n * prefixes, so a normal right-side ellipsis hides the only part that differs;\n * clipping the start surfaces the distinguishing tail. The text stays a single\n * node (the CSS direction trick puts the ellipsis on the left), so the full\n * value remains in the title tooltip and queryable by tests.\n */\nfunction TailLabel({ text }) {\n  return (\n    <span className=\"chip-label chip-label-clip\" title={text}>\n      <bdi className=\"chip-label-inner\">{text}</bdi>\n    </span>\n  );\n}\n\n/**\n * SelectionPanel - Browse and select metrics and dimensions\n * Features selected items as chips at the top for visibility\n * Includes cube preset loading for quick configuration\n */\nexport function SelectionPanel({\n  metrics,\n  selectedMetrics,\n  onMetricsChange,\n  dimensions,\n  selectedDimensions,\n  onDimensionsChange,\n  loading,\n  cubes = [],\n  onLoadCubePreset,\n  loadedCubeName = null, // Managed by parent for URL persistence\n  onClearSelection,\n  filters = [],\n  onFiltersChange,\n  selectedEngine = null,\n  onEngineChange,\n  onRunQuery,\n  canRunQuery = false,\n  queryLoading = false,\n  compatibleMetrics = null, // Set<string> of compatible metric names, or null if no filter\n}) {\n  const [metricsSearch, setMetricsSearch] = useState('');\n  const [dimensionsSearch, setDimensionsSearch] = useState('');\n  const [expandedNamespaces, setExpandedNamespaces] = useState(new Set());\n  const [expandedDimGroups, setExpandedDimGroups] = useState(new Set());\n  const [expandedRolePaths, setExpandedRolePaths] = useState(new Set());\n  const [showCubeDropdown, setShowCubeDropdown] = useState(false);\n  const [cubeSearch, setCubeSearch] = useState('');\n  const [metricsChipsExpanded, setMetricsChipsExpanded] = useState(false);\n  const [dimensionsChipsExpanded, setDimensionsChipsExpanded] = useState(false);\n  const [filterInput, setFilterInput] = useState('');\n  // Highlights the Filters section while a dimension is dragged over it.\n  const [filterDropActive, setFilterDropActive] = useState(false);\n  const [split1, setSplit1] = useState(35); // metrics / dims boundary (%)\n  const [split2, setSplit2] = useState(65); // dims / filters boundary (%)\n  const [split3, setSplit3] = useState(85); // filters / engine+run boundary (%)\n  const prevSearchRef = useRef('');\n  const cubeDropdownRef = useRef(null);\n  const metricsSearchRef = useRef(null);\n  const dimensionsSearchRef = useRef(null);\n  const filterInputRef = useRef(null);\n  const sectionsRef = useRef(null);\n  const dragRef = useRef(null);\n  const splitRef = useRef({ split1: 35, split2: 65, split3: 85 });\n  useEffect(() => {\n    splitRef.current = { split1, split2, split3 };\n  }, [split1, split2, split3]);\n\n  // Threshold for showing expand/collapse button\n  const CHIPS_COLLAPSE_THRESHOLD = 8;\n\n  // Find the loaded cube object from the name\n  const loadedCube = useMemo(() => {\n    if (!loadedCubeName) return null;\n    return (\n      cubes.find(c => c.name === loadedCubeName) || { name: loadedCubeName }\n    );\n  }, [loadedCubeName, cubes]);\n\n  // Close cube dropdown when clicking outside\n  useEffect(() => {\n    const handleClickOutside = event => {\n      if (\n        cubeDropdownRef.current &&\n        !cubeDropdownRef.current.contains(event.target)\n      ) {\n        setShowCubeDropdown(false);\n      }\n    };\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => document.removeEventListener('mousedown', handleClickOutside);\n  }, []);\n\n  // Filter cubes by search (GraphQL returns display_name)\n  const filteredCubes = useMemo(() => {\n    const search = cubeSearch.toLowerCase().trim();\n    if (!search) return cubes;\n    return cubes.filter(cube => {\n      const name = cube.name || '';\n      const displayName = cube.display_name || '';\n      return (\n        name.toLowerCase().includes(search) ||\n        displayName.toLowerCase().includes(search)\n      );\n    });\n  }, [cubes, cubeSearch]);\n\n  // Get short name from full metric name\n  const getShortName = fullName => {\n    const parts = fullName.split('.');\n    return parts[parts.length - 1];\n  };\n\n  // Get namespace from full metric name\n  const getNamespace = fullName => {\n    const parts = fullName.split('.');\n    return parts.length > 1 ? parts.slice(0, -1).join('.') : 'default';\n  };\n\n  // Group metrics by namespace (e.g., \"default.cube\" -> \"default\")\n  const groupedMetrics = useMemo(() => {\n    const groups = {};\n    metrics.forEach(metric => {\n      const namespace = getNamespace(metric);\n      if (!groups[namespace]) {\n        groups[namespace] = [];\n      }\n      groups[namespace].push(metric);\n    });\n    return groups;\n  }, [metrics]);\n\n  // Filter and sort namespaces/metrics by search relevance\n  const { filteredGroups, sortedNamespaces } = useMemo(() => {\n    const search = metricsSearch.trim().toLowerCase();\n\n    if (!search) {\n      const namespaces = Object.keys(groupedMetrics).sort();\n      return { filteredGroups: groupedMetrics, sortedNamespaces: namespaces };\n    }\n\n    const filtered = {};\n    Object.entries(groupedMetrics).forEach(([namespace, items]) => {\n      const matchingItems = items.filter(m => m.toLowerCase().includes(search));\n      if (matchingItems.length > 0) {\n        matchingItems.sort((a, b) => {\n          const aShort = getShortName(a).toLowerCase();\n          const bShort = getShortName(b).toLowerCase();\n          const aPrefix = aShort.startsWith(search);\n          const bPrefix = bShort.startsWith(search);\n          if (aPrefix && !bPrefix) return -1;\n          if (!aPrefix && bPrefix) return 1;\n          return aShort.localeCompare(bShort);\n        });\n        filtered[namespace] = matchingItems;\n      }\n    });\n\n    const namespaces = Object.keys(filtered).sort((a, b) => {\n      const aLower = a.toLowerCase();\n      const bLower = b.toLowerCase();\n      const aPrefix = aLower.startsWith(search);\n      const bPrefix = bLower.startsWith(search);\n      if (aPrefix && !bPrefix) return -1;\n      if (!aPrefix && bPrefix) return 1;\n      const aContains = aLower.includes(search);\n      const bContains = bLower.includes(search);\n      if (aContains && !bContains) return -1;\n      if (!aContains && bContains) return 1;\n      const aCount = filtered[a].length;\n      const bCount = filtered[b].length;\n      if (aCount !== bCount) return bCount - aCount;\n      return aLower.localeCompare(bLower);\n    });\n\n    return { filteredGroups: filtered, sortedNamespaces: namespaces };\n  }, [groupedMetrics, metricsSearch]);\n\n  // Auto-expand all matching namespaces when search changes\n  useEffect(() => {\n    const currentSearch = metricsSearch.trim();\n    const prevSearch = prevSearchRef.current;\n    if (currentSearch && currentSearch !== prevSearch) {\n      setExpandedNamespaces(new Set(sortedNamespaces));\n    }\n    prevSearchRef.current = currentSearch;\n  }, [metricsSearch, sortedNamespaces]);\n\n  // Dedupe dimensions by name, keeping shortest path per name\n  const dedupedDimensions = useMemo(() => {\n    const byName = new Map();\n    dimensions.forEach(d => {\n      if (!d.name) return;\n      const existing = byName.get(d.name);\n      if (\n        !existing ||\n        (d.path?.length || 0) < (existing.path?.length || Infinity)\n      ) {\n        byName.set(d.name, d);\n      }\n    });\n    return Array.from(byName.values());\n  }, [dimensions]);\n\n  // Extract role path from a dimension name, e.g. \"foo.bar[a->b->c]\" → \"a->b->c\" (or null)\n  const getRolePath = name => {\n    const match = name.match(/\\[([^\\]]+)\\]$/);\n    return match ? match[1] : null;\n  };\n\n  // Format a role path for display: \"a->b->c\" → \"via a → b → c\"\n  const formatRolePath = roleKey =>\n    roleKey ? 'via ' + roleKey.replace(/->/g, ' → ') : 'direct';\n\n  // Count hops in a role path string\n  const rolePathHops = roleKey => (roleKey ? roleKey.split('->').length : 0);\n\n  // Group dimensions by node, then by role path within each node\n  const groupedDimensions = useMemo(() => {\n    const search = dimensionsSearch.trim().toLowerCase();\n    const nodeMap = new Map();\n\n    dedupedDimensions.forEach(d => {\n      if (!d.name) return;\n      const nodeKey =\n        d.path?.length > 0\n          ? d.path[d.path.length - 1]\n          : d.name.split('.').slice(0, -1).join('.');\n      const distance = Math.max(0, d.path ? d.path.length - 1 : 0);\n      const roleKey = getRolePath(d.name); // e.g. \"title_deal_window->title\" or null\n\n      if (!nodeMap.has(nodeKey)) {\n        nodeMap.set(nodeKey, {\n          nodeKey,\n          minDistance: distance,\n          rolePathMap: new Map(),\n        });\n      }\n      const node = nodeMap.get(nodeKey);\n      node.minDistance = Math.min(node.minDistance, distance);\n\n      if (!node.rolePathMap.has(roleKey)) {\n        node.rolePathMap.set(roleKey, { roleKey, dimensions: [] });\n      }\n      node.rolePathMap.get(roleKey).dimensions.push(d);\n    });\n\n    let groupsArray = Array.from(nodeMap.values()).map(node => {\n      // Sort role paths: direct (null) first, then by hop count, then alphabetically\n      const rolePaths = Array.from(node.rolePathMap.values()).sort(\n        (a, b) =>\n          rolePathHops(a.roleKey) - rolePathHops(b.roleKey) ||\n          (a.roleKey || '').localeCompare(b.roleKey || ''),\n      );\n      // Sort dims within each role path alphabetically\n      rolePaths.forEach(rp => {\n        rp.dimensions.sort((a, b) => a.name.localeCompare(b.name));\n      });\n      return {\n        nodeKey: node.nodeKey,\n        minDistance: node.minDistance,\n        rolePaths,\n        totalCount: rolePaths.reduce((n, rp) => n + rp.dimensions.length, 0),\n      };\n    });\n\n    // Apply search: filter within role paths, prune empty role paths and nodes\n    if (search) {\n      groupsArray = groupsArray\n        .map(group => ({\n          ...group,\n          rolePaths: group.rolePaths\n            .map(rp => ({\n              ...rp,\n              dimensions: rp.dimensions.filter(d => {\n                const lower = d.name.toLowerCase();\n                return (\n                  lower.includes(search) ||\n                  d.name.split('.').pop().toLowerCase().includes(search)\n                );\n              }),\n            }))\n            .filter(\n              rp =>\n                rp.dimensions.length > 0 ||\n                (rp.roleKey || '').toLowerCase().includes(search),\n            ),\n        }))\n        .filter(\n          group =>\n            group.rolePaths.length > 0 ||\n            group.nodeKey.toLowerCase().includes(search),\n        )\n        .map(group => ({\n          ...group,\n          totalCount: group.rolePaths.reduce(\n            (n, rp) => n + rp.dimensions.length,\n            0,\n          ),\n        }));\n    }\n\n    // Sort node groups by distance, then alphabetically\n    groupsArray.sort(\n      (a, b) =>\n        a.minDistance - b.minDistance || a.nodeKey.localeCompare(b.nodeKey),\n    );\n\n    return groupsArray;\n  }, [dedupedDimensions, dimensionsSearch]);\n\n  // Auto-expand on first load and when searching\n  useEffect(() => {\n    if (groupedDimensions.length === 0) return;\n    if (dimensionsSearch.trim()) {\n      // Expand everything with matches\n      setExpandedDimGroups(new Set(groupedDimensions.map(g => g.nodeKey)));\n      setExpandedRolePaths(\n        new Set(\n          groupedDimensions.flatMap(g =>\n            g.rolePaths.map(rp => `${g.nodeKey}::${rp.roleKey}`),\n          ),\n        ),\n      );\n    } else {\n      // On first load: expand distance-0 node groups and their direct (null) role paths\n      setExpandedDimGroups(prev => {\n        if (prev.size > 0) return prev;\n        return new Set(\n          groupedDimensions\n            .filter(g => g.minDistance === 0)\n            .map(g => g.nodeKey),\n        );\n      });\n      setExpandedRolePaths(prev => {\n        if (prev.size > 0) return prev;\n        return new Set(\n          groupedDimensions\n            .filter(g => g.minDistance === 0)\n            .map(g => `${g.nodeKey}::null`),\n        );\n      });\n    }\n  }, [groupedDimensions, dimensionsSearch]);\n\n  // Get display name for dimension (last 2 segments)\n  const getDimDisplayName = fullName => {\n    const parts = (fullName || '').split('.');\n    return parts.slice(-2).join('.');\n  };\n\n  const toggleNamespace = namespace => {\n    setExpandedNamespaces(prev => {\n      const next = new Set(prev);\n      if (next.has(namespace)) {\n        next.delete(namespace);\n      } else {\n        next.add(namespace);\n      }\n      return next;\n    });\n  };\n\n  const toggleDimGroup = nodeKey => {\n    setExpandedDimGroups(prev => {\n      const next = new Set(prev);\n      if (next.has(nodeKey)) {\n        next.delete(nodeKey);\n      } else {\n        next.add(nodeKey);\n      }\n      return next;\n    });\n  };\n\n  const toggleRolePath = (nodeKey, roleKey) => {\n    const key = `${nodeKey}::${roleKey}`;\n    setExpandedRolePaths(prev => {\n      const next = new Set(prev);\n      if (next.has(key)) {\n        next.delete(key);\n      } else {\n        next.add(key);\n      }\n      return next;\n    });\n  };\n\n  const getDimGroupShortName = nodeKey => nodeKey.split('.').pop();\n\n  const handleDividerMouseDown = useCallback((e, divider) => {\n    e.preventDefault();\n    const startSplit =\n      divider === 1\n        ? splitRef.current.split1\n        : divider === 2\n        ? splitRef.current.split2\n        : splitRef.current.split3;\n    dragRef.current = { divider, startY: e.clientY, startSplit };\n  }, []);\n\n  useEffect(() => {\n    const onMouseMove = e => {\n      if (!dragRef.current || !sectionsRef.current) return;\n      const height = sectionsRef.current.getBoundingClientRect().height;\n      const deltaPct = ((e.clientY - dragRef.current.startY) / height) * 100;\n      const { divider, startSplit } = dragRef.current;\n      const { split1, split2, split3 } = splitRef.current;\n      if (divider === 1) {\n        setSplit1(Math.max(10, Math.min(split2 - 15, startSplit + deltaPct)));\n      } else if (divider === 2) {\n        setSplit2(\n          Math.max(split1 + 15, Math.min(split3 - 10, startSplit + deltaPct)),\n        );\n      } else {\n        setSplit3(Math.max(split2 + 10, Math.min(95, startSplit + deltaPct)));\n      }\n    };\n    const onMouseUp = () => {\n      dragRef.current = null;\n    };\n    window.addEventListener('mousemove', onMouseMove);\n    window.addEventListener('mouseup', onMouseUp);\n    return () => {\n      window.removeEventListener('mousemove', onMouseMove);\n      window.removeEventListener('mouseup', onMouseUp);\n    };\n  }, []);\n\n  const toggleMetric = metric => {\n    if (selectedMetrics.includes(metric)) {\n      onMetricsChange(selectedMetrics.filter(m => m !== metric));\n    } else {\n      onMetricsChange([...selectedMetrics, metric]);\n    }\n  };\n\n  const removeMetric = metric => {\n    onMetricsChange(selectedMetrics.filter(m => m !== metric));\n  };\n\n  const toggleDimension = dimName => {\n    if (selectedDimensions.includes(dimName)) {\n      onDimensionsChange(selectedDimensions.filter(d => d !== dimName));\n    } else {\n      onDimensionsChange([...selectedDimensions, dimName]);\n    }\n  };\n\n  const removeDimension = dimName => {\n    onDimensionsChange(selectedDimensions.filter(d => d !== dimName));\n  };\n\n  const selectAllInNamespace = (namespace, items) => {\n    const newSelection = [...new Set([...selectedMetrics, ...items])];\n    onMetricsChange(newSelection);\n  };\n\n  const deselectAllInNamespace = (namespace, items) => {\n    onMetricsChange(selectedMetrics.filter(m => !items.includes(m)));\n  };\n\n  const handleCubeSelect = cube => {\n    if (onLoadCubePreset) {\n      onLoadCubePreset(cube.name);\n    }\n    // loadedCubeName is now managed by parent via onLoadCubePreset\n    setShowCubeDropdown(false);\n    setCubeSearch('');\n  };\n\n  const clearSelection = () => {\n    if (onClearSelection) {\n      onClearSelection(); // Parent handles clearing metrics, dimensions, and cube\n    } else {\n      onMetricsChange([]);\n      onDimensionsChange([]);\n    }\n  };\n\n  const handleAddFilter = () => {\n    const trimmed = filterInput.trim();\n    if (trimmed && !filters.includes(trimmed) && onFiltersChange) {\n      onFiltersChange([...filters, trimmed]);\n      setFilterInput('');\n    }\n  };\n\n  const handleFilterKeyDown = e => {\n    if (e.key === 'Enter') {\n      e.preventDefault();\n      handleAddFilter();\n    }\n  };\n\n  const handleRemoveFilter = filterToRemove => {\n    if (onFiltersChange) {\n      onFiltersChange(filters.filter(f => f !== filterToRemove));\n    }\n  };\n\n  // Click a filter chip to edit it: pull it back into the input (preserving any\n  // in-progress text by ANDing onto it) and remove the chip.\n  const handleEditFilter = filter => {\n    setFilterInput(prev => andAppend(prev, filter));\n    if (onFiltersChange) {\n      onFiltersChange(filters.filter(f => f !== filter));\n    }\n    filterInputRef.current?.focus();\n  };\n\n  // Append a dimension to the filter input (ANDing onto any existing expression)\n  // then focus so the user can type the operator/value. Functional update keeps\n  // it correct whether called from a click or a drag-and-drop handler.\n  const appendDimToFilterInput = dimName => {\n    setFilterInput(prev => andAppend(prev, dimName + ' '));\n    filterInputRef.current?.focus();\n  };\n\n  const addDimAsFilter = (e, dimName) => {\n    e.preventDefault();\n    e.stopPropagation();\n    appendDimToFilterInput(dimName);\n  };\n\n  // Drag a dimension chip/row onto the Filters section to start filtering on it.\n  const handleDimDragStart = (e, dimName) => {\n    e.dataTransfer.setData(DIM_DRAG_MIME, dimName);\n    // Plain-text fallback so the drag has a sensible payload everywhere.\n    e.dataTransfer.setData('text/plain', dimName);\n    e.dataTransfer.effectAllowed = 'copy';\n  };\n\n  const handleFilterDragOver = e => {\n    if (e.dataTransfer.types.includes(DIM_DRAG_MIME)) {\n      e.preventDefault(); // allow drop\n      e.dataTransfer.dropEffect = 'copy';\n      if (!filterDropActive) setFilterDropActive(true);\n    }\n  };\n\n  const handleFilterDragLeave = e => {\n    // Ignore leaves into child elements of the filters section.\n    if (!e.currentTarget.contains(e.relatedTarget)) {\n      setFilterDropActive(false);\n    }\n  };\n\n  const handleFilterDrop = e => {\n    const dimName = e.dataTransfer.getData(DIM_DRAG_MIME);\n    if (dimName) {\n      e.preventDefault();\n      appendDimToFilterInput(dimName);\n    }\n    setFilterDropActive(false);\n  };\n\n  return (\n    <div className=\"selection-panel\">\n      {/* Cube Preset Dropdown */}\n      {cubes.length > 0 && (\n        <div className=\"cube-preset-section\" ref={cubeDropdownRef}>\n          <div className=\"preset-row\">\n            <button\n              className={`preset-button ${loadedCube ? 'has-preset' : ''}`}\n              onClick={() => setShowCubeDropdown(!showCubeDropdown)}\n            >\n              <span className=\"preset-icon\">{loadedCube ? '📦' : '📂'}</span>\n              <span className=\"preset-label\">\n                {loadedCube\n                  ? loadedCube.display_name ||\n                    (loadedCube.name\n                      ? loadedCube.name.split('.').pop()\n                      : 'Cube')\n                  : 'Load from Cube'}\n              </span>\n              <span className=\"dropdown-arrow\">\n                {showCubeDropdown ? '▲' : '▼'}\n              </span>\n            </button>\n            {(selectedMetrics.length > 0 || selectedDimensions.length > 0) && (\n              <button className=\"clear-all-btn\" onClick={clearSelection}>\n                Clear\n              </button>\n            )}\n          </div>\n\n          {showCubeDropdown && (\n            <div className=\"cube-dropdown\">\n              <input\n                type=\"text\"\n                className=\"cube-search\"\n                placeholder=\"Search cubes...\"\n                value={cubeSearch}\n                onChange={e => setCubeSearch(e.target.value)}\n                autoFocus\n              />\n              <div className=\"cube-list\">\n                {filteredCubes.length === 0 ? (\n                  <div className=\"cube-empty\">\n                    {cubeSearch\n                      ? 'No cubes match your search'\n                      : 'No cubes available'}\n                  </div>\n                ) : (\n                  filteredCubes.map(cube => (\n                    <button\n                      key={cube.name}\n                      className={`cube-option ${\n                        loadedCubeName === cube.name ? 'selected' : ''\n                      }`}\n                      onClick={() => handleCubeSelect(cube)}\n                    >\n                      <span className=\"cube-name\">\n                        {cube.display_name ||\n                          (cube.name ? cube.name.split('.').pop() : 'Unknown')}\n                      </span>\n                      <span className=\"cube-info\">{cube.name}</span>\n                      {loadedCubeName === cube.name && (\n                        <span className=\"cube-selected-icon\">✓</span>\n                      )}\n                    </button>\n                  ))\n                )}\n              </div>\n            </div>\n          )}\n        </div>\n      )}\n\n      {/* Resizable sections */}\n      <div className=\"resizable-sections\" ref={sectionsRef}>\n        {/* Metrics Section */}\n        <div className=\"selection-section\" style={{ flex: split1 }}>\n          <div className=\"section-header\">\n            <h3>Metrics</h3>\n            <span className=\"selection-count\">\n              {selectedMetrics.length} selected\n            </span>\n          </div>\n\n          {/* Combined Chips + Search Input */}\n          <div\n            className=\"combobox-input\"\n            onClick={() => metricsSearchRef.current?.focus()}\n          >\n            {selectedMetrics.length > 0 && (\n              <div\n                className={`combobox-chips ${\n                  selectedMetrics.length > CHIPS_COLLAPSE_THRESHOLD\n                    ? metricsChipsExpanded\n                      ? 'expanded'\n                      : 'collapsed'\n                    : ''\n                }`}\n              >\n                {selectedMetrics.map(metric => (\n                  <span key={metric} className=\"selected-chip metric-chip\">\n                    <TailLabel text={getShortName(metric)} />\n                    <button\n                      className=\"chip-remove\"\n                      onClick={e => {\n                        e.stopPropagation();\n                        removeMetric(metric);\n                      }}\n                      title={`Remove ${getShortName(metric)}`}\n                    >\n                      ×\n                    </button>\n                  </span>\n                ))}\n              </div>\n            )}\n            <div className=\"combobox-input-row\">\n              <input\n                ref={metricsSearchRef}\n                type=\"text\"\n                className=\"combobox-search\"\n                placeholder=\"Search metrics...\"\n                value={metricsSearch}\n                onChange={e => setMetricsSearch(e.target.value)}\n                onClick={e => e.stopPropagation()}\n              />\n              {selectedMetrics.length > CHIPS_COLLAPSE_THRESHOLD && (\n                <button\n                  className=\"combobox-action\"\n                  onClick={e => {\n                    e.stopPropagation();\n                    setMetricsChipsExpanded(!metricsChipsExpanded);\n                  }}\n                >\n                  {metricsChipsExpanded ? 'Show less' : 'Show all'}\n                </button>\n              )}\n              {selectedMetrics.length > 0 && (\n                <button\n                  className=\"combobox-action\"\n                  onClick={e => {\n                    e.stopPropagation();\n                    onMetricsChange([]);\n                  }}\n                >\n                  Clear\n                </button>\n              )}\n            </div>\n          </div>\n\n          <div className=\"selection-list\">\n            {sortedNamespaces.map(namespace => {\n              const items = filteredGroups[namespace];\n              const isExpanded = expandedNamespaces.has(namespace);\n              const selectedInNamespace = items.filter(m =>\n                selectedMetrics.includes(m),\n              ).length;\n\n              return (\n                <div key={namespace} className=\"namespace-group\">\n                  <div\n                    className=\"namespace-header\"\n                    onClick={() => toggleNamespace(namespace)}\n                  >\n                    <span className=\"expand-icon\">\n                      {isExpanded ? '▼' : '▶'}\n                    </span>\n                    <span className=\"namespace-name\">{namespace}</span>\n                    <span className=\"namespace-count\">\n                      {selectedInNamespace > 0 && (\n                        <span className=\"selected-badge\">\n                          {selectedInNamespace}\n                        </span>\n                      )}\n                      {items.length}\n                    </span>\n                  </div>\n\n                  {isExpanded && (\n                    <div className=\"namespace-items\">\n                      <div className=\"namespace-actions\">\n                        <button\n                          type=\"button\"\n                          className=\"select-all-btn\"\n                          onClick={() => selectAllInNamespace(namespace, items)}\n                        >\n                          Select all\n                        </button>\n                        <button\n                          type=\"button\"\n                          className=\"select-all-btn\"\n                          onClick={() =>\n                            deselectAllInNamespace(namespace, items)\n                          }\n                        >\n                          Clear\n                        </button>\n                      </div>\n                      {items.map(metric => {\n                        const isIncompatible =\n                          compatibleMetrics !== null &&\n                          !compatibleMetrics.has(metric) &&\n                          !selectedMetrics.includes(metric);\n                        return (\n                          <label\n                            key={metric}\n                            className={`selection-item${\n                              isIncompatible ? ' metric-incompatible' : ''\n                            }`}\n                            title={\n                              isIncompatible\n                                ? 'Not compatible with selected dimensions'\n                                : metric\n                            }\n                          >\n                            <input\n                              type=\"checkbox\"\n                              checked={selectedMetrics.includes(metric)}\n                              onChange={() => toggleMetric(metric)}\n                            />\n                            <span className=\"item-name\">\n                              {getShortName(metric)}\n                            </span>\n                            {compatibleMetrics !== null &&\n                              compatibleMetrics.has(metric) &&\n                              !selectedMetrics.includes(metric) && (\n                                <span\n                                  className=\"metric-compatible-badge\"\n                                  title=\"Compatible with selected dimensions\"\n                                >\n                                  ✓\n                                </span>\n                              )}\n                          </label>\n                        );\n                      })}\n                    </div>\n                  )}\n                </div>\n              );\n            })}\n\n            {sortedNamespaces.length === 0 && (\n              <div className=\"empty-list\">\n                {metricsSearch\n                  ? 'No metrics match your search'\n                  : 'No metrics available'}\n              </div>\n            )}\n          </div>\n        </div>\n\n        {/* Draggable Divider 1: metrics / dims */}\n        <div\n          className=\"section-divider draggable-divider\"\n          onMouseDown={e => handleDividerMouseDown(e, 1)}\n        />\n\n        {/* Dimensions Section */}\n        <div className=\"selection-section\" style={{ flex: split2 - split1 }}>\n          <div className=\"section-header\">\n            <h3>Dimensions</h3>\n            <span className=\"selection-count\">\n              {selectedDimensions.length} selected\n              {dimensions.length > 0 && ` / ${dimensions.length} available`}\n            </span>\n          </div>\n\n          {selectedMetrics.length === 0 ? (\n            <div className=\"empty-list hint\">\n              Select metrics to see available dimensions\n            </div>\n          ) : loading ? (\n            <div className=\"empty-list\">Loading dimensions...</div>\n          ) : (\n            <>\n              {/* Combined Chips + Search Input */}\n              <div\n                className=\"combobox-input\"\n                onClick={() => dimensionsSearchRef.current?.focus()}\n              >\n                {selectedDimensions.length > 0 && (\n                  <div\n                    className={`combobox-chips ${\n                      selectedDimensions.length > CHIPS_COLLAPSE_THRESHOLD\n                        ? dimensionsChipsExpanded\n                          ? 'expanded'\n                          : 'collapsed'\n                        : ''\n                    }`}\n                  >\n                    {selectedDimensions.map(dimName => (\n                      <span\n                        key={dimName}\n                        className=\"selected-chip dimension-chip draggable-dim\"\n                        title={`${dimName} — drag to Filters to filter on it`}\n                        draggable\n                        onDragStart={e => handleDimDragStart(e, dimName)}\n                      >\n                        <TailLabel text={getDimDisplayName(dimName)} />\n                        <button\n                          className=\"chip-remove\"\n                          onClick={e => {\n                            e.stopPropagation();\n                            removeDimension(dimName);\n                          }}\n                          title={`Remove ${getDimDisplayName(dimName)}`}\n                        >\n                          ×\n                        </button>\n                      </span>\n                    ))}\n                  </div>\n                )}\n                <div className=\"combobox-input-row\">\n                  <input\n                    ref={dimensionsSearchRef}\n                    type=\"text\"\n                    className=\"combobox-search\"\n                    placeholder=\"Search dimensions...\"\n                    value={dimensionsSearch}\n                    onChange={e => setDimensionsSearch(e.target.value)}\n                    onClick={e => e.stopPropagation()}\n                  />\n                  {selectedDimensions.length > CHIPS_COLLAPSE_THRESHOLD && (\n                    <button\n                      className=\"combobox-action\"\n                      onClick={e => {\n                        e.stopPropagation();\n                        setDimensionsChipsExpanded(!dimensionsChipsExpanded);\n                      }}\n                    >\n                      {dimensionsChipsExpanded ? 'Show less' : 'Show all'}\n                    </button>\n                  )}\n                  {selectedDimensions.length > 0 && (\n                    <button\n                      className=\"combobox-action\"\n                      onClick={e => {\n                        e.stopPropagation();\n                        onDimensionsChange([]);\n                      }}\n                    >\n                      Clear\n                    </button>\n                  )}\n                </div>\n              </div>\n\n              <div className=\"selection-list dimensions-list\">\n                {groupedDimensions.map(group => {\n                  const nodeExpanded = expandedDimGroups.has(group.nodeKey);\n                  return (\n                    <div key={group.nodeKey} className=\"dim-group\">\n                      <div\n                        className=\"dim-group-header\"\n                        onClick={() => toggleDimGroup(group.nodeKey)}\n                        title={group.nodeKey}\n                      >\n                        <span className=\"expand-icon\">\n                          {nodeExpanded ? '▼' : '▶'}\n                        </span>\n                        <span className=\"dim-group-name\">\n                          {getDimGroupShortName(group.nodeKey)}\n                        </span>\n                        <span className=\"dim-group-count\">\n                          {group.totalCount}\n                        </span>\n                      </div>\n                      {nodeExpanded &&\n                        group.rolePaths.map(rp => {\n                          const rpKey = `${group.nodeKey}::${rp.roleKey}`;\n                          const rpExpanded = expandedRolePaths.has(rpKey);\n                          const hops = rolePathHops(rp.roleKey);\n                          const hopsLabel =\n                            hops === 0\n                              ? 'direct'\n                              : `${hops} hop${hops > 1 ? 's' : ''}`;\n                          return (\n                            <div key={rpKey} className=\"dim-role-group\">\n                              <div\n                                className=\"dim-role-header\"\n                                onClick={() =>\n                                  toggleRolePath(group.nodeKey, rp.roleKey)\n                                }\n                              >\n                                <span className=\"expand-icon\">\n                                  {rpExpanded ? '▼' : '▶'}\n                                </span>\n                                <span className=\"dim-role-label\">\n                                  {formatRolePath(rp.roleKey)}\n                                </span>\n                                <span className=\"dim-group-meta\">\n                                  {hopsLabel}\n                                </span>\n                                <span className=\"dim-group-count\">\n                                  {rp.dimensions.length}\n                                </span>\n                              </div>\n                              {rpExpanded &&\n                                rp.dimensions.map(dim => (\n                                  <label\n                                    key={dim.name}\n                                    className=\"selection-item dimension-item dim-role-item draggable-dim\"\n                                    title={`${dim.name} — drag to Filters to filter on it`}\n                                    draggable\n                                    onDragStart={e =>\n                                      handleDimDragStart(e, dim.name)\n                                    }\n                                  >\n                                    <input\n                                      type=\"checkbox\"\n                                      checked={selectedDimensions.includes(\n                                        dim.name,\n                                      )}\n                                      onChange={() => toggleDimension(dim.name)}\n                                    />\n                                    <div className=\"dimension-info\">\n                                      <span className=\"item-name\">\n                                        {getDimDisplayName(\n                                          dim.name.replace(/\\[[^\\]]*\\]$/, ''),\n                                        )}\n                                      </span>\n                                    </div>\n                                    <button\n                                      className=\"dim-filter-btn\"\n                                      title={`Add \"${dim.name}\" to filters`}\n                                      onClick={e => addDimAsFilter(e, dim.name)}\n                                    >\n                                      + filter\n                                    </button>\n                                  </label>\n                                ))}\n                            </div>\n                          );\n                        })}\n                    </div>\n                  );\n                })}\n\n                {groupedDimensions.length === 0 && (\n                  <div className=\"empty-list\">\n                    {dimensionsSearch\n                      ? 'No dimensions match your search'\n                      : 'No shared dimensions'}\n                  </div>\n                )}\n              </div>\n            </>\n          )}\n        </div>\n\n        {/* Draggable Divider 2: dims / filters */}\n        <div\n          className=\"section-divider draggable-divider\"\n          onMouseDown={e => handleDividerMouseDown(e, 2)}\n        />\n\n        {/* Filters Section (drop target for dragged dimensions) */}\n        <div\n          className={`selection-section filters-section${\n            filterDropActive ? ' drop-active' : ''\n          }`}\n          style={{ flex: split3 - split2 }}\n          onDragOver={handleFilterDragOver}\n          onDragLeave={handleFilterDragLeave}\n          onDrop={handleFilterDrop}\n        >\n          <div className=\"section-header\">\n            <h3>Filters</h3>\n            <span className=\"selection-count\">{filters.length} applied</span>\n          </div>\n          {filterDropActive && (\n            <div className=\"filter-drop-hint\">\n              Drop to filter on this dimension\n            </div>\n          )}\n\n          {/* Filter chips */}\n          {filters.length > 0 && (\n            <div className=\"filter-chips-container\">\n              {filters.map((filter, idx) => (\n                <span key={idx} className=\"filter-chip\">\n                  <button\n                    type=\"button\"\n                    className=\"filter-chip-text filter-chip-edit\"\n                    onClick={() => handleEditFilter(filter)}\n                    title={`${filter} — click to edit`}\n                  >\n                    {filter}\n                  </button>\n                  <button\n                    className=\"filter-chip-remove\"\n                    onClick={() => handleRemoveFilter(filter)}\n                    title=\"Remove filter\"\n                  >\n                    ×\n                  </button>\n                </span>\n              ))}\n            </div>\n          )}\n\n          {/* Filter input */}\n          <div className=\"filter-input-container\">\n            <input\n              ref={filterInputRef}\n              type=\"text\"\n              className=\"filter-input\"\n              placeholder=\"e.g. v3.date.date_id >= '2024-01-01'\"\n              value={filterInput}\n              onChange={e => setFilterInput(e.target.value)}\n              onKeyDown={handleFilterKeyDown}\n            />\n            <button\n              className=\"filter-add-btn\"\n              onClick={handleAddFilter}\n              disabled={!filterInput.trim()}\n            >\n              Add\n            </button>\n          </div>\n        </div>\n\n        {/* Draggable Divider 3: filters / engine+run */}\n        <div\n          className=\"section-divider draggable-divider\"\n          onMouseDown={e => handleDividerMouseDown(e, 3)}\n        />\n\n        {/* Engine + Run Query Section */}\n        <div\n          className=\"selection-section engine-run-section\"\n          style={{ flex: 100 - split3 }}\n        >\n          {/* Engine Selection */}\n          <div className=\"engine-section\">\n            <span className=\"engine-label\">Engine</span>\n            <div className=\"engine-pills\">\n              {ENGINE_OPTIONS.map(({ value, label }) => (\n                <button\n                  key={label}\n                  className={`engine-pill${\n                    selectedEngine === value ? ' active' : ''\n                  }`}\n                  onClick={() => onEngineChange && onEngineChange(value)}\n                >\n                  {label}\n                </button>\n              ))}\n            </div>\n          </div>\n\n          {/* Run Query Section */}\n          <div className=\"run-query-section\">\n            <button\n              className=\"run-query-btn\"\n              onClick={onRunQuery}\n              disabled={!canRunQuery || queryLoading}\n            >\n              {queryLoading ? (\n                <>\n                  <span className=\"spinner small\" />\n                  Running...\n                </>\n              ) : (\n                <>\n                  <span className=\"run-icon\">▶</span>\n                  Run Query\n                </>\n              )}\n            </button>\n            {!canRunQuery && (\n              <span className=\"run-hint\">\n                Select at least one metric to run a query\n              </span>\n            )}\n          </div>\n        </div>\n      </div>\n      {/* end resizable-sections */}\n    </div>\n  );\n}\n\nexport default SelectionPanel;\n","import { useState, useCallback, useMemo, useEffect, useRef, memo } from 'react';\nimport { Light as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport foundation from 'react-syntax-highlighter/dist/esm/styles/hljs/foundation';\nimport sql from 'react-syntax-highlighter/dist/esm/languages/hljs/sql';\nimport {\n  LineChart,\n  Line,\n  BarChart,\n  Bar,\n  XAxis,\n  YAxis,\n  CartesianGrid,\n  Tooltip,\n  ResponsiveContainer,\n} from 'recharts';\n\nSyntaxHighlighter.registerLanguage('sql', sql);\n\nconst SERIES_COLORS = [\n  '#60a5fa',\n  '#34d399',\n  '#fbbf24',\n  '#f87171',\n  '#a78bfa',\n  '#22d3ee',\n  '#fb923c',\n];\n\n// Threshold for switching from multi-series to small multiples\nconst SMALL_MULTIPLES_THRESHOLD = 2;\n\nfunction isTimeColumn(col) {\n  const name = col.name.toLowerCase();\n  const type = (col.type || '').toLowerCase();\n  return (\n    type.includes('date') ||\n    type.includes('timestamp') ||\n    type.includes('time') ||\n    name === 'date' ||\n    name === 'day' ||\n    name === 'week' ||\n    name === 'month' ||\n    name === 'year' ||\n    name === 'quarter' ||\n    name.endsWith('_date') ||\n    name.endsWith('_day') ||\n    name.endsWith('_week') ||\n    name.endsWith('_month') ||\n    name.endsWith('_year') ||\n    name.endsWith('_at') ||\n    name.startsWith('date') ||\n    name.startsWith('ds')\n  );\n}\n\nfunction isNumericColumn(col) {\n  const type = (col.type || '').toLowerCase();\n  return (\n    type.includes('int') ||\n    type.includes('float') ||\n    type.includes('double') ||\n    type.includes('decimal') ||\n    type.includes('numeric') ||\n    type.includes('real') ||\n    type.includes('number')\n  );\n}\n\nfunction detectChartConfig(columns, rows) {\n  if (!columns.length || !rows.length) return null;\n\n  const tagged = columns.map((c, i) => ({ ...c, idx: i }));\n  const timeCols = tagged.filter(c => isTimeColumn(c));\n  const numericCols = tagged.filter(c => isNumericColumn(c));\n  const nonNumericCols = tagged.filter(c => !isNumericColumn(c));\n  const nonTimeCatCols = nonNumericCols.filter(c => !isTimeColumn(c));\n\n  // Time dimension present → line chart\n  if (timeCols.length > 0) {\n    const xCol = timeCols[0];\n    const metricCols = numericCols.filter(c => c.idx !== xCol.idx);\n    if (metricCols.length > 0) {\n      // Exactly one categorical dim + one metric → pivot as series\n      if (nonTimeCatCols.length === 1) {\n        return {\n          type: 'line',\n          xCol,\n          groupByCol: nonTimeCatCols[0],\n          metricCols,\n        };\n      }\n      return { type: 'line', xCol, metricCols };\n    }\n  }\n\n  // Categorical dimension(s) → bar chart\n  if (nonTimeCatCols.length > 0 && numericCols.length > 0) {\n    if (nonTimeCatCols.length === 1) {\n      return { type: 'bar', xCol: nonTimeCatCols[0], metricCols: numericCols };\n    }\n    if (nonTimeCatCols.length === 2) {\n      return {\n        type: 'bar',\n        xCol: nonTimeCatCols[0],\n        groupByCol: nonTimeCatCols[1],\n        metricCols: numericCols,\n      };\n    }\n    // 3+ cats → fall back to first cat as x-axis\n    return { type: 'bar', xCol: nonTimeCatCols[0], metricCols: numericCols };\n  }\n\n  // Multiple numeric columns, no string/time dim → treat first as x-axis (line)\n  if (numericCols.length > 1) {\n    const xCol = numericCols[0];\n    const metricCols = numericCols.slice(1);\n    return { type: 'line', xCol, metricCols };\n  }\n\n  // Scalar result → KPI cards\n  if (numericCols.length > 0) {\n    return { type: 'kpi', metricCols: numericCols };\n  }\n\n  return null;\n}\n\nconst MAX_GROUP_VALUES = 50;\n\nfunction buildPivotedData(rows, columns, xCol, groupByCol, metricCols) {\n  const xIdx = xCol.idx;\n  const gIdx = groupByCol.idx;\n  const metricIdxs = metricCols.map(c => c.idx);\n\n  // Pass 1: group totals only (cheap — just numbers)\n  const groupTotals = {};\n  for (const row of rows) {\n    const gVal = String(row[gIdx] ?? '(null)');\n    groupTotals[gVal] =\n      (groupTotals[gVal] || 0) + (Number(row[metricIdxs[0]]) || 0);\n  }\n  const groupValues = Object.entries(groupTotals)\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, MAX_GROUP_VALUES)\n    .map(([k]) => k);\n  const groupSet = new Set(groupValues);\n\n  // Pass 2: build ALL metric pivot maps in one sweep\n  const pivotMaps = metricCols.map(() => ({}));\n  for (const row of rows) {\n    const gVal = String(row[gIdx] ?? '(null)');\n    if (!groupSet.has(gVal)) continue;\n    const xVal = row[xIdx];\n    const mapKey = String(xVal ?? '(null)');\n    for (let m = 0; m < metricCols.length; m++) {\n      const pm = pivotMaps[m];\n      if (!pm[mapKey]) pm[mapKey] = { [xCol.name]: xVal };\n      pm[mapKey][gVal] = row[metricIdxs[m]];\n    }\n  }\n\n  const sortFn = (a, b) => {\n    const av = a[xCol.name];\n    const bv = b[xCol.name];\n    if (av === null && bv === null) return 0;\n    if (av === null) return 1;\n    if (bv === null) return -1;\n    if (typeof av === 'number' && typeof bv === 'number') return av - bv;\n    return String(av).localeCompare(String(bv));\n  };\n\n  const pivotedByMetric = metricCols.map((metricCol, m) => {\n    const pivoted = Object.values(pivotMaps[m]);\n    pivoted.sort(sortFn);\n    return { col: metricCol, data: pivoted };\n  });\n\n  return { pivotedByMetric, groupValues };\n}\n\nfunction buildChartData(columns, rows, xCol) {\n  const data = rows.map(row => {\n    const obj = {};\n    columns.forEach((col, i) => {\n      obj[col.name] = row[i];\n    });\n    return obj;\n  });\n  const key = xCol.name;\n  data.sort((a, b) => {\n    const av = a[key];\n    const bv = b[key];\n    if (av === null && bv === null) return 0;\n    if (av === null) return 1;\n    if (bv === null) return -1;\n    if (typeof av === 'number' && typeof bv === 'number') return av - bv;\n    return String(av).localeCompare(String(bv));\n  });\n  return data;\n}\n\nfunction formatYAxis(value) {\n  if (Math.abs(value) >= 1_000_000_000)\n    return (value / 1_000_000_000).toFixed(1) + 'B';\n  if (Math.abs(value) >= 1_000_000) return (value / 1_000_000).toFixed(1) + 'M';\n  if (Math.abs(value) >= 1_000) return (value / 1_000).toFixed(1) + 'K';\n  return value;\n}\n\nfunction KpiCards({ rows, metricCols }) {\n  const row = rows[0] || [];\n  return (\n    <div className=\"kpi-cards\">\n      {metricCols.map(col => {\n        const val = row[col.idx];\n        const formatted =\n          val == null\n            ? '—'\n            : typeof val === 'number'\n            ? val.toLocaleString(undefined, { maximumFractionDigits: 4 })\n            : String(val);\n        return (\n          <div key={col.idx} className=\"kpi-card\">\n            <div className=\"kpi-label\">{col.name}</div>\n            <div className=\"kpi-value\">{formatted}</div>\n            {col.type && <div className=\"kpi-type\">{col.type}</div>}\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n\nconst CHART_MARGIN = { top: 8, right: 24, left: 8, bottom: 40 };\nconst AXIS_TICK = { fontSize: 11, fill: '#64748b' };\nconst TOOLTIP_STYLE = { fontSize: 12, border: '1px solid #e2e8f0' };\nconst TOOLTIP_WRAPPER_STYLE = { zIndex: 9999 };\n\nconst Chart = memo(function Chart({\n  type,\n  xCol,\n  metricCols,\n  seriesKeys,\n  chartData,\n  seriesColors = SERIES_COLORS,\n}) {\n  const showDots = chartData.length <= 60;\n  const keys = seriesKeys || metricCols.map(c => c.name);\n  const xInterval =\n    type === 'line'\n      ? 'preserveStartEnd'\n      : Math.max(0, Math.ceil(chartData.length / 20) - 1);\n  if (type === 'line') {\n    return (\n      <ResponsiveContainer width=\"100%\" height=\"100%\">\n        <LineChart data={chartData} margin={CHART_MARGIN}>\n          <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#e2e8f0\" />\n          <XAxis\n            dataKey={xCol.name}\n            tick={AXIS_TICK}\n            angle={-35}\n            textAnchor=\"end\"\n            interval={xInterval}\n          />\n          <YAxis tickFormatter={formatYAxis} tick={AXIS_TICK} width={60} />\n          <Tooltip\n            contentStyle={TOOLTIP_STYLE}\n            wrapperStyle={TOOLTIP_WRAPPER_STYLE}\n          />\n          {keys.map((key, i) => (\n            <Line\n              key={key}\n              type=\"monotone\"\n              dataKey={key}\n              stroke={seriesColors[i % seriesColors.length]}\n              dot={showDots}\n              strokeWidth={2}\n              isAnimationActive={false}\n            />\n          ))}\n        </LineChart>\n      </ResponsiveContainer>\n    );\n  }\n  return (\n    <ResponsiveContainer width=\"100%\" height=\"100%\">\n      <BarChart data={chartData} margin={CHART_MARGIN}>\n        <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#e2e8f0\" />\n        <XAxis\n          dataKey={xCol.name}\n          tick={AXIS_TICK}\n          angle={-35}\n          textAnchor=\"end\"\n          interval={xInterval}\n        />\n        <YAxis tickFormatter={formatYAxis} tick={AXIS_TICK} width={60} />\n        <Tooltip contentStyle={TOOLTIP_STYLE} />\n        {keys.map((key, i) => (\n          <Bar\n            key={key}\n            dataKey={key}\n            fill={seriesColors[i % seriesColors.length]}\n            isAnimationActive={false}\n          />\n        ))}\n      </BarChart>\n    </ResponsiveContainer>\n  );\n});\n\nconst ChartView = memo(function ChartView({\n  chartConfig,\n  chartData,\n  pivotedByMetric,\n  groupValues,\n  rows,\n  columns,\n}) {\n  if (!chartConfig) {\n    return <div className=\"chart-no-data\">No chartable data detected</div>;\n  }\n\n  if (chartConfig.type === 'kpi') {\n    return <KpiCards rows={rows} metricCols={chartConfig.metricCols} />;\n  }\n\n  const { type, xCol, metricCols } = chartConfig;\n\n  // Pivoted multi-metric: small multiples, one per metric, each with groupBy series\n  if (pivotedByMetric && pivotedByMetric.length > 1) {\n    return (\n      <div className=\"small-multiples\">\n        {pivotedByMetric.map(({ col, data }) => (\n          <div key={col.idx} className=\"small-multiple\">\n            <div className=\"small-multiple-label\">{col.name}</div>\n            <div className=\"small-multiple-chart\">\n              <Chart\n                type={type}\n                xCol={xCol}\n                metricCols={[col]}\n                seriesKeys={groupValues}\n                chartData={data}\n              />\n            </div>\n          </div>\n        ))}\n      </div>\n    );\n  }\n\n  // Pivoted single-metric: one chart with groupBy as series\n  if (groupValues) {\n    return (\n      <Chart\n        type={type}\n        xCol={xCol}\n        metricCols={metricCols}\n        seriesKeys={groupValues}\n        chartData={chartData}\n      />\n    );\n  }\n\n  // No groupBy: standard small multiples or single chart\n  if (metricCols.length > SMALL_MULTIPLES_THRESHOLD) {\n    return (\n      <div className=\"small-multiples\">\n        {metricCols.map((col, i) => (\n          <div key={col.idx} className=\"small-multiple\">\n            <div className=\"small-multiple-label\">{col.name}</div>\n            <div className=\"small-multiple-chart\">\n              <Chart\n                type={type}\n                xCol={xCol}\n                metricCols={[col]}\n                chartData={chartData}\n                seriesColors={[SERIES_COLORS[i % SERIES_COLORS.length]]}\n              />\n            </div>\n          </div>\n        ))}\n      </div>\n    );\n  }\n\n  return (\n    <Chart\n      type={type}\n      xCol={xCol}\n      metricCols={metricCols}\n      chartData={chartData}\n    />\n  );\n});\n\n/**\n * ResultsView - Displays query results with SQL and data table\n * Layout: SQL in top ~25%, results in bottom ~75% with Table/Chart tabs\n */\nexport function ResultsView({\n  sql: sqlQuery,\n  results,\n  loading,\n  error,\n  elapsedTime,\n  onBackToPlan,\n  selectedMetrics,\n  selectedDimensions,\n  filters,\n  dialect,\n  cubeName,\n  availability,\n  links,\n}) {\n  const [copied, setCopied] = useState(false);\n  const [sortColumn, setSortColumn] = useState(null);\n  const [sortDirection, setSortDirection] = useState('asc');\n  const [activeTab, setActiveTab] = useState('table');\n\n  // Resizable SQL pane height (px); null = use CSS default\n  const [sqlPaneHeight, setSqlPaneHeight] = useState(null);\n  const resultsPanesRef = useRef(null);\n\n  const handleSqlResizerMouseDown = useCallback(\n    e => {\n      e.preventDefault();\n      const container = resultsPanesRef.current;\n      if (!container) return;\n      const startY = e.clientY;\n      const startHeight = sqlPaneHeight ?? container.offsetHeight * 0.333;\n\n      const onMouseMove = moveEvent => {\n        const delta = moveEvent.clientY - startY;\n        const newHeight = Math.max(\n          80,\n          Math.min(container.offsetHeight * 0.8, startHeight + delta),\n        );\n        setSqlPaneHeight(newHeight);\n      };\n\n      const onMouseUp = () => {\n        document.removeEventListener('mousemove', onMouseMove);\n        document.removeEventListener('mouseup', onMouseUp);\n      };\n\n      document.addEventListener('mousemove', onMouseMove);\n      document.addEventListener('mouseup', onMouseUp);\n    },\n    [sqlPaneHeight],\n  );\n\n  const handleCopySql = useCallback(() => {\n    if (sqlQuery) {\n      navigator.clipboard.writeText(sqlQuery);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n    }\n  }, [sqlQuery]);\n\n  const columns = useMemo(\n    () => results?.results?.[0]?.columns || [],\n    [results],\n  );\n  const rows = useMemo(() => results?.results?.[0]?.rows || [], [results]);\n  const rowCount = rows.length;\n\n  const handleSort = useCallback(\n    columnIndex => {\n      if (sortColumn === columnIndex) {\n        setSortDirection(d => (d === 'asc' ? 'desc' : 'asc'));\n      } else {\n        setSortColumn(columnIndex);\n        setSortDirection('asc');\n      }\n    },\n    [sortColumn],\n  );\n\n  const sortedRows = useMemo(() => {\n    if (sortColumn === null) return rows;\n    return [...rows].sort((a, b) => {\n      const aVal = a[sortColumn];\n      const bVal = b[sortColumn];\n      if (aVal === null && bVal === null) return 0;\n      if (aVal === null) return 1;\n      if (bVal === null) return -1;\n      let cmp;\n      if (typeof aVal === 'number' && typeof bVal === 'number') {\n        cmp = aVal - bVal;\n      } else {\n        cmp = String(aVal).localeCompare(String(bVal));\n      }\n      return sortDirection === 'asc' ? cmp : -cmp;\n    });\n  }, [rows, sortColumn, sortDirection]);\n\n  const chartConfig = useMemo(\n    () => detectChartConfig(columns, rows),\n    [columns, rows],\n  );\n  const { chartData, pivotedByMetric, groupValues } = useMemo(() => {\n    if (!chartConfig || !chartConfig.xCol)\n      return { chartData: [], pivotedByMetric: null, groupValues: null };\n    if (chartConfig.groupByCol) {\n      const { pivotedByMetric, groupValues } = buildPivotedData(\n        rows,\n        columns,\n        chartConfig.xCol,\n        chartConfig.groupByCol,\n        chartConfig.metricCols,\n      );\n      return {\n        chartData: pivotedByMetric[0].data,\n        pivotedByMetric,\n        groupValues,\n      };\n    }\n    return {\n      chartData: buildChartData(columns, rows, chartConfig.xCol),\n      pivotedByMetric: null,\n      groupValues: null,\n    };\n  }, [columns, rows, chartConfig]);\n\n  const canChart = rowCount > 0;\n\n  // Reset to table view if new results can't be charted\n  useEffect(() => {\n    if (!canChart && activeTab === 'chart') setActiveTab('table');\n  }, [canChart, activeTab]);\n\n  return (\n    <div className=\"results-view\">\n      {/* Header */}\n      <div className=\"results-header\">\n        <button className=\"back-to-plan-btn\" onClick={onBackToPlan}>\n          <span className=\"back-arrow\">←</span>\n          <span>Back to Plan</span>\n        </button>\n        <div className=\"results-summary\">\n          {loading ? (\n            <span className=\"results-loading-text\">Running query...</span>\n          ) : error ? (\n            <span className=\"results-error-text\">Query failed</span>\n          ) : (\n            <>\n              <span className=\"results-count\">\n                {rowCount.toLocaleString()} rows\n              </span>\n              {elapsedTime != null && (\n                <span className=\"results-time\">{elapsedTime.toFixed(2)}s</span>\n              )}\n            </>\n          )}\n        </div>\n      </div>\n\n      {/* Two-pane layout: SQL (top) + Results (bottom) */}\n      <div className=\"results-panes\" ref={resultsPanesRef}>\n        {/* SQL Pane */}\n        <div\n          className=\"sql-pane\"\n          style={\n            sqlPaneHeight != null\n              ? { flex: `0 0 ${sqlPaneHeight}px`, maxHeight: sqlPaneHeight }\n              : undefined\n          }\n        >\n          <div className=\"sql-pane-header\">\n            <span className=\"sql-pane-title\">SQL Query</span>\n            {cubeName && (\n              <span\n                className=\"sql-pane-info\"\n                title={\n                  availability\n                    ? `Querying materialized dataset ${[\n                        availability.catalog,\n                        availability.schema_,\n                        availability.table,\n                      ]\n                        .filter(Boolean)\n                        .join('.')}, last refreshed for data through ${new Date(\n                        availability.validThroughTs,\n                      ).toLocaleDateString()}`\n                    : undefined\n                }\n              >\n                <span className=\"info-materialized\">\n                  <span style={{ fontFamily: 'sans-serif' }}>⚡</span> Using\n                  materialized cube\n                </span>\n                {availability?.validThroughTs && (\n                  <>\n                    {' · Valid thru '}\n                    {new Date(availability.validThroughTs).toLocaleDateString()}\n                  </>\n                )}\n              </span>\n            )}\n            <button\n              className={`copy-btn ${copied ? 'copied' : ''}`}\n              onClick={handleCopySql}\n              disabled={!sqlQuery}\n            >\n              {copied ? '✓ Copied' : 'Copy'}\n            </button>\n          </div>\n          <div className=\"sql-pane-content\">\n            {sqlQuery ? (\n              <SyntaxHighlighter\n                language=\"sql\"\n                style={foundation}\n                wrapLongLines={true}\n                customStyle={{\n                  margin: 0,\n                  padding: '12px 16px',\n                  background: '#f8fafc',\n                  fontSize: '12px',\n                  height: '100%',\n                  overflow: 'auto',\n                }}\n              >\n                {sqlQuery}\n              </SyntaxHighlighter>\n            ) : (\n              <div className=\"sql-pane-empty\">Generating SQL...</div>\n            )}\n          </div>\n        </div>\n\n        {/* Horizontal resizer between SQL and results panes */}\n        <div\n          className=\"horizontal-resizer\"\n          onMouseDown={handleSqlResizerMouseDown}\n          title=\"Drag to resize\"\n        />\n\n        {/* Results Pane */}\n        <div className=\"results-pane\">\n          {loading ? (\n            <div className=\"results-loading\">\n              <div className=\"loading-spinner large\" />\n              <span>Executing query...</span>\n              <span className=\"loading-hint\">\n                Querying {selectedMetrics.length} metric(s) with{' '}\n                {selectedDimensions.length} dimension(s)\n              </span>\n              {links && links.length > 0 && (\n                <span className=\"results-links\">\n                  {links.map((link, idx) => (\n                    <a\n                      key={idx}\n                      href={link}\n                      target=\"_blank\"\n                      rel=\"noopener noreferrer\"\n                      className=\"results-link\"\n                    >\n                      View query ↗\n                    </a>\n                  ))}\n                </span>\n              )}\n            </div>\n          ) : error ? (\n            <div className=\"results-error\">\n              <div className=\"error-icon\">⚠</div>\n              <h3>Query Failed</h3>\n              <p className=\"error-message\">{error}</p>\n              <button\n                className=\"action-btn action-btn-primary\"\n                onClick={onBackToPlan}\n              >\n                Back to Plan\n              </button>\n            </div>\n          ) : (\n            <div className=\"results-table-section\">\n              {/* Tab bar */}\n              <div className=\"results-tabs-bar\">\n                <div className=\"results-tabs\">\n                  <button\n                    className={`results-tab ${\n                      activeTab === 'table' ? 'active' : ''\n                    }`}\n                    onClick={() => setActiveTab('table')}\n                  >\n                    Table\n                  </button>\n                  <button\n                    className={`results-tab ${\n                      activeTab === 'chart' ? 'active' : ''\n                    } ${!canChart ? 'disabled' : ''}`}\n                    onClick={() => canChart && setActiveTab('chart')}\n                    title={\n                      !canChart\n                        ? 'No chartable data (need at least one numeric column)'\n                        : undefined\n                    }\n                  >\n                    Chart\n                  </button>\n                </div>\n                <div className=\"results-tabs-meta\">\n                  <span className=\"table-count\">\n                    {rowCount.toLocaleString()} rows\n                  </span>\n                  {filters && filters.length > 0 && (\n                    <div className=\"table-filters\">\n                      {filters.map((filter, idx) => (\n                        <span key={idx} className=\"filter-chip small\">\n                          {filter}\n                        </span>\n                      ))}\n                    </div>\n                  )}\n                </div>\n              </div>\n\n              {/* Content */}\n              {activeTab === 'table' ? (\n                <div className=\"results-table-wrapper\">\n                  {rowCount === 0 ? (\n                    <div className=\"table-empty\">\n                      <p>No results returned</p>\n                    </div>\n                  ) : (\n                    <table className=\"results-table\">\n                      <thead>\n                        <tr>\n                          {columns.map((col, idx) => (\n                            <th\n                              key={idx}\n                              title={col.semantic_name || col.name}\n                              onClick={() => handleSort(idx)}\n                              className={sortColumn === idx ? 'sorted' : ''}\n                            >\n                              <span className=\"col-header-content\">\n                                {col.name}\n                                <span className=\"sort-arrows\">\n                                  <span\n                                    className={`sort-arrow up ${\n                                      sortColumn === idx &&\n                                      sortDirection === 'asc'\n                                        ? 'active'\n                                        : ''\n                                    }`}\n                                  >\n                                    ▲\n                                  </span>\n                                  <span\n                                    className={`sort-arrow down ${\n                                      sortColumn === idx &&\n                                      sortDirection === 'desc'\n                                        ? 'active'\n                                        : ''\n                                    }`}\n                                  >\n                                    ▼\n                                  </span>\n                                </span>\n                              </span>\n                              <span className=\"col-type\">{col.type}</span>\n                            </th>\n                          ))}\n                        </tr>\n                      </thead>\n                      <tbody>\n                        {sortedRows.map((row, rowIdx) => (\n                          <tr key={rowIdx}>\n                            {row.map((cell, cellIdx) => (\n                              <td key={cellIdx}>\n                                {cell === null ? (\n                                  <span className=\"null-value\">NULL</span>\n                                ) : (\n                                  String(cell)\n                                )}\n                              </td>\n                            ))}\n                          </tr>\n                        ))}\n                      </tbody>\n                    </table>\n                  )}\n                </div>\n              ) : (\n                <div className=\"results-chart-wrapper\">\n                  {canChart ? (\n                    <ChartView\n                      chartConfig={chartConfig}\n                      chartData={chartData}\n                      pivotedByMetric={pivotedByMetric}\n                      groupValues={groupValues}\n                      rows={rows}\n                      columns={columns}\n                    />\n                  ) : (\n                    <div className=\"chart-no-data\">\n                      No chartable data detected\n                    </div>\n                  )}\n                </div>\n              )}\n            </div>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ResultsView;\n","import {\n  useContext,\n  useEffect,\n  useState,\n  useCallback,\n  useRef,\n  lazy,\n  Suspense,\n} from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport DJClientContext from '../../providers/djclient';\nimport SelectionPanel from './SelectionPanel';\nimport {\n  PreAggDetailsPanel,\n  MetricDetailsPanel,\n  QueryOverviewPanel,\n} from './PreAggDetailsPanel';\nimport ResultsView from './ResultsView';\nimport './styles.css';\n\n// Lazy load the graph component - ReactFlow and dagre are heavy (~500KB)\n// This allows API calls to start immediately while the graph loads in parallel\nconst MetricFlowGraph = lazy(() => import('./MetricFlowGraph'));\n\n/**\n * Helper to normalize grain columns to short names for comparison\n * \"default.date_dim.date_id\" -> \"date_id\"\n */\nfunction normalizeGrain(grainCols) {\n  return (grainCols || [])\n    .map(col => col.split('.').pop())\n    .sort()\n    .join(',');\n}\n\nexport function QueryPlannerPage() {\n  const djClient = useContext(DJClientContext).DataJunctionAPI;\n  const location = useLocation();\n  const navigate = useNavigate();\n\n  // Available options\n  const [metrics, setMetrics] = useState([]);\n  const [commonDimensions, setCommonDimensions] = useState([]);\n  const [cubes, setCubes] = useState([]);\n\n  // Selection state - initialized from URL params\n  const [selectedMetrics, setSelectedMetrics] = useState([]);\n  const [selectedDimensions, setSelectedDimensions] = useState([]);\n  const [loadedCubeName, setLoadedCubeName] = useState(null); // Track loaded cube preset\n\n  // Track if we've initialized from URL (to avoid overwriting URL on first render)\n  const initializedFromUrl = useRef(false);\n  const pendingDimensionsFromUrl = useRef([]);\n  const pendingCubeFromUrl = useRef(null);\n  // Dimension objects seeded directly from a loaded cube preset. Kept so the\n  // background common-dimensions fetch can be merged in (union) without dropping\n  // the cube's own dimensions from the available list or the selection.\n  const cubeDimensionObjects = useRef([]);\n\n  // Compatible metrics when dimensions are selected (phase 1: dimension-first flow)\n  const [compatibleMetrics, setCompatibleMetrics] = useState(null); // null = no filter active\n\n  // Results state\n  const [measuresResult, setMeasuresResult] = useState(null);\n  const [metricsResult, setMetricsResult] = useState(null);\n  const [loading, setLoading] = useState(false);\n  const [dimensionsLoading, setDimensionsLoading] = useState(false);\n  const [error, setError] = useState(null);\n\n  // Query execution state\n  const [showResults, setShowResults] = useState(false);\n  const [queryResults, setQueryResults] = useState(null);\n  const [queryLoading, setQueryLoading] = useState(false);\n  const [queryError, setQueryError] = useState(null);\n  const [queryStartTime, setQueryStartTime] = useState(null);\n  const [queryElapsedTime, setQueryElapsedTime] = useState(null);\n  const [queryLinks, setQueryLinks] = useState([]);\n\n  // Filters state\n  const [filters, setFilters] = useState([]);\n\n  // Engine selection: null = auto, 'druid', 'trino'\n  const [selectedEngine, setSelectedEngine] = useState(null);\n\n  // Cube availability state (for displaying freshness info)\n  const [cubeAvailability, setCubeAvailability] = useState(null);\n\n  // Node selection for details panel\n  const [selectedNode, setSelectedNode] = useState(null);\n\n  // Resizable pane widths (px); null = use CSS default\n  const [selectionWidth, setSelectionWidth] = useState(null);\n  const [detailsWidth, setDetailsWidth] = useState(null);\n  const plannerLayoutRef = useRef(null);\n\n  const handleSelectionResizerMouseDown = useCallback(\n    e => {\n      e.preventDefault();\n      const container = plannerLayoutRef.current;\n      if (!container) return;\n      const startX = e.clientX;\n      const startWidth = selectionWidth ?? container.offsetWidth * 0.2; // match CSS default 20%\n\n      const onMouseMove = moveEvent => {\n        const delta = moveEvent.clientX - startX;\n        const newWidth = Math.max(\n          200,\n          Math.min(container.offsetWidth * 0.5, startWidth + delta),\n        );\n        setSelectionWidth(newWidth);\n      };\n\n      const onMouseUp = () => {\n        document.removeEventListener('mousemove', onMouseMove);\n        document.removeEventListener('mouseup', onMouseUp);\n      };\n\n      document.addEventListener('mousemove', onMouseMove);\n      document.addEventListener('mouseup', onMouseUp);\n    },\n    [selectionWidth],\n  );\n\n  const handleDetailsResizerMouseDown = useCallback(\n    e => {\n      e.preventDefault();\n      const container = plannerLayoutRef.current;\n      if (!container) return;\n      const startX = e.clientX;\n      const startWidth = detailsWidth ?? container.offsetWidth * 0.4; // match CSS default 40%\n\n      const onMouseMove = moveEvent => {\n        const delta = startX - moveEvent.clientX;\n        const newWidth = Math.max(\n          280,\n          Math.min(container.offsetWidth * 0.7, startWidth + delta),\n        );\n        setDetailsWidth(newWidth);\n      };\n\n      const onMouseUp = () => {\n        document.removeEventListener('mousemove', onMouseMove);\n        document.removeEventListener('mouseup', onMouseUp);\n      };\n\n      document.addEventListener('mousemove', onMouseMove);\n      document.addEventListener('mouseup', onMouseUp);\n    },\n    [detailsWidth],\n  );\n\n  // Materialization state - map of grain_key -> pre-agg info\n  const [plannedPreaggs, setPlannedPreaggs] = useState({});\n\n  // Materialization error state\n  const [materializationError, setMaterializationError] = useState(null);\n\n  // Workflow URLs from successful cube materialization\n  const [workflowUrls, setWorkflowUrls] = useState([]);\n\n  // Full cube materialization info (for edit/refresh/backfill)\n  const [cubeMaterialization, setCubeMaterialization] = useState(null);\n\n  // Initialize selection from URL params on mount\n  useEffect(() => {\n    const params = new URLSearchParams(location.search);\n    const urlMetrics = params.get('metrics')?.split(',').filter(Boolean) || [];\n    const urlDimensions =\n      params.get('dimensions')?.split(',').filter(Boolean) || [];\n    const urlFilters = params.getAll('filters');\n    const urlCube = params.get('cube');\n\n    if (urlFilters.length > 0) {\n      setFilters(urlFilters);\n    }\n\n    if (urlMetrics.length > 0) {\n      setSelectedMetrics(urlMetrics);\n      // Store dimensions to apply after commonDimensions are loaded\n      if (urlDimensions.length > 0) {\n        pendingDimensionsFromUrl.current = urlDimensions;\n      }\n      // Store cube name - will be set after cube data is loaded\n      if (urlCube) {\n        pendingCubeFromUrl.current = urlCube;\n        // Don't set loadedCubeName here - wait until cube data loads\n      }\n      initializedFromUrl.current = true;\n    } else if (urlCube) {\n      // Cube specified without metrics - will load cube on mount\n      pendingCubeFromUrl.current = urlCube;\n      initializedFromUrl.current = true;\n    }\n  }, []); // Only run on mount\n\n  // Update URL when selection changes\n  useEffect(() => {\n    // Skip the first render if we just initialized from URL\n    if (\n      !initializedFromUrl.current &&\n      selectedMetrics.length === 0 &&\n      !loadedCubeName\n    ) {\n      return;\n    }\n\n    const params = new URLSearchParams();\n    if (loadedCubeName) {\n      // Cube is loaded - only include cube name (metrics/dims come from cube definition)\n      params.set('cube', loadedCubeName);\n    } else {\n      // No cube - include metrics and dimensions\n      if (selectedMetrics.length > 0) {\n        params.set('metrics', selectedMetrics.join(','));\n      }\n      if (selectedDimensions.length > 0) {\n        params.set('dimensions', selectedDimensions.join(','));\n      }\n      filters.forEach(f => params.append('filters', f));\n    }\n\n    const newSearch = params.toString();\n    const currentSearch = location.search.replace(/^\\?/, '');\n\n    // Only update if different (avoid unnecessary history entries)\n    if (newSearch !== currentSearch) {\n      navigate(\n        {\n          pathname: location.pathname,\n          search: newSearch ? `?${newSearch}` : '',\n        },\n        { replace: true },\n      );\n    }\n  }, [\n    selectedMetrics,\n    selectedDimensions,\n    filters,\n    loadedCubeName,\n    location.pathname,\n    navigate,\n  ]);\n\n  // Get metrics list and cube names on mount\n  // Uses GraphQL for lightweight cube listing with display names\n  useEffect(() => {\n    const fetchData = async () => {\n      const [metricsList, cubesList] = await Promise.all([\n        djClient.metrics(),\n        djClient.listCubesForPreset().catch(() => []),\n      ]);\n      setMetrics(metricsList);\n      // cubesList returns [{name, display_name}] from GraphQL\n      setCubes(cubesList);\n\n      // If there's a pending cube from URL, load it now\n      if (pendingCubeFromUrl.current) {\n        const cubeName = pendingCubeFromUrl.current;\n        pendingCubeFromUrl.current = null; // Clear to prevent re-loading\n        try {\n          // Use lightweight GraphQL query - much faster than REST endpoint\n          const cubeData = await djClient.cubeForPlanner(cubeName);\n          // Validate cube data has expected fields\n          if (cubeData && Array.isArray(cubeData.cube_node_metrics)) {\n            const cubeMetrics = cubeData.cube_node_metrics || [];\n            const cubeDimensions = cubeData.cube_node_dimensions || [];\n            const cubeDimObjects = cubeData.cube_dimension_objects || [];\n            setLoadedCubeName(cubeName);\n            setSelectedMetrics(cubeMetrics);\n            // Seed the dimension picker and selection straight from the cube so\n            // they appear instantly and correctly; the full common-dimensions\n            // list is fetched in the background (and merged) for adding more.\n            cubeDimensionObjects.current = cubeDimObjects;\n            setCommonDimensions(cubeDimObjects);\n            setSelectedDimensions(cubeDimensions);\n\n            // Materialization info is included in the GraphQL response\n            const cubeMat = cubeData.cubeMaterialization;\n            setCubeMaterialization(cubeMat || null);\n            setWorkflowUrls(cubeMat?.workflowUrls || []);\n          } else {\n            console.error('Invalid cube data from URL:', cubeData);\n          }\n        } catch (err) {\n          console.error('Failed to load cube from URL:', err);\n        }\n      }\n    };\n    fetchData().catch(console.error);\n  }, [djClient]);\n\n  // Get common dimensions when metrics change\n  useEffect(() => {\n    const fetchData = async () => {\n      if (selectedMetrics.length > 0) {\n        // Capture cube-seeded dimensions for this run. When a cube preset is\n        // loaded its dimensions are already shown and selected, so the (slow)\n        // common-dimensions intersection runs in the background — don't blank\n        // the list behind a spinner, and merge rather than replace below.\n        const seeded = cubeDimensionObjects.current;\n        if (seeded.length === 0) {\n          setDimensionsLoading(true);\n        }\n        try {\n          const dims = await djClient.commonDimensions(selectedMetrics);\n          // Server returns an error body (e.g. {message: \"...\"}) on 404/422 with\n          // a non-OK status, but commonDimensions() doesn't surface that — guard\n          // against passing a non-array into setCommonDimensions.\n          if (!Array.isArray(dims)) {\n            console.error('commonDimensions returned non-array:', dims);\n            // Keep the cube-seeded dims (if any) rather than blanking the list.\n            setCommonDimensions(seeded);\n            return;\n          }\n          // Merge: fetched dims win (richer: path/type), but keep any cube\n          // dimensions the intersection omits so the cube's selection stays valid.\n          const fetchedNames = new Set(dims.map(d => d.name));\n          const merged = [\n            ...dims,\n            ...seeded.filter(d => !fetchedNames.has(d.name)),\n          ];\n          setCommonDimensions(merged);\n\n          // Apply pending dimensions from URL if we have them (metrics+dimensions\n          // URL path; cube presets seed their dimensions directly instead).\n          if (pendingDimensionsFromUrl.current.length > 0) {\n            const validDimNames = merged.map(d => d.name);\n            const validPending = pendingDimensionsFromUrl.current.filter(d =>\n              validDimNames.includes(d),\n            );\n            if (validPending.length > 0) {\n              setSelectedDimensions(validPending);\n            }\n            pendingDimensionsFromUrl.current = []; // Clear after applying\n          }\n        } catch (err) {\n          console.error('Failed to fetch dimensions:', err);\n          // Preserve cube-seeded dims on failure rather than blanking the list.\n          setCommonDimensions(seeded);\n        }\n        setDimensionsLoading(false);\n      } else {\n        setCommonDimensions([]);\n        setSelectedDimensions([]);\n      }\n    };\n    fetchData().catch(console.error);\n  }, [selectedMetrics, djClient]);\n\n  // Clear dimension selections that are no longer valid\n  useEffect(() => {\n    const validDimNames = commonDimensions.map(d => d.name);\n    const validSelections = selectedDimensions.filter(d =>\n      validDimNames.includes(d),\n    );\n    if (validSelections.length !== selectedDimensions.length) {\n      setSelectedDimensions(validSelections);\n    }\n  }, [commonDimensions, selectedDimensions]);\n\n  // Phase 1: When dimensions are selected, reactively find compatible metrics\n  useEffect(() => {\n    if (selectedDimensions.length === 0) {\n      setCompatibleMetrics(null);\n      return;\n    }\n    let cancelled = false;\n    djClient\n      .commonMetrics(selectedDimensions)\n      .then(result => {\n        if (cancelled) return;\n        // API returns array of node names (strings) or objects with a name field\n        if (Array.isArray(result)) {\n          const names = result.map(r => (typeof r === 'string' ? r : r.name));\n          setCompatibleMetrics(new Set(names));\n        } else {\n          setCompatibleMetrics(null);\n        }\n      })\n      .catch(() => {\n        if (!cancelled) setCompatibleMetrics(null);\n      });\n    return () => {\n      cancelled = true;\n    };\n  }, [selectedDimensions, djClient]);\n\n  // Fetch V3 measures and metrics SQL when selection, filters, or engine changes\n  useEffect(() => {\n    const fetchData = async () => {\n      if (selectedMetrics.length > 0) {\n        setLoading(true);\n        setError(null);\n        setSelectedNode(null);\n        try {\n          // Derive useMaterialized and dialect from selectedEngine\n          const useMaterialized = selectedEngine !== 'trino';\n          const dialect = selectedEngine || null;\n          // Fetch both measures and metrics SQL in parallel\n          const [measures, metrics] = await Promise.all([\n            djClient.measuresV3(selectedMetrics, selectedDimensions),\n            djClient.metricsV3(\n              selectedMetrics,\n              selectedDimensions,\n              filters,\n              useMaterialized,\n              dialect,\n            ),\n          ]);\n          setMeasuresResult(measures);\n          setMetricsResult(metrics);\n        } catch (err) {\n          setError(err.message || 'Failed to fetch data');\n          setMeasuresResult(null);\n          setMetricsResult(null);\n        }\n        setLoading(false);\n      } else {\n        setMeasuresResult(null);\n        setMetricsResult(null);\n      }\n    };\n    fetchData().catch(console.error);\n  }, [djClient, selectedMetrics, selectedDimensions, filters, selectedEngine]);\n\n  // Fetch existing pre-aggregations for the grain groups\n  useEffect(() => {\n    const fetchExistingPreaggs = async () => {\n      if (!measuresResult?.grain_groups?.length) {\n        setPlannedPreaggs({});\n        return;\n      }\n\n      // Get unique node names from grain groups\n      try {\n        // For each grain group, ask server to find matching pre-aggs\n        const newPreaggs = {};\n\n        // Use requested_dimensions from the measures result - these are the fully qualified\n        // dimension references that pre-aggs are created with\n        const requestedDims = measuresResult.requested_dimensions || [];\n        const grainColsForLookup = requestedDims.join(',');\n        console.log(\n          'grainCols for pre-agg lookup (from requested_dimensions):',\n          grainColsForLookup,\n        );\n\n        await Promise.all(\n          measuresResult.grain_groups.map(async gg => {\n            const grainKey = `${gg.parent_name}|${normalizeGrain(gg.grain)}`;\n\n            // Extract measure names\n            const measureNames = (gg.components || [])\n              .map(c => c.name)\n              .filter(Boolean)\n              .join(',');\n\n            console.log(\n              `Looking for pre-agg: node=${gg.parent_name}, grain=${grainColsForLookup}, measures=${measureNames}`,\n            );\n\n            // First try exact match using requested_dimensions\n            let result = await djClient.listPreaggs({\n              node_name: gg.parent_name,\n              grain: grainColsForLookup,\n              grain_mode: 'exact',\n              measures: measureNames || undefined,\n            });\n\n            console.log(`Exact match result for ${gg.parent_name}:`, result);\n\n            let preaggs = result.items || result.pre_aggregations || [];\n            let match = preaggs[0];\n\n            // If no exact match, try superset (finer grain)\n            if (!match) {\n              result = await djClient.listPreaggs({\n                node_name: gg.parent_name,\n                grain: grainColsForLookup,\n                grain_mode: 'superset',\n                measures: measureNames || undefined,\n              });\n              console.log(\n                `Superset match result for ${gg.parent_name}:`,\n                result,\n              );\n              preaggs = result.items || result.pre_aggregations || [];\n              match = preaggs[0];\n\n              // Mark as compatible (not exact match)\n              if (match) {\n                match = { ...match, _isCompatible: true };\n              }\n            }\n\n            if (match) {\n              console.log(`Found pre-agg match for ${gg.parent_name}:`, match);\n              newPreaggs[grainKey] = match;\n            } else {\n              console.log(`No pre-agg match found for ${gg.parent_name}`);\n            }\n          }),\n        );\n\n        setPlannedPreaggs(newPreaggs);\n      } catch (err) {\n        console.error('Failed to fetch existing pre-aggs:', err);\n      }\n    };\n\n    fetchExistingPreaggs();\n  }, [measuresResult, djClient]);\n\n  // Auto-detect cube info when metricsResult has cube_name (backend found a matching cube)\n  // This effect manages cubeAvailability, cubeMaterialization, and workflowUrls based on\n  // either: 1) explicit user selection (loadedCubeName), or 2) auto-detected cube (metricsResult.cube_name)\n  useEffect(() => {\n    const fetchCubeInfo = async () => {\n      // Determine which cube to use: explicit selection takes precedence over auto-detection\n      const cubeName = loadedCubeName || metricsResult?.cube_name;\n\n      if (!cubeName) {\n        // No cube - clear state\n        setCubeAvailability(null);\n        setCubeMaterialization(null);\n        setWorkflowUrls([]);\n        return;\n      }\n\n      try {\n        // Fetch full cube info including materialization\n        const cubeData = await djClient.cubeForPlanner(cubeName);\n        setCubeAvailability(cubeData?.availability || null);\n\n        if (cubeData) {\n          const cubeMat = cubeData.cubeMaterialization;\n          setCubeMaterialization(cubeMat || null);\n          setWorkflowUrls(cubeMat?.workflowUrls || []);\n        } else {\n          setCubeMaterialization(null);\n          setWorkflowUrls([]);\n        }\n      } catch (err) {\n        console.error('Failed to fetch cube info:', err);\n        setCubeAvailability(null);\n        setCubeMaterialization(null);\n        setWorkflowUrls([]);\n      }\n    };\n\n    fetchCubeInfo();\n  }, [metricsResult?.cube_name, loadedCubeName, djClient]);\n\n  // Leave cube-preset mode: drop the cube name (so the URL expands to its\n  // components and workflow/materialization state is recomputed) and forget the\n  // cube-seeded dims, which are no longer authoritative once the user edits.\n  const leaveCubeMode = useCallback(() => {\n    setLoadedCubeName(null);\n    cubeDimensionObjects.current = [];\n  }, []);\n\n  const handleMetricsChange = useCallback(\n    newMetrics => {\n      setSelectedMetrics(newMetrics);\n      setSelectedNode(null);\n      leaveCubeMode();\n    },\n    [leaveCubeMode],\n  );\n\n  // Load a cube preset - sets both metrics and dimensions from the cube definition\n  const handleLoadCubePreset = useCallback(\n    async cubeName => {\n      if (!cubeName) return;\n\n      try {\n        // Use lightweight GraphQL query - much faster than REST endpoint\n        const cubeData = await djClient.cubeForPlanner(cubeName);\n        // Validate cube data has expected fields\n        if (cubeData && Array.isArray(cubeData.cube_node_metrics)) {\n          // Extract metrics and dimensions from the cube\n          const cubeMetrics = cubeData.cube_node_metrics || [];\n          const cubeDimensions = cubeData.cube_node_dimensions || [];\n          const cubeDimObjects = cubeData.cube_dimension_objects || [];\n\n          // Set the cube name for URL and display\n          setLoadedCubeName(cubeName);\n          // Set the metrics first - common dimensions load in the background\n          setSelectedMetrics(cubeMetrics);\n          // Seed the dimension picker and selection straight from the cube so\n          // they appear instantly and correctly, without waiting on the slow\n          // common-dimensions intersection over every cube metric.\n          cubeDimensionObjects.current = cubeDimObjects;\n          setCommonDimensions(cubeDimObjects);\n          setSelectedDimensions(cubeDimensions);\n          // Start with a clean slate: filters from a previously loaded cube may\n          // reference dimensions this cube doesn't have, so don't carry them over.\n          setFilters([]);\n          setSelectedNode(null);\n\n          // Materialization and availability info is included in the GraphQL response\n          setCubeAvailability(cubeData.availability || null);\n          const cubeMat = cubeData.cubeMaterialization;\n          setCubeMaterialization(cubeMat || null);\n          setWorkflowUrls(cubeMat?.workflowUrls || []);\n        } else {\n          console.error('Invalid cube data received:', cubeData);\n        }\n      } catch (err) {\n        console.error('Failed to load cube preset:', err);\n      }\n    },\n    [djClient],\n  );\n\n  // Clear cube preset when selection is manually cleared\n  const handleClearSelection = useCallback(() => {\n    setSelectedMetrics([]);\n    setSelectedDimensions([]);\n    setFilters([]);\n    setWorkflowUrls([]);\n    setCubeMaterialization(null);\n    leaveCubeMode();\n  }, [leaveCubeMode]);\n\n  const handleDimensionsChange = useCallback(\n    newDimensions => {\n      setSelectedDimensions(newDimensions);\n      setSelectedNode(null);\n      leaveCubeMode();\n    },\n    [leaveCubeMode],\n  );\n\n  const handleNodeSelect = useCallback(node => {\n    setSelectedNode(node);\n  }, []);\n\n  const handleClosePanel = useCallback(() => {\n    setSelectedNode(null);\n  }, []);\n\n  // Handle planning/saving a new materialization configuration\n  // Note: This creates pre-aggs for ALL grain groups with the same settings\n  const handlePlanMaterialization = useCallback(\n    async (grainGroup, config) => {\n      setMaterializationError(null); // Clear any previous error\n\n      try {\n        // Step 1: Create the pre-agg records with config\n        const result = await djClient.planPreaggs(\n          selectedMetrics,\n          selectedDimensions,\n          config.strategy,\n          config.schedule,\n          config.lookbackWindow,\n        );\n\n        // Check for error in response\n        if (result._error || result.message || result.detail) {\n          const errorMsg =\n            result.message ||\n            result.detail ||\n            'Failed to plan pre-aggregations';\n          setMaterializationError(errorMsg);\n          throw new Error(errorMsg);\n        }\n\n        // Get the created pre-aggs (API returns `preaggs`, list endpoint returns `items`)\n        const preaggs =\n          result.preaggs || result.items || result.pre_aggregations || [];\n\n        // Update local state\n        const newPreaggs = { ...plannedPreaggs };\n        preaggs.forEach(preagg => {\n          const grainKey = `${preagg.node_name}|${normalizeGrain(\n            preagg.grain_columns,\n          )}`;\n          newPreaggs[grainKey] = preagg;\n        });\n        setPlannedPreaggs(newPreaggs);\n\n        // Step 2: Create scheduled workflows and optionally run backfills\n        if (preaggs.length > 0 && config.schedule) {\n          const workflowPromises = [];\n          const backfillPromises = [];\n\n          for (const preagg of preaggs) {\n            // Always create the scheduled workflow when a schedule is provided\n            workflowPromises.push(\n              djClient.materializePreagg(preagg.id).catch(err => {\n                console.error(\n                  `Failed to create workflow for preagg ${preagg.id}:`,\n                  err,\n                );\n                return null;\n              }),\n            );\n          }\n\n          // First: Wait for all workflows to be created\n          const workflowResults = await Promise.all(workflowPromises);\n\n          // Second: Only after workflows are created, start backfills\n          for (const preagg of preaggs) {\n            if (\n              config.runBackfill &&\n              config.backfillFrom &&\n              config.backfillTo\n            ) {\n              backfillPromises.push(\n                djClient\n                  .runPreaggBackfill(\n                    preagg.id,\n                    config.backfillFrom,\n                    config.backfillTo,\n                  )\n                  .catch(err => {\n                    console.error(\n                      `Failed to run backfill for preagg ${preagg.id}:`,\n                      err,\n                    );\n                    return null;\n                  }),\n              );\n            }\n          }\n\n          // Wait for all backfills to complete\n          const backfillResults = await Promise.all(backfillPromises);\n\n          // Update state with workflow URLs\n          const updatedPreaggs = { ...newPreaggs };\n          preaggs.forEach((preagg, idx) => {\n            const grainKey = `${preagg.node_name}|${normalizeGrain(\n              preagg.grain_columns,\n            )}`;\n            const workflowResult = workflowResults[idx];\n            if (workflowResult?.workflow_urls?.length > 0) {\n              updatedPreaggs[grainKey] = {\n                ...updatedPreaggs[grainKey],\n                workflow_urls: workflowResult.workflow_urls,\n                workflow_status: workflowResult.workflow_status || 'active',\n              };\n            }\n          });\n          setPlannedPreaggs(updatedPreaggs);\n\n          // Show toast with backfill info\n          const successfulBackfills = backfillResults.filter(r => r?.job_url);\n          if (successfulBackfills.length > 0) {\n            console.log('Backfills started:', successfulBackfills);\n          }\n        }\n\n        // Step 3: If Druid cube enabled, schedule cube materialization\n        console.log(\n          'Scheduling Druid cube materialization for:',\n          config.enableDruidCube,\n        );\n        if (config.enableDruidCube) {\n          // Use existing cube if loaded, otherwise use the new cube name from config\n          const cubeName = loadedCubeName || config.druidCubeName;\n\n          if (!cubeName) {\n            const errorMsg = 'Cube name is required for Druid materialization';\n            setMaterializationError(errorMsg);\n            throw new Error(errorMsg); // Throw so form doesn't close\n          }\n\n          // Continue with cube creation/materialization\n          console.log('Scheduling Druid cube materialization for:', cubeName);\n\n          // If no existing cube, create one first\n          if (!loadedCubeName && config.druidCubeName) {\n            const cubeResult = await djClient.createCube(\n              config.druidCubeName, // name\n              config.druidCubeName.split('.').pop(), // display_name (short name)\n              `Druid cube for ${selectedMetrics.join(', ')}`, // description\n              'published', // mode\n              selectedMetrics, // metrics\n              selectedDimensions, // dimensions\n              [], // filters\n            );\n\n            if (cubeResult.status >= 400) {\n              const errorMsg =\n                cubeResult.json?.message ||\n                cubeResult.json?.detail ||\n                'Failed to create cube';\n              // Check if it's a \"cube already exists\" error - that's okay\n              if (!errorMsg.toLowerCase().includes('already exists')) {\n                setMaterializationError(`Failed to create cube: ${errorMsg}`);\n                return result; // Don't proceed with materialization\n              }\n              console.log(\n                'Cube already exists, proceeding with materialization',\n              );\n            }\n            // Set the loaded cube name so the banner shows it\n            setLoadedCubeName(config.druidCubeName);\n          }\n\n          // Schedule cube materialization (waits on pre-aggs, ingests to Druid)\n          const cubeMaterializeResult = await djClient.materializeCubeV2(\n            cubeName,\n            config.schedule || '0 6 * * *',\n            config.strategy,\n            config.lookbackWindow,\n            config.runBackfill ?? true,\n          );\n\n          if (cubeMaterializeResult.status >= 400) {\n            const errorMsg =\n              cubeMaterializeResult.json?.message ||\n              cubeMaterializeResult.json?.detail ||\n              'Failed to schedule cube materialization';\n            console.error('Cube materialization failed:', errorMsg);\n            // Don't throw - pre-aggs were still created successfully\n            setMaterializationError(\n              `Pre-aggs created but cube materialization failed: ${errorMsg}`,\n            );\n          } else {\n            console.log(\n              'Cube materialization scheduled:',\n              cubeMaterializeResult.json,\n            );\n            console.log(\n              'Workflow URLs from response:',\n              cubeMaterializeResult.json?.workflow_urls,\n            );\n            // Store workflow URLs for display\n            const urls = cubeMaterializeResult.json?.workflow_urls || [];\n            console.log('Setting workflowUrls to:', urls);\n            setWorkflowUrls(urls);\n\n            // If backfill is enabled, also kick off cube backfill\n            if (\n              config.runBackfill &&\n              config.backfillFrom &&\n              config.backfillTo\n            ) {\n              console.log(\n                'Running cube backfill from',\n                config.backfillFrom,\n                'to',\n                config.backfillTo,\n              );\n              try {\n                const cubeBackfillResult = await djClient.runCubeBackfill(\n                  cubeName,\n                  config.backfillFrom,\n                  config.backfillTo,\n                );\n                if (cubeBackfillResult._error) {\n                  console.error(\n                    'Cube backfill failed:',\n                    cubeBackfillResult.message,\n                  );\n                  // Don't throw - cube materialization was still created\n                } else {\n                  console.log(\n                    'Cube backfill started:',\n                    cubeBackfillResult.job_url,\n                  );\n                }\n              } catch (cubeBackfillErr) {\n                console.error('Failed to run cube backfill:', cubeBackfillErr);\n                // Don't throw - cube materialization was still created\n              }\n            }\n          }\n        }\n\n        return result;\n      } catch (err) {\n        console.error('Failed to plan materialization:', err);\n        const errorMsg = err.message || 'Failed to plan materialization';\n        setMaterializationError(errorMsg);\n        throw err;\n      }\n    },\n    [\n      djClient,\n      selectedMetrics,\n      selectedDimensions,\n      plannedPreaggs,\n      loadedCubeName,\n    ],\n  );\n\n  // Handle updating config for a single existing pre-agg\n  const handleUpdateConfig = useCallback(\n    async (preaggId, config) => {\n      setMaterializationError(null);\n      try {\n        const result = await djClient.updatePreaggConfig(\n          preaggId,\n          config.strategy,\n          config.schedule,\n          config.lookbackWindow,\n        );\n\n        if (result._error || result.message || result.detail) {\n          const errorMsg =\n            result.message || result.detail || 'Failed to update config';\n          setMaterializationError(errorMsg);\n          throw new Error(errorMsg);\n        }\n\n        // Update the specific pre-agg in our state\n        setPlannedPreaggs(prev => {\n          const updated = { ...prev };\n          for (const key in updated) {\n            if (updated[key].id === preaggId) {\n              updated[key] = { ...updated[key], ...result };\n              break;\n            }\n          }\n          return updated;\n        });\n\n        return result;\n      } catch (err) {\n        console.error('Failed to update config:', err);\n        const errorMsg = err.message || 'Failed to update config';\n        setMaterializationError(errorMsg);\n        throw err;\n      }\n    },\n    [djClient],\n  );\n\n  // Handle creating/refreshing a scheduled workflow for a pre-agg\n  const handleCreateWorkflow = useCallback(\n    async preaggId => {\n      setMaterializationError(null);\n      try {\n        const result = await djClient.materializePreagg(preaggId);\n\n        if (result._error || result.message || result.detail) {\n          const errorMsg =\n            result.message || result.detail || 'Failed to create workflow';\n          setMaterializationError(errorMsg);\n          return null;\n        }\n\n        // Update the pre-agg with workflow info\n        setPlannedPreaggs(prev => {\n          const updated = { ...prev };\n          for (const key in updated) {\n            if (updated[key].id === preaggId) {\n              updated[key] = {\n                ...updated[key],\n                workflow_urls: result.workflow_urls,\n                workflow_status: result.workflow_status || 'active',\n              };\n              break;\n            }\n          }\n          return updated;\n        });\n\n        return result;\n      } catch (err) {\n        console.error('Failed to create workflow:', err);\n        setMaterializationError(err.message || 'Failed to create workflow');\n        return null;\n      }\n    },\n    [djClient],\n  );\n\n  // Handle running a backfill for a pre-agg\n  const handleRunBackfill = useCallback(\n    async (preaggId, startDate, endDate) => {\n      setMaterializationError(null);\n      try {\n        const result = await djClient.runPreaggBackfill(\n          preaggId,\n          startDate,\n          endDate,\n        );\n\n        if (result._error || result.message || result.detail) {\n          const errorMsg =\n            result.message || result.detail || 'Failed to run backfill';\n          setMaterializationError(errorMsg);\n          return null;\n        }\n\n        // Return the job URL so the UI can display it\n        return result;\n      } catch (err) {\n        console.error('Failed to run backfill:', err);\n        setMaterializationError(err.message || 'Failed to run backfill');\n        return null;\n      }\n    },\n    [djClient],\n  );\n\n  // Handle running an ad-hoc job for a pre-agg (uses backfill with same start/end date)\n  const handleRunAdhoc = useCallback(\n    async (preaggId, partitionDate) => {\n      setMaterializationError(null);\n      try {\n        // Use backfill endpoint with same start and end date for single-date runs\n        const result = await djClient.runPreaggBackfill(\n          preaggId,\n          partitionDate,\n          partitionDate,\n        );\n\n        if (result._error || result.message || result.detail) {\n          const errorMsg =\n            result.message || result.detail || 'Failed to run ad-hoc job';\n          setMaterializationError(errorMsg);\n          return null;\n        }\n\n        // Return the job URL so the UI can display it\n        return result;\n      } catch (err) {\n        console.error('Failed to run ad-hoc job:', err);\n        setMaterializationError(err.message || 'Failed to run ad-hoc job');\n        return null;\n      }\n    },\n    [djClient],\n  );\n\n  // Handle deactivating (pausing) a pre-agg workflow\n  const handleDeactivatePreaggWorkflow = useCallback(\n    async preaggId => {\n      setMaterializationError(null);\n      try {\n        const result = await djClient.deactivatePreaggWorkflow(preaggId);\n\n        if (result._error || result.message?.includes('Failed')) {\n          const errorMsg =\n            result.message || result.detail || 'Failed to deactivate workflow';\n          setMaterializationError(errorMsg);\n          return null;\n        }\n\n        // Update the pre-agg in our state to reflect deactivation\n        // Backend clears all config, so we clear it here too for clean slate\n        setPlannedPreaggs(prev => {\n          const updated = { ...prev };\n          for (const key in updated) {\n            if (updated[key].id === preaggId) {\n              updated[key] = {\n                ...updated[key],\n                strategy: null,\n                schedule: null,\n                lookback_window: null,\n                workflow_status: null,\n                workflow_urls: null,\n              };\n              break;\n            }\n          }\n          return updated;\n        });\n\n        return result;\n      } catch (err) {\n        console.error('Failed to deactivate workflow:', err);\n        setMaterializationError(err.message || 'Failed to deactivate workflow');\n        return null;\n      }\n    },\n    [djClient],\n  );\n\n  // Handle deactivating cube workflow\n  const handleDeactivateCubeWorkflow = useCallback(async () => {\n    if (!loadedCubeName) {\n      setMaterializationError('No cube loaded');\n      return null;\n    }\n    setMaterializationError(null);\n    try {\n      const result = await djClient.deactivateCubeWorkflow(loadedCubeName);\n\n      if (result.status >= 400) {\n        const errorMsg =\n          result.json?.message ||\n          result.json?.detail ||\n          'Failed to deactivate cube workflow';\n        setMaterializationError(errorMsg);\n        return null;\n      }\n\n      // Clear cube materialization state\n      setWorkflowUrls([]);\n      setCubeMaterialization(null);\n\n      return result.json;\n    } catch (err) {\n      console.error('Failed to deactivate cube workflow:', err);\n      setMaterializationError(\n        err.message || 'Failed to deactivate cube workflow',\n      );\n      return null;\n    }\n  }, [djClient, loadedCubeName]);\n\n  // Handle updating cube config\n  const handleUpdateCubeConfig = useCallback(\n    async config => {\n      if (!loadedCubeName) {\n        setMaterializationError('No cube loaded');\n        return null;\n      }\n      setMaterializationError(null);\n      try {\n        // Re-call materialize with new config (run_backfill=false to just update)\n        const result = await djClient.refreshCubeWorkflow(\n          loadedCubeName,\n          config.schedule,\n          config.strategy,\n          config.lookbackWindow,\n        );\n\n        if (result.status >= 400) {\n          const errorMsg =\n            result.json?.message ||\n            result.json?.detail ||\n            'Failed to update cube config';\n          setMaterializationError(errorMsg);\n          return null;\n        }\n\n        // Update local state\n        const urls = result.json?.workflow_urls || [];\n        setWorkflowUrls(urls);\n        setCubeMaterialization(prev => ({\n          ...prev,\n          schedule: config.schedule,\n          strategy: config.strategy,\n          lookbackWindow: config.lookbackWindow,\n          workflowUrls: urls,\n        }));\n\n        return result.json;\n      } catch (err) {\n        console.error('Failed to update cube config:', err);\n        setMaterializationError(err.message || 'Failed to update cube config');\n        return null;\n      }\n    },\n    [djClient, loadedCubeName],\n  );\n\n  // Handle refreshing cube workflow\n  const handleRefreshCubeWorkflow = useCallback(async () => {\n    if (!loadedCubeName || !cubeMaterialization) {\n      setMaterializationError('No cube materialization to refresh');\n      return null;\n    }\n    setMaterializationError(null);\n    try {\n      const result = await djClient.refreshCubeWorkflow(\n        loadedCubeName,\n        cubeMaterialization.schedule,\n        cubeMaterialization.strategy,\n        cubeMaterialization.lookbackWindow,\n      );\n\n      if (result.status >= 400) {\n        const errorMsg =\n          result.json?.message ||\n          result.json?.detail ||\n          'Failed to refresh cube workflow';\n        setMaterializationError(errorMsg);\n        return null;\n      }\n\n      // Update workflow URLs\n      const urls = result.json?.workflow_urls || [];\n      setWorkflowUrls(urls);\n      setCubeMaterialization(prev => ({\n        ...prev,\n        workflowUrls: urls,\n      }));\n\n      return result.json;\n    } catch (err) {\n      console.error('Failed to refresh cube workflow:', err);\n      setMaterializationError(err.message || 'Failed to refresh cube workflow');\n      return null;\n    }\n  }, [djClient, loadedCubeName, cubeMaterialization]);\n\n  // Handle running cube backfill with date range\n  const handleRunCubeBackfill = useCallback(\n    async (startDate, endDate) => {\n      if (!loadedCubeName) {\n        setMaterializationError('No cube to backfill');\n        return null;\n      }\n      if (!startDate) {\n        setMaterializationError('Start date is required');\n        return null;\n      }\n      setMaterializationError(null);\n      try {\n        const result = await djClient.runCubeBackfill(\n          loadedCubeName,\n          startDate,\n          endDate,\n        );\n\n        if (result._error) {\n          setMaterializationError(\n            result.message || 'Failed to run cube backfill',\n          );\n          return null;\n        }\n\n        return result;\n      } catch (err) {\n        console.error('Failed to run cube backfill:', err);\n        setMaterializationError(err.message || 'Failed to run cube backfill');\n        return null;\n      }\n    },\n    [djClient, loadedCubeName],\n  );\n\n  // Fetch raw SQL (without pre-aggregations)\n  const handleFetchRawSql = useCallback(async () => {\n    try {\n      const result = await djClient.metricsV3(\n        selectedMetrics,\n        selectedDimensions,\n        '',\n        false, // useMaterialized = false for raw SQL\n      );\n      return result; // Return full result including scan_estimate\n    } catch (err) {\n      console.error('Failed to fetch raw SQL:', err);\n      return null;\n    }\n  }, [djClient, selectedMetrics, selectedDimensions]);\n\n  // Set partition on a column (for enabling incremental materialization)\n  const handleSetPartition = useCallback(\n    async (nodeName, columnName, partitionType, format, granularity) => {\n      try {\n        return await djClient.setPartition(\n          nodeName,\n          columnName,\n          partitionType,\n          format,\n          granularity,\n        );\n      } catch (err) {\n        console.error('Failed to set partition:', err);\n        throw err;\n      }\n    },\n    [djClient],\n  );\n\n  // Refresh measures result (after setting partition)\n  const handleRefreshMeasures = useCallback(async () => {\n    if (selectedMetrics.length > 0) {\n      try {\n        const [measures, metrics] = await Promise.all([\n          djClient.measuresV3(selectedMetrics, selectedDimensions),\n          djClient.metricsV3(selectedMetrics, selectedDimensions),\n        ]);\n        setMeasuresResult(measures);\n        setMetricsResult(metrics);\n      } catch (err) {\n        console.error('Failed to refresh measures:', err);\n      }\n    }\n  }, [djClient, selectedMetrics, selectedDimensions]);\n\n  // Fetch node columns with partition info (for checking if temporal partitions exist)\n  const handleFetchNodePartitions = useCallback(\n    async nodeName => {\n      return await djClient.getNodeColumnsWithPartitions(nodeName);\n    },\n    [djClient],\n  );\n\n  // Run query and fetch results\n  const handleRunQuery = useCallback(async () => {\n    if (selectedMetrics.length === 0) {\n      setQueryError('Select at least one metric');\n      return;\n    }\n\n    setQueryLoading(true);\n    setQueryError(null);\n    setQueryResults(null);\n    setQueryLinks([]);\n    setShowResults(true);\n    const startTime = Date.now();\n    setQueryStartTime(startTime);\n    setQueryElapsedTime(null);\n\n    try {\n      // Fetch data from /data/ endpoint\n      const results = await djClient.data(\n        selectedMetrics,\n        selectedDimensions,\n        filters,\n        selectedEngine || null,\n        progress => setQueryLinks(progress.links || []),\n      );\n      const elapsed = (Date.now() - startTime) / 1000;\n      setQueryElapsedTime(elapsed);\n      setQueryResults(results);\n    } catch (err) {\n      console.error('Query failed:', err);\n      setQueryError(err.message || 'Failed to execute query');\n    } finally {\n      setQueryLoading(false);\n    }\n  }, [djClient, selectedMetrics, selectedDimensions, filters, selectedEngine]);\n\n  // Handle back to plan view\n  const handleBackToPlan = useCallback(() => {\n    setShowResults(false);\n    setQueryResults(null);\n    setQueryError(null);\n  }, []);\n\n  // Handle filter changes\n  const handleFiltersChange = useCallback(\n    newFilters => {\n      setFilters(newFilters);\n      // A cube-based URL (?cube=...) only encodes the cube name, so filters can't\n      // be represented while a cube preset is loaded. Leaving cube mode expands\n      // the URL into its fully-qualified metrics/dimensions/filters form so the\n      // applied filter is reflected in the URL and the link stays shareable.\n      leaveCubeMode();\n    },\n    [leaveCubeMode],\n  );\n\n  return (\n    <div className=\"planner-page\">\n      {error && (\n        <div className=\"header-error planner-error-banner\">{error}</div>\n      )}\n\n      {/* Three-column layout */}\n      <div className=\"planner-layout\" ref={plannerLayoutRef}>\n        {/* Left: Selection Panel */}\n        <aside\n          className=\"planner-selection\"\n          style={selectionWidth != null ? { width: selectionWidth } : undefined}\n        >\n          <SelectionPanel\n            metrics={metrics}\n            selectedMetrics={selectedMetrics}\n            onMetricsChange={handleMetricsChange}\n            dimensions={commonDimensions}\n            selectedDimensions={selectedDimensions}\n            onDimensionsChange={handleDimensionsChange}\n            loading={dimensionsLoading}\n            cubes={cubes}\n            onLoadCubePreset={handleLoadCubePreset}\n            loadedCubeName={loadedCubeName}\n            onClearSelection={handleClearSelection}\n            filters={filters}\n            onFiltersChange={handleFiltersChange}\n            selectedEngine={selectedEngine}\n            onEngineChange={setSelectedEngine}\n            onRunQuery={handleRunQuery}\n            canRunQuery={selectedMetrics.length > 0}\n            queryLoading={queryLoading}\n            compatibleMetrics={compatibleMetrics}\n          />\n        </aside>\n\n        {/* Vertical resizer between selection panel and main content */}\n        <div\n          className=\"vertical-resizer\"\n          onMouseDown={handleSelectionResizerMouseDown}\n          title=\"Drag to resize\"\n        />\n\n        {/* Main Content Area - Either Results or Graph+Details */}\n        {showResults ? (\n          <ResultsView\n            sql={metricsResult?.sql}\n            results={queryResults}\n            loading={queryLoading}\n            error={queryError}\n            elapsedTime={queryElapsedTime}\n            onBackToPlan={handleBackToPlan}\n            selectedMetrics={selectedMetrics}\n            selectedDimensions={selectedDimensions}\n            filters={filters}\n            dialect={metricsResult?.dialect}\n            cubeName={metricsResult?.cube_name}\n            availability={cubeAvailability}\n            links={queryLinks}\n          />\n        ) : (\n          <>\n            {/* Center: Graph */}\n            <main className=\"planner-graph\">\n              {loading ? (\n                <div className=\"graph-loading\">\n                  <div className=\"loading-spinner\" />\n                  <span>Building data flow...</span>\n                </div>\n              ) : measuresResult ? (\n                <>\n                  <div className=\"graph-header\">\n                    <span className=\"graph-stats\">\n                      {measuresResult.grain_groups?.length || 0}{' '}\n                      pre-aggregations →{' '}\n                      {measuresResult.metric_formulas?.length || 0} metrics\n                    </span>\n                  </div>\n                  {/* Suspense boundary for lazy-loaded ReactFlow graph */}\n                  <Suspense\n                    fallback={\n                      <div className=\"graph-loading\">\n                        <div className=\"loading-spinner\" />\n                        <span>Loading graph...</span>\n                      </div>\n                    }\n                  >\n                    <MetricFlowGraph\n                      grainGroups={measuresResult.grain_groups}\n                      metricFormulas={measuresResult.metric_formulas}\n                      selectedNode={selectedNode}\n                      onNodeSelect={handleNodeSelect}\n                    />\n                  </Suspense>\n                </>\n              ) : (\n                <div className=\"graph-empty\">\n                  <div className=\"empty-icon\">⊞</div>\n                  <h3>Select Metrics & Dimensions</h3>\n                  <p>\n                    Choose metrics from the left panel, then select dimensions\n                    to see how they decompose into pre-aggregations.\n                  </p>\n                </div>\n              )}\n            </main>\n\n            {/* Vertical resizer between graph and details */}\n            <div\n              className=\"vertical-resizer\"\n              onMouseDown={handleDetailsResizerMouseDown}\n              title=\"Drag to resize\"\n            />\n\n            {/* Right: Details Panel */}\n            <aside\n              className=\"planner-details\"\n              style={detailsWidth != null ? { width: detailsWidth } : undefined}\n            >\n              {selectedNode?.type === 'preagg' ||\n              selectedNode?.type === 'component' ? (\n                <PreAggDetailsPanel\n                  preAgg={\n                    selectedNode?.type === 'component'\n                      ? measuresResult?.grain_groups?.[\n                          selectedNode.data?.grainGroupIndex\n                        ]\n                      : selectedNode.data\n                  }\n                  metricFormulas={measuresResult?.metric_formulas}\n                  onClose={handleClosePanel}\n                  highlightedComponent={\n                    selectedNode?.type === 'component'\n                      ? selectedNode.data?.name\n                      : null\n                  }\n                />\n              ) : selectedNode?.type === 'metric' ? (\n                <MetricDetailsPanel\n                  metric={selectedNode.data}\n                  grainGroups={measuresResult?.grain_groups}\n                  onClose={handleClosePanel}\n                />\n              ) : (\n                <QueryOverviewPanel\n                  measuresResult={measuresResult}\n                  metricsResult={metricsResult}\n                  selectedMetrics={selectedMetrics}\n                  selectedDimensions={selectedDimensions}\n                  plannedPreaggs={plannedPreaggs}\n                  onPlanMaterialization={handlePlanMaterialization}\n                  onUpdateConfig={handleUpdateConfig}\n                  onCreateWorkflow={handleCreateWorkflow}\n                  onRunBackfill={handleRunBackfill}\n                  onRunAdhoc={handleRunAdhoc}\n                  onFetchRawSql={handleFetchRawSql}\n                  onSetPartition={handleSetPartition}\n                  onRefreshMeasures={handleRefreshMeasures}\n                  onFetchNodePartitions={handleFetchNodePartitions}\n                  materializationError={materializationError}\n                  onClearError={() => setMaterializationError(null)}\n                  workflowUrls={workflowUrls}\n                  onClearWorkflowUrls={() => setWorkflowUrls([])}\n                  loadedCubeName={loadedCubeName}\n                  cubeMaterialization={cubeMaterialization}\n                  cubeAvailability={cubeAvailability}\n                  onUpdateCubeConfig={handleUpdateCubeConfig}\n                  onRefreshCubeWorkflow={handleRefreshCubeWorkflow}\n                  onRunCubeBackfill={handleRunCubeBackfill}\n                  onDeactivatePreaggWorkflow={handleDeactivatePreaggWorkflow}\n                  onDeactivateCubeWorkflow={handleDeactivateCubeWorkflow}\n                />\n              )}\n            </aside>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default QueryPlannerPage;\n"],"names":["ENGINE_OPTIONS","DIM_DRAG_MIME","andAppend","prev","expr","TailLabel","text","jsx","SelectionPanel","metrics","selectedMetrics","onMetricsChange","dimensions","selectedDimensions","onDimensionsChange","loading","cubes","onLoadCubePreset","loadedCubeName","onClearSelection","filters","onFiltersChange","selectedEngine","onEngineChange","onRunQuery","canRunQuery","queryLoading","compatibleMetrics","metricsSearch","setMetricsSearch","useState","dimensionsSearch","setDimensionsSearch","expandedNamespaces","setExpandedNamespaces","expandedDimGroups","setExpandedDimGroups","expandedRolePaths","setExpandedRolePaths","showCubeDropdown","setShowCubeDropdown","cubeSearch","setCubeSearch","metricsChipsExpanded","setMetricsChipsExpanded","dimensionsChipsExpanded","setDimensionsChipsExpanded","filterInput","setFilterInput","filterDropActive","setFilterDropActive","split1","setSplit1","split2","setSplit2","split3","setSplit3","prevSearchRef","useRef","cubeDropdownRef","metricsSearchRef","dimensionsSearchRef","filterInputRef","sectionsRef","dragRef","splitRef","useEffect","CHIPS_COLLAPSE_THRESHOLD","loadedCube","useMemo","c","handleClickOutside","event","filteredCubes","search","cube","name","displayName","getShortName","fullName","parts","getNamespace","groupedMetrics","groups","metric","namespace","filteredGroups","sortedNamespaces","namespaces","filtered","items","matchingItems","m","a","b","aShort","bShort","aPrefix","bPrefix","aLower","bLower","aContains","bContains","aCount","bCount","currentSearch","prevSearch","dedupedDimensions","byName","d","existing","_a","_b","getRolePath","match","formatRolePath","roleKey","rolePathHops","groupedDimensions","nodeMap","nodeKey","distance","node","groupsArray","rolePaths","rp","n","group","g","getDimDisplayName","toggleNamespace","next","toggleDimGroup","toggleRolePath","key","getDimGroupShortName","handleDividerMouseDown","useCallback","e","divider","startSplit","onMouseMove","height","deltaPct","onMouseUp","toggleMetric","removeMetric","toggleDimension","dimName","removeDimension","selectAllInNamespace","newSelection","deselectAllInNamespace","handleCubeSelect","clearSelection","handleAddFilter","trimmed","handleFilterKeyDown","handleRemoveFilter","filterToRemove","f","handleEditFilter","filter","appendDimToFilterInput","addDimAsFilter","handleDimDragStart","handleFilterDragOver","handleFilterDragLeave","handleFilterDrop","jsxs","isExpanded","selectedInNamespace","isIncompatible","Fragment","nodeExpanded","rpKey","rpExpanded","hops","hopsLabel","dim","idx","value","label","SyntaxHighlighter","sql","SERIES_COLORS","SMALL_MULTIPLES_THRESHOLD","isTimeColumn","col","type","isNumericColumn","detectChartConfig","columns","rows","tagged","i","timeCols","numericCols","nonTimeCatCols","xCol","metricCols","MAX_GROUP_VALUES","buildPivotedData","groupByCol","xIdx","gIdx","metricIdxs","groupTotals","row","gVal","groupValues","k","groupSet","pivotMaps","xVal","mapKey","pm","sortFn","av","bv","metricCol","pivoted","buildChartData","data","obj","formatYAxis","KpiCards","val","formatted","CHART_MARGIN","AXIS_TICK","TOOLTIP_STYLE","TOOLTIP_WRAPPER_STYLE","Chart","memo","seriesKeys","chartData","seriesColors","showDots","keys","xInterval","ResponsiveContainer","LineChart","CartesianGrid","XAxis","YAxis","Tooltip","Line","BarChart","Bar","ChartView","chartConfig","pivotedByMetric","ResultsView","sqlQuery","results","error","elapsedTime","onBackToPlan","dialect","cubeName","availability","links","copied","setCopied","sortColumn","setSortColumn","sortDirection","setSortDirection","activeTab","setActiveTab","sqlPaneHeight","setSqlPaneHeight","resultsPanesRef","handleSqlResizerMouseDown","container","startY","startHeight","moveEvent","delta","newHeight","handleCopySql","rowCount","handleSort","columnIndex","sortedRows","aVal","bVal","cmp","canChart","foundation","link","rowIdx","cell","cellIdx","MetricFlowGraph","lazy","normalizeGrain","grainCols","QueryPlannerPage","djClient","useContext","DJClientContext","location","useLocation","navigate","useNavigate","setMetrics","commonDimensions","setCommonDimensions","setCubes","setSelectedMetrics","setSelectedDimensions","setLoadedCubeName","initializedFromUrl","pendingDimensionsFromUrl","pendingCubeFromUrl","cubeDimensionObjects","setCompatibleMetrics","measuresResult","setMeasuresResult","metricsResult","setMetricsResult","setLoading","dimensionsLoading","setDimensionsLoading","setError","showResults","setShowResults","queryResults","setQueryResults","setQueryLoading","queryError","setQueryError","queryStartTime","setQueryStartTime","queryElapsedTime","setQueryElapsedTime","queryLinks","setQueryLinks","setFilters","setSelectedEngine","cubeAvailability","setCubeAvailability","selectedNode","setSelectedNode","selectionWidth","setSelectionWidth","detailsWidth","setDetailsWidth","plannerLayoutRef","handleSelectionResizerMouseDown","startX","startWidth","newWidth","handleDetailsResizerMouseDown","plannedPreaggs","setPlannedPreaggs","materializationError","setMaterializationError","workflowUrls","setWorkflowUrls","cubeMaterialization","setCubeMaterialization","params","urlMetrics","urlDimensions","urlFilters","urlCube","newSearch","metricsList","cubesList","cubeData","cubeMetrics","cubeDimensions","cubeDimObjects","cubeMat","err","seeded","dims","fetchedNames","merged","validDimNames","validPending","validSelections","cancelled","result","names","r","useMaterialized","measures","newPreaggs","grainColsForLookup","gg","grainKey","measureNames","preaggs","leaveCubeMode","handleMetricsChange","newMetrics","handleLoadCubePreset","handleClearSelection","handleDimensionsChange","newDimensions","handleNodeSelect","handleClosePanel","handlePlanMaterialization","grainGroup","config","errorMsg","preagg","workflowPromises","backfillPromises","workflowResults","backfillResults","updatedPreaggs","workflowResult","successfulBackfills","cubeResult","cubeMaterializeResult","_c","_d","_e","urls","_f","cubeBackfillResult","cubeBackfillErr","handleUpdateConfig","preaggId","updated","handleCreateWorkflow","handleRunBackfill","startDate","endDate","handleRunAdhoc","partitionDate","handleDeactivatePreaggWorkflow","handleDeactivateCubeWorkflow","handleUpdateCubeConfig","handleRefreshCubeWorkflow","handleRunCubeBackfill","handleFetchRawSql","handleSetPartition","nodeName","columnName","partitionType","format","granularity","handleRefreshMeasures","handleFetchNodePartitions","handleRunQuery","startTime","progress","elapsed","handleBackToPlan","handleFiltersChange","newFilters","Suspense","PreAggDetailsPanel","MetricDetailsPanel","QueryOverviewPanel"],"mappings":"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"}