drizzle-cube 0.2.23 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/adapters/compiler-C6JQHGrF.cjs +22 -0
  2. package/dist/adapters/{compiler-DDXMrb9d.js → compiler-Ddwn99Ja.js} +1434 -1289
  3. package/dist/adapters/express/index.cjs +1 -1
  4. package/dist/adapters/express/index.d.ts +6 -1
  5. package/dist/adapters/express/index.js +22 -20
  6. package/dist/adapters/fastify/index.cjs +1 -1
  7. package/dist/adapters/fastify/index.d.ts +6 -1
  8. package/dist/adapters/fastify/index.js +18 -16
  9. package/dist/adapters/hono/index.cjs +1 -1
  10. package/dist/adapters/hono/index.d.ts +6 -1
  11. package/dist/adapters/hono/index.js +87 -85
  12. package/dist/adapters/nextjs/index.cjs +1 -1
  13. package/dist/adapters/nextjs/index.d.ts +6 -1
  14. package/dist/adapters/nextjs/index.js +64 -63
  15. package/dist/adapters/utils.d.ts +18 -0
  16. package/dist/client/charts.js +2 -2
  17. package/dist/client/chunks/{charts-DboFPJFN.js → charts-BsXrHSCm.js} +32 -32
  18. package/dist/client/chunks/{charts-DboFPJFN.js.map → charts-BsXrHSCm.js.map} +1 -1
  19. package/dist/client/chunks/{charts--hFH-bsu.js → charts-BvLb1eub.js} +710 -703
  20. package/dist/client/chunks/charts-BvLb1eub.js.map +1 -0
  21. package/dist/client/chunks/{components-D7wTB56l.js → components-DhA8GIUY.js} +6019 -5299
  22. package/dist/client/chunks/components-DhA8GIUY.js.map +1 -0
  23. package/dist/client/chunks/core-DcwgBEzv.js +6 -0
  24. package/dist/client/chunks/core-DcwgBEzv.js.map +1 -0
  25. package/dist/client/chunks/{index-yc7cf-yE.js → index-9x0R-Fme.js} +2 -2
  26. package/dist/client/chunks/{index-yc7cf-yE.js.map → index-9x0R-Fme.js.map} +1 -1
  27. package/dist/client/components/AnalysisBuilder/AnalysisQueryPanel.d.ts +3 -2
  28. package/dist/client/components/AnalysisBuilder/types.d.ts +63 -15
  29. package/dist/client/components/DashboardPortletCard.d.ts +12 -0
  30. package/dist/client/components/DebugModal.d.ts +7 -1
  31. package/dist/client/components.js +2 -2
  32. package/dist/client/hooks/useMultiCubeQuery.d.ts +36 -0
  33. package/dist/client/hooks.js +2 -2
  34. package/dist/client/icons.js +1 -1
  35. package/dist/client/index.d.ts +7 -1
  36. package/dist/client/index.js +70 -52
  37. package/dist/client/providers.js +1 -1
  38. package/dist/client/styles.css +1 -1
  39. package/dist/client/types.d.ts +32 -0
  40. package/dist/client/utils/multiQueryUtils.d.ts +86 -0
  41. package/dist/client/utils/multiQueryValidation.d.ts +69 -0
  42. package/dist/client/utils/shareUtils.d.ts +3 -3
  43. package/dist/client-bundle-stats.html +1 -1
  44. package/dist/server/index.cjs +17 -17
  45. package/dist/server/index.d.ts +326 -1
  46. package/dist/server/index.js +2441 -2147
  47. package/package.json +1 -1
  48. package/dist/adapters/compiler-S2NEGW7Q.cjs +0 -22
  49. package/dist/client/chunks/charts--hFH-bsu.js.map +0 -1
  50. package/dist/client/chunks/components-D7wTB56l.js.map +0 -1
  51. package/dist/client/chunks/core-PxWXpBbW.js +0 -6
  52. package/dist/client/chunks/core-PxWXpBbW.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components-DhA8GIUY.js","sources":["../../../node_modules/react-intersection-observer/dist/index.mjs","../../../src/client/utils/multiQueryUtils.ts","../../../src/client/hooks/useMultiCubeQuery.ts","../../../src/client/components/ChartErrorBoundary.tsx","../../../src/client/types.ts","../../../src/client/utils/filterUtils.ts","../../../src/client/components/AnalyticsPortlet.tsx","../../../src/client/hooks/useScrollDetection.ts","../../../src/client/hooks/useElementVisibility.ts","../../../src/client/utils/syntaxHighlighting.ts","../../../src/client/components/DebugModal.tsx","../../../src/client/components/DashboardPortletCard.tsx","../../../src/client/components/RowManagedLayout.tsx","../../../src/client/utils/colorPalettes.ts","../../../src/client/components/FloatingEditToolbar.tsx","../../../src/client/components/Modal.tsx","../../../src/shared/date-utils.ts","../../../src/client/components/AnalysisBuilder/utils.ts","../../../src/client/components/AnalysisBuilder/FieldSearchItem.tsx","../../../src/client/components/AnalysisBuilder/FieldDetailPanel.tsx","../../../src/client/components/AnalysisBuilder/FieldSearchModal.tsx","../../../src/client/shared/types.ts","../../../src/client/shared/utils.ts","../../../src/client/shared/components/QueryAnalysisPanel.tsx","../../../node_modules/highlight.js/lib/core.js","../../../node_modules/highlight.js/es/languages/json.js","../../../node_modules/highlight.js/es/languages/sql.js","../../../src/client/shared/components/CodeBlock.tsx","../../../src/client/shared/chartDefaults.ts","../../../src/client/components/ColorPaletteSelector.tsx","../../../src/client/components/AnalysisBuilder/AnalysisResultsPanel.tsx","../../../src/client/components/AnalysisBuilder/MetricItemCard.tsx","../../../src/client/components/AnalysisBuilder/MetricsSection.tsx","../../../src/client/components/AnalysisBuilder/types.ts","../../../src/client/components/AnalysisBuilder/BreakdownItemCard.tsx","../../../src/client/components/AnalysisBuilder/BreakdownSection.tsx","../../../src/client/components/AnalysisBuilder/FilterConfigModal.tsx","../../../src/client/components/AnalysisBuilder/AnalysisFilterItem.tsx","../../../src/client/components/AnalysisBuilder/AnalysisFilterGroup.tsx","../../../src/client/components/AnalysisBuilder/AnalysisFilterSection.tsx","../../../src/client/components/AnalysisBuilder/AnalysisAxisDropZone.tsx","../../../src/client/charts/chartConfigRegistry.ts","../../../src/client/components/ChartTypeSelector.tsx","../../../src/client/components/AnalysisBuilder/AnalysisChartConfigPanel.tsx","../../../src/client/components/AnalysisBuilder/AnalysisDisplayConfigPanel.tsx","../../../src/client/components/AnalysisBuilder/AnalysisQueryPanel.tsx","../../../node_modules/lz-string/libs/lz-string.js","../../../src/client/utils/shareUtils.ts","../../../src/client/components/AIAssistant/utils.ts","../../../src/client/utils/multiQueryValidation.ts","../../../src/client/components/AnalysisBuilder/AnalysisAIPanel.tsx","../../../src/client/components/AnalysisBuilder/index.tsx","../../../src/client/components/QueryBuilderShim.tsx","../../../src/client/components/AxisDropZone.tsx","../../../src/client/components/ChartConfigPanel.tsx","../../../src/client/components/PortletEditModal.tsx","../../../src/client/components/PortletAnalysisModal.tsx","../../../src/client/components/PortletFilterConfigModal.tsx","../../../src/client/components/shared/FilterValueSelector.tsx","../../../src/client/components/shared/utils.ts","../../../src/client/utils/measureIcons.tsx","../../../src/client/components/shared/FilterItem.tsx","../../../src/client/components/shared/FilterGroup.tsx","../../../src/client/components/shared/FilterBuilder.tsx","../../../src/client/components/shared/DateRangeSelector.tsx","../../../src/client/components/shared/CubeMetaExplorer.tsx","../../../src/client/components/DashboardFilters/FilterEditModal.tsx","../../../src/client/components/DashboardFilters/ReadOnlyFilterList.tsx","../../../src/client/components/DashboardFilters/EditModeFilterList.tsx","../../../src/client/components/DashboardFilterPanel.tsx","../../../src/client/components/ScaledGridWrapper.tsx","../../../src/client/components/MobileStackedLayout.tsx","../../../src/client/components/DashboardGrid.tsx","../../../src/client/components/AnalyticsDashboard.tsx","../../../src/client/components/PortletContainer.tsx","../../../src/client/components/DashboardEditModal.tsx"],"sourcesContent":["\"use client\";\nvar __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// src/InView.tsx\nimport * as React from \"react\";\n\n// src/observe.ts\nvar observerMap = /* @__PURE__ */ new Map();\nvar RootIds = /* @__PURE__ */ new WeakMap();\nvar rootId = 0;\nvar unsupportedValue;\nfunction defaultFallbackInView(inView) {\n unsupportedValue = inView;\n}\nfunction getRootId(root) {\n if (!root) return \"0\";\n if (RootIds.has(root)) return RootIds.get(root);\n rootId += 1;\n RootIds.set(root, rootId.toString());\n return RootIds.get(root);\n}\nfunction optionsToId(options) {\n return Object.keys(options).sort().filter(\n (key) => options[key] !== void 0\n ).map((key) => {\n return `${key}_${key === \"root\" ? getRootId(options.root) : options[key]}`;\n }).toString();\n}\nfunction createObserver(options) {\n const id = optionsToId(options);\n let instance = observerMap.get(id);\n if (!instance) {\n const elements = /* @__PURE__ */ new Map();\n let thresholds;\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n var _a2;\n const inView = entry.isIntersecting && thresholds.some((threshold) => entry.intersectionRatio >= threshold);\n if (options.trackVisibility && typeof entry.isVisible === \"undefined\") {\n entry.isVisible = inView;\n }\n (_a2 = elements.get(entry.target)) == null ? void 0 : _a2.forEach((callback) => {\n callback(inView, entry);\n });\n });\n }, options);\n thresholds = observer.thresholds || (Array.isArray(options.threshold) ? options.threshold : [options.threshold || 0]);\n instance = {\n id,\n observer,\n elements\n };\n observerMap.set(id, instance);\n }\n return instance;\n}\nfunction observe(element, callback, options = {}, fallbackInView = unsupportedValue) {\n if (typeof window.IntersectionObserver === \"undefined\" && fallbackInView !== void 0) {\n const bounds = element.getBoundingClientRect();\n callback(fallbackInView, {\n isIntersecting: fallbackInView,\n target: element,\n intersectionRatio: typeof options.threshold === \"number\" ? options.threshold : 0,\n time: 0,\n boundingClientRect: bounds,\n intersectionRect: bounds,\n rootBounds: bounds\n });\n return () => {\n };\n }\n const { id, observer, elements } = createObserver(options);\n const callbacks = elements.get(element) || [];\n if (!elements.has(element)) {\n elements.set(element, callbacks);\n }\n callbacks.push(callback);\n observer.observe(element);\n return function unobserve() {\n callbacks.splice(callbacks.indexOf(callback), 1);\n if (callbacks.length === 0) {\n elements.delete(element);\n observer.unobserve(element);\n }\n if (elements.size === 0) {\n observer.disconnect();\n observerMap.delete(id);\n }\n };\n}\n\n// src/InView.tsx\nfunction isPlainChildren(props) {\n return typeof props.children !== \"function\";\n}\nvar InView = class extends React.Component {\n constructor(props) {\n super(props);\n __publicField(this, \"node\", null);\n __publicField(this, \"_unobserveCb\", null);\n __publicField(this, \"lastInView\");\n __publicField(this, \"handleNode\", (node) => {\n if (this.node) {\n this.unobserve();\n if (!node && !this.props.triggerOnce && !this.props.skip) {\n this.setState({ inView: !!this.props.initialInView, entry: void 0 });\n this.lastInView = this.props.initialInView;\n }\n }\n this.node = node ? node : null;\n this.observeNode();\n });\n __publicField(this, \"handleChange\", (inView, entry) => {\n const previousInView = this.lastInView;\n this.lastInView = inView;\n if (previousInView === void 0 && !inView) {\n return;\n }\n if (inView && this.props.triggerOnce) {\n this.unobserve();\n }\n if (!isPlainChildren(this.props)) {\n this.setState({ inView, entry });\n }\n if (this.props.onChange) {\n this.props.onChange(inView, entry);\n }\n });\n this.state = {\n inView: !!props.initialInView,\n entry: void 0\n };\n this.lastInView = props.initialInView;\n }\n componentDidMount() {\n this.unobserve();\n this.observeNode();\n }\n componentDidUpdate(prevProps) {\n if (prevProps.rootMargin !== this.props.rootMargin || prevProps.root !== this.props.root || prevProps.threshold !== this.props.threshold || prevProps.skip !== this.props.skip || prevProps.trackVisibility !== this.props.trackVisibility || prevProps.delay !== this.props.delay) {\n this.unobserve();\n this.observeNode();\n }\n }\n componentWillUnmount() {\n this.unobserve();\n }\n observeNode() {\n if (!this.node || this.props.skip) return;\n const {\n threshold,\n root,\n rootMargin,\n trackVisibility,\n delay,\n fallbackInView\n } = this.props;\n if (this.lastInView === void 0) {\n this.lastInView = this.props.initialInView;\n }\n this._unobserveCb = observe(\n this.node,\n this.handleChange,\n {\n threshold,\n root,\n rootMargin,\n // @ts-expect-error\n trackVisibility,\n delay\n },\n fallbackInView\n );\n }\n unobserve() {\n if (this._unobserveCb) {\n this._unobserveCb();\n this._unobserveCb = null;\n }\n }\n render() {\n const { children } = this.props;\n if (typeof children === \"function\") {\n const { inView, entry } = this.state;\n return children({ inView, entry, ref: this.handleNode });\n }\n const {\n as,\n triggerOnce,\n threshold,\n root,\n rootMargin,\n onChange,\n skip,\n trackVisibility,\n delay,\n initialInView,\n fallbackInView,\n ...props\n } = this.props;\n return React.createElement(\n as || \"div\",\n { ref: this.handleNode, ...props },\n children\n );\n }\n};\n\n// src/useInView.tsx\nimport * as React2 from \"react\";\nfunction useInView({\n threshold,\n delay,\n trackVisibility,\n rootMargin,\n root,\n triggerOnce,\n skip,\n initialInView,\n fallbackInView,\n onChange\n} = {}) {\n var _a2;\n const [ref, setRef] = React2.useState(null);\n const callback = React2.useRef(onChange);\n const lastInViewRef = React2.useRef(initialInView);\n const [state, setState] = React2.useState({\n inView: !!initialInView,\n entry: void 0\n });\n callback.current = onChange;\n React2.useEffect(\n () => {\n if (lastInViewRef.current === void 0) {\n lastInViewRef.current = initialInView;\n }\n if (skip || !ref) return;\n let unobserve;\n unobserve = observe(\n ref,\n (inView, entry) => {\n const previousInView = lastInViewRef.current;\n lastInViewRef.current = inView;\n if (previousInView === void 0 && !inView) {\n return;\n }\n setState({\n inView,\n entry\n });\n if (callback.current) callback.current(inView, entry);\n if (entry.isIntersecting && triggerOnce && unobserve) {\n unobserve();\n unobserve = void 0;\n }\n },\n {\n root,\n rootMargin,\n threshold,\n // @ts-expect-error\n trackVisibility,\n delay\n },\n fallbackInView\n );\n return () => {\n if (unobserve) {\n unobserve();\n }\n };\n },\n // We break the rule here, because we aren't including the actual `threshold` variable\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n // If the threshold is an array, convert it to a string, so it won't change between renders.\n Array.isArray(threshold) ? threshold.toString() : threshold,\n ref,\n root,\n rootMargin,\n triggerOnce,\n skip,\n trackVisibility,\n fallbackInView,\n delay\n ]\n );\n const entryTarget = (_a2 = state.entry) == null ? void 0 : _a2.target;\n const previousEntryTarget = React2.useRef(void 0);\n if (!ref && entryTarget && !triggerOnce && !skip && previousEntryTarget.current !== entryTarget) {\n previousEntryTarget.current = entryTarget;\n setState({\n inView: !!initialInView,\n entry: void 0\n });\n lastInViewRef.current = initialInView;\n }\n const result = [setRef, state.inView, state.entry];\n result.ref = result[0];\n result.inView = result[1];\n result.entry = result[2];\n return result;\n}\n\n// src/useOnInView.tsx\nimport * as React3 from \"react\";\nvar _a, _b;\nvar useSyncEffect = (_b = (_a = React3.useInsertionEffect) != null ? _a : React3.useLayoutEffect) != null ? _b : React3.useEffect;\nvar useOnInView = (onIntersectionChange, {\n threshold,\n root,\n rootMargin,\n trackVisibility,\n delay,\n triggerOnce,\n skip\n} = {}) => {\n const onIntersectionChangeRef = React3.useRef(onIntersectionChange);\n const observedElementRef = React3.useRef(null);\n const observerCleanupRef = React3.useRef(void 0);\n const lastInViewRef = React3.useRef(void 0);\n useSyncEffect(() => {\n onIntersectionChangeRef.current = onIntersectionChange;\n }, [onIntersectionChange]);\n return React3.useCallback(\n (element) => {\n const cleanupExisting = () => {\n if (observerCleanupRef.current) {\n const cleanup = observerCleanupRef.current;\n observerCleanupRef.current = void 0;\n cleanup();\n }\n };\n if (element === observedElementRef.current) {\n return observerCleanupRef.current;\n }\n if (!element || skip) {\n cleanupExisting();\n observedElementRef.current = null;\n lastInViewRef.current = void 0;\n return;\n }\n cleanupExisting();\n observedElementRef.current = element;\n let destroyed = false;\n const destroyObserver = observe(\n element,\n (inView, entry) => {\n const previousInView = lastInViewRef.current;\n lastInViewRef.current = inView;\n if (previousInView === void 0 && !inView) {\n return;\n }\n onIntersectionChangeRef.current(\n inView,\n entry\n );\n if (triggerOnce && inView) {\n stopObserving();\n }\n },\n {\n threshold,\n root,\n rootMargin,\n trackVisibility,\n delay\n }\n );\n function stopObserving() {\n if (destroyed) return;\n destroyed = true;\n destroyObserver();\n observedElementRef.current = null;\n observerCleanupRef.current = void 0;\n lastInViewRef.current = void 0;\n }\n observerCleanupRef.current = stopObserving;\n return observerCleanupRef.current;\n },\n [\n Array.isArray(threshold) ? threshold.toString() : threshold,\n root,\n rootMargin,\n trackVisibility,\n delay,\n triggerOnce,\n skip\n ]\n );\n};\nexport {\n InView,\n defaultFallbackInView,\n observe,\n useInView,\n useOnInView\n};\n//# sourceMappingURL=index.mjs.map","/**\n * Multi-Query Data Utilities\n * Handles merging results from multiple CubeQuery executions\n *\n * Pattern follows comparisonUtils.ts for metadata injection:\n * - __queryIndex: numeric index of the source query (0-based)\n * - __queryLabel: user-defined or auto-generated label for the query\n */\n\nimport type { CubeResultSet, CubeQuery, QueryMergeStrategy } from '../types'\n\n/**\n * Metadata fields injected into multi-query data\n */\nexport interface MultiQueryMetadata {\n __queryIndex: number\n __queryLabel: string\n}\n\n/**\n * Check if data contains multi-query metadata\n */\nexport function isMultiQueryData(data: unknown[]): boolean {\n return data.length > 0 && typeof data[0] === 'object' && data[0] !== null && '__queryIndex' in data[0]\n}\n\n/**\n * Get unique query labels from multi-query data\n */\nexport function getQueryLabels(data: unknown[]): string[] {\n if (!isMultiQueryData(data)) return []\n\n const labels = new Set<string>()\n for (const row of data) {\n const label = (row as Record<string, unknown>).__queryLabel\n if (typeof label === 'string') {\n labels.add(label)\n }\n }\n return Array.from(labels)\n}\n\n/**\n * Get query indices from multi-query data\n */\nexport function getQueryIndices(data: unknown[]): number[] {\n if (!isMultiQueryData(data)) return []\n\n const indices = new Set<number>()\n for (const row of data) {\n const index = (row as Record<string, unknown>).__queryIndex\n if (typeof index === 'number') {\n indices.add(index)\n }\n }\n return Array.from(indices).sort((a, b) => a - b)\n}\n\n/**\n * Merge results using 'concat' strategy\n * Appends all rows with __queryIndex and __queryLabel metadata\n *\n * @param resultSets - Array of CubeResultSet from each query\n * @param queries - Original CubeQuery objects\n * @param labels - Optional user-defined labels per query\n * @returns Merged data array with query metadata\n */\nexport function mergeResultsConcat(\n resultSets: CubeResultSet[],\n _queries: CubeQuery[],\n labels?: string[]\n): unknown[] {\n const merged: unknown[] = []\n\n resultSets.forEach((resultSet, queryIndex) => {\n const data = resultSet.rawData()\n const label = labels?.[queryIndex] || `Query ${queryIndex + 1}`\n\n data.forEach(row => {\n merged.push({\n ...row,\n __queryIndex: queryIndex,\n __queryLabel: label\n })\n })\n })\n\n return merged\n}\n\n/**\n * Merge results using 'merge' strategy\n * Aligns data by common dimensions (composite key), combining measures from all queries\n *\n * Example:\n * Query 1: [{ date: '2024-01', revenue: 100 }]\n * Query 2: [{ date: '2024-01', cost: 50 }]\n * Result: [{ date: '2024-01', revenue: 100, cost: 50 }]\n *\n * If multiple queries have the same measure, the first query's value is used.\n *\n * @param resultSets - Array of CubeResultSet from each query\n * @param queries - Original CubeQuery objects\n * @param mergeKeys - Dimension fields to align data on (composite key)\n * @param _labels - Optional user-defined labels per query (unused, kept for API compatibility)\n * @returns Merged data array with combined measures\n */\nexport function mergeResultsByKey(\n resultSets: CubeResultSet[],\n queries: CubeQuery[],\n mergeKeys: string[],\n _labels?: string[]\n): unknown[] {\n const mergedMap = new Map<string, Record<string, unknown>>()\n\n resultSets.forEach((resultSet, queryIndex) => {\n const data = resultSet.rawData()\n const measures = queries[queryIndex].measures || []\n\n data.forEach(row => {\n // Create composite key from all merge dimensions\n const keyValue = mergeKeys.map(k => String(row[k] ?? '')).join('|')\n\n if (!mergedMap.has(keyValue)) {\n // Initialize with all dimension values\n const baseRow: Record<string, unknown> = {}\n mergeKeys.forEach(k => { baseRow[k] = row[k] })\n mergedMap.set(keyValue, baseRow)\n }\n\n const mergedRow = mergedMap.get(keyValue)!\n\n // Add measures using raw field names (no prefix)\n // If same measure exists in multiple queries, first one wins\n measures.forEach(measure => {\n if (!(measure in mergedRow)) {\n mergedRow[measure] = row[measure]\n }\n })\n\n // Copy other dimensions (non-measure, non-merge-key fields) from first query\n if (queryIndex === 0) {\n Object.keys(row).forEach(field => {\n if (!mergeKeys.includes(field) && !measures.includes(field)) {\n if (!(field in mergedRow)) {\n mergedRow[field] = row[field]\n }\n }\n })\n }\n })\n })\n\n // Sort by first merge key for consistent ordering\n return Array.from(mergedMap.values()).sort((a, b) => {\n const aKey = String(a[mergeKeys[0]] ?? '')\n const bKey = String(b[mergeKeys[0]] ?? '')\n return aKey.localeCompare(bKey)\n })\n}\n\n/**\n * Main entry point for merging query results\n * Delegates to appropriate strategy implementation\n *\n * @param resultSets - Array of CubeResultSet from each query\n * @param queries - Original CubeQuery objects\n * @param strategy - Merge strategy ('concat' or 'merge')\n * @param mergeKeys - Dimension fields to align on (required for 'merge' strategy)\n * @param labels - Optional user-defined labels per query\n * @returns Merged data array\n */\nexport function mergeQueryResults(\n resultSets: CubeResultSet[],\n queries: CubeQuery[],\n strategy: QueryMergeStrategy,\n mergeKeys?: string[],\n labels?: string[]\n): unknown[] {\n // Handle edge cases\n if (resultSets.length === 0) return []\n if (resultSets.length === 1) return resultSets[0].rawData()\n\n // Use merge strategy if we have merge keys\n if (strategy === 'merge' && mergeKeys && mergeKeys.length > 0) {\n return mergeResultsByKey(resultSets, queries, mergeKeys, labels)\n }\n\n // Fall back to concat strategy\n return mergeResultsConcat(resultSets, queries, labels)\n}\n\n/**\n * Get combined fields from all queries\n * Used for chart configuration to show all available measures/dimensions\n *\n * @param queries - Array of CubeQuery objects\n * @param _labels - Optional user-defined labels per query (unused, kept for API compatibility)\n * @returns Object containing combined measures, dimensions, and time dimensions\n */\nexport function getCombinedFields(\n queries: CubeQuery[],\n _labels?: string[]\n): {\n measures: string[]\n dimensions: string[]\n timeDimensions: string[]\n} {\n const measures = new Set<string>()\n const dimensions = new Set<string>()\n const timeDimensions = new Set<string>()\n\n queries.forEach((query) => {\n // Measures use raw field names (no prefix), de-duplicated\n query.measures?.forEach(m => measures.add(m))\n\n // Dimensions are shared across queries (de-duplicated)\n query.dimensions?.forEach(d => dimensions.add(d))\n\n // Time dimensions are also shared\n query.timeDimensions?.forEach(td => timeDimensions.add(td.dimension))\n })\n\n return {\n measures: Array.from(measures),\n dimensions: Array.from(dimensions),\n timeDimensions: Array.from(timeDimensions)\n }\n}\n\n/**\n * Generate a default label for a query based on its measures\n * Used when user doesn't provide custom labels\n */\nexport function generateQueryLabel(query: CubeQuery, index: number): string {\n // Try to use first measure name without cube prefix\n if (query.measures && query.measures.length > 0) {\n const firstMeasure = query.measures[0]\n const parts = firstMeasure.split('.')\n if (parts.length > 1) {\n return parts[parts.length - 1] // Use measure name without cube prefix\n }\n return firstMeasure\n }\n\n // Fall back to indexed label\n return `Query ${index + 1}`\n}\n\n/**\n * Validate merge key exists in all queries\n * Returns validation result with details\n */\nexport function validateMergeKey(\n queries: CubeQuery[],\n mergeKey: string\n): {\n isValid: boolean\n missingInQueries: number[]\n} {\n const missingInQueries: number[] = []\n\n queries.forEach((query, index) => {\n const allDimensions = [\n ...(query.dimensions || []),\n ...(query.timeDimensions?.map(td => td.dimension) || [])\n ]\n\n if (!allDimensions.includes(mergeKey)) {\n missingInQueries.push(index)\n }\n })\n\n return {\n isValid: missingInQueries.length === 0,\n missingInQueries\n }\n}\n","/**\n * React hook for executing multiple Cube queries\n * Extends useCubeQuery pattern for multi-query support\n *\n * Integrates with BatchCoordinator for dashboard-level batching:\n * - All queries are registered individually with BatchCoordinator\n * - Gets batched with other portlet queries in the same render cycle\n * - Single network request for entire dashboard load\n */\n\nimport { useState, useEffect, useRef } from 'react'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport type { CubeQueryOptions, CubeResultSet, MultiQueryConfig } from '../types'\nimport { mergeQueryResults } from '../utils/multiQueryUtils'\n\nexport interface UseMultiCubeQueryResult {\n /** Merged data from all queries (null while loading) */\n data: unknown[] | null\n /** Individual result sets from each query */\n resultSets: CubeResultSet[] | null\n /** Whether any query is still loading */\n isLoading: boolean\n /** First error encountered (null if all succeeded) */\n error: Error | null\n /** Per-query errors (null for successful queries) */\n errors: (Error | null)[]\n /** Unique identifier for this query execution */\n queryId: string | null\n}\n\n/**\n * Hook for executing multiple Cube queries with merged results\n *\n * @param config - MultiQueryConfig containing queries and merge settings\n * @param options - Query options (skip, resetResultSetOnChange)\n * @returns Query results with merged data and per-query error tracking\n *\n * @example\n * ```typescript\n * const { data, isLoading, error } = useMultiCubeQuery({\n * queries: [\n * { measures: ['Sales.revenue'] },\n * { measures: ['Costs.total'] }\n * ],\n * mergeStrategy: 'merge',\n * mergeKey: 'Sales.date',\n * queryLabels: ['Revenue', 'Costs']\n * })\n * ```\n */\nexport function useMultiCubeQuery(\n config: MultiQueryConfig | null,\n options: CubeQueryOptions = {}\n): UseMultiCubeQueryResult {\n const { cubeApi, batchCoordinator, enableBatching } = useCubeContext()\n\n const [state, setState] = useState<UseMultiCubeQueryResult>({\n data: null,\n resultSets: null,\n isLoading: false,\n error: null,\n errors: [],\n queryId: null\n })\n\n // Track the last config to avoid unnecessary re-fetches\n const lastConfigRef = useRef<string>('')\n\n useEffect(() => {\n // Skip if config is null, skip option is true, or no queries\n if (!config || options.skip || config.queries.length === 0) {\n return\n }\n\n // Create a stable config string for comparison\n const configString = JSON.stringify(config)\n\n // Skip if config hasn't changed (unless resetResultSetOnChange is true)\n if (configString === lastConfigRef.current && !options.resetResultSetOnChange) {\n return\n }\n\n lastConfigRef.current = configString\n\n // Create a unique ID for this query execution\n const queryId = `multi_${Date.now()}_${Math.random().toString(36).substring(7)}`\n\n // Update state atomically with new query ID and loading state\n setState(prevState => ({\n data: options.resetResultSetOnChange ? null : prevState.data,\n resultSets: options.resetResultSetOnChange ? null : prevState.resultSets,\n isLoading: true,\n error: null,\n errors: config.queries.map(() => null),\n queryId\n }))\n\n // Execute queries using BatchCoordinator if enabled, otherwise use direct batchLoad\n const executeQueries = (): Promise<CubeResultSet[]> => {\n if (enableBatching && batchCoordinator) {\n // All queries go through BatchCoordinator - batched with entire dashboard\n return Promise.all(\n config.queries.map(query => batchCoordinator.register(query))\n )\n }\n // Fallback: direct batch call if batching disabled\n return cubeApi.batchLoad(config.queries)\n }\n\n executeQueries()\n .then((resultSets) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId !== queryId) return prevState\n\n // Check for per-query errors\n const errors = resultSets.map(rs => {\n if (rs && 'error' in rs && (rs as { error?: string }).error) {\n return new Error((rs as { error: string }).error)\n }\n return null\n })\n\n const firstError = errors.find(e => e !== null) || null\n\n // Filter successful results for merging\n const successfulResults = resultSets.filter((_, i) => !errors[i])\n const successfulQueries = config.queries.filter((_, i) => !errors[i])\n\n // Merge results using configured strategy\n const data = successfulResults.length > 0\n ? mergeQueryResults(\n successfulResults,\n successfulQueries,\n config.mergeStrategy,\n config.mergeKeys,\n config.queryLabels\n )\n : []\n\n return {\n data,\n resultSets,\n isLoading: false,\n error: firstError,\n errors,\n queryId\n }\n })\n })\n .catch((err) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId !== queryId) return prevState\n\n const error = err instanceof Error ? err : new Error(String(err))\n\n return {\n data: null,\n resultSets: null,\n isLoading: false,\n error,\n // All queries failed with the same error\n errors: config.queries.map(() => error),\n queryId\n }\n })\n })\n }, [config, cubeApi, batchCoordinator, enableBatching, options.skip, options.resetResultSetOnChange])\n\n return state\n}\n","import React, { Component, ReactNode } from 'react'\nimport { getIcon } from '../icons'\n\nconst RefreshIcon = getIcon('refresh')\n\ninterface Props {\n children: ReactNode\n fallback?: ReactNode\n portletTitle?: string\n portletConfig?: any\n cubeQuery?: string\n}\n\ninterface State {\n hasError: boolean\n error: Error | null\n errorInfo: string | null\n}\n\nexport default class ChartErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props)\n this.state = {\n hasError: false,\n error: null,\n errorInfo: null\n }\n }\n\n static getDerivedStateFromError(error: Error): State {\n // Update state so the next render will show the fallback UI\n return {\n hasError: true,\n error,\n errorInfo: null\n }\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n // Update state with error details\n this.setState({\n error,\n errorInfo: errorInfo.componentStack || null\n })\n\n // Log the error for debugging\n console.error('Chart Error Boundary caught a rendering error:', error, errorInfo)\n }\n\n handleReset = () => {\n this.setState({\n hasError: false,\n error: null,\n errorInfo: null\n })\n }\n\n render() {\n if (this.state.hasError) {\n // Custom fallback UI\n if (this.props.fallback) {\n return this.props.fallback\n }\n\n // Default error display\n return (\n <div className=\"flex flex-col items-center justify-center w-full h-full p-6 text-center border border-dashed rounded-lg\"\n style={{ borderColor: 'var(--dc-border)', backgroundColor: 'var(--dc-surface)' }}>\n <div className=\"h-12 w-12 mb-4 text-dc-text-muted\">⚠️</div>\n <h3 className=\"text-lg font-semibold mb-2 text-dc-text\">\n {this.props.portletTitle ? `Unable to render ${this.props.portletTitle}` : 'Unable to render chart'}\n </h3>\n <p className=\"text-sm text-dc-text-secondary mb-4 max-w-md\">\n There was an error rendering this chart component. The error details are shown below.\n </p>\n\n {/* Error details */}\n <div className=\"w-full max-w-2xl mb-4\">\n <div className=\"bg-dc-surface-secondary rounded-lg p-3 text-left\">\n <div className=\"text-xs font-mono mb-2 text-dc-text\">\n <strong>Error:</strong> {this.state.error?.message}\n </div>\n {this.state.error?.name && (\n <div className=\"text-xs font-mono text-dc-text-secondary mb-2\">\n <strong>Type:</strong> {this.state.error.name}\n </div>\n )}\n\n {/* Portlet Config Debug Info */}\n {this.props.portletConfig && (\n <details className=\"text-xs font-mono text-dc-text-secondary mb-2\">\n <summary className=\"cursor-pointer\">Portlet Configuration</summary>\n <pre className=\"mt-2 whitespace-pre-wrap p-2 rounded-sm overflow-auto max-h-32\"\n style={{ backgroundColor: 'rgba(var(--dc-primary-rgb), 0.1)' }}>\n {JSON.stringify(this.props.portletConfig, null, 2)}\n </pre>\n </details>\n )}\n\n {/* Cube Query Debug Info */}\n {this.props.cubeQuery && (\n <details className=\"text-xs font-mono text-dc-text-secondary mb-2\">\n <summary className=\"cursor-pointer\">Cube Query</summary>\n <pre className=\"mt-2 whitespace-pre-wrap p-2 rounded-sm overflow-auto max-h-32\"\n style={{ backgroundColor: '#d1fae5' }}>\n {typeof this.props.cubeQuery === 'string' \n ? JSON.stringify(JSON.parse(this.props.cubeQuery), null, 2)\n : JSON.stringify(this.props.cubeQuery, null, 2)\n }\n </pre>\n </details>\n )}\n\n {this.state.errorInfo && (\n <details className=\"text-xs font-mono text-dc-text-secondary\">\n <summary className=\"cursor-pointer\">Component Stack</summary>\n <pre className=\"mt-2 whitespace-pre-wrap\">{this.state.errorInfo}</pre>\n </details>\n )}\n </div>\n </div>\n\n {/* Reset button */}\n <button\n onClick={this.handleReset}\n className=\"px-3 py-1 text-white rounded-sm text-sm hover:opacity-90 transition-opacity\"\n style={{\n backgroundColor: 'var(--dc-primary)'\n }}\n >\n <RefreshIcon style={{ width: '16px', height: '16px', display: 'inline', marginRight: '4px' }} />Try Again\n </button>\n </div>\n )\n }\n\n return this.props.children\n }\n}","/**\n * Type definitions for drizzle-cube client components\n */\n\nimport type { ReactNode } from 'react'\nimport type { ColorPalette } from './utils/colorPalettes'\n\n// Re-export metadata types from useCubeMeta hook\nexport type { CubeMeta, CubeMetaCube, CubeMetaField, CubeMetaRelationship, FieldLabelMap } from './hooks/useCubeMeta'\n\n// Re-export color palette types\nexport type { ColorPalette } from './utils/colorPalettes'\n\n// Chart types\nexport type ChartType = \n | 'line' \n | 'bar' \n | 'pie' \n | 'table' \n | 'area' \n | 'scatter' \n | 'radar' \n | 'radialBar' \n | 'treemap'\n | 'bubble'\n | 'activityGrid'\n | 'kpiNumber'\n | 'kpiDelta'\n | 'kpiText'\n | 'markdown'\n\n// Axis formatting configuration\nexport interface AxisFormatConfig {\n label?: string // Custom axis label (overrides auto-generated)\n unit?: 'currency' | 'percent' | 'number' | 'custom' // Unit type for formatting\n abbreviate?: boolean // Use K, M, B suffixes for large numbers\n decimals?: number // Decimal places (0-4, undefined = auto)\n customPrefix?: string // Prefix for 'custom' unit type\n customSuffix?: string // Suffix for 'custom' unit type\n}\n\n// Chart configuration\nexport interface ChartAxisConfig {\n // New format (for advanced portlet editor)\n xAxis?: string[] // Dimension fields for X axis\n yAxis?: string[] // Measure fields for Y axis \n series?: string[] // Fields to use for series/grouping\n \n // Bubble chart specific fields\n sizeField?: string // Field for bubble size\n colorField?: string // Field for bubble color\n \n // Activity grid chart specific fields\n dateField?: string[] // Time dimension field for activity grid\n valueField?: string[] // Measure field for activity intensity\n \n // Legacy format (for backward compatibility)\n x?: string // Single dimension field for X axis\n y?: string[] // Measure fields for Y axis\n\n // Dual Y-axis support: per-measure axis assignment (left or right)\n // Default: 'left' for all measures (backward compatible)\n yAxisAssignment?: Record<string, 'left' | 'right'>\n}\n\nexport interface ChartDisplayConfig {\n showLegend?: boolean\n showGrid?: boolean\n showTooltip?: boolean\n colors?: string[]\n orientation?: 'horizontal' | 'vertical'\n stacked?: boolean // Deprecated: use stackType instead\n stackType?: 'none' | 'normal' | 'percent' // Stacking mode: none, normal (sum), or percent (100%)\n connectNulls?: boolean // For Area/Line charts: draw continuous lines through missing data\n hideHeader?: boolean // Hide portlet header in non-edit mode\n \n // Bubble chart specific display options\n minBubbleSize?: number\n maxBubbleSize?: number\n bubbleOpacity?: number\n \n // Activity grid specific display options\n showLabels?: boolean\n fitToWidth?: boolean\n\n // DataTable specific display options\n pivotTimeDimension?: boolean // Pivot time dimension as columns (default: true when time dimension present)\n\n // Target functionality\n target?: string // Target values as string (single value or comma-separated for spread)\n \n // KPI specific display options\n template?: string // JavaScript template string for KPI Text\n prefix?: string // Text prefix for KPI Number\n suffix?: string // Text suffix for KPI Number\n decimals?: number // Number of decimal places\n formatValue?: (value: number | null | undefined) => string // Custom value formatter function (takes precedence over prefix/suffix/decimals)\n valueColor?: string // Color for the KPI value (legacy)\n valueColorIndex?: number // Index of color from dashboard palette for KPI value\n \n // KPI Delta specific display options\n positiveColorIndex?: number // Index of color from dashboard palette for positive changes\n negativeColorIndex?: number // Index of color from dashboard palette for negative changes\n showHistogram?: boolean // Whether to show variance histogram\n\n // KPI time period handling\n useLastCompletePeriod?: boolean // Exclude incomplete current period (e.g., partial week/month)\n skipLastPeriod?: boolean // Always exclude the last period regardless of completeness\n \n // Markdown specific display options\n content?: string // Markdown content text\n accentColorIndex?: number // Index of color from dashboard palette for headers, bullets, links\n fontSize?: 'small' | 'medium' | 'large' // Text size for markdown content\n alignment?: 'left' | 'center' | 'right' // Text alignment for markdown content\n\n // Axis formatting options (for Line, Area, Bar, Scatter charts)\n xAxisFormat?: AxisFormatConfig // Formatting for X-axis values\n leftYAxisFormat?: AxisFormatConfig // Formatting for left Y-axis values\n rightYAxisFormat?: AxisFormatConfig // Formatting for right Y-axis values (dual-axis charts)\n\n // Period comparison display options (for compareDateRange queries)\n /**\n * How to display compared periods:\n * - 'separate': Each period as distinct series with different colors (default)\n * - 'overlay': Periods aligned by day-of-period index with ghost styling for prior periods\n */\n comparisonMode?: 'separate' | 'overlay'\n /** Line style for prior periods in overlay mode */\n priorPeriodStyle?: 'solid' | 'dashed' | 'dotted'\n /** Opacity for prior period lines (0-1), default: 0.5 */\n priorPeriodOpacity?: number\n /** Include period labels in legend */\n showPeriodLabels?: boolean\n}\n\n// Portlet configuration\nexport interface PortletConfig {\n id: string\n title: string\n query: string // JSON string of cube query\n chartType: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n dashboardFilterMapping?: string[] // Array of dashboard filter IDs that apply to this portlet\n eagerLoad?: boolean // Force immediate loading (overrides dashboard lazy loading setting)\n w: number // Grid width\n h: number // Grid height\n x: number // Grid x position\n y: number // Grid y position\n}\n\nexport type DashboardLayoutMode = 'grid' | 'rows'\n\nexport interface DashboardGridSettings {\n cols: number\n rowHeight: number\n minW: number\n minH: number\n}\n\nexport interface RowLayoutColumn {\n portletId: string\n w: number\n}\n\nexport interface RowLayout {\n id: string\n h: number\n columns: RowLayoutColumn[]\n}\n\n// Dashboard configuration\nexport interface DashboardConfig {\n portlets: PortletConfig[]\n layoutMode?: DashboardLayoutMode\n grid?: DashboardGridSettings\n rows?: RowLayout[]\n layouts?: { [key: string]: any } // react-grid-layout layouts\n colorPalette?: string // Name of the color palette to use (defaults to 'default')\n filters?: DashboardFilter[] // Dashboard-level filters that can be applied to portlets\n eagerLoad?: boolean // Force immediate loading for all portlets (default: false, lazy load enabled)\n}\n\n// Filter types - hierarchical structure supporting AND/OR logic\nexport type FilterOperator = \n // String operators\n | 'equals' | 'notEquals' | 'contains' | 'notContains' \n | 'startsWith' | 'notStartsWith' | 'endsWith' | 'notEndsWith'\n | 'like' | 'notLike' | 'ilike'\n // Numeric operators \n | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'notBetween'\n // Array operators\n | 'in' | 'notIn'\n // PostgreSQL array operators\n | 'arrayContains' | 'arrayOverlaps' | 'arrayContained'\n // Null/Empty operators\n | 'set' | 'notSet' | 'isEmpty' | 'isNotEmpty'\n // Date operators\n | 'inDateRange' | 'beforeDate' | 'afterDate'\n // Regex operators\n | 'regex' | 'notRegex'\n\nexport interface SimpleFilter {\n member: string\n operator: FilterOperator\n values: any[]\n dateRange?: string | string[]\n}\n\nexport interface GroupFilter {\n type: 'and' | 'or'\n filters: Filter[]\n}\n\nexport type Filter = SimpleFilter | GroupFilter\n\n// Dashboard filter with ID and label for dashboard-level filtering\nexport interface DashboardFilter {\n id: string // Unique identifier for the filter\n label: string // Display label for the filter\n filter: Filter // The actual filter definition\n isUniversalTime?: boolean // When true, applies to all timeDimensions in portlets (ignores member field)\n}\n\n// Cube query types\nexport interface CubeQuery {\n measures?: string[]\n dimensions?: string[]\n timeDimensions?: Array<{\n dimension: string\n granularity?: string\n dateRange?: string[] | string\n fillMissingDates?: boolean\n /**\n * Array of date ranges for period-over-period comparison.\n * When specified, queries are executed for each period and results are merged.\n */\n compareDateRange?: (string | [string, string])[]\n }>\n filters?: Filter[]\n order?: { [key: string]: 'asc' | 'desc' }\n limit?: number\n offset?: number\n segments?: string[]\n}\n\n/**\n * Merge strategy for combining multiple query results\n * - 'concat': Append rows with __queryIndex marker (for separate series per query)\n * - 'merge': Align data by common dimension key (for combined visualization)\n */\nexport type QueryMergeStrategy = 'concat' | 'merge'\n\n/**\n * Configuration for multi-query portlets\n * Detected by presence of 'queries' array property\n */\nexport interface MultiQueryConfig {\n queries: CubeQuery[]\n mergeStrategy: QueryMergeStrategy\n mergeKeys?: string[] // Dimensions to align on (for 'merge' strategy) - composite key\n queryLabels?: string[] // User-defined labels per query\n}\n\n/**\n * Type guard to detect multi-query configuration\n */\nexport function isMultiQueryConfig(obj: unknown): obj is MultiQueryConfig {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n 'queries' in obj &&\n Array.isArray((obj as MultiQueryConfig).queries) &&\n (obj as MultiQueryConfig).queries.length > 0\n )\n}\n\nexport interface CubeQueryOptions {\n skip?: boolean\n resetResultSetOnChange?: boolean\n subscribe?: boolean\n}\n\nexport interface CubeApiOptions {\n apiUrl?: string\n token?: string\n headers?: Record<string, string>\n credentials?: 'include' | 'omit' | 'same-origin'\n}\n\n// Result set types\nexport interface CubeResultSet {\n rawData(): any[]\n tablePivot(): any[]\n series(): any[]\n annotation(): any\n loadResponse?: any\n cacheInfo?(): { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number } | undefined\n}\n\n// Component props\nexport interface AnalyticsPortletProps {\n query: string\n chartType: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n dashboardFilters?: DashboardFilter[] // Dashboard-level filters to merge with portlet query\n dashboardFilterMapping?: string[] // Array of dashboard filter IDs that apply to this portlet\n eagerLoad?: boolean // Force immediate loading (default: false, lazy load enabled)\n isVisible?: boolean // Whether the portlet is visible in the viewport (for lazy loading)\n height?: string | number\n title?: string\n colorPalette?: ColorPalette // Complete palette with both colors and gradient\n loadingComponent?: ReactNode // Custom loading indicator (defaults to LoadingIndicator)\n onDebugDataReady?: (debugData: {\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n queryObject: any\n data: any[]\n chartType: ChartType\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n }) => void\n}\n\nexport interface AnalyticsDashboardProps {\n config: DashboardConfig\n editable?: boolean\n dashboardFilters?: DashboardFilter[] // Programmatic dashboard filters (merged with config.filters)\n loadingComponent?: ReactNode // Custom loading indicator for all portlets (defaults to LoadingIndicator)\n onConfigChange?: (config: DashboardConfig) => void\n onSave?: (config: DashboardConfig) => Promise<void> | void\n onDirtyStateChange?: (isDirty: boolean) => void\n}\n\nexport interface ChartProps {\n data: any[]\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n queryObject?: CubeQuery\n height?: string | number\n colorPalette?: ColorPalette // Complete palette with both colors and gradient\n}\n\n// Features configuration\nexport interface FeaturesConfig {\n enableAI?: boolean // Default: true for backward compatibility\n aiEndpoint?: string // Custom AI endpoint (default: '/api/ai/generate')\n showSchemaDiagram?: boolean // Show schema diagram in QueryBuilder (default: false, requires reactflow/dagre)\n useAnalysisBuilder?: boolean // Use new AnalysisBuilder modal for portlet editing (default: false)\n editToolbar?: 'floating' | 'top' | 'both' // Which edit toolbar(s) to show: 'floating' only, 'top' only, or 'both' (default: 'both')\n floatingToolbarPosition?: 'left' | 'right' // Position of floating toolbar when enabled (default: 'right')\n}\n\n// Grid layout types (simplified)\nexport interface GridLayout {\n i: string\n x: number\n y: number\n w: number\n h: number\n minW?: number\n minH?: number\n}\n\nexport interface ResponsiveLayout {\n [breakpoint: string]: GridLayout[]\n}\n\n// Dashboard display modes for responsive layout\nexport type DashboardDisplayMode = 'desktop' | 'scaled' | 'mobile'\n","/**\n * Filter utility functions for dashboard-level filtering\n */\n\nimport type { Filter, DashboardFilter, CubeMeta, GroupFilter, DashboardConfig, SimpleFilter } from '../types'\n\n/**\n * Memoization infrastructure to prevent creating new array references\n * when filter data is semantically identical\n */\n\n// Stable empty array reference (frozen to prevent mutations)\nexport const EMPTY_FILTERS: Filter[] = []\n\n/**\n * Simple memoization cache using Map with JSON-stringified keys\n * WeakMap can't be used because primitives aren't valid keys\n */\nclass FilterCache<T> {\n private cache = new Map<string, T>()\n private maxSize = 100 // Prevent unbounded growth\n\n get(key: any): T | undefined {\n try {\n const keyStr = JSON.stringify(key)\n return this.cache.get(keyStr)\n } catch {\n return undefined\n }\n }\n\n set(key: any, value: T): void {\n try {\n const keyStr = JSON.stringify(key)\n\n // Simple LRU: if cache is full, delete oldest entry\n if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value\n if (firstKey) this.cache.delete(firstKey)\n }\n\n this.cache.set(keyStr, value)\n } catch {\n // Ignore cache failures - just don't cache\n }\n }\n\n clear(): void {\n this.cache.clear()\n }\n}\n\n// Cache instances for each memoized function\nconst applicableFiltersCache = new FilterCache<Filter[]>()\nconst mergedFiltersCache = new FilterCache<Filter[] | undefined>()\nconst timeDimensionsCache = new FilterCache<any[] | undefined>()\n\n/**\n * Check if a filter should be included in the query (has valid values or doesn't require values)\n * @param filter - The filter to check\n * @returns true if the filter should be included, false otherwise\n */\nfunction shouldIncludeFilter(filter: Filter): boolean {\n // Handle SimpleFilter\n if ('member' in filter && 'operator' in filter) {\n const simpleFilter = filter as SimpleFilter\n\n // Operators that don't require values\n const noValueOperators = ['set', 'notSet', 'isEmpty', 'isNotEmpty']\n if (noValueOperators.includes(simpleFilter.operator)) {\n return true\n }\n\n // For inDateRange, check if dateRange is provided as alternative to values\n if (simpleFilter.operator === 'inDateRange' && simpleFilter.dateRange) {\n return true\n }\n\n // For other operators, check if values exist and are non-empty\n return !!(simpleFilter.values && simpleFilter.values.length > 0)\n }\n\n // Handle GroupFilter - recursively check nested filters\n if ('type' in filter && 'filters' in filter) {\n const groupFilter = filter as GroupFilter\n // Include group filter if at least one nested filter is valid\n const validFilters = groupFilter.filters.filter(f => shouldIncludeFilter(f))\n return validFilters.length > 0\n }\n\n return false\n}\n\n/**\n * Get dashboard filters that should be applied to a portlet based on its mapping configuration\n * MEMOIZED: Returns stable array reference when inputs are semantically identical\n * @param dashboardFilters - All available dashboard filters\n * @param filterMapping - Array of filter IDs that apply to this portlet\n * @returns Array of filters that should be applied to the portlet\n */\nexport function getApplicableDashboardFilters(\n dashboardFilters: DashboardFilter[] | undefined,\n filterMapping: string[] | undefined\n): Filter[] {\n if (!dashboardFilters || !dashboardFilters.length) {\n return EMPTY_FILTERS\n }\n\n // If no mapping is specified, no dashboard filters apply\n if (!filterMapping || !filterMapping.length) {\n return EMPTY_FILTERS\n }\n\n // Check cache first using both inputs as cache key\n const cacheKey = { dashboardFilters, filterMapping }\n const cached = applicableFiltersCache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n // Compute filters that are in the mapping AND have valid values\n const result = dashboardFilters\n .filter(df => filterMapping.includes(df.id))\n .filter(df => shouldIncludeFilter(df.filter))\n .map(df => df.filter)\n\n // Freeze result to prevent mutations and cache it\n const frozenResult = Object.freeze(result) as Filter[]\n applicableFiltersCache.set(cacheKey, frozenResult)\n\n return frozenResult\n}\n\n/**\n * Convert GroupFilter format to server format\n * GroupFilter: { type: 'and', filters: [...] }\n * Server format: { and: [...] } or { or: [...] }\n */\nfunction convertToServerFormat(filter: Filter): any {\n // Handle GroupFilter format\n if ('type' in filter && 'filters' in filter) {\n const groupFilter = filter as GroupFilter\n const convertedFilters = groupFilter.filters.map(convertToServerFormat)\n\n if (groupFilter.type === 'and') {\n return { and: convertedFilters }\n } else {\n return { or: convertedFilters }\n }\n }\n\n // Simple filter - return as-is\n return filter\n}\n\n/**\n * Merge dashboard filters with portlet filters using AND logic\n * Dashboard filters are combined with portlet filters so both sets of filters apply\n * MEMOIZED: Returns stable array reference when inputs are semantically identical\n * @param dashboardFilters - Filters from dashboard-level configuration\n * @param portletFilters - Filters from portlet query\n * @returns Merged filter array with AND logic\n */\nexport function mergeDashboardAndPortletFilters(\n dashboardFilters: Filter[],\n portletFilters: Filter[] | undefined\n): Filter[] | undefined {\n // If no dashboard filters, return portlet filters as-is\n if (!dashboardFilters || dashboardFilters.length === 0) {\n return portletFilters\n }\n\n // If no portlet filters, return dashboard filters (frozen to prevent mutations)\n if (!portletFilters || portletFilters.length === 0) {\n // Return frozen copy of dashboardFilters\n const frozen = Object.freeze([...dashboardFilters]) as Filter[]\n return frozen\n }\n\n // Check cache for merged result\n const cacheKey = { dashboardFilters, portletFilters }\n const cached = mergedFiltersCache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n // Both exist - need to merge with AND logic\n // We need to combine them in a way that both sets of filters apply\n\n // Flatten both filter arrays and convert to server format\n const allFilters = [...dashboardFilters, ...portletFilters].map(convertToServerFormat)\n\n // Wrap all filters in a single AND group using server format\n const result = [{\n and: allFilters\n } as any]\n\n // Freeze result and cache it\n const frozenResult = Object.freeze(result) as Filter[]\n mergedFiltersCache.set(cacheKey, frozenResult)\n\n return frozenResult\n}\n\n/**\n * Check if a filter field exists in the cube metadata\n * This helps identify filters that might not apply to a specific portlet's data\n * @param filter - The filter to validate\n * @param cubeMeta - Cube metadata to validate against\n * @returns true if the filter field exists in any cube's measures or dimensions\n */\nexport function validateFilterForCube(\n filter: Filter,\n cubeMeta: CubeMeta | null\n): boolean {\n if (!cubeMeta || !cubeMeta.cubes) {\n // If no metadata available, assume filter is valid (fail open)\n return true\n }\n\n // Extract member names from filter recursively\n const memberNames = extractMemberNamesFromFilter(filter)\n\n // Check if any of the member names exist in cube metadata\n return memberNames.some(memberName => {\n return cubeMeta.cubes.some(cube => {\n // Check measures\n const inMeasures = cube.measures?.some(m => m.name === memberName) ?? false\n // Check dimensions\n const inDimensions = cube.dimensions?.some(d => d.name === memberName) ?? false\n\n return inMeasures || inDimensions\n })\n })\n}\n\n/**\n * Extract all member names from a filter (handles nested group filters)\n * @param filter - The filter to extract members from\n * @returns Array of member names\n */\nfunction extractMemberNamesFromFilter(filter: Filter): string[] {\n if ('member' in filter) {\n // SimpleFilter\n return [filter.member]\n } else if ('type' in filter && 'filters' in filter) {\n // GroupFilter - recursively extract from nested filters\n return filter.filters.flatMap(f => extractMemberNamesFromFilter(f))\n }\n\n return []\n}\n\n/**\n * Validate that all dashboard filters in a portlet's mapping exist and are valid\n * @param dashboardFilters - All available dashboard filters\n * @param filterMapping - The portlet's filter mapping\n * @param cubeMeta - Cube metadata for validation\n * @returns Object with validation result and list of invalid filter IDs\n */\nexport function validatePortletFilterMapping(\n dashboardFilters: DashboardFilter[] | undefined,\n filterMapping: string[] | undefined,\n cubeMeta: CubeMeta | null\n): { isValid: boolean; invalidFilterIds: string[]; missingFilterIds: string[] } {\n if (!filterMapping || !filterMapping.length) {\n return { isValid: true, invalidFilterIds: [], missingFilterIds: [] }\n }\n\n if (!dashboardFilters || !dashboardFilters.length) {\n // Mapping references filters that don't exist\n return {\n isValid: false,\n invalidFilterIds: [],\n missingFilterIds: filterMapping\n }\n }\n\n const invalidFilterIds: string[] = []\n const missingFilterIds: string[] = []\n\n filterMapping.forEach(filterId => {\n const dashboardFilter = dashboardFilters.find(df => df.id === filterId)\n\n if (!dashboardFilter) {\n // Filter ID in mapping doesn't exist in dashboard filters\n missingFilterIds.push(filterId)\n } else {\n // Check if filter is valid for the cube metadata\n const isValid = validateFilterForCube(dashboardFilter.filter, cubeMeta)\n if (!isValid) {\n invalidFilterIds.push(filterId)\n }\n }\n })\n\n return {\n isValid: invalidFilterIds.length === 0 && missingFilterIds.length === 0,\n invalidFilterIds,\n missingFilterIds\n }\n}\n\n/**\n * Extract all unique measures, dimensions, and timeDimensions used across all portlets in a dashboard\n * This helps create a filtered schema view showing only fields relevant to the dashboard\n * @param dashboardConfig - Dashboard configuration\n * @returns Object with unique measures, dimensions, and timeDimensions\n */\nexport function extractDashboardFields(\n dashboardConfig: DashboardConfig\n): { measures: Set<string>; dimensions: Set<string>; timeDimensions: Set<string> } {\n const measures = new Set<string>()\n const dimensions = new Set<string>()\n const timeDimensions = new Set<string>()\n\n // Iterate through all portlets\n dashboardConfig.portlets.forEach(portlet => {\n try {\n // Parse the query JSON\n const query = JSON.parse(portlet.query)\n\n // Extract measures\n if (query.measures && Array.isArray(query.measures)) {\n query.measures.forEach((measure: string) => measures.add(measure))\n }\n\n // Extract dimensions\n if (query.dimensions && Array.isArray(query.dimensions)) {\n query.dimensions.forEach((dimension: string) => dimensions.add(dimension))\n }\n\n // Extract timeDimensions\n if (query.timeDimensions && Array.isArray(query.timeDimensions)) {\n query.timeDimensions.forEach((td: any) => {\n if (td.dimension) {\n timeDimensions.add(td.dimension)\n }\n })\n }\n\n // Also extract from filters to catch any filtered fields\n if (query.filters) {\n extractFieldsFromFilters(query.filters).forEach(field => {\n // Try to determine if it's a measure, dimension, or timeDimension\n // by checking cube metadata or convention (add to dimensions by default)\n dimensions.add(field)\n })\n }\n } catch (e) {\n // Skip portlets with invalid query JSON\n console.warn('Failed to parse portlet query:', portlet.id, e)\n }\n })\n\n return { measures, dimensions, timeDimensions }\n}\n\n/**\n * Extract field names from filters recursively\n * @param filters - Filter array\n * @returns Array of unique field names\n */\nfunction extractFieldsFromFilters(filters: Filter[]): string[] {\n const fields: string[] = []\n\n filters.forEach(filter => {\n if ('member' in filter) {\n // SimpleFilter\n fields.push(filter.member)\n } else if ('type' in filter && 'filters' in filter) {\n // GroupFilter - recurse\n fields.push(...extractFieldsFromFilters(filter.filters))\n }\n })\n\n return [...new Set(fields)] // Return unique fields\n}\n\n/**\n * Time dimension type from CubeQuery\n */\ntype TimeDimension = {\n dimension: string\n granularity?: string\n dateRange?: string[] | string\n}\n\n/**\n * Helper to get date range from a SimpleFilter (backward compatible)\n * Reads from both dateRange and values for compatibility\n * Handles both:\n * - Preset ranges: [\"this quarter\"], [\"last 7 days\"] (single string value)\n * - Custom ranges: [\"2024-01-01\", \"2024-12-31\"] (two date values)\n */\nfunction getDateRangeFromFilter(filter: SimpleFilter): string[] | string | undefined {\n // Prefer dateRange for backward compatibility, fall back to values\n if (filter.dateRange) {\n return filter.dateRange\n }\n if (filter.values && filter.values.length > 0) {\n // Single value = preset like \"this quarter\", return as string\n // Multiple values = custom date range, return as array\n return filter.values.length === 1 ? filter.values[0] : filter.values\n }\n return undefined\n}\n\n/**\n * Apply universal time filters to a portlet's timeDimensions\n * Universal time filters apply their dateRange to ALL time dimensions in the portlet\n * MEMOIZED: Returns stable array reference when inputs are semantically identical\n *\n * @param dashboardFilters - All dashboard filters\n * @param filterMapping - Filter IDs that apply to this portlet\n * @param portletTimeDimensions - The portlet's existing timeDimensions array\n * @returns Updated timeDimensions array with date ranges applied\n */\nexport function applyUniversalTimeFilters(\n dashboardFilters: DashboardFilter[] | undefined,\n filterMapping: string[] | undefined,\n portletTimeDimensions: TimeDimension[] | undefined\n): TimeDimension[] | undefined {\n // Return as-is if no time dimensions in portlet (skip silently)\n if (!portletTimeDimensions || portletTimeDimensions.length === 0) {\n return portletTimeDimensions\n }\n\n // If no mapping specified, no filters apply\n if (!filterMapping || filterMapping.length === 0) {\n return portletTimeDimensions\n }\n\n // Check cache first\n const cacheKey = { dashboardFilters, filterMapping, portletTimeDimensions }\n const cached = timeDimensionsCache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n // Find applicable universal time filters that have valid date ranges\n const universalTimeFilters = dashboardFilters\n ?.filter(df => df.isUniversalTime && filterMapping.includes(df.id))\n ?.filter(df => {\n // Must be a SimpleFilter with a valid dateRange\n if (!('member' in df.filter)) return false\n const simpleFilter = df.filter as SimpleFilter\n const dateRange = getDateRangeFromFilter(simpleFilter)\n return dateRange !== undefined\n })\n\n if (!universalTimeFilters || universalTimeFilters.length === 0) {\n return portletTimeDimensions\n }\n\n // Use the first universal time filter's dateRange (typically only one)\n const timeFilter = universalTimeFilters[0]\n const simpleFilter = timeFilter.filter as SimpleFilter\n const dateRange = getDateRangeFromFilter(simpleFilter)\n\n // Apply dateRange to ALL time dimensions (dashboard wins - overrides portlet dateRange)\n const result = portletTimeDimensions.map(td => ({\n ...td,\n dateRange: dateRange\n }))\n\n // Freeze result and cache it\n const frozenResult = Object.freeze(result) as TimeDimension[]\n timeDimensionsCache.set(cacheKey, frozenResult)\n\n return frozenResult\n}\n","/**\n * Analytics Portlet Component\n * Simplified version with minimal dependencies\n */\n\nimport React, { useMemo, useState, forwardRef, useImperativeHandle, useEffect, useRef } from 'react'\nimport { useInView } from 'react-intersection-observer'\nimport { useCubeQuery } from '../hooks/useCubeQuery'\nimport { useMultiCubeQuery } from '../hooks/useMultiCubeQuery'\nimport { useScrollContainer } from '../providers/ScrollContainerContext'\nimport ChartErrorBoundary from './ChartErrorBoundary'\nimport LoadingIndicator from './LoadingIndicator'\nimport { LazyChart, isValidChartType } from '../charts/ChartLoader'\nimport { useChartConfig } from '../charts/lazyChartConfigRegistry'\nimport type { AnalyticsPortletProps, MultiQueryConfig } from '../types'\nimport { isMultiQueryConfig } from '../types'\nimport { getApplicableDashboardFilters, mergeDashboardAndPortletFilters, applyUniversalTimeFilters } from '../utils/filterUtils'\n\n\ninterface AnalyticsPortletRef {\n refresh: () => void\n}\n\n// Memoize component to prevent re-renders when props haven't changed\nconst AnalyticsPortlet = React.memo(forwardRef<AnalyticsPortletRef, AnalyticsPortletProps>(({\n query,\n chartType,\n chartConfig,\n displayConfig,\n dashboardFilters,\n dashboardFilterMapping,\n eagerLoad = false,\n isVisible: _isVisible, // Deprecated - visibility now handled internally via useInView\n height = 300,\n title: _title,\n colorPalette,\n loadingComponent,\n onDebugDataReady\n}, ref) => {\n const [refreshCounter, setRefreshCounter] = useState(0)\n const onDebugDataReadyRef = useRef(onDebugDataReady)\n\n // Lazy loading: Use IntersectionObserver to detect when portlet is visible\n // Get scroll container from context (null = viewport, element = container scroll)\n const scrollContainer = useScrollContainer()\n const { ref: inViewRef, inView } = useInView({\n root: scrollContainer,\n rootMargin: '500px', // Start loading 500px before entering viewport (about half screen)\n triggerOnce: true, // Once visible, stay \"visible\" (don't unload data)\n initialInView: false, // Start as not visible, let observer determine actual state\n skip: eagerLoad // Skip observation entirely if eagerLoad is true\n })\n\n // Effective visibility: eagerLoad forces visible, otherwise use inView from IntersectionObserver\n // Note: Batching is handled by BatchCoordinator which collects queries for 100ms before flushing\n const isVisible = eagerLoad || inView\n\n // Update ref when callback changes\n useEffect(() => {\n onDebugDataReadyRef.current = onDebugDataReady\n }, [onDebugDataReady])\n\n // Check if this chart type skips queries (using lazy-loaded config)\n const { config: chartTypeConfig } = useChartConfig(chartType)\n const shouldSkipQuery = chartTypeConfig.skipQuery === true\n\n // Memoize regular filters to prevent array recreation on every render\n const regularFilters = useMemo(() => {\n return dashboardFilters?.filter(df => !df.isUniversalTime)\n }, [dashboardFilters])\n\n // Parse query from JSON string, merge dashboard filters, and include refresh counter to force re-query\n // Supports both single CubeQuery and MultiQueryConfig formats\n const { queryObject, multiQueryConfig } = useMemo(() => {\n // Skip query parsing for charts that don't need queries\n if (shouldSkipQuery) {\n return { queryObject: null, multiQueryConfig: null }\n }\n\n try {\n const parsed = JSON.parse(query)\n\n // Get applicable dashboard filters (excluding universal time filters - they apply to timeDimensions)\n const applicableFilters = getApplicableDashboardFilters(regularFilters, dashboardFilterMapping)\n\n // Check if this is a multi-query configuration\n if (isMultiQueryConfig(parsed)) {\n // Multi-query: apply filters to each query in the array\n const multiConfig: MultiQueryConfig = {\n ...parsed,\n queries: parsed.queries.map(q => ({\n ...q,\n filters: mergeDashboardAndPortletFilters(applicableFilters, q.filters),\n timeDimensions: applyUniversalTimeFilters(dashboardFilters, dashboardFilterMapping, q.timeDimensions),\n __refresh_counter: refreshCounter\n }))\n }\n return { queryObject: null, multiQueryConfig: multiConfig }\n }\n\n // Single query: existing behavior\n const mergedFilters = mergeDashboardAndPortletFilters(applicableFilters, parsed.filters)\n const mergedTimeDimensions = applyUniversalTimeFilters(\n dashboardFilters,\n dashboardFilterMapping,\n parsed.timeDimensions\n )\n\n return {\n queryObject: {\n ...parsed,\n filters: mergedFilters,\n timeDimensions: mergedTimeDimensions,\n __refresh_counter: refreshCounter\n },\n multiQueryConfig: null\n }\n } catch (e) {\n console.error('AnalyticsPortlet: Invalid query JSON:', e)\n return { queryObject: null, multiQueryConfig: null }\n }\n }, [query, refreshCounter, shouldSkipQuery, regularFilters, dashboardFilters, dashboardFilterMapping])\n\n // Determine whether to skip queries based on various conditions\n const isMultiQuery = multiQueryConfig !== null\n const shouldSkipSingle = !queryObject || shouldSkipQuery || (!eagerLoad && !isVisible) || isMultiQuery\n const shouldSkipMulti = !multiQueryConfig || shouldSkipQuery || (!eagerLoad && !isVisible)\n\n // Use single query hook (skip if multi-query or other skip conditions)\n const singleQueryResult = useCubeQuery(queryObject, {\n skip: shouldSkipSingle,\n resetResultSetOnChange: true\n })\n\n // Use multi-query hook (skip if single query or other skip conditions)\n const multiQueryResult = useMultiCubeQuery(multiQueryConfig, {\n skip: shouldSkipMulti,\n resetResultSetOnChange: true\n })\n\n // Combine results from both hooks\n const resultSet = isMultiQuery ? null : singleQueryResult.resultSet\n const isLoading = isMultiQuery ? multiQueryResult.isLoading : singleQueryResult.isLoading\n const error = isMultiQuery ? multiQueryResult.error : singleQueryResult.error\n const multiQueryData = isMultiQuery ? multiQueryResult.data : null\n\n // Expose refresh function through ref\n useImperativeHandle(ref, () => ({\n refresh: () => {\n setRefreshCounter(prev => prev + 1)\n }\n }), [])\n\n\n // Send debug data to parent when ready (must be before any returns)\n useEffect(() => {\n if (onDebugDataReadyRef.current && chartConfig && queryObject && resultSet && !error) {\n const getData = () => {\n switch (chartType) {\n case 'pie':\n case 'table':\n return resultSet.tablePivot()\n default:\n return resultSet.rawData()\n }\n }\n const data = getData()\n\n if (data) {\n onDebugDataReadyRef.current({\n chartConfig: chartConfig || {},\n displayConfig: displayConfig || {},\n queryObject,\n data,\n chartType,\n cacheInfo: resultSet.cacheInfo?.()\n })\n }\n }\n }, [chartConfig, displayConfig, queryObject, resultSet, chartType, error]) // Use ref for callback to prevent infinite loops\n\n // Validate that chartConfig is provided when required (not required for skipQuery charts)\n // Check if any dropZones are mandatory for this chart type\n const hasMandatoryFields = !shouldSkipQuery && chartTypeConfig.dropZones.some(zone => zone.mandatory === true)\n \n if (!chartConfig && hasMandatoryFields) {\n return (\n <div ref={inViewRef} className=\"flex items-center justify-center w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">Configuration Required</div>\n <div className=\"text-xs text-dc-text-secondary\">Please configure this chart</div>\n </div>\n </div>\n )\n }\n\n // Show placeholder for lazy-loaded portlets that aren't visible yet\n if (!shouldSkipQuery && !eagerLoad && !isVisible) {\n return (\n <div ref={inViewRef} className=\"w-full h-full\" style={{ height }}>\n <div className=\"w-full h-full animate-pulse bg-dc-surface-secondary rounded\" style={{ minHeight: '100px' }} />\n </div>\n )\n }\n\n // Skip loading and error handling for charts that don't need queries\n if (!shouldSkipQuery) {\n if (isLoading || (queryObject && !resultSet && !error)) {\n return (\n <div ref={inViewRef} className=\"flex items-center justify-center w-full\" style={{ height }}>\n {loadingComponent || <LoadingIndicator size=\"md\" />}\n </div>\n )\n }\n\n if (error) {\n return (\n <div ref={inViewRef} className=\"p-4 border rounded-sm\" style={{ height, borderColor: 'var(--dc-border)', backgroundColor: 'var(--dc-surface)' }}>\n <div className=\"mb-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium text-sm\" style={{ color: 'var(--dc-text)' }}>⚠️ Query Error</span>\n <button\n onClick={() => setRefreshCounter(prev => prev + 1)}\n className=\"px-2 py-1 text-white rounded-sm text-xs\"\n style={{ backgroundColor: 'var(--dc-primary)' }}\n >\n Retry\n </button>\n </div>\n </div>\n\n <div className=\"mb-3\">\n <div className=\"text-xs p-2 rounded-sm border\" style={{ color: 'var(--dc-text-secondary)', backgroundColor: 'var(--dc-surface)', borderColor: 'var(--dc-border)' }}>\n {error.message || error.toString()}\n </div>\n </div>\n\n <div className=\"space-y-2 text-xs\">\n <details>\n <summary className=\"cursor-pointer font-medium\" style={{ color: 'var(--dc-text-secondary)' }}>Query (with filters applied)</summary>\n <pre className=\"mt-1 p-2 rounded-sm text-xs overflow-auto max-h-20\" style={{ backgroundColor: 'rgba(var(--dc-primary-rgb), 0.1)' }}>\n {queryObject ? JSON.stringify(queryObject, null, 2) : query}\n </pre>\n </details>\n\n <details>\n <summary className=\"cursor-pointer font-medium\" style={{ color: 'var(--dc-text-secondary)' }}>Chart Config</summary>\n <pre className=\"mt-1 p-2 rounded-sm text-xs overflow-auto max-h-20\" style={{ backgroundColor: 'rgba(var(--dc-primary-rgb), 0.05)' }}>\n {JSON.stringify({\n chartType,\n chartConfig,\n displayConfig: displayConfig\n }, null, 2)}\n </pre>\n </details>\n </div>\n </div>\n )\n }\n\n // Check for valid data based on query type\n const hasValidData = isMultiQuery\n ? (multiQueryData !== null && multiQueryConfig !== null)\n : (resultSet !== null && queryObject !== null)\n\n if (!hasValidData) {\n return (\n <div ref={inViewRef} className=\"flex items-center justify-center w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">No data available</div>\n <div className=\"text-xs\">Invalid query or no results</div>\n </div>\n </div>\n )\n }\n }\n\n // Get data based on chart type needs\n const getData = () => {\n // Return empty array for charts that don't use query data\n if (shouldSkipQuery) {\n return []\n }\n\n // Multi-query: return merged data directly\n if (isMultiQuery) {\n return multiQueryData || []\n }\n\n // Single query: return empty array if no resultSet\n if (!resultSet) {\n return []\n }\n\n switch (chartType) {\n case 'pie':\n case 'table':\n return resultSet.tablePivot()\n default:\n return resultSet.rawData()\n }\n }\n\n const data = getData()\n\n // Render appropriate chart component using lazy loading\n // Each chart type is dynamically imported for code splitting\n const renderChart = () => {\n try {\n const chartHeight = height\n\n // Handle unsupported chart types\n if (!isValidChartType(chartType)) {\n return (\n <div className=\"flex items-center justify-center w-full\" style={{ height }}>\n <div className=\"text-center text-dc-text-muted\">\n <div className=\"text-sm font-semibold mb-1\">Unsupported chart type</div>\n <div className=\"text-xs\">{chartType}</div>\n </div>\n </div>\n )\n }\n\n // For markdown chart, use empty data array\n const chartData = chartType === 'markdown' ? [] : data\n\n return (\n <LazyChart\n chartType={chartType}\n data={chartData}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n queryObject={queryObject ?? undefined}\n height={chartHeight}\n colorPalette={colorPalette}\n fallback={\n <div\n className=\"flex items-center justify-center w-full\"\n style={{ height: typeof chartHeight === 'number' ? `${chartHeight}px` : chartHeight }}\n >\n <div className=\"animate-pulse bg-dc-surface-secondary rounded w-full h-full min-h-[100px]\" />\n </div>\n }\n />\n )\n } catch (error) {\n console.error('Chart rendering error:', error)\n return (\n <div className=\"flex items-center justify-center w-full text-dc-text-muted p-4\" style={{ height }}>\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">Unable to render chart</div>\n <div className=\"text-xs text-dc-text-secondary\">{error instanceof Error ? error.message : 'Unknown error'}</div>\n </div>\n </div>\n )\n }\n }\n\n return (\n <div ref={inViewRef} className=\"w-full h-full\">\n <ChartErrorBoundary\n portletTitle={_title}\n portletConfig={{\n chartType,\n chartConfig,\n displayConfig,\n height\n }}\n cubeQuery={query}\n >\n <div className=\"w-full h-full flex flex-col flex-1\" style={{ minHeight: '200px' }}>\n {renderChart()}\n </div>\n </ChartErrorBoundary>\n </div>\n )\n}))\n\nAnalyticsPortlet.displayName = 'AnalyticsPortlet'\n\nexport default AnalyticsPortlet","/**\n * useScrollDetection - Debounced Scroll Detection Hook\n *\n * Detects when a container has been scrolled past a threshold with debouncing\n * to prevent excessive state updates.\n *\n * This fixes the issue where scroll detection was listening to window.pageYOffset\n * instead of the actual scroll container (overflow-y-auto div in Layout).\n */\n\nimport { useEffect, useState, useRef, type RefObject } from 'react'\n\ninterface UseScrollDetectionOptions {\n /** Scroll threshold in pixels (default: 20) */\n threshold?: number\n /** Debounce delay in milliseconds (default: 150) */\n debounceMs?: number\n /** Optional container state to trigger re-initialization when found */\n container?: HTMLElement | null\n}\n\n/**\n * Hook to detect scroll position in a container\n *\n * @param containerRef - Ref to the scrollable container element\n * @param options - Configuration options for threshold and debounce\n * @returns Boolean indicating if scrolled past threshold\n *\n * @example\n * const scrollContainerRef = useRef<HTMLDivElement>(null)\n * const isScrolled = useScrollDetection(scrollContainerRef, {\n * threshold: 20,\n * debounceMs: 150\n * })\n *\n * <div ref={scrollContainerRef} className=\"overflow-y-auto\">\n * {isScrolled && <div>Shadow visible</div>}\n * </div>\n */\nexport function useScrollDetection(\n containerRef: RefObject<HTMLElement | null>,\n { threshold = 20, debounceMs = 150, container }: UseScrollDetectionOptions = {}\n) {\n const [isScrolled, setIsScrolled] = useState(false)\n const timeoutRef = useRef<number>()\n\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n const handleScroll = () => {\n // Clear existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n // Debounce scroll updates\n timeoutRef.current = window.setTimeout(() => {\n const scrollTop = container.scrollTop\n const shouldBeScrolled = scrollTop > threshold\n\n // Only update state if value actually changed\n setIsScrolled(prev => prev !== shouldBeScrolled ? shouldBeScrolled : prev)\n }, debounceMs)\n }\n\n // Attach scroll listener to actual container (not window!)\n container.addEventListener('scroll', handleScroll, { passive: true })\n\n // Initial check\n handleScroll()\n\n // Cleanup\n return () => {\n container.removeEventListener('scroll', handleScroll)\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n }\n }, [threshold, debounceMs, container])\n\n return isScrolled\n}\n","/**\n * useElementVisibility - Detects when an element scrolls out of view\n *\n * Used to detect when the static edit bar scrolls out of view, triggering\n * the floating toolbar to appear. Works with both viewport and custom\n * scroll containers.\n */\n\nimport { useEffect, useState, useRef, type RefObject } from 'react'\n\ninterface UseElementVisibilityOptions {\n /** Threshold in pixels - element considered out of view when this much scrolls past top */\n threshold?: number\n /** Debounce delay in milliseconds */\n debounceMs?: number\n /** Custom scroll container ref (uses viewport if not provided) */\n containerRef?: RefObject<HTMLElement | null>\n /** Optional state value to trigger re-initialization when container is found */\n container?: HTMLElement | null\n}\n\n/**\n * Hook to detect whether an element is visible in the viewport/container\n *\n * @param elementRef - Ref to the element to track\n * @param options - Configuration options\n * @returns Boolean indicating if the element is visible (true when in view, false when scrolled out)\n *\n * @example\n * const editBarRef = useRef<HTMLDivElement>(null)\n * const isEditBarVisible = useElementVisibility(editBarRef, {\n * threshold: 80,\n * containerRef: scrollContainerRef\n * })\n *\n * // Show floating toolbar when edit bar scrolls out of view\n * {!isEditBarVisible && <FloatingToolbar />}\n */\nexport function useElementVisibility(\n elementRef: RefObject<HTMLElement | null>,\n { threshold = 80, debounceMs = 100, containerRef, container }: UseElementVisibilityOptions = {}\n): boolean {\n // Start with visible=true to prevent flash on initial render\n const [isVisible, setIsVisible] = useState(true)\n const timeoutRef = useRef<number>()\n // Track if we've ever seen the element visible (prevents animation on load)\n const hasBeenVisibleRef = useRef(false)\n\n useEffect(() => {\n const container = containerRef?.current\n\n const checkVisibility = () => {\n const element = elementRef.current\n // If element not yet mounted, stay visible (don't show floating toolbar)\n if (!element) return\n\n // Clear existing timeout for debouncing\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n timeoutRef.current = window.setTimeout(() => {\n const elementRect = element.getBoundingClientRect()\n\n if (container) {\n // Check against scroll container\n const containerRect = container.getBoundingClientRect()\n // Element is \"visible\" when its bottom is below the container's top by at least threshold\n const visible = elementRect.bottom > containerRect.top + threshold\n\n // Track that we've seen the element visible at least once\n if (visible) {\n hasBeenVisibleRef.current = true\n }\n\n // Only update state if value changed\n setIsVisible(prev => prev !== visible ? visible : prev)\n } else {\n // Check against viewport (window)\n // Element is \"visible\" when its bottom is in the viewport (plus threshold buffer)\n const visible = elementRect.bottom > threshold\n\n // Track that we've seen the element visible at least once\n if (visible) {\n hasBeenVisibleRef.current = true\n }\n\n // Only update state if value changed\n setIsVisible(prev => prev !== visible ? visible : prev)\n }\n }, debounceMs)\n }\n\n // Attach scroll listener to container or window\n const scrollTarget = container || window\n scrollTarget.addEventListener('scroll', checkVisibility, { passive: true })\n\n // Also listen for resize events\n window.addEventListener('resize', checkVisibility, { passive: true })\n\n // Initial check\n checkVisibility()\n\n // Deferred re-check after React render cycle completes\n // This handles the case where elementRef.current isn't set yet on first render\n const rafId = requestAnimationFrame(() => {\n checkVisibility()\n })\n\n // Cleanup\n return () => {\n scrollTarget.removeEventListener('scroll', checkVisibility)\n window.removeEventListener('resize', checkVisibility)\n cancelAnimationFrame(rafId)\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n }\n }, [elementRef, containerRef, threshold, debounceMs, container])\n\n return isVisible\n}\n","/**\n * Syntax Highlighting Utility\n *\n * Lazy-loads highlight.js only when needed for syntax highlighting in debug panels.\n * This minimizes bundle size impact since syntax highlighting is not needed on initial load.\n *\n * Usage:\n * await highlightCodeBlocks()\n */\n\nlet highlightJs: any = null\nlet loadingPromise: Promise<void> | null = null\n\n/**\n * Lazy-loads highlight.js and registers supported languages.\n * Only loads once - subsequent calls return immediately.\n */\nexport async function loadSyntaxHighlighter(): Promise<void> {\n // Already loaded\n if (highlightJs) {\n return\n }\n\n // Loading in progress - wait for it\n if (loadingPromise) {\n return loadingPromise\n }\n\n loadingPromise = (async () => {\n try {\n // Dynamic imports to enable code splitting\n const hljs = await import('highlight.js/lib/core')\n const javascript = await import('highlight.js/lib/languages/javascript')\n const sql = await import('highlight.js/lib/languages/sql')\n const json = await import('highlight.js/lib/languages/json')\n\n // Register languages we need\n hljs.default.registerLanguage('javascript', javascript.default)\n hljs.default.registerLanguage('sql', sql.default)\n hljs.default.registerLanguage('json', json.default)\n\n // Store the instance\n highlightJs = hljs.default\n } catch (err) {\n console.error('Failed to load syntax highlighter:', err)\n // Clear loading promise so it can be retried\n loadingPromise = null\n }\n })()\n\n return loadingPromise\n}\n\n/**\n * Highlights all code blocks on the page that haven't been highlighted yet.\n * Gracefully handles cases where highlight.js fails to load.\n */\nexport async function highlightCodeBlocks(): Promise<void> {\n // Load highlighter if not already loaded\n await loadSyntaxHighlighter()\n\n // If loading failed, return silently (code blocks remain unstyled)\n if (!highlightJs) {\n return\n }\n\n // Find all code blocks and highlight them\n document.querySelectorAll('pre code').forEach((block) => {\n // Skip if already highlighted\n if (!block.classList.contains('hljs')) {\n highlightJs.highlightElement(block)\n }\n })\n}\n\n/**\n * Highlights a specific code block element.\n * Useful for dynamically added content.\n *\n * @param element - The code block element to highlight\n */\nexport async function highlightCodeBlock(element: HTMLElement): Promise<void> {\n await loadSyntaxHighlighter()\n\n if (!highlightJs) {\n return\n }\n\n if (!element.classList.contains('hljs')) {\n highlightJs.highlightElement(element)\n }\n}\n\n/**\n * Returns whether syntax highlighting is available.\n * Useful for conditional rendering or feature detection.\n */\nexport function isSyntaxHighlightingAvailable(): boolean {\n return highlightJs !== null\n}\n","import { useState, useEffect } from 'react'\nimport { highlightCodeBlocks } from '../utils/syntaxHighlighting'\n\ninterface DebugModalProps {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n}\n\nexport default function DebugModal({\n chartConfig,\n displayConfig,\n queryObject,\n data,\n chartType,\n cacheInfo\n}: DebugModalProps) {\n const [isOpen, setIsOpen] = useState(false)\n\n // Handle ESC key to close modal\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && isOpen) {\n setIsOpen(false)\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [isOpen])\n\n // Trigger syntax highlighting when modal opens and content is rendered\n useEffect(() => {\n if (isOpen) {\n // Small delay to ensure DOM is updated\n const timer = setTimeout(() => {\n highlightCodeBlocks().catch((err) => {\n console.debug('Syntax highlighting not available:', err)\n })\n }, 10)\n\n return () => clearTimeout(timer)\n }\n }, [isOpen])\n\n\n if (!isOpen) {\n return (\n <button\n onClick={() => setIsOpen(true)}\n className=\"p-1 text-dc-text-muted hover:text-dc-text-secondary transition-colors\"\n title=\"Debug chart configuration\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/>\n </svg>\n </button>\n )\n }\n\n return (\n <div\n className=\"absolute inset-0 bg-dc-surface border border-dc-border rounded-lg z-50 overflow-auto\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"p-4 h-full flex flex-col\">\n <div className=\"flex justify-between items-center mb-4 shrink-0\">\n <h2 className=\"text-lg font-semibold text-dc-text\">Chart Debug Information</h2>\n <button\n onClick={() => setIsOpen(false)}\n className=\"p-2 text-dc-text-muted hover:text-dc-text-secondary hover:bg-dc-surface-secondary rounded-sm\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4 flex-1 overflow-auto\">\n <div>\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Chart Type</h3>\n <div className=\"bg-dc-surface-secondary p-2 rounded-sm text-sm font-mono border border-dc-border\">\n {chartType}\n </div>\n </div>\n\n <div>\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Field Analysis</h3>\n <div className=\"bg-dc-surface-secondary p-2 rounded-sm text-xs space-y-1 border border-dc-border\">\n <div>\n <strong>xAxis:</strong> {Array.isArray(chartConfig?.xAxis) ? `Array: [${chartConfig.xAxis.join(', ')}]` : `String: \"${chartConfig?.xAxis}\"`}\n </div>\n <div>\n <strong>yAxis:</strong> {Array.isArray(chartConfig?.yAxis) ? `Array: [${chartConfig.yAxis.join(', ')}]` : `String: \"${chartConfig?.yAxis}\"`}\n </div>\n <div>\n <strong>series:</strong> {Array.isArray(chartConfig?.series) ? `Array: [${chartConfig.series.join(', ')}]` : `String: \"${chartConfig?.series}\"`}\n </div>\n {chartConfig?.sizeField && (\n <div>\n <strong>sizeField:</strong> {Array.isArray(chartConfig?.sizeField) ? `Array: [${chartConfig.sizeField.join(', ')}]` : `String: \"${chartConfig?.sizeField}\"`}\n </div>\n )}\n {chartConfig?.colorField && (\n <div>\n <strong>colorField:</strong> {Array.isArray(chartConfig?.colorField) ? `Array: [${chartConfig.colorField.join(', ')}]` : `String: \"${chartConfig?.colorField}\"`}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Chart Config</h3>\n <pre className=\"text-dc-text-secondary overflow-x-auto font-mono p-2 rounded-sm border border-dc-border\" style={{ fontSize: '10px', lineHeight: '1.4' }}>\n <code className=\"language-json\">{JSON.stringify(chartConfig, null, 2)}</code>\n </pre>\n </div>\n\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Display Config</h3>\n <pre className=\"text-dc-text-secondary overflow-x-auto font-mono p-2 rounded-sm border border-dc-border\" style={{ fontSize: '10px', lineHeight: '1.4' }}>\n <code className=\"language-json\">{JSON.stringify(displayConfig, null, 2)}</code>\n </pre>\n </div>\n\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Query Object</h3>\n <pre className=\"text-dc-text-secondary overflow-x-auto font-mono p-2 rounded-sm border border-dc-border\" style={{ fontSize: '10px', lineHeight: '1.4' }}>\n <code className=\"language-json\">{JSON.stringify(queryObject, null, 2)}</code>\n </pre>\n </div>\n\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Data Sample (first 3 rows)</h3>\n <pre className=\"text-dc-text-secondary overflow-x-auto font-mono p-2 rounded-sm border border-dc-border\" style={{ fontSize: '10px', lineHeight: '1.4' }}>\n <code className=\"language-json\">{JSON.stringify(data?.slice(0, 3) || [], null, 2)}</code>\n </pre>\n </div>\n\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-medium text-dc-text-secondary mb-2\">Cache Status</h3>\n <div className=\"bg-dc-surface-secondary p-2 rounded-sm text-xs border border-dc-border\">\n {cacheInfo ? (\n <div className=\"flex items-center gap-4 flex-wrap\">\n <span className=\"inline-flex items-center px-2 py-0.5 rounded-sm text-xs font-medium bg-dc-success-bg text-dc-success\">\n Cache Hit\n </span>\n <span><strong>Cached At:</strong> {new Date(cacheInfo.cachedAt).toLocaleString()}</span>\n <span><strong>TTL:</strong> {Math.round(cacheInfo.ttlMs / 1000)}s</span>\n <span><strong>TTL Remaining:</strong> {Math.round(cacheInfo.ttlRemainingMs / 1000)}s</span>\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <span className=\"inline-flex items-center px-2 py-0.5 rounded-sm text-xs font-medium bg-dc-surface text-dc-text-muted border border-dc-border\">\n Fresh Query\n </span>\n <span className=\"text-dc-text-muted\">Result not served from cache</span>\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 pt-2 border-t border-dc-border text-xs text-dc-text-muted shrink-0\">\n Press <kbd className=\"px-1 py-0.5 bg-dc-surface-secondary rounded-sm text-xs\">ESC</kbd> to close\n </div>\n </div>\n </div>\n )\n}","import React, { useCallback, type HTMLAttributes, type ReactNode, type CSSProperties, type ComponentType } from 'react'\nimport type { DashboardFilter, PortletConfig } from '../types'\nimport AnalyticsPortlet from './AnalyticsPortlet'\nimport DebugModal from './DebugModal'\nimport type { ColorPalette } from '../utils/colorPalettes'\n\n// Constant style object to prevent re-renders from inline object recreation\nconst ICON_STYLE: CSSProperties = { width: '16px', height: '16px', color: 'currentColor' }\n\ninterface DashboardPortletCardProps {\n portlet: PortletConfig\n editable: boolean\n isEditMode: boolean\n selectedFilterId: string | null\n debugData?: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n }\n dashboardFilters?: DashboardFilter[]\n configEagerLoad?: boolean\n loadingComponent?: ReactNode\n colorPalette?: ColorPalette\n containerProps?: HTMLAttributes<HTMLDivElement>\n headerProps?: HTMLAttributes<HTMLDivElement>\n onToggleFilter: (portletId: string, filterId: string) => void\n onRefresh: (portletId: string) => void\n onDuplicate: (portletId: string) => void\n onEdit: (portlet: PortletConfig) => void\n onDelete: (portletId: string) => void\n onOpenFilterConfig: (portlet: PortletConfig) => void\n onDebugDataReady: (portletId: string, data: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n }) => void\n setPortletRef: (portletId: string, element: HTMLDivElement | null) => void\n setPortletComponentRef: (portletId: string, element: { refresh: () => void } | null) => void\n icons: {\n RefreshIcon: ComponentType<{ className?: string; style?: CSSProperties }>\n EditIcon: ComponentType<{ className?: string; style?: CSSProperties }>\n DeleteIcon: ComponentType<{ className?: string; style?: CSSProperties }>\n CopyIcon: ComponentType<{ className?: string; style?: CSSProperties }>\n FilterIcon: ComponentType<{ className?: string; style?: CSSProperties }>\n }\n}\n\n// Custom comparison function to handle containerProps/headerProps object recreation\nfunction arePropsEqual(\n prevProps: DashboardPortletCardProps,\n nextProps: DashboardPortletCardProps\n): boolean {\n // Fast path: if object references are the same, props are equal\n if (prevProps === nextProps) return true\n\n // Check all scalar props\n if (\n prevProps.editable !== nextProps.editable ||\n prevProps.isEditMode !== nextProps.isEditMode ||\n prevProps.selectedFilterId !== nextProps.selectedFilterId ||\n prevProps.configEagerLoad !== nextProps.configEagerLoad\n ) {\n return false\n }\n\n // Check object/array props by reference (React.memo default behavior)\n if (\n prevProps.portlet !== nextProps.portlet ||\n prevProps.debugData !== nextProps.debugData ||\n prevProps.dashboardFilters !== nextProps.dashboardFilters ||\n prevProps.colorPalette !== nextProps.colorPalette ||\n prevProps.loadingComponent !== nextProps.loadingComponent ||\n prevProps.icons !== nextProps.icons\n ) {\n return false\n }\n\n // Check function props by reference\n if (\n prevProps.onToggleFilter !== nextProps.onToggleFilter ||\n prevProps.onRefresh !== nextProps.onRefresh ||\n prevProps.onDuplicate !== nextProps.onDuplicate ||\n prevProps.onEdit !== nextProps.onEdit ||\n prevProps.onDelete !== nextProps.onDelete ||\n prevProps.onOpenFilterConfig !== nextProps.onOpenFilterConfig ||\n prevProps.onDebugDataReady !== nextProps.onDebugDataReady ||\n prevProps.setPortletRef !== nextProps.setPortletRef ||\n prevProps.setPortletComponentRef !== nextProps.setPortletComponentRef\n ) {\n return false\n }\n\n // Special handling for containerProps and headerProps - compare properties shallowly\n // These objects may be recreated but with the same values (especially function references)\n const containerPropsEqual = shallowEqualObjects(prevProps.containerProps, nextProps.containerProps)\n const headerPropsEqual = shallowEqualObjects(prevProps.headerProps, nextProps.headerProps)\n\n return containerPropsEqual && headerPropsEqual\n}\n\n// Shallow comparison for objects - compares keys and values by reference\nfunction shallowEqualObjects(\n a: Record<string, any> | undefined,\n b: Record<string, any> | undefined\n): boolean {\n if (a === b) return true\n if (!a || !b) return a === b\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n\n if (keysA.length !== keysB.length) return false\n\n for (const key of keysA) {\n if (a[key] !== b[key]) return false\n }\n\n return true\n}\n\n// Memoize component to prevent re-renders when props haven't changed\nconst DashboardPortletCard = React.memo(function DashboardPortletCard({\n portlet,\n editable,\n isEditMode,\n selectedFilterId,\n debugData,\n dashboardFilters,\n configEagerLoad,\n loadingComponent,\n colorPalette,\n containerProps,\n headerProps,\n onToggleFilter,\n onRefresh,\n onDuplicate,\n onEdit,\n onDelete,\n onOpenFilterConfig,\n onDebugDataReady,\n setPortletRef,\n setPortletComponentRef,\n icons\n}: DashboardPortletCardProps) {\n const hasSelectedFilter = selectedFilterId\n ? (portlet.dashboardFilterMapping || []).includes(selectedFilterId)\n : false\n const isInSelectionMode = !!selectedFilterId\n\n const mergedContainerClassName = [\n 'bg-dc-surface border rounded-lg flex flex-col h-full transition-all',\n isInSelectionMode ? 'cursor-pointer' : '',\n containerProps?.className\n ]\n .filter(Boolean)\n .join(' ')\n\n const mergedHeaderClassName = [\n 'flex items-center justify-between px-3 py-1.5 md:px-4 md:py-1 border-b border-dc-border shrink-0 bg-dc-surface-secondary rounded-t-lg portlet-drag-handle',\n isEditMode ? 'cursor-move' : 'cursor-default',\n headerProps?.className\n ]\n .filter(Boolean)\n .join(' ')\n\n const {\n onClick: containerOnClick,\n className: _containerClassName,\n style: containerStyle,\n ...restContainerProps\n } = containerProps ?? {}\n\n const {\n onClick: headerOnClick,\n className: _headerClassName,\n style: headerStyle,\n ...restHeaderProps\n } = headerProps ?? {}\n\n // Memoize debug data callback to prevent AnalyticsPortlet re-renders\n const handleDebugDataReady = useCallback((data: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n }) => {\n onDebugDataReady(portlet.id, data)\n }, [portlet.id, onDebugDataReady])\n\n return (\n <div\n data-portlet-id={portlet.id}\n ref={el => setPortletRef(portlet.id, el)}\n className={mergedContainerClassName}\n style={{\n boxShadow: 'var(--dc-shadow-sm)',\n borderColor: isInSelectionMode && hasSelectedFilter\n ? 'var(--dc-primary)'\n : 'var(--dc-border)',\n borderWidth: isInSelectionMode && hasSelectedFilter ? '2px' : '1px',\n backgroundColor: isInSelectionMode && hasSelectedFilter\n ? 'rgba(var(--dc-primary-rgb), 0.05)'\n : 'var(--dc-surface)',\n opacity: isInSelectionMode && !hasSelectedFilter ? '0.5' : '1',\n ...containerStyle\n }}\n onClick={(event) => {\n if (isInSelectionMode && selectedFilterId) {\n event.stopPropagation()\n onToggleFilter(portlet.id, selectedFilterId)\n }\n containerOnClick?.(event)\n }}\n {...restContainerProps}\n >\n {(!portlet.displayConfig?.hideHeader || isEditMode) && (\n <div\n className={mergedHeaderClassName}\n style={headerStyle}\n onClick={(event) => {\n headerOnClick?.(event)\n }}\n {...restHeaderProps}\n >\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n <h3 className=\"font-semibold text-sm text-dc-text truncate\">{portlet.title}</h3>\n {editable && isEditMode && debugData && (\n <div\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => event.stopPropagation()}\n onTouchStart={(event) => event.stopPropagation()}\n onTouchEnd={(event) => event.stopPropagation()}\n >\n <DebugModal\n chartConfig={debugData.chartConfig}\n displayConfig={debugData.displayConfig}\n queryObject={debugData.queryObject}\n data={debugData.data}\n chartType={debugData.chartType}\n cacheInfo={debugData.cacheInfo}\n />\n </div>\n )}\n </div>\n <div\n className=\"flex items-center gap-1 shrink-0 ml-4 -mr-2\"\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => event.stopPropagation()}\n onTouchStart={(event) => event.stopPropagation()}\n onTouchEnd={(event) => event.stopPropagation()}\n >\n {/* Cache indicator - show when result was served from cache */}\n {debugData?.cacheInfo && (\n <span\n className=\"p-1 text-dc-text-muted opacity-40\"\n title={`Cached ${Math.round((Date.now() - new Date(debugData.cacheInfo.cachedAt).getTime()) / 1000)}s ago`}\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\" />\n <path d=\"M3 12c0 1.66 4 3 9 3s9-1.34 9-3\" />\n </svg>\n </span>\n )}\n <button\n onClick={(event) => {\n event.stopPropagation()\n onRefresh(portlet.id)\n }}\n onTouchEnd={(event) => {\n event.stopPropagation()\n event.preventDefault()\n onRefresh(portlet.id)\n }}\n disabled={isInSelectionMode}\n className={`p-1 bg-transparent border-none rounded-sm text-dc-text-secondary transition-colors ${\n isInSelectionMode ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:bg-dc-surface-hover'\n }`}\n title=\"Refresh portlet data\"\n >\n <icons.RefreshIcon style={ICON_STYLE} />\n </button>\n\n {editable && isEditMode && !isInSelectionMode && (\n <>\n <button\n onClick={(event) => {\n event.stopPropagation()\n onOpenFilterConfig(portlet)\n }}\n onTouchEnd={(event) => {\n event.stopPropagation()\n event.preventDefault()\n onOpenFilterConfig(portlet)\n }}\n className=\"p-1 bg-transparent border-none rounded-sm cursor-pointer hover:bg-dc-surface-hover transition-colors relative\"\n title={`Configure dashboard filters${portlet.dashboardFilterMapping && portlet.dashboardFilterMapping.length > 0 ? ` (${portlet.dashboardFilterMapping.length} active)` : ''}`}\n style={{\n color: portlet.dashboardFilterMapping && portlet.dashboardFilterMapping.length > 0\n ? 'var(--dc-primary)'\n : 'var(--dc-text-secondary)'\n }}\n >\n <icons.FilterIcon style={ICON_STYLE} />\n </button>\n\n <button\n onClick={(event) => {\n event.stopPropagation()\n onDuplicate(portlet.id)\n }}\n onTouchEnd={(event) => {\n event.stopPropagation()\n event.preventDefault()\n onDuplicate(portlet.id)\n }}\n className=\"p-1 bg-transparent border-none rounded-sm text-dc-text-secondary cursor-pointer hover:bg-dc-surface-hover transition-colors\"\n title=\"Duplicate portlet\"\n >\n <icons.CopyIcon style={ICON_STYLE} />\n </button>\n <button\n onClick={(event) => {\n event.stopPropagation()\n onEdit(portlet)\n }}\n onTouchEnd={(event) => {\n event.stopPropagation()\n event.preventDefault()\n onEdit(portlet)\n }}\n className=\"p-1 bg-transparent border-none rounded-sm text-dc-text-secondary cursor-pointer hover:bg-dc-surface-hover transition-colors\"\n title=\"Edit portlet\"\n >\n <icons.EditIcon style={ICON_STYLE} />\n </button>\n <button\n onClick={(event) => {\n event.stopPropagation()\n onDelete(portlet.id)\n }}\n onTouchEnd={(event) => {\n event.stopPropagation()\n event.preventDefault()\n onDelete(portlet.id)\n }}\n className=\"p-1 mr-0.5 bg-transparent border-none rounded-sm cursor-pointer hover:bg-dc-danger-bg text-dc-danger transition-colors\"\n title=\"Delete portlet\"\n >\n <icons.DeleteIcon style={ICON_STYLE} />\n </button>\n </>\n )}\n </div>\n </div>\n )}\n\n <div className=\"flex-1 px-2 py-3 md:px-4 md:py-4 min-h-0 overflow-visible flex flex-col\">\n <AnalyticsPortlet\n ref={el => setPortletComponentRef(portlet.id, el)}\n query={portlet.query}\n chartType={portlet.chartType}\n chartConfig={portlet.chartConfig}\n displayConfig={portlet.displayConfig}\n dashboardFilters={dashboardFilters}\n dashboardFilterMapping={portlet.dashboardFilterMapping}\n eagerLoad={portlet.eagerLoad ?? configEagerLoad ?? false}\n title={portlet.title}\n height=\"100%\"\n colorPalette={colorPalette}\n loadingComponent={loadingComponent}\n onDebugDataReady={handleDebugDataReady}\n />\n </div>\n </div>\n )\n}, arePropsEqual)\n\nexport default DashboardPortletCard\n","import { useState, useCallback, type HTMLAttributes, type ReactNode, type MouseEvent, type DragEvent } from 'react'\nimport type { DashboardGridSettings, PortletConfig, RowLayout } from '../types'\n\ninterface RowManagedLayoutProps {\n rows: RowLayout[]\n portlets: PortletConfig[]\n gridSettings: DashboardGridSettings\n gridWidth: number\n canEdit: boolean\n isDragging: boolean\n onRowResize: (rowIndex: number, event: MouseEvent<HTMLDivElement>) => void\n onColumnResize: (rowIndex: number, columnIndex: number, event: MouseEvent<HTMLDivElement>) => void\n onPortletDragStart: (rowIndex: number, columnIndex: number, portletId: string, event: DragEvent<HTMLDivElement>) => void\n onPortletDragEnd: () => void\n onRowDrop: (rowIndex: number, insertIndex: number | null) => void\n onNewRowDrop: (insertIndex: number) => void\n renderPortlet: (portlet: PortletConfig, containerProps?: HTMLAttributes<HTMLDivElement>, headerProps?: HTMLAttributes<HTMLDivElement>) => ReactNode\n}\n\nconst COLUMN_GAP = 16\n\nexport default function RowManagedLayout({\n rows,\n portlets,\n gridSettings,\n gridWidth,\n canEdit,\n isDragging,\n onRowResize,\n onColumnResize,\n onPortletDragStart,\n onPortletDragEnd,\n onRowDrop,\n onNewRowDrop,\n renderPortlet\n}: RowManagedLayoutProps) {\n const portletMap = new Map(portlets.map(portlet => [portlet.id, portlet]))\n const [activeDropKey, setActiveDropKey] = useState<string | null>(null)\n\n const setDropActive = (key: string | null) => {\n setActiveDropKey(key)\n }\n\n const isDragActive = isDragging || activeDropKey !== null\n\n // Stable drag event handlers using data attributes to prevent containerProps recreation\n const handlePortletDragStart = useCallback((event: DragEvent<HTMLDivElement>) => {\n const rowIndex = parseInt(event.currentTarget.dataset.rowIndex || '0', 10)\n const columnIndex = parseInt(event.currentTarget.dataset.columnIndex || '0', 10)\n const portletId = event.currentTarget.dataset.portletId || ''\n onPortletDragStart(rowIndex, columnIndex, portletId, event)\n }, [onPortletDragStart])\n\n const handlePortletDragEnd = useCallback(() => {\n setDropActive(null)\n onPortletDragEnd()\n }, [onPortletDragEnd])\n\n const topDropActive = activeDropKey === 'row-insert-0'\n const bottomDropActive = activeDropKey === 'row-bottom'\n\n return (\n <div\n className={`dc-row-layout${canEdit ? ' dc-row-layout-editable' : ''}${isDragActive ? ' dc-row-layout-dragging' : ''}`}\n style={{\n ['--dc-row-gap' as string]: '24px',\n ['--dc-column-gap' as string]: `${COLUMN_GAP}px`,\n ['--dc-top-drop-space' as string]: topDropActive ? '24px' : '0px',\n ['--dc-bottom-drop-space' as string]: bottomDropActive ? '24px' : '0px'\n }}\n >\n {canEdit && (\n <div\n className={`dc-row-boundary-drop dc-row-boundary-drop-top dc-split-handle${activeDropKey === 'row-insert-0' ? ' dc-drop-zone-active' : ''}`}\n onDragOver={(event) => {\n event.preventDefault()\n setDropActive('row-insert-0')\n }}\n onDragLeave={() => setDropActive(null)}\n onDrop={(event) => {\n event.preventDefault()\n setDropActive(null)\n onNewRowDrop(0)\n }}\n />\n )}\n {rows.map((row, rowIndex) => {\n const rowHeight = row.h * gridSettings.rowHeight\n const safeGridWidth = gridWidth || gridSettings.cols * gridSettings.rowHeight\n const paddingLeft = activeDropKey === `row-${rowIndex}-insert-0` ? COLUMN_GAP : 0\n const paddingRight = activeDropKey === `row-${rowIndex}-insert-${row.columns.length}` ? COLUMN_GAP : 0\n const rowContentWidth = safeGridWidth - (row.columns.length - 1) * COLUMN_GAP - paddingLeft - paddingRight\n const unitWidth = rowContentWidth / gridSettings.cols\n\n return (\n <div key={row.id} className=\"dc-row-layout-row-wrapper\">\n <div\n className=\"dc-row-layout-row\"\n style={{ height: rowHeight, paddingLeft, paddingRight }}\n >\n {row.columns.map((column, columnIndex) => {\n const portlet = portletMap.get(column.portletId)\n if (!portlet) return null\n const width = column.w * unitWidth\n\n const containerProps = {\n draggable: canEdit,\n 'data-row-index': rowIndex.toString(),\n 'data-column-index': columnIndex.toString(),\n 'data-portlet-id': portlet.id,\n onDragStart: handlePortletDragStart,\n onDragEnd: handlePortletDragEnd,\n className: 'dc-row-layout-column'\n } as HTMLAttributes<HTMLDivElement>\n\n return (\n <div\n key={portlet.id}\n className=\"dc-row-layout-column-wrapper\"\n style={{\n flex: `0 0 ${width}px`,\n maxWidth: `${width}px`\n }}\n >\n {renderPortlet(portlet, containerProps)}\n {columnIndex < row.columns.length - 1 && (\n <div\n className={`dc-column-resize-handle dc-split-handle${activeDropKey === `row-${rowIndex}-insert-${columnIndex + 1}` ? ' dc-drop-zone-active' : ''}`}\n onMouseDown={(event) => onColumnResize(rowIndex, columnIndex, event)}\n onDragOver={(event) => {\n if (!canEdit) return\n event.preventDefault()\n setDropActive(`row-${rowIndex}-insert-${columnIndex + 1}`)\n }}\n onDragLeave={() => setDropActive(null)}\n onDrop={(event) => {\n if (!canEdit) return\n event.preventDefault()\n event.stopPropagation()\n setDropActive(null)\n onRowDrop(rowIndex, columnIndex + 1)\n }}\n />\n )}\n </div>\n )\n })}\n </div>\n {canEdit && (\n <>\n <div\n className={`dc-row-edge-drop dc-row-edge-drop-left dc-split-handle${activeDropKey === `row-${rowIndex}-insert-0` ? ' dc-drop-zone-active' : ''}`}\n onDragOver={(event) => {\n event.preventDefault()\n setDropActive(`row-${rowIndex}-insert-0`)\n }}\n onDragLeave={() => {\n setDropActive(null)\n }}\n onDrop={(event) => {\n event.preventDefault()\n setDropActive(null)\n onRowDrop(rowIndex, 0)\n }}\n />\n <div\n className={`dc-row-edge-drop dc-row-edge-drop-right dc-split-handle${activeDropKey === `row-${rowIndex}-insert-${row.columns.length}` ? ' dc-drop-zone-active' : ''}`}\n onDragOver={(event) => {\n event.preventDefault()\n setDropActive(`row-${rowIndex}-insert-${row.columns.length}`)\n }}\n onDragLeave={() => {\n setDropActive(null)\n }}\n onDrop={(event) => {\n event.preventDefault()\n setDropActive(null)\n onRowDrop(rowIndex, row.columns.length)\n }}\n />\n </>\n )}\n {canEdit && (\n <div\n className={`dc-row-resize-handle dc-split-handle${activeDropKey === `row-insert-${rowIndex + 1}` ? ' dc-drop-zone-active' : ''}`}\n onMouseDown={(event) => onRowResize(rowIndex, event)}\n onDragOver={(event) => {\n event.preventDefault()\n setDropActive(`row-insert-${rowIndex + 1}`)\n }}\n onDragLeave={() => setDropActive(null)}\n onDrop={(event) => {\n event.preventDefault()\n setDropActive(null)\n onNewRowDrop(rowIndex + 1)\n }}\n />\n )}\n </div>\n )\n })}\n {canEdit && (\n <div\n className={`dc-row-boundary-drop dc-row-boundary-drop-bottom dc-split-handle${activeDropKey === 'row-bottom' ? ' dc-drop-zone-active' : ''}`}\n onDragOver={(event) => {\n event.preventDefault()\n setDropActive('row-bottom')\n }}\n onDragLeave={() => setDropActive(null)}\n onDrop={(event) => {\n event.preventDefault()\n setDropActive(null)\n onNewRowDrop(rows.length)\n }}\n />\n )}\n </div>\n )\n}\n","/**\n * Unified Color Palette System\n * Each palette contains coordinated series and gradient colors that work well together\n */\n\nexport interface ColorPalette {\n name: string\n label: string\n colors: string[] // For series-based charts (bar, line, pie, area, scatter, radar, etc.)\n gradient: string[] // For gradient-based charts (bubble, activity grid)\n}\n\n// Predefined color palettes with visually coordinated series and gradient colors\nexport const COLOR_PALETTES: ColorPalette[] = [\n {\n name: 'default',\n label: 'Default',\n colors: [\n '#3b82f6', // blue\n '#10b981', // green\n '#f59e0b', // yellow\n '#ef4444', // red\n '#8b5cf6', // purple\n '#f97316', // orange\n '#06b6d4', // cyan\n '#84cc16', // lime\n ],\n gradient: [\n '#440154', // dark purple\n '#414487', // purple-blue\n '#2a788e', // teal\n '#22a884', // green-teal \n '#7ad151', // green\n '#fde725', // yellow\n ]\n },\n {\n name: 'ocean',\n label: 'Ocean',\n colors: [\n '#1e3a8a', // deep blue\n '#1e40af', // blue\n '#2563eb', // bright blue\n '#3b82f6', // light blue\n '#06b6d4', // cyan\n '#0891b2', // dark cyan\n '#0e7490', // teal\n '#0f766e', // dark teal\n ],\n gradient: [\n '#0c4a6e', // very dark blue\n '#075985', // dark blue\n '#0369a1', // medium blue\n '#0284c7', // bright blue\n '#0ea5e9', // light blue\n '#38bdf8', // cyan blue\n ]\n },\n {\n name: 'sunset',\n label: 'Sunset',\n colors: [\n '#dc2626', // red\n '#ea580c', // orange-red\n '#f59e0b', // orange\n '#eab308', // yellow-orange\n '#d97706', // amber\n '#b45309', // dark amber\n '#92400e', // brown\n '#7c2d12', // dark brown\n ],\n gradient: [\n '#7c2d12', // dark brown\n '#92400e', // brown\n '#b45309', // dark amber\n '#d97706', // amber\n '#f59e0b', // orange\n '#fbbf24', // light orange\n ]\n },\n {\n name: 'forest',\n label: 'Forest',\n colors: [\n '#166534', // dark green\n '#15803d', // green\n '#16a34a', // bright green\n '#22c55e', // light green\n '#4ade80', // lighter green\n '#65a30d', // lime green\n '#84cc16', // lime\n '#a3e635', // light lime\n ],\n gradient: [\n '#14532d', // very dark green\n '#166534', // dark green\n '#15803d', // green\n '#16a34a', // bright green\n '#22c55e', // light green\n '#4ade80', // lighter green\n ]\n },\n {\n name: 'purple',\n label: 'Purple',\n colors: [\n '#581c87', // dark purple\n '#7c3aed', // purple\n '#8b5cf6', // bright purple\n '#a855f7', // light purple\n '#c084fc', // lighter purple\n '#e879f9', // magenta\n '#f0abfc', // light magenta\n '#fbbf24', // accent yellow\n ],\n gradient: [\n '#4c1d95', // very dark purple\n '#581c87', // dark purple\n '#6d28d9', // medium purple\n '#7c3aed', // purple\n '#8b5cf6', // bright purple\n '#a855f7', // light purple\n ]\n },\n {\n name: 'monochrome',\n label: 'Monochrome',\n colors: [\n '#1f2937', // very dark gray\n '#374151', // dark gray\n '#4b5563', // medium gray\n '#6b7280', // gray\n '#9ca3af', // light gray\n '#d1d5db', // lighter gray\n '#e5e7eb', // very light gray\n '#f3f4f6', // almost white\n ],\n gradient: [\n '#111827', // black\n '#1f2937', // very dark gray\n '#374151', // dark gray\n '#4b5563', // medium gray\n '#6b7280', // gray\n '#9ca3af', // light gray\n ]\n },\n {\n name: 'pastel',\n label: 'Pastel',\n colors: [\n '#93c5fd', // light blue\n '#86efac', // light green\n '#fde047', // light yellow\n '#fca5a5', // light red\n '#c4b5fd', // light purple\n '#fdba74', // light orange\n '#67e8f9', // light cyan\n '#bef264', // light lime\n ],\n gradient: [\n '#bfdbfe', // very light blue\n '#a7f3d0', // very light green\n '#fef08a', // very light yellow\n '#fecaca', // very light red\n '#ddd6fe', // very light purple\n '#fed7aa', // very light orange\n ]\n },\n {\n name: 'vibrant',\n label: 'Vibrant',\n colors: [\n '#0000ff', // pure blue\n '#00ff00', // pure green\n '#ffff00', // pure yellow\n '#ff0000', // pure red\n '#ff00ff', // pure magenta\n '#ff8000', // pure orange\n '#00ffff', // pure cyan\n '#8000ff', // pure violet\n ],\n gradient: [\n '#4000ff', // blue-violet\n '#0080ff', // blue\n '#00ffff', // cyan\n '#00ff80', // green\n '#80ff00', // lime\n '#ffff00', // yellow\n ]\n },\n {\n name: 'd3Category10',\n label: 'D3 Category 10',\n colors: [\n '#1f77b4', // blue\n '#ff7f0e', // orange\n '#2ca02c', // green\n '#d62728', // red\n '#9467bd', // purple\n '#8c564b', // brown\n '#e377c2', // pink\n '#7f7f7f', // gray\n '#bcbd22', // olive\n '#17becf', // cyan\n ],\n gradient: [\n '#1f77b4', // blue\n '#2ca02c', // green\n '#bcbd22', // olive\n '#ff7f0e', // orange\n '#d62728', // red\n '#9467bd', // purple\n ]\n },\n {\n name: 'd3Tableau10',\n label: 'D3 Tableau 10',\n colors: [\n '#4e79a7', // blue\n '#f28e2c', // orange\n '#e15759', // red\n '#76b7b2', // teal\n '#59a14f', // green\n '#edc949', // yellow\n '#af7aa1', // purple\n '#ff9da7', // pink\n '#9c755f', // brown\n '#bab0ab', // gray\n ],\n gradient: [\n '#4e79a7', // blue\n '#76b7b2', // teal\n '#59a14f', // green\n '#edc949', // yellow\n '#f28e2c', // orange\n '#e15759', // red\n ]\n },\n {\n name: 'colorBrewerSet1',\n label: 'ColorBrewer Set 1',\n colors: [\n '#e41a1c', // red\n '#377eb8', // blue\n '#4daf4a', // green\n '#984ea3', // purple\n '#ff7f00', // orange\n '#ffff33', // yellow\n '#a65628', // brown\n '#f781bf', // pink\n '#999999', // gray\n ],\n gradient: [\n '#377eb8', // blue\n '#4daf4a', // green\n '#ffff33', // yellow\n '#ff7f00', // orange\n '#e41a1c', // red\n '#984ea3', // purple\n ]\n },\n {\n name: 'colorBrewerSet2',\n label: 'ColorBrewer Set 2',\n colors: [\n '#66c2a5', // teal\n '#fc8d62', // orange\n '#8da0cb', // blue\n '#e78ac3', // pink\n '#a6d854', // lime\n '#ffd92f', // yellow\n '#e5c494', // tan\n '#b3b3b3', // gray\n ],\n gradient: [\n '#8da0cb', // blue\n '#66c2a5', // teal\n '#a6d854', // lime\n '#ffd92f', // yellow\n '#fc8d62', // orange\n '#e78ac3', // pink\n ]\n },\n {\n name: 'colorBrewerDark2',\n label: 'ColorBrewer Dark 2',\n colors: [\n '#1b9e77', // dark teal\n '#d95f02', // dark orange\n '#7570b3', // dark blue\n '#e7298a', // dark pink\n '#66a61e', // dark green\n '#e6ab02', // dark yellow\n '#a6761d', // dark brown\n '#666666', // dark gray\n ],\n gradient: [\n '#7570b3', // dark blue\n '#1b9e77', // dark teal\n '#66a61e', // dark green\n '#e6ab02', // dark yellow\n '#d95f02', // dark orange\n '#e7298a', // dark pink\n ]\n },\n {\n name: 'colorBrewerPaired',\n label: 'ColorBrewer Paired',\n colors: [\n '#a6cee3', // light blue\n '#1f78b4', // blue\n '#b2df8a', // light green\n '#33a02c', // green\n '#fb9a99', // light red\n '#e31a1c', // red\n '#fdbf6f', // light orange\n '#ff7f00', // orange\n '#cab2d6', // light purple\n '#6a3d9a', // purple\n '#ffff99', // light yellow\n '#b15928', // brown\n ],\n gradient: [\n '#1f78b4', // blue\n '#33a02c', // green\n '#ffff99', // light yellow\n '#ff7f00', // orange\n '#e31a1c', // red\n '#6a3d9a', // purple\n ]\n },\n {\n name: 'viridis',\n label: 'Viridis',\n colors: [\n '#440154', // dark purple\n '#482677', // purple\n '#3f4a8a', // blue-purple\n '#31678e', // blue\n '#26838f', // teal\n '#1f9d8a', // green-teal\n '#6cce5a', // green\n '#b6de2b', // yellow-green\n ],\n gradient: [\n '#440154', // dark purple\n '#482677', // purple\n '#3f4a8a', // blue-purple\n '#31678e', // blue\n '#26838f', // teal\n '#1f9d8a', // green-teal\n '#6cce5a', // green\n '#b6de2b', // yellow-green\n ]\n },\n {\n name: 'plasma',\n label: 'Plasma',\n colors: [\n '#0c0786', // dark blue\n '#5c01a6', // purple\n '#900da4', // magenta\n '#bf3984', // pink\n '#e16462', // coral\n '#f99b45', // orange\n '#fcce25', // yellow\n '#f0f921', // bright yellow\n ],\n gradient: [\n '#0c0786', // dark blue\n '#5c01a6', // purple\n '#900da4', // magenta\n '#bf3984', // pink\n '#e16462', // coral\n '#f99b45', // orange\n '#fcce25', // yellow\n '#f0f921', // bright yellow\n ]\n },\n {\n name: 'inferno',\n label: 'Inferno',\n colors: [\n '#000003', // black\n '#1f0c47', // dark blue\n '#550f6d', // purple\n '#88226a', // magenta\n '#a83655', // red\n '#cc4f39', // orange-red\n '#e6862a', // orange\n '#fec228', // yellow\n ],\n gradient: [\n '#000003', // black\n '#1f0c47', // dark blue\n '#550f6d', // purple\n '#88226a', // magenta\n '#a83655', // red\n '#cc4f39', // orange-red\n '#e6862a', // orange\n '#fec228', // yellow\n ]\n },\n {\n name: 'magma',\n label: 'Magma',\n colors: [\n '#000003', // black\n '#140b34', // dark purple\n '#3b0f6f', // purple\n '#641a80', // magenta\n '#8b2981', // pink\n '#b63679', // coral\n '#de4968', // red\n '#fd9f6c', // orange\n ],\n gradient: [\n '#000003', // black\n '#140b34', // dark purple\n '#3b0f6f', // purple\n '#641a80', // magenta\n '#8b2981', // pink\n '#b63679', // coral\n '#de4968', // red\n '#fd9f6c', // orange\n ]\n },\n {\n name: 'cividis',\n label: 'Cividis',\n colors: [\n '#00204c', // dark blue\n '#003f5c', // blue\n '#2c4b7a', // blue\n '#51576f', // blue-gray\n '#7f6874', // gray\n '#a8786e', // brown\n '#d2906d', // orange\n '#ffb570', // yellow\n ],\n gradient: [\n '#00204c', // dark blue\n '#003f5c', // blue\n '#2c4b7a', // blue\n '#51576f', // blue-gray\n '#7f6874', // gray\n '#a8786e', // brown\n '#d2906d', // orange\n '#ffb570', // yellow\n ]\n },\n {\n name: 'turbo',\n label: 'Turbo',\n colors: [\n '#30123b', // purple\n '#4454c4', // blue\n '#1dd3c0', // cyan\n '#42f465', // green\n '#b2df22', // lime\n '#faba39', // yellow\n '#f66c19', // orange\n '#c42e02', // red\n ],\n gradient: [\n '#30123b', // purple\n '#4454c4', // blue\n '#1dd3c0', // cyan\n '#42f465', // green\n '#b2df22', // lime\n '#faba39', // yellow\n '#f66c19', // orange\n '#c42e02', // red\n ]\n },\n {\n name: 'warm',\n label: 'Warm',\n colors: [\n '#8b0000', // dark red\n '#b22222', // red\n '#cd5c5c', // light red\n '#ff6347', // tomato\n '#ff8c00', // dark orange\n '#ffa500', // orange\n '#ffd700', // gold\n '#ffff00', // yellow\n ],\n gradient: [\n '#8b0000', // dark red\n '#b22222', // red\n '#ff6347', // tomato\n '#ff8c00', // dark orange\n '#ffa500', // orange\n '#ffd700', // gold\n ]\n },\n {\n name: 'cool',\n label: 'Cool',\n colors: [\n '#000080', // navy\n '#0000ff', // blue\n '#4169e1', // royal blue\n '#00bfff', // deep sky blue\n '#00ffff', // cyan\n '#40e0d0', // turquoise\n '#20b2aa', // light sea green\n '#008b8b', // dark cyan\n ],\n gradient: [\n '#000080', // navy\n '#0000ff', // blue\n '#4169e1', // royal blue\n '#00bfff', // deep sky blue\n '#00ffff', // cyan\n '#40e0d0', // turquoise\n ]\n },\n {\n name: 'earth',\n label: 'Earth',\n colors: [\n '#8b4513', // saddle brown\n '#a0522d', // sienna\n '#cd853f', // peru\n '#daa520', // goldenrod\n '#d2691e', // chocolate\n '#bc8f8f', // rosy brown\n '#f4a460', // sandy brown\n '#deb887', // burlywood\n ],\n gradient: [\n '#8b4513', // saddle brown\n '#a0522d', // sienna\n '#cd853f', // peru\n '#daa520', // goldenrod\n '#d2691e', // chocolate\n '#f4a460', // sandy brown\n ]\n },\n {\n name: 'autumn',\n label: 'Autumn',\n colors: [\n '#8b0000', // dark red\n '#a0522d', // sienna\n '#cd853f', // peru\n '#daa520', // goldenrod\n '#ff8c00', // dark orange\n '#ff4500', // orange red\n '#dc143c', // crimson\n '#b22222', // fire brick\n ],\n gradient: [\n '#8b0000', // dark red\n '#a0522d', // sienna\n '#cd853f', // peru\n '#daa520', // goldenrod\n '#ff8c00', // dark orange\n '#ff4500', // orange red\n ]\n },\n {\n name: 'spring',\n label: 'Spring',\n colors: [\n '#32cd32', // lime green\n '#98fb98', // pale green\n '#90ee90', // light green\n '#ffb6c1', // light pink\n '#ffc0cb', // pink\n '#ffffe0', // light yellow\n '#f0fff0', // honeydew\n '#e0ffff', // light cyan\n ],\n gradient: [\n '#32cd32', // lime green\n '#98fb98', // pale green\n '#ffffe0', // light yellow\n '#ffb6c1', // light pink\n '#ffc0cb', // pink\n '#e0ffff', // light cyan\n ]\n },\n {\n name: 'winter',\n label: 'Winter',\n colors: [\n '#191970', // midnight blue\n '#4682b4', // steel blue\n '#87ceeb', // sky blue\n '#b0e0e6', // powder blue\n '#e0ffff', // light cyan\n '#f0f8ff', // alice blue\n '#c0c0c0', // silver\n '#708090', // slate gray\n ],\n gradient: [\n '#191970', // midnight blue\n '#4682b4', // steel blue\n '#87ceeb', // sky blue\n '#b0e0e6', // powder blue\n '#e0ffff', // light cyan\n '#f0f8ff', // alice blue\n ]\n },\n {\n name: 'neon',\n label: 'Neon',\n colors: [\n '#ff0080', // neon pink\n '#00ff80', // neon green\n '#8000ff', // neon purple\n '#ff8000', // neon orange\n '#0080ff', // neon blue\n '#80ff00', // neon lime\n '#ff0040', // neon red\n '#40ff00', // bright green\n ],\n gradient: [\n '#8000ff', // neon purple\n '#0080ff', // neon blue\n '#00ff80', // neon green\n '#80ff00', // neon lime\n '#ff8000', // neon orange\n '#ff0080', // neon pink\n ]\n },\n {\n name: 'retro',\n label: 'Retro',\n colors: [\n '#ff69b4', // hot pink\n '#ffd700', // gold\n '#32cd32', // lime green\n '#00ced1', // dark turquoise\n '#ff6347', // tomato\n '#9370db', // medium purple\n '#ffa500', // orange\n '#20b2aa', // light sea green\n ],\n gradient: [\n '#9370db', // medium purple\n '#ff69b4', // hot pink\n '#ff6347', // tomato\n '#ffd700', // gold\n '#32cd32', // lime green\n '#00ced1', // dark turquoise\n ]\n },\n {\n name: 'corporate',\n label: 'Corporate',\n colors: [\n '#003366', // dark blue\n '#0066cc', // blue\n '#336699', // steel blue\n '#6699cc', // light blue\n '#4d4d4d', // dark gray\n '#808080', // gray\n '#b3b3b3', // light gray\n '#cccccc', // very light gray\n ],\n gradient: [\n '#003366', // dark blue\n '#0066cc', // blue\n '#336699', // steel blue\n '#6699cc', // light blue\n '#808080', // gray\n '#b3b3b3', // light gray\n ]\n },\n {\n name: 'material',\n label: 'Material Design',\n colors: [\n '#f44336', // red\n '#e91e63', // pink\n '#9c27b0', // purple\n '#673ab7', // deep purple\n '#3f51b5', // indigo\n '#2196f3', // blue\n '#03a9f4', // light blue\n '#00bcd4', // cyan\n ],\n gradient: [\n '#673ab7', // deep purple\n '#3f51b5', // indigo\n '#2196f3', // blue\n '#00bcd4', // cyan\n '#03a9f4', // light blue\n '#e91e63', // pink\n ]\n }\n]\n\n/**\n * Get a color palette by name, with fallback to default\n */\nexport function getColorPalette(paletteName?: string): ColorPalette {\n if (!paletteName) {\n return COLOR_PALETTES[0] // default palette\n }\n \n const palette = COLOR_PALETTES.find(p => p.name === paletteName)\n return palette || COLOR_PALETTES[0] // fallback to default\n}\n\n/**\n * Get just the series colors for a palette\n */\nexport function getSeriesColors(paletteName?: string): string[] {\n return getColorPalette(paletteName).colors\n}\n\n/**\n * Get just the gradient colors for a palette\n */\nexport function getGradientColors(paletteName?: string): string[] {\n return getColorPalette(paletteName).gradient\n}\n\n/**\n * Chart types that use series colors (discrete categories)\n */\nexport const SERIES_CHART_TYPES = [\n 'bar', 'line', 'area', 'pie', 'scatter', 'radar', 'radialBar', 'treeMap'\n] as const\n\n/**\n * Chart types that use gradient colors (continuous values)\n */\nexport const GRADIENT_CHART_TYPES = [\n 'bubble', 'activityGrid'\n] as const\n\n/**\n * Determine if a chart type uses gradient colors\n */\nexport function usesGradientColors(chartType: string): boolean {\n return GRADIENT_CHART_TYPES.includes(chartType as any)\n}","/**\n * FloatingEditToolbar - Vertical floating toolbar for dashboard editing\n *\n * Appears when the static edit bar scrolls out of view, providing quick access\n * to edit controls in a compact vertical format with icon-only buttons.\n *\n * Features:\n * - Icon-only buttons with tooltips\n * - Configurable left/right positioning\n * - Smooth slide-in/out animation\n * - Only visible on desktop (≥1200px)\n * - Compact palette dropdown that opens opposite to toolbar position\n */\n\nimport React, { useState, useRef, useEffect } from 'react'\nimport { createPortal } from 'react-dom'\nimport { getIcon } from '../icons'\nimport { COLOR_PALETTES } from '../utils/colorPalettes'\nimport type { DashboardLayoutMode } from '../types'\n\nconst EditIcon = getIcon('edit')\nconst CheckIcon = getIcon('check')\nconst GridIcon = getIcon('segment')\nconst RowsIcon = getIcon('table')\nconst AddIcon = getIcon('add')\nconst SwatchIcon = getIcon('swatch')\n\ninterface FloatingEditToolbarProps {\n /** Whether the static edit bar is visible (toolbar hidden when true) */\n isEditBarVisible: boolean\n /** Position of the floating toolbar */\n position: 'left' | 'right'\n /** Whether currently in edit mode */\n isEditMode: boolean\n /** Toggle edit mode on/off */\n onEditModeToggle: () => void\n /** Current layout mode */\n layoutMode: DashboardLayoutMode\n /** Change layout mode */\n onLayoutModeChange: (mode: DashboardLayoutMode) => void\n /** Available layout modes */\n allowedModes: DashboardLayoutMode[]\n /** Whether layout mode can be changed */\n canChangeLayoutMode: boolean\n /** Current color palette name */\n currentPalette: string\n /** Change color palette */\n onPaletteChange: (palette: string) => void\n /** Add new portlet */\n onAddPortlet: () => void\n}\n\nexport default function FloatingEditToolbar({\n isEditBarVisible,\n position,\n isEditMode,\n onEditModeToggle,\n layoutMode,\n onLayoutModeChange,\n allowedModes,\n canChangeLayoutMode,\n currentPalette,\n onPaletteChange,\n onAddPortlet\n}: FloatingEditToolbarProps) {\n const [isPaletteOpen, setIsPaletteOpen] = useState(false)\n const paletteRef = useRef<HTMLDivElement>(null)\n\n // Close palette dropdown on outside click\n useEffect(() => {\n if (!isPaletteOpen) return\n\n const handleClickOutside = (e: MouseEvent) => {\n if (paletteRef.current && !paletteRef.current.contains(e.target as Node)) {\n setIsPaletteOpen(false)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [isPaletteOpen])\n\n // Close palette when toolbar hides\n useEffect(() => {\n if (isEditBarVisible) {\n setIsPaletteOpen(false)\n }\n }, [isEditBarVisible])\n\n // Position classes - fixed positioning with vertical centering\n const positionClasses = position === 'left'\n ? 'left-4'\n : 'right-4'\n\n // Animation: slide in from edge when edit bar not visible\n // When edit bar IS visible, slide out and hide\n const isHidden = isEditBarVisible\n const translateClasses = position === 'left'\n ? (isHidden ? '-translate-x-16 opacity-0 pointer-events-none' : 'translate-x-0 opacity-100')\n : (isHidden ? 'translate-x-16 opacity-0 pointer-events-none' : 'translate-x-0 opacity-100')\n\n // Use portal to render outside the grid container to avoid react-grid-layout issues\n const toolbarContent = (\n <div\n className={`fixed top-1/2 -translate-y-1/2 z-50 flex flex-col gap-1.5 p-2\n bg-dc-surface-tertiary border border-dc-border rounded-lg\n transition-all duration-300 ease-in-out\n ${positionClasses} ${translateClasses}`}\n style={{\n boxShadow: 'var(--dc-shadow-lg)'\n }}\n >\n {/* Edit Toggle */}\n <ToolbarButton\n icon={isEditMode ? CheckIcon : EditIcon}\n tooltip={isEditMode ? 'Finish Editing' : 'Edit Dashboard'}\n isActive={isEditMode}\n onClick={onEditModeToggle}\n />\n\n {/* Layout Mode Switcher - only in edit mode with multiple modes */}\n {isEditMode && allowedModes.length > 1 && (\n <>\n <div className=\"w-full h-px bg-dc-border my-0.5\" />\n <ToolbarButton\n icon={GridIcon}\n tooltip=\"Grid Layout\"\n isActive={layoutMode === 'grid'}\n disabled={!canChangeLayoutMode}\n onClick={() => onLayoutModeChange('grid')}\n />\n <ToolbarButton\n icon={RowsIcon}\n tooltip=\"Rows Layout\"\n isActive={layoutMode === 'rows'}\n disabled={!canChangeLayoutMode}\n onClick={() => onLayoutModeChange('rows')}\n />\n </>\n )}\n\n {/* Color Palette - only in edit mode */}\n {isEditMode && (\n <>\n <div className=\"w-full h-px bg-dc-border my-0.5\" />\n <div ref={paletteRef} className=\"relative\">\n <ToolbarButton\n icon={SwatchIcon}\n tooltip=\"Color Palette\"\n isActive={isPaletteOpen}\n onClick={() => setIsPaletteOpen(!isPaletteOpen)}\n />\n {isPaletteOpen && (\n <CompactPaletteDropdown\n position={position}\n currentPalette={currentPalette}\n onPaletteChange={(palette) => {\n onPaletteChange(palette)\n setIsPaletteOpen(false)\n }}\n />\n )}\n </div>\n </>\n )}\n\n {/* Add Portlet - only in edit mode */}\n {isEditMode && (\n <>\n <div className=\"w-full h-px bg-dc-border my-0.5\" />\n <ToolbarButton\n icon={AddIcon}\n tooltip=\"Add Portlet\"\n onClick={onAddPortlet}\n />\n </>\n )}\n </div>\n )\n\n // Render via portal to document.body to avoid react-grid-layout child iteration issues\n if (typeof document === 'undefined') {\n return null // SSR safety\n }\n\n return createPortal(toolbarContent, document.body)\n}\n\n// Internal ToolbarButton component\ninterface ToolbarButtonProps {\n icon: React.ComponentType<{ className?: string }>\n tooltip: string\n isActive?: boolean\n disabled?: boolean\n onClick: () => void\n}\n\nfunction ToolbarButton({ icon: Icon, tooltip, isActive, disabled, onClick }: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n title={tooltip}\n className={`p-2 rounded-md transition-colors focus:outline-hidden focus:ring-2 focus:ring-dc-accent\n ${disabled\n ? 'opacity-50 cursor-not-allowed bg-dc-surface-secondary'\n : isActive\n ? 'bg-dc-surface-secondary'\n : 'bg-dc-surface hover:bg-dc-surface-hover'\n }`}\n style={{\n color: disabled ? 'var(--dc-text-muted)' : isActive ? 'var(--dc-primary)' : 'var(--dc-text-secondary)',\n borderColor: isActive ? 'var(--dc-primary)' : 'transparent'\n }}\n >\n <Icon className=\"w-5 h-5\" />\n </button>\n )\n}\n\n// Compact palette dropdown for floating toolbar\ninterface CompactPaletteDropdownProps {\n position: 'left' | 'right'\n currentPalette: string\n onPaletteChange: (palette: string) => void\n}\n\nfunction CompactPaletteDropdown({ position, currentPalette, onPaletteChange }: CompactPaletteDropdownProps) {\n // Position dropdown opposite to toolbar position to avoid off-screen\n const positionClasses = position === 'left' ? 'left-full ml-2' : 'right-full mr-2'\n\n return (\n <div\n className={`absolute top-0 ${positionClasses} w-52 bg-dc-surface border border-dc-border rounded-md z-50 max-h-72 overflow-y-auto`}\n style={{\n boxShadow: 'var(--dc-shadow-lg)'\n }}\n >\n <div className=\"py-1\">\n {COLOR_PALETTES.slice().sort((a, b) => a.label.localeCompare(b.label)).map((palette) => (\n <button\n key={palette.name}\n type=\"button\"\n onClick={() => onPaletteChange(palette.name)}\n className={`w-full px-3 py-2 text-left text-sm hover:bg-dc-surface-hover transition-colors ${\n palette.name === currentPalette ? 'bg-dc-surface-secondary text-dc-primary' : 'text-dc-text-secondary'\n }`}\n >\n <div className=\"flex items-center gap-2\">\n {/* Compact color preview - 4 series colors */}\n <div className=\"flex gap-0.5 shrink-0\">\n {palette.colors.slice(0, 4).map((color, index) => (\n <div\n key={index}\n className=\"w-2.5 h-2.5 rounded-xs border border-dc-border\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n <span className=\"text-xs font-medium truncate text-dc-text\">{palette.label}</span>\n {/* Current indicator */}\n {palette.name === currentPalette && (\n <div className=\"ml-auto w-1.5 h-1.5 rounded-full shrink-0 bg-dc-primary\" />\n )}\n </div>\n </button>\n ))}\n </div>\n </div>\n )\n}\n","import React, { useEffect, useCallback } from 'react'\n\nexport interface ModalProps {\n isOpen: boolean\n onClose: () => void\n title?: string\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'full' | 'fullscreen' | 'fullscreen-mobile'\n closeOnBackdropClick?: boolean\n closeOnEscape?: boolean\n showCloseButton?: boolean\n className?: string\n children: React.ReactNode\n footer?: React.ReactNode\n noPadding?: boolean\n}\n\nconst Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n size = 'md',\n closeOnBackdropClick = true,\n closeOnEscape = true,\n showCloseButton = true,\n children,\n footer,\n noPadding = false\n}) => {\n // Handle ESC key press\n const handleEscapeKey = useCallback((event: KeyboardEvent) => {\n if (event.key === 'Escape' && closeOnEscape) {\n onClose()\n }\n }, [closeOnEscape, onClose])\n\n\n // Manage ESC key listener and body scroll\n useEffect(() => {\n if (isOpen) {\n // Add ESC key listener\n if (closeOnEscape) {\n document.addEventListener('keydown', handleEscapeKey)\n }\n\n // Prevent body scroll when modal is open\n document.body.style.overflow = 'hidden'\n } else {\n // Restore body scroll\n document.body.style.overflow = 'unset'\n }\n\n // Cleanup\n return () => {\n document.removeEventListener('keydown', handleEscapeKey)\n document.body.style.overflow = 'unset'\n }\n }, [isOpen, closeOnEscape, handleEscapeKey])\n\n\n if (!isOpen) return null\n\n const getSizeClasses = () => {\n switch (size) {\n case 'sm':\n return 'max-w-md'\n case 'md':\n return 'max-w-lg'\n case 'lg':\n return 'max-w-2xl'\n case 'xl':\n return 'max-w-6xl'\n case 'xxl':\n return 'max-w-[1400px]' // Good for retina/mac displays\n case 'full':\n return 'max-w-7xl'\n case 'fullscreen':\n return 'w-[90vw] h-[90vh] max-w-none'\n case 'fullscreen-mobile':\n return 'w-full h-full md:w-[min(90vw,1400px)] md:h-[90vh]'\n default:\n return 'max-w-lg'\n }\n }\n\n return (\n <div\n className={`fixed inset-0 z-50 backdrop-blur-md ${size === 'fullscreen-mobile' ? 'flex md:flex md:items-center md:justify-center' : 'flex items-center justify-center'}`}\n style={{ backgroundColor: 'var(--dc-overlay)' }}\n onClick={closeOnBackdropClick ? onClose : undefined}\n >\n <div\n className={`relative bg-dc-surface border border-dc-border ${size === 'fullscreen-mobile' ? 'rounded-none md:rounded-lg' : 'rounded-lg'} ${size === 'fullscreen' || size === 'fullscreen-mobile' ? '' : 'mx-4'} ${getSizeClasses()} ${size === 'fullscreen' || size === 'fullscreen-mobile' ? '' : 'max-h-[90vh]'} flex flex-col`}\n style={{ boxShadow: 'var(--dc-shadow-2xl)' }}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? 'modal-title' : undefined}\n >\n {/* Header */}\n {(title || showCloseButton) && (\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-dc-border\">\n {title && (\n <h2 id=\"modal-title\" className=\"text-xl font-semibold text-dc-text\">\n {title}\n </h2>\n )}\n {showCloseButton && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-dc-text-muted hover:text-dc-text-secondary transition-colors p-2 -mr-2\"\n aria-label=\"Close modal\"\n >\n <svg width=\"24\" height=\"24\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n )}\n\n {/* Content */}\n <div className={`flex-1 overflow-y-auto ${noPadding ? '' : 'px-6 py-4'}`}>\n {children}\n </div>\n\n {/* Footer */}\n {footer && (\n <div className=\"flex items-center justify-end space-x-3 px-6 py-4 border-t border-dc-border bg-dc-surface-secondary\">\n {React.Children.toArray(footer)}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default Modal","/**\n * Shared date range parsing utilities\n * Used by both server (DateTimeBuilder) and client (comparison feature)\n *\n * These utilities handle:\n * - Relative date range parsing (today, yesterday, last 7 days, this month, etc.)\n * - Prior period calculation for comparison features\n * - Date formatting for cube queries\n */\n\n/**\n * Parse relative date range expressions like \"today\", \"yesterday\", \"last 7 days\", \"this month\", etc.\n * Returns start/end dates in UTC\n *\n * Handles all 14 DATE_RANGE_OPTIONS from the client:\n * - today, yesterday\n * - last 7 days, last 14 days, last 30 days\n * - last N days/weeks/months/years (legacy patterns)\n * - this week, last week\n * - this month, last month\n * - this quarter, last quarter\n * - this year, last year\n * - last 12 months\n */\nexport function parseRelativeDateRange(dateRange: string): { start: Date; end: Date } | null {\n const now = new Date()\n const lowerRange = dateRange.toLowerCase().trim()\n\n // Extract UTC date components for consistent calculations\n const utcYear = now.getUTCFullYear()\n const utcMonth = now.getUTCMonth()\n const utcDate = now.getUTCDate()\n const utcDay = now.getUTCDay()\n\n // Handle \"today\"\n if (lowerRange === 'today') {\n const start = new Date(now)\n start.setUTCHours(0, 0, 0, 0)\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"yesterday\"\n if (lowerRange === 'yesterday') {\n const start = new Date(now)\n start.setUTCDate(utcDate - 1)\n start.setUTCHours(0, 0, 0, 0)\n const end = new Date(now)\n end.setUTCDate(utcDate - 1)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"this week\" (Monday to Sunday)\n if (lowerRange === 'this week') {\n const mondayOffset = utcDay === 0 ? -6 : 1 - utcDay // If Sunday, go back 6 days, otherwise go to Monday\n const start = new Date(now)\n start.setUTCDate(utcDate + mondayOffset)\n start.setUTCHours(0, 0, 0, 0)\n\n const end = new Date(start)\n end.setUTCDate(start.getUTCDate() + 6) // Sunday\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"this month\"\n if (lowerRange === 'this month') {\n const start = new Date(Date.UTC(utcYear, utcMonth, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(utcYear, utcMonth + 1, 0, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"this quarter\"\n if (lowerRange === 'this quarter') {\n const quarter = Math.floor(utcMonth / 3)\n const start = new Date(Date.UTC(utcYear, quarter * 3, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(utcYear, quarter * 3 + 3, 0, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"this year\"\n if (lowerRange === 'this year') {\n const start = new Date(Date.UTC(utcYear, 0, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(utcYear, 11, 31, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"last N days\" pattern\n const lastDaysMatch = lowerRange.match(/^last\\s+(\\d+)\\s+days?$/)\n if (lastDaysMatch) {\n const days = parseInt(lastDaysMatch[1], 10)\n const start = new Date(now)\n start.setUTCDate(utcDate - days + 1) // Include today in the count\n start.setUTCHours(0, 0, 0, 0)\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"last N weeks\" pattern\n const lastWeeksMatch = lowerRange.match(/^last\\s+(\\d+)\\s+weeks?$/)\n if (lastWeeksMatch) {\n const weeks = parseInt(lastWeeksMatch[1], 10)\n const days = weeks * 7\n const start = new Date(now)\n start.setUTCDate(utcDate - days + 1) // Include today in the count\n start.setUTCHours(0, 0, 0, 0)\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"last week\" (previous Monday to Sunday)\n if (lowerRange === 'last week') {\n const lastMondayOffset = utcDay === 0 ? -13 : -6 - utcDay // Go to previous Monday\n const start = new Date(now)\n start.setUTCDate(utcDate + lastMondayOffset)\n start.setUTCHours(0, 0, 0, 0)\n\n const end = new Date(start)\n end.setUTCDate(start.getUTCDate() + 6) // Previous Sunday\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"last month\"\n if (lowerRange === 'last month') {\n const start = new Date(Date.UTC(utcYear, utcMonth - 1, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(utcYear, utcMonth, 0, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"last quarter\"\n if (lowerRange === 'last quarter') {\n const currentQuarter = Math.floor(utcMonth / 3)\n const lastQuarter = currentQuarter === 0 ? 3 : currentQuarter - 1\n const year = currentQuarter === 0 ? utcYear - 1 : utcYear\n const start = new Date(Date.UTC(year, lastQuarter * 3, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(year, lastQuarter * 3 + 3, 0, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"last year\"\n if (lowerRange === 'last year') {\n const start = new Date(Date.UTC(utcYear - 1, 0, 1, 0, 0, 0, 0))\n const end = new Date(Date.UTC(utcYear - 1, 11, 31, 23, 59, 59, 999))\n return { start, end }\n }\n\n // Handle \"last 12 months\" (rolling 12 months)\n if (lowerRange === 'last 12 months') {\n const start = new Date(Date.UTC(utcYear, utcMonth - 11, 1, 0, 0, 0, 0))\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"last N months\" pattern (legacy support)\n const lastMonthsMatch = lowerRange.match(/^last\\s+(\\d+)\\s+months?$/)\n if (lastMonthsMatch) {\n const months = parseInt(lastMonthsMatch[1], 10)\n const start = new Date(Date.UTC(utcYear, utcMonth - months + 1, 1, 0, 0, 0, 0))\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n // Handle \"last N years\" pattern (legacy support)\n const lastYearsMatch = lowerRange.match(/^last\\s+(\\d+)\\s+years?$/)\n if (lastYearsMatch) {\n const years = parseInt(lastYearsMatch[1], 10)\n const start = new Date(Date.UTC(utcYear - years, 0, 1, 0, 0, 0, 0))\n const end = new Date(now)\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n\n return null\n}\n\n/**\n * Parse a date range (string or array) to start/end dates\n * Handles both relative date expressions and explicit date arrays\n */\nexport function parseDateRange(dateRange: string | string[]): { start: Date; end: Date } | null {\n if (Array.isArray(dateRange)) {\n if (dateRange.length < 2) return null\n const start = new Date(dateRange[0])\n const end = new Date(dateRange[1])\n if (isNaN(start.getTime()) || isNaN(end.getTime())) return null\n // Normalize end to end of day\n end.setUTCHours(23, 59, 59, 999)\n return { start, end }\n }\n return parseRelativeDateRange(dateRange)\n}\n\n/**\n * Format date as YYYY-MM-DD for cube queries\n */\nexport function formatDateForCube(date: Date): string {\n return date.toISOString().split('T')[0]\n}\n\n/**\n * Calculate the prior period (same length, immediately before the current period)\n *\n * Example:\n * Current: Jan 1-7 (7 days)\n * Prior: Dec 25-31 (7 days)\n */\nexport function calculatePriorPeriod(currentStart: Date, currentEnd: Date): { start: Date; end: Date } {\n // Calculate period length in days (inclusive of both start and end dates)\n const periodLengthMs = currentEnd.getTime() - currentStart.getTime()\n const periodLengthDays = Math.ceil(periodLengthMs / (1000 * 60 * 60 * 24))\n\n // Prior period ends the day before current period starts\n const priorEnd = new Date(currentStart)\n priorEnd.setUTCDate(priorEnd.getUTCDate() - 1)\n priorEnd.setUTCHours(23, 59, 59, 999)\n\n // Prior period starts (periodLengthDays - 1) days before priorEnd\n const priorStart = new Date(priorEnd)\n priorStart.setUTCDate(priorStart.getUTCDate() - periodLengthDays + 1)\n priorStart.setUTCHours(0, 0, 0, 0)\n\n return { start: priorStart, end: priorEnd }\n}\n","/**\n * Utility functions for PortletBuilder component\n */\n\nimport type {\n MetricItem,\n BreakdownItem,\n FieldOption,\n FieldType,\n RecentFieldsStorage\n} from './types'\nimport type { MetaResponse, MetaField } from '../../shared/types'\nimport type { CubeQuery, Filter } from '../../types'\n\n// ============================================================================\n// ID Generation\n// ============================================================================\n\n/**\n * Generate a unique ID for items\n */\nexport function generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n}\n\n/**\n * Generate letter label for metrics (A, B, C, ..., AA, AB, ...)\n */\nexport function generateMetricLabel(index: number): string {\n let label = ''\n let n = index\n do {\n label = String.fromCharCode(65 + (n % 26)) + label\n n = Math.floor(n / 26) - 1\n } while (n >= 0)\n return label\n}\n\n// ============================================================================\n// Query Building\n// ============================================================================\n\n/**\n * Convert metrics and breakdowns to CubeQuery format\n */\nexport function buildCubeQuery(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n filters: Filter[]\n): CubeQuery {\n const query: CubeQuery = {\n measures: metrics.map((m) => m.field),\n dimensions: breakdowns.filter((b) => !b.isTimeDimension).map((b) => b.field),\n timeDimensions: breakdowns\n .filter((b) => b.isTimeDimension)\n .map((b) => ({\n dimension: b.field,\n granularity: b.granularity || 'day'\n })),\n filters: filters.length > 0 ? filters : undefined\n }\n\n // Clean up empty arrays\n if (query.measures?.length === 0) delete query.measures\n if (query.dimensions?.length === 0) delete query.dimensions\n if (query.timeDimensions?.length === 0) delete query.timeDimensions\n\n return query\n}\n\n/**\n * Check if a query has any content\n */\nexport function hasQueryContent(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n filters: Filter[]\n): boolean {\n return metrics.length > 0 || breakdowns.length > 0 || filters.length > 0\n}\n\n// ============================================================================\n// Field Utilities\n// ============================================================================\n\n/**\n * Get cube name from a field name (e.g., \"Employees.count\" -> \"Employees\")\n */\nexport function getCubeNameFromField(fieldName: string): string {\n return fieldName.split('.')[0]\n}\n\n/**\n * Get field short name from full name (e.g., \"Employees.count\" -> \"count\")\n */\nexport function getFieldShortName(fieldName: string): string {\n const parts = fieldName.split('.')\n return parts.length > 1 ? parts.slice(1).join('.') : fieldName\n}\n\n/**\n * Find field metadata from schema\n */\nexport function findFieldInSchema(\n fieldName: string,\n schema: MetaResponse | null\n): { field: MetaField; cubeName: string; fieldType: FieldType } | null {\n if (!schema) return null\n\n for (const cube of schema.cubes) {\n // Check measures\n const measure = cube.measures.find((m) => m.name === fieldName)\n if (measure) {\n return { field: measure, cubeName: cube.name, fieldType: 'measure' }\n }\n\n // Check dimensions\n const dimension = cube.dimensions.find((d) => d.name === fieldName)\n if (dimension) {\n return {\n field: dimension,\n cubeName: cube.name,\n fieldType: dimension.type === 'time' ? 'timeDimension' : 'dimension'\n }\n }\n }\n\n return null\n}\n\n/**\n * Get display title for a field\n */\nexport function getFieldTitle(fieldName: string, schema: MetaResponse | null): string {\n const found = findFieldInSchema(fieldName, schema)\n if (found) {\n return found.field.title || found.field.shortTitle || fieldName\n }\n return fieldName\n}\n\n/**\n * Determine field type from metadata\n */\nexport function getFieldType(field: MetaField): FieldType {\n if (field.type === 'time') return 'timeDimension'\n // Measures typically have aggregation types\n if (['count', 'countDistinct', 'sum', 'avg', 'min', 'max', 'runningTotal', 'countDistinctApprox'].includes(field.type)) {\n return 'measure'\n }\n return 'dimension'\n}\n\n// ============================================================================\n// Field Search & Filtering\n// ============================================================================\n\n/**\n * Convert schema to flat list of field options\n */\nexport function schemaToFieldOptions(\n schema: MetaResponse | null,\n mode: 'metrics' | 'breakdown' | 'filter'\n): FieldOption[] {\n if (!schema) return []\n\n const options: FieldOption[] = []\n\n for (const cube of schema.cubes) {\n if (mode === 'metrics') {\n // Add measures only\n for (const measure of cube.measures) {\n options.push({\n name: measure.name,\n title: measure.title || measure.shortTitle || measure.name,\n shortTitle: measure.shortTitle || measure.title || measure.name,\n type: measure.type,\n description: measure.description,\n cubeName: cube.name,\n fieldType: 'measure'\n })\n }\n } else if (mode === 'breakdown') {\n // Add dimensions only (both regular and time)\n for (const dimension of cube.dimensions) {\n const isTime = dimension.type === 'time'\n options.push({\n name: dimension.name,\n title: dimension.title || dimension.shortTitle || dimension.name,\n shortTitle: dimension.shortTitle || dimension.title || dimension.name,\n type: dimension.type,\n description: dimension.description,\n cubeName: cube.name,\n fieldType: isTime ? 'timeDimension' : 'dimension'\n })\n }\n } else {\n // 'filter' mode - add BOTH measures AND dimensions\n // Add measures first\n for (const measure of cube.measures) {\n options.push({\n name: measure.name,\n title: measure.title || measure.shortTitle || measure.name,\n shortTitle: measure.shortTitle || measure.title || measure.name,\n type: measure.type,\n description: measure.description,\n cubeName: cube.name,\n fieldType: 'measure'\n })\n }\n // Add dimensions (both regular and time)\n for (const dimension of cube.dimensions) {\n const isTime = dimension.type === 'time'\n options.push({\n name: dimension.name,\n title: dimension.title || dimension.shortTitle || dimension.name,\n shortTitle: dimension.shortTitle || dimension.title || dimension.name,\n type: dimension.type,\n description: dimension.description,\n cubeName: cube.name,\n fieldType: isTime ? 'timeDimension' : 'dimension'\n })\n }\n }\n }\n\n return options\n}\n\n/**\n * Filter field options by search term\n */\nexport function filterFieldOptions(\n options: FieldOption[],\n searchTerm: string,\n selectedCube?: string | null\n): FieldOption[] {\n let filtered = options\n\n // Filter by cube if selected\n if (selectedCube && selectedCube !== 'all') {\n filtered = filtered.filter((opt) => opt.cubeName === selectedCube)\n }\n\n // Filter by search term\n if (searchTerm.trim()) {\n const term = searchTerm.toLowerCase()\n filtered = filtered.filter(\n (opt) =>\n opt.name.toLowerCase().includes(term) ||\n opt.title.toLowerCase().includes(term) ||\n (opt.description?.toLowerCase().includes(term) ?? false)\n )\n }\n\n return filtered\n}\n\n/**\n * Group field options by cube\n */\nexport function groupFieldsByCube(options: FieldOption[]): Map<string, FieldOption[]> {\n const grouped = new Map<string, FieldOption[]>()\n\n for (const option of options) {\n const existing = grouped.get(option.cubeName) || []\n existing.push(option)\n grouped.set(option.cubeName, existing)\n }\n\n return grouped\n}\n\n// ============================================================================\n// Recent Fields Storage\n// ============================================================================\n\nconst RECENT_FIELDS_KEY = 'drizzle-cube-recent-fields'\nconst MAX_RECENT_FIELDS = 10\n\n/**\n * Get recent fields from localStorage\n */\nexport function getRecentFields(): RecentFieldsStorage {\n try {\n const stored = localStorage.getItem(RECENT_FIELDS_KEY)\n if (stored) {\n return JSON.parse(stored)\n }\n } catch {\n // Ignore errors\n }\n return { metrics: [], breakdowns: [] }\n}\n\n/**\n * Add a field to recent fields\n */\nexport function addRecentField(fieldName: string, mode: 'metrics' | 'breakdowns'): void {\n try {\n const recent = getRecentFields()\n const list = recent[mode]\n\n // Remove if already exists\n const filtered = list.filter((f) => f !== fieldName)\n\n // Add to front\n filtered.unshift(fieldName)\n\n // Limit size\n recent[mode] = filtered.slice(0, MAX_RECENT_FIELDS)\n\n localStorage.setItem(RECENT_FIELDS_KEY, JSON.stringify(recent))\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Get recent field options from schema\n */\nexport function getRecentFieldOptions(\n schema: MetaResponse | null,\n mode: 'metrics' | 'breakdown' | 'filter',\n recentFieldNames: string[]\n): FieldOption[] {\n if (!schema || recentFieldNames.length === 0) return []\n\n const allOptions = schemaToFieldOptions(schema, mode)\n const recentOptions: FieldOption[] = []\n\n for (const fieldName of recentFieldNames) {\n const option = allOptions.find((opt) => opt.name === fieldName)\n if (option) {\n recentOptions.push(option)\n }\n }\n\n return recentOptions\n}\n\n// ============================================================================\n// Cube List Utilities\n// ============================================================================\n\n/**\n * Get list of cube names from schema\n */\nexport function getCubeNames(schema: MetaResponse | null): string[] {\n if (!schema) return []\n return schema.cubes.map((cube) => cube.name)\n}\n\n/**\n * Get cube title by name\n */\nexport function getCubeTitle(cubeName: string, schema: MetaResponse | null): string {\n if (!schema) return cubeName\n const cube = schema.cubes.find((c) => c.name === cubeName)\n return cube?.title || cubeName\n}\n\n// ============================================================================\n// State Persistence\n// ============================================================================\n\nconst STORAGE_KEY = 'drizzle-cube-portlet-builder-state'\n\n/**\n * Save state to localStorage\n */\nexport function saveStateToStorage(state: {\n metrics: MetricItem[]\n breakdowns: BreakdownItem[]\n filters: Filter[]\n chartType: string\n chartConfig: object\n displayConfig: object\n activeView: string\n}): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(state))\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Load state from localStorage\n */\nexport function loadStateFromStorage(): {\n metrics: MetricItem[]\n breakdowns: BreakdownItem[]\n filters: Filter[]\n chartType: string\n chartConfig: object\n displayConfig: object\n activeView: string\n} | null {\n try {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) {\n return JSON.parse(stored)\n }\n } catch {\n // Ignore errors\n }\n return null\n}\n\n/**\n * Clear state from localStorage\n */\nexport function clearStateFromStorage(): void {\n try {\n localStorage.removeItem(STORAGE_KEY)\n } catch {\n // Ignore errors\n }\n}\n","/**\n * FieldSearchItem Component\n *\n * A single field item in the search results list.\n * Shows field icon, title, type badge, and selection state.\n */\n\nimport { memo } from 'react'\nimport { getIcon, getMeasureTypeIcon, getFieldTypeIcon } from '../../icons'\nimport type { FieldSearchItemProps } from './types'\n\nconst CheckIcon = getIcon('check')\n\nfunction FieldSearchItem({\n field,\n isSelected,\n isFocused,\n onClick,\n onMouseEnter,\n ...props\n}: FieldSearchItemProps & { 'data-field-index'?: number }) {\n // Get appropriate icon based on field type\n const getFieldIcon = () => {\n if (field.fieldType === 'measure') {\n const Icon = getMeasureTypeIcon(field.type)\n return Icon ? <Icon className=\"w-4 h-4\" /> : null\n } else if (field.fieldType === 'timeDimension') {\n const Icon = getFieldTypeIcon('time')\n return Icon ? <Icon className=\"w-4 h-4\" /> : null\n } else {\n const Icon = getFieldTypeIcon('dimension')\n return Icon ? <Icon className=\"w-4 h-4\" /> : null\n }\n }\n\n // Get badge color based on field type\n const getBadgeStyle = () => {\n if (field.fieldType === 'measure') {\n return 'bg-dc-measure text-dc-measure-text'\n } else if (field.fieldType === 'timeDimension') {\n return 'bg-dc-time-dimension text-dc-time-dimension-text'\n } else {\n return 'bg-dc-dimension text-dc-dimension-text'\n }\n }\n\n // Get short type label\n const getTypeLabel = () => {\n if (field.fieldType === 'measure') {\n return field.type.charAt(0).toUpperCase() + field.type.slice(1)\n } else if (field.fieldType === 'timeDimension') {\n return 'Time'\n } else {\n return 'Dim'\n }\n }\n\n return (\n <button\n onClick={onClick}\n onMouseEnter={onMouseEnter}\n className={`w-full text-left px-3 py-2 rounded-lg flex items-center gap-3 transition-colors group ${\n isFocused\n ? 'bg-dc-primary/10 ring-1 ring-dc-primary'\n : isSelected\n ? 'bg-dc-success/10'\n : 'hover:bg-dc-surface-hover'\n }`}\n {...props}\n >\n {/* Icon */}\n <span\n className={`shrink-0 w-8 h-8 flex items-center justify-center rounded-md ${\n field.fieldType === 'measure'\n ? 'bg-dc-measure text-dc-measure-text'\n : field.fieldType === 'timeDimension'\n ? 'bg-dc-time-dimension text-dc-time-dimension-text'\n : 'bg-dc-dimension text-dc-dimension-text'\n }`}\n >\n {getFieldIcon()}\n </span>\n\n {/* Title and name */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-dc-text truncate\">\n {field.title}\n </div>\n <div className=\"text-xs text-dc-text-muted truncate\">{field.name}</div>\n </div>\n\n {/* Type badge */}\n <span\n className={`shrink-0 px-2 py-0.5 rounded text-xs font-medium ${getBadgeStyle()}`}\n >\n {getTypeLabel()}\n </span>\n\n {/* Selection indicator */}\n {isSelected && (\n <span className=\"shrink-0 w-5 h-5 flex items-center justify-center rounded-full bg-dc-success text-white\">\n <CheckIcon className=\"w-3 h-3\" />\n </span>\n )}\n </button>\n )\n}\n\nexport default memo(FieldSearchItem)\n","/**\n * FieldDetailPanel Component\n *\n * Shows detailed information about the currently focused/hovered field.\n * Displays: icon, title, description, type, cube name, and technical name.\n */\n\nimport { memo } from 'react'\nimport { getMeasureTypeIcon, getFieldTypeIcon } from '../../icons'\nimport type { FieldDetailPanelProps } from './types'\n\nfunction FieldDetailPanel({ field }: FieldDetailPanelProps) {\n if (!field) {\n return (\n <div className=\"p-6 text-center text-dc-text-muted\">\n <p className=\"text-sm\">Hover over a field to see details</p>\n </div>\n )\n }\n\n // Get appropriate icon based on field type\n const getFieldIcon = () => {\n if (field.fieldType === 'measure') {\n const Icon = getMeasureTypeIcon(field.type)\n return Icon ? <Icon className=\"w-6 h-6\" /> : null\n } else if (field.fieldType === 'timeDimension') {\n const Icon = getFieldTypeIcon('time')\n return Icon ? <Icon className=\"w-6 h-6\" /> : null\n } else {\n const Icon = getFieldTypeIcon('dimension')\n return Icon ? <Icon className=\"w-6 h-6\" /> : null\n }\n }\n\n // Get icon background color - use field type specific colors for consistency\n const getIconBgStyle = () => {\n if (field.fieldType === 'measure') {\n return 'bg-dc-measure text-dc-measure-text'\n } else if (field.fieldType === 'timeDimension') {\n return 'bg-dc-time-dimension text-dc-time-dimension-text'\n } else {\n return 'bg-dc-dimension text-dc-dimension-text'\n }\n }\n\n // Get type display name\n const getTypeDisplay = () => {\n if (field.fieldType === 'measure') {\n const typeMap: Record<string, string> = {\n count: 'Count',\n countDistinct: 'Count Distinct',\n countDistinctApprox: 'Count Distinct (Approx)',\n sum: 'Sum',\n avg: 'Average',\n min: 'Minimum',\n max: 'Maximum',\n runningTotal: 'Running Total',\n number: 'Number'\n }\n return typeMap[field.type] || field.type\n } else if (field.fieldType === 'timeDimension') {\n return 'Time Dimension'\n } else {\n const typeMap: Record<string, string> = {\n string: 'Text',\n number: 'Number',\n boolean: 'Boolean',\n geo: 'Geographic'\n }\n return typeMap[field.type] || 'Dimension'\n }\n }\n\n return (\n <div className=\"p-4\">\n {/* Header with icon and title */}\n <div className=\"flex items-start gap-3 mb-4\">\n <span\n className={`shrink-0 w-12 h-12 flex items-center justify-center rounded-lg ${getIconBgStyle()}`}\n >\n {getFieldIcon()}\n </span>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-base font-semibold text-dc-text leading-tight\">\n {field.title}\n </h3>\n <p className=\"text-xs text-dc-text-muted mt-0.5 truncate\">\n {field.name}\n </p>\n </div>\n </div>\n\n {/* Description */}\n {field.description && (\n <div className=\"mb-4\">\n <p className=\"text-sm text-dc-text-secondary leading-relaxed\">\n {field.description}\n </p>\n </div>\n )}\n\n {/* Metadata */}\n <div className=\"space-y-3 pt-4 border-t border-dc-border\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-dc-text-muted\">Type</span>\n <span className=\"text-sm text-dc-text font-medium\">{getTypeDisplay()}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-dc-text-muted\">Cube</span>\n <span className=\"text-sm text-dc-text font-medium\">{field.cubeName}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-dc-text-muted\">Category</span>\n <span\n className={`text-xs px-2 py-0.5 rounded font-medium ${\n field.fieldType === 'measure'\n ? 'bg-dc-measure text-dc-measure-text'\n : field.fieldType === 'timeDimension'\n ? 'bg-dc-time-dimension text-dc-time-dimension-text'\n : 'bg-dc-dimension text-dc-dimension-text'\n }`}\n >\n {field.fieldType === 'measure'\n ? 'Measure'\n : field.fieldType === 'timeDimension'\n ? 'Time Dimension'\n : 'Dimension'}\n </span>\n </div>\n </div>\n\n {/* Usage hint */}\n <div className=\"mt-6 p-3 bg-dc-surface rounded-lg\">\n <p className=\"text-xs text-dc-text-muted\">\n Press <kbd className=\"px-1 py-0.5 bg-dc-surface-tertiary rounded text-xs\">Enter</kbd> or click to add this field to your query.\n </p>\n </div>\n </div>\n )\n}\n\nexport default memo(FieldDetailPanel)\n","/**\n * FieldSearchModal Component\n *\n * A full-screen search modal for selecting cube fields (measures/dimensions).\n * Features:\n * - Real-time search filtering\n * - Cube-based category filtering\n * - Three-column layout: Categories | Results | Details\n * - Keyboard navigation support\n * - Recent fields tracking\n */\n\nimport { useState, useMemo, useCallback, useEffect, useRef, KeyboardEvent } from 'react'\nimport { getIcon } from '../../icons'\nimport type { FieldSearchModalProps, FieldOption } from './types'\nimport type { MetaField } from '../../shared/types'\nimport {\n schemaToFieldOptions,\n filterFieldOptions,\n groupFieldsByCube,\n getCubeNames,\n getCubeTitle,\n getRecentFields,\n addRecentField,\n getRecentFieldOptions\n} from './utils'\nimport FieldSearchItem from './FieldSearchItem'\nimport FieldDetailPanel from './FieldDetailPanel'\n\nconst SearchIcon = getIcon('search')\nconst CloseIcon = getIcon('close')\n\nexport default function FieldSearchModal({\n isOpen,\n onClose,\n onSelect,\n mode,\n schema,\n selectedFields,\n recentFields: externalRecentFields\n}: FieldSearchModalProps) {\n // State\n const [searchTerm, setSearchTerm] = useState('')\n const [selectedCube, setSelectedCube] = useState<string | null>(null)\n const [focusedField, setFocusedField] = useState<FieldOption | null>(null)\n const [focusedIndex, setFocusedIndex] = useState(-1)\n const [lastSelectedIndex, setLastSelectedIndex] = useState<number | null>(null)\n\n // Refs\n const searchInputRef = useRef<HTMLInputElement>(null)\n const resultsContainerRef = useRef<HTMLDivElement>(null)\n\n // Get recent fields from localStorage or props\n const recentFieldNames = useMemo(() => {\n if (externalRecentFields) return externalRecentFields\n const stored = getRecentFields()\n return mode === 'metrics' ? stored.metrics : stored.breakdowns\n }, [externalRecentFields, mode])\n\n // Map mode to field options mode\n const fieldOptionsMode = mode\n\n // Get all field options for current mode\n const allFieldOptions = useMemo(() => {\n return schemaToFieldOptions(schema, fieldOptionsMode)\n }, [schema, fieldOptionsMode])\n\n // Get cube names for category filter\n const cubeNames = useMemo(() => {\n return getCubeNames(schema)\n }, [schema])\n\n // Filter fields by search and cube\n const filteredFields = useMemo(() => {\n return filterFieldOptions(allFieldOptions, searchTerm, selectedCube)\n }, [allFieldOptions, searchTerm, selectedCube])\n\n // Group filtered fields by cube\n const groupedFields = useMemo(() => {\n return groupFieldsByCube(filteredFields)\n }, [filteredFields])\n\n // Get recent field options (only when not searching)\n const recentOptions = useMemo(() => {\n if (searchTerm.trim()) return []\n return getRecentFieldOptions(schema, fieldOptionsMode, recentFieldNames).filter(\n (f) => !selectedCube || f.cubeName === selectedCube\n )\n }, [schema, fieldOptionsMode, recentFieldNames, searchTerm, selectedCube])\n\n // Flat list of visible fields for keyboard navigation\n const flatFieldsList = useMemo(() => {\n const list: FieldOption[] = [...recentOptions]\n groupedFields.forEach((fields) => {\n list.push(...fields)\n })\n return list\n }, [recentOptions, groupedFields])\n\n // Focus search input when modal opens\n useEffect(() => {\n if (isOpen && searchInputRef.current) {\n searchInputRef.current.focus()\n }\n }, [isOpen])\n\n // Reset state when modal closes\n useEffect(() => {\n if (!isOpen) {\n setSearchTerm('')\n setSelectedCube(null)\n setFocusedField(null)\n setFocusedIndex(-1)\n setLastSelectedIndex(null)\n }\n }, [isOpen])\n\n // Handle single field selection\n const selectSingleField = useCallback(\n (field: FieldOption, keepOpen: boolean = false) => {\n // Add to recent fields\n addRecentField(field.name, mode === 'metrics' ? 'metrics' : 'breakdowns')\n\n // Create MetaField object for callback\n const metaField: MetaField = {\n name: field.name,\n title: field.title,\n shortTitle: field.shortTitle,\n type: field.type,\n description: field.description\n }\n\n onSelect(metaField, field.fieldType, field.cubeName, keepOpen)\n },\n [mode, onSelect]\n )\n\n // Handle field selection with shift-click support for range selection\n const handleSelectField = useCallback(\n (field: FieldOption, fieldIndex: number, shiftKey: boolean = false) => {\n // Shift-click for range selection - keep modal open\n if (shiftKey && lastSelectedIndex !== null && lastSelectedIndex !== fieldIndex) {\n const startIndex = Math.min(lastSelectedIndex, fieldIndex)\n const endIndex = Math.max(lastSelectedIndex, fieldIndex)\n\n // Select all fields in the range, keep modal open for all\n for (let i = startIndex; i <= endIndex; i++) {\n const rangeField = flatFieldsList[i]\n if (rangeField && !selectedFields.includes(rangeField.name)) {\n selectSingleField(rangeField, true) // Keep modal open\n }\n }\n } else if (shiftKey) {\n // Shift-click on single item - select but keep modal open\n selectSingleField(field, true)\n } else {\n // Normal single selection - close modal after\n selectSingleField(field, false)\n }\n\n // Update last selected index for next shift-click\n setLastSelectedIndex(fieldIndex)\n },\n [flatFieldsList, lastSelectedIndex, selectSingleField, selectedFields]\n )\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (flatFieldsList.length === 0) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setFocusedIndex((prev) => {\n const next = Math.min(prev + 1, flatFieldsList.length - 1)\n setFocusedField(flatFieldsList[next])\n return next\n })\n break\n\n case 'ArrowUp':\n e.preventDefault()\n setFocusedIndex((prev) => {\n const next = Math.max(prev - 1, 0)\n setFocusedField(flatFieldsList[next])\n return next\n })\n break\n\n case 'Enter':\n e.preventDefault()\n if (focusedIndex >= 0 && flatFieldsList[focusedIndex]) {\n handleSelectField(flatFieldsList[focusedIndex], focusedIndex, e.shiftKey)\n }\n break\n\n case 'Escape':\n e.preventDefault()\n onClose()\n break\n }\n },\n [flatFieldsList, focusedIndex, handleSelectField, onClose]\n )\n\n // Scroll focused item into view\n useEffect(() => {\n if (focusedIndex >= 0 && resultsContainerRef.current) {\n const focusedElement = resultsContainerRef.current.querySelector(\n `[data-field-index=\"${focusedIndex}\"]`\n )\n if (focusedElement) {\n focusedElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' })\n }\n }\n }, [focusedIndex])\n\n if (!isOpen) return null\n\n const searchPlaceholder =\n mode === 'metrics' ? 'Search metrics...' : mode === 'filter' ? 'Search fields to filter...' : 'Search dimensions...'\n\n const modalTitle = mode === 'metrics' ? 'Select a Metric' : mode === 'filter' ? 'Select a Field to Filter' : 'Select a Dimension'\n const focusedFieldId = focusedIndex >= 0 && flatFieldsList[focusedIndex]\n ? `field-option-${flatFieldsList[focusedIndex].name.replace(/\\./g, '-')}`\n : undefined\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n style={{ backgroundColor: 'var(--dc-overlay)' }}\n onClick={onClose}\n role=\"presentation\"\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={modalTitle}\n className=\"bg-dc-surface shadow-xl w-full h-full md:rounded-lg md:w-[900px] md:max-w-[900px] md:h-[80vh] md:max-h-[700px] flex flex-col overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handleKeyDown}\n >\n {/* Header with Search */}\n <div className=\"shrink-0 border-b border-dc-border\">\n <div className=\"flex items-center px-4 py-3 gap-3\">\n <SearchIcon className=\"w-5 h-5 text-dc-text-muted\" aria-hidden={true} />\n <input\n ref={searchInputRef}\n type=\"text\"\n value={searchTerm}\n onChange={(e) => {\n setSearchTerm(e.target.value)\n setFocusedIndex(-1)\n }}\n placeholder={searchPlaceholder}\n className=\"flex-1 bg-transparent border-none outline-none text-dc-text placeholder-dc-text-muted text-lg\"\n aria-label={searchPlaceholder}\n aria-controls=\"field-search-results\"\n aria-activedescendant={focusedFieldId}\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n />\n <button\n onClick={onClose}\n className=\"p-1 text-dc-text-secondary hover:text-dc-text rounded\"\n aria-label=\"Close dialog\"\n >\n <CloseIcon className=\"w-5 h-5\" aria-hidden={true} />\n </button>\n </div>\n {/* Mobile cube filter - shown only on mobile */}\n {cubeNames.length > 1 && (\n <div className=\"md:hidden px-4 pb-3\">\n <select\n value={selectedCube || ''}\n onChange={(e) => setSelectedCube(e.target.value || null)}\n className=\"w-full px-3 py-2 bg-dc-surface border border-dc-border rounded-lg text-sm text-dc-text focus:outline-none focus:ring-1 focus:ring-dc-primary\"\n aria-label=\"Filter by cube\"\n >\n <option value=\"\">All Cubes</option>\n {cubeNames.map((cubeName) => (\n <option key={cubeName} value={cubeName}>\n {getCubeTitle(cubeName, schema)}\n </option>\n ))}\n </select>\n </div>\n )}\n </div>\n\n {/* Three Column Layout - Single column on mobile */}\n <div className=\"flex-1 flex overflow-hidden\">\n {/* Left Column - Categories (hidden on mobile) */}\n <nav\n className=\"hidden md:block w-48 shrink-0 border-r border-dc-border overflow-y-auto bg-dc-surface-secondary\"\n aria-label=\"Filter by cube\"\n >\n <div className=\"p-2\" role=\"group\" aria-label=\"Cube categories\">\n <button\n onClick={() => setSelectedCube(null)}\n className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${\n selectedCube === null\n ? 'bg-dc-primary/10 text-dc-primary font-medium'\n : 'text-dc-text hover:bg-dc-surface-hover'\n }`}\n aria-pressed={selectedCube === null}\n >\n All\n </button>\n {cubeNames.map((cubeName) => (\n <button\n key={cubeName}\n onClick={() => setSelectedCube(cubeName)}\n className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors truncate ${\n selectedCube === cubeName\n ? 'bg-dc-primary/10 text-dc-primary font-medium'\n : 'text-dc-text hover:bg-dc-surface-hover'\n }`}\n title={getCubeTitle(cubeName, schema)}\n aria-pressed={selectedCube === cubeName}\n >\n {getCubeTitle(cubeName, schema)}\n </button>\n ))}\n </div>\n </nav>\n\n {/* Middle Column - Results */}\n <div\n id=\"field-search-results\"\n ref={resultsContainerRef}\n className=\"flex-1 overflow-y-auto p-4\"\n role=\"listbox\"\n aria-label=\"Available fields\"\n >\n {filteredFields.length === 0 && recentOptions.length === 0 ? (\n <div className=\"text-center py-12 text-dc-text-muted\">\n <p className=\"text-lg mb-2\">No fields found</p>\n <p className=\"text-sm\">\n {searchTerm\n ? `No ${mode === 'metrics' ? 'metrics' : 'dimensions'} match \"${searchTerm}\"`\n : `No ${mode === 'metrics' ? 'metrics' : 'dimensions'} available`}\n </p>\n </div>\n ) : (\n <div className=\"space-y-6\">\n {/* Recent Fields */}\n {recentOptions.length > 0 && (\n <div>\n <h3 className=\"text-xs font-semibold text-dc-text-muted uppercase tracking-wider mb-2\">\n Recents\n </h3>\n <div className=\"space-y-1\">\n {recentOptions.map((field, idx) => (\n <FieldSearchItem\n key={`recent-${field.name}`}\n field={field}\n isSelected={selectedFields.includes(field.name)}\n isFocused={focusedIndex === idx}\n onClick={(e) => handleSelectField(field, idx, e.shiftKey)}\n onMouseEnter={() => {\n setFocusedField(field)\n setFocusedIndex(idx)\n }}\n data-field-index={idx}\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Grouped by Cube */}\n {Array.from(groupedFields.entries()).map(([cubeName, fields]) => (\n <div key={cubeName}>\n <h3 className=\"text-xs font-semibold text-dc-text-muted uppercase tracking-wider mb-2\">\n {getCubeTitle(cubeName, schema)}\n </h3>\n <div className=\"space-y-1\">\n {fields.map((field) => {\n const fieldIndex =\n recentOptions.length +\n Array.from(groupedFields.entries())\n .slice(\n 0,\n Array.from(groupedFields.keys()).indexOf(cubeName)\n )\n .reduce((sum, [, f]) => sum + f.length, 0) +\n fields.indexOf(field)\n\n return (\n <FieldSearchItem\n key={field.name}\n field={field}\n isSelected={selectedFields.includes(field.name)}\n isFocused={focusedIndex === fieldIndex}\n onClick={(e) => handleSelectField(field, fieldIndex, e.shiftKey)}\n onMouseEnter={() => {\n setFocusedField(field)\n setFocusedIndex(fieldIndex)\n }}\n data-field-index={fieldIndex}\n />\n )\n })}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Right Column - Field Details (hidden on mobile) */}\n <div className=\"hidden md:block w-72 shrink-0 border-l border-dc-border bg-dc-surface-secondary overflow-y-auto\">\n <FieldDetailPanel field={focusedField} />\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"shrink-0 border-t border-dc-border px-4 py-3 flex items-center justify-between text-sm text-dc-text-muted\">\n <div>\n <span className=\"text-dc-text-secondary\">{filteredFields.length}</span>{' '}\n {mode === 'metrics' ? 'metrics' : mode === 'filter' ? 'fields' : 'dimensions'} available\n </div>\n {/* Keyboard shortcuts - hidden on mobile */}\n <div className=\"hidden md:flex items-center gap-4\">\n <span>\n <kbd className=\"px-1.5 py-0.5 bg-dc-surface-tertiary rounded text-xs\">↑↓</kbd> Navigate\n </span>\n <span>\n <kbd className=\"px-1.5 py-0.5 bg-dc-surface-tertiary rounded text-xs\">Enter</kbd> Select\n </span>\n <span>\n <kbd className=\"px-1.5 py-0.5 bg-dc-surface-tertiary rounded text-xs\">Shift</kbd>+Click Multi-select\n </span>\n <span>\n <kbd className=\"px-1.5 py-0.5 bg-dc-surface-tertiary rounded text-xs\">Esc</kbd> Close\n </span>\n </div>\n </div>\n </div>\n </div>\n )\n}\n","/**\n * Shared type definitions used across QueryBuilder and AnalysisBuilder\n */\n\nimport type { CubeQuery, FilterOperator } from '../types'\n\n// ============================================================================\n// Meta endpoint response types\n// ============================================================================\n\nexport interface MetaField {\n name: string // e.g., \"Employees.count\"\n title: string // e.g., \"Total Employees\"\n shortTitle: string // e.g., \"Total Employees\"\n type: string // e.g., \"count\", \"string\", \"time\", \"number\"\n description?: string // Optional description\n}\n\nexport interface MetaCube {\n name: string // e.g., \"Employees\"\n title: string // e.g., \"Employee Analytics\"\n description: string // e.g., \"Employee data and metrics\"\n measures: MetaField[] // e.g., \"Employees.count\"\n dimensions: MetaField[] // e.g., \"Employees.name\"\n segments: MetaField[] // Currently empty in examples\n}\n\nexport interface MetaResponse {\n cubes: MetaCube[]\n}\n\n// ============================================================================\n// Query analysis types for debugging transparency\n// ============================================================================\n\nexport type PrimaryCubeSelectionReason =\n | 'most_dimensions'\n | 'most_connected'\n | 'alphabetical_fallback'\n | 'single_cube'\n\nexport interface PrimaryCubeCandidate {\n cubeName: string\n dimensionCount: number\n joinCount: number\n canReachAll: boolean\n}\n\nexport interface PrimaryCubeAnalysis {\n selectedCube: string\n reason: PrimaryCubeSelectionReason\n explanation: string\n candidates?: PrimaryCubeCandidate[]\n}\n\nexport interface JoinPathStep {\n fromCube: string\n toCube: string\n relationship: 'belongsTo' | 'hasOne' | 'hasMany' | 'belongsToMany'\n joinType: 'inner' | 'left' | 'right' | 'full'\n joinColumns: Array<{\n sourceColumn: string\n targetColumn: string\n }>\n junctionTable?: {\n tableName: string\n sourceColumns: string[]\n targetColumns: string[]\n }\n}\n\nexport interface JoinPathAnalysis {\n targetCube: string\n pathFound: boolean\n path?: JoinPathStep[]\n pathLength?: number\n error?: string\n visitedCubes?: string[]\n}\n\nexport interface PreAggregationAnalysis {\n cubeName: string\n cteAlias: string\n reason: string\n measures: string[]\n joinKeys: Array<{\n sourceColumn: string\n targetColumn: string\n }>\n}\n\nexport interface QuerySummary {\n queryType: 'single_cube' | 'multi_cube_join' | 'multi_cube_cte'\n joinCount: number\n cteCount: number\n hasPreAggregation: boolean\n}\n\nexport interface QueryAnalysis {\n timestamp: string\n cubeCount: number\n cubesInvolved: string[]\n primaryCube: PrimaryCubeAnalysis\n joinPaths: JoinPathAnalysis[]\n preAggregations: PreAggregationAnalysis[]\n querySummary: QuerySummary\n warnings?: string[]\n}\n\n// ============================================================================\n// Validation response from /dry-run endpoint\n// ============================================================================\n\nexport interface ValidationResult {\n valid?: boolean // Our custom property (may not be present in official Cube.js)\n error?: string\n query?: CubeQuery\n sql?: {\n sql: string[]\n params: any[]\n }\n queryType?: string // Always present in successful Cube.js responses\n normalizedQueries?: any[]\n queryOrder?: string[]\n transformedQueries?: any[]\n pivotQuery?: any\n complexity?: string\n cubesUsed?: string[]\n joinType?: string\n // Query analysis for debugging transparency\n analysis?: QueryAnalysis\n}\n\n// ============================================================================\n// Filter operator metadata\n// ============================================================================\n\nexport interface FilterOperatorMeta {\n label: string\n description: string\n requiresValues: boolean\n supportsMultipleValues: boolean\n valueType: 'string' | 'number' | 'date' | 'boolean' | 'any'\n fieldTypes: string[] // Which field types support this operator\n}\n\nexport const FILTER_OPERATORS: Record<FilterOperator, FilterOperatorMeta> = {\n // String operators\n equals: {\n label: 'equals',\n description: 'Exact match',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'boolean', 'time']\n },\n notEquals: {\n label: 'not equals',\n description: 'Does not match',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'boolean', 'time']\n },\n contains: {\n label: 'contains',\n description: 'Contains text (case insensitive)',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n notContains: {\n label: 'not contains',\n description: 'Does not contain text',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n startsWith: {\n label: 'starts with',\n description: 'Starts with text',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n notStartsWith: {\n label: 'not starts with',\n description: 'Does not start with text',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n endsWith: {\n label: 'ends with',\n description: 'Ends with text',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n notEndsWith: {\n label: 'not ends with',\n description: 'Does not end with text',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n like: {\n label: 'like',\n description: 'SQL LIKE pattern matching (case sensitive)',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n notLike: {\n label: 'not like',\n description: 'SQL NOT LIKE pattern matching (case sensitive)',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n ilike: {\n label: 'ilike',\n description: 'SQL ILIKE pattern matching (case insensitive)',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n // Numeric operators\n gt: {\n label: 'greater than',\n description: 'Greater than value',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n gte: {\n label: 'greater than or equal',\n description: 'Greater than or equal to value',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n lt: {\n label: 'less than',\n description: 'Less than value',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n lte: {\n label: 'less than or equal',\n description: 'Less than or equal to value',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n between: {\n label: 'between',\n description: 'Between two values (inclusive)',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n notBetween: {\n label: 'not between',\n description: 'Not between two values',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'number',\n fieldTypes: ['number', 'count', 'sum', 'avg', 'min', 'max']\n },\n // Array operators\n in: {\n label: 'in',\n description: 'Matches any of the provided values',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'boolean']\n },\n notIn: {\n label: 'not in',\n description: 'Does not match any of the provided values',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'boolean']\n },\n // Null/Empty operators\n set: {\n label: 'is set',\n description: 'Is not null/empty',\n requiresValues: false,\n supportsMultipleValues: false,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'time', 'boolean']\n },\n notSet: {\n label: 'is not set',\n description: 'Is null/empty',\n requiresValues: false,\n supportsMultipleValues: false,\n valueType: 'any',\n fieldTypes: ['string', 'number', 'time', 'boolean']\n },\n isEmpty: {\n label: 'is empty',\n description: 'Is empty string or null',\n requiresValues: false,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n isNotEmpty: {\n label: 'is not empty',\n description: 'Is not empty string and not null',\n requiresValues: false,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n // Date operators\n inDateRange: {\n label: 'in date range',\n description: 'Between two dates',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'date',\n fieldTypes: ['time']\n },\n beforeDate: {\n label: 'before date',\n description: 'Before specified date',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'date',\n fieldTypes: ['time']\n },\n afterDate: {\n label: 'after date',\n description: 'After specified date',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'date',\n fieldTypes: ['time']\n },\n // Regex operators\n regex: {\n label: 'matches regex',\n description: 'Matches regular expression pattern',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n notRegex: {\n label: 'not matches regex',\n description: 'Does not match regular expression pattern',\n requiresValues: true,\n supportsMultipleValues: false,\n valueType: 'string',\n fieldTypes: ['string']\n },\n // PostgreSQL array operators\n arrayContains: {\n label: 'array contains all',\n description: 'Array field contains all specified values (PostgreSQL only)',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'string',\n fieldTypes: ['string']\n },\n arrayOverlaps: {\n label: 'array contains any',\n description: 'Array field contains any of the specified values (PostgreSQL only)',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'string',\n fieldTypes: ['string']\n },\n arrayContained: {\n label: 'array values in',\n description: 'All array field values are within specified values (PostgreSQL only)',\n requiresValues: true,\n supportsMultipleValues: true,\n valueType: 'string',\n fieldTypes: ['string']\n }\n}\n\n// ============================================================================\n// Date range types\n// ============================================================================\n\nexport type DateRangeType =\n | 'custom'\n | 'today'\n | 'yesterday'\n | 'this_week'\n | 'this_month'\n | 'this_quarter'\n | 'this_year'\n | 'last_7_days'\n | 'last_30_days'\n | 'last_week'\n | 'last_month'\n | 'last_quarter'\n | 'last_year'\n | 'last_12_months'\n | 'last_n_days'\n | 'last_n_weeks'\n | 'last_n_months'\n | 'last_n_quarters'\n | 'last_n_years'\n\nexport interface DateRangeOption {\n value: DateRangeType\n label: string\n}\n\nexport const DATE_RANGE_OPTIONS: DateRangeOption[] = [\n { value: 'custom', label: 'Custom' },\n { value: 'today', label: 'Today' },\n { value: 'yesterday', label: 'Yesterday' },\n { value: 'this_week', label: 'This week' },\n { value: 'this_month', label: 'This month' },\n { value: 'this_quarter', label: 'This quarter' },\n { value: 'this_year', label: 'This year' },\n { value: 'last_7_days', label: 'Last 7 days' },\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_n_days', label: 'Last N days' },\n { value: 'last_week', label: 'Last week' },\n { value: 'last_n_weeks', label: 'Last N weeks' },\n { value: 'last_month', label: 'Last month' },\n { value: 'last_12_months', label: 'Last 12 months' },\n { value: 'last_n_months', label: 'Last N months' },\n { value: 'last_quarter', label: 'Last quarter' },\n { value: 'last_n_quarters', label: 'Last N quarters' },\n { value: 'last_year', label: 'Last year' },\n { value: 'last_n_years', label: 'Last N years' }\n] as const\n\n// ============================================================================\n// Time dimension granularity options\n// ============================================================================\n\nexport const TIME_GRANULARITIES = [\n { value: 'hour', label: 'Hour' },\n { value: 'day', label: 'Day' },\n { value: 'week', label: 'Week' },\n { value: 'month', label: 'Month' },\n { value: 'quarter', label: 'Quarter' },\n { value: 'year', label: 'Year' }\n] as const\n\nexport type TimeGranularity = typeof TIME_GRANULARITIES[number]['value']\n","/**\n * Shared utility functions used across QueryBuilder and AnalysisBuilder\n */\n\nimport type { CubeQuery, Filter, SimpleFilter, GroupFilter } from '../types'\nimport type { MetaField, MetaResponse } from './types'\nimport { FILTER_OPERATORS } from './types'\n\n// ============================================================================\n// Filter type guards\n// ============================================================================\n\n/**\n * Check if a filter is a simple filter\n */\nexport function isSimpleFilter(filter: Filter): filter is SimpleFilter {\n return 'member' in filter && 'operator' in filter && 'values' in filter\n}\n\n/**\n * Check if a filter is a group filter\n */\nexport function isGroupFilter(filter: Filter): filter is GroupFilter {\n return 'type' in filter && 'filters' in filter\n}\n\n/**\n * Check if a filter is an AND filter\n */\nexport function isAndFilter(filter: Filter): filter is GroupFilter {\n return isGroupFilter(filter) && filter.type === 'and'\n}\n\n/**\n * Check if a filter is an OR filter\n */\nexport function isOrFilter(filter: Filter): filter is GroupFilter {\n return isGroupFilter(filter) && filter.type === 'or'\n}\n\n// ============================================================================\n// Filter manipulation functions\n// ============================================================================\n\n/**\n * Flatten all simple filters from a hierarchical filter structure\n */\nexport function flattenFilters(filters: Filter[]): SimpleFilter[] {\n const simple: SimpleFilter[] = []\n\n const flatten = (filter: Filter) => {\n if (isSimpleFilter(filter)) {\n simple.push(filter)\n } else if (isGroupFilter(filter)) {\n filter.filters.forEach(flatten)\n }\n }\n\n filters.forEach(flatten)\n return simple\n}\n\n/**\n * Count total filters in hierarchical structure\n */\nexport function countFilters(filters: Filter[]): number {\n let count = 0\n\n const countFilter = (filter: Filter) => {\n if (isSimpleFilter(filter)) {\n count++\n } else if (isGroupFilter(filter)) {\n filter.filters.forEach(countFilter)\n }\n }\n\n filters.forEach(countFilter)\n return count\n}\n\n/**\n * Create a new simple filter\n */\nexport function createSimpleFilter(member: string, operator: string = 'equals', values: any[] = []): SimpleFilter {\n return {\n member,\n operator: operator as any,\n values\n }\n}\n\n/**\n * Create a new AND filter group\n */\nexport function createAndFilter(filters: Filter[] = []): GroupFilter {\n return {\n type: 'and',\n filters\n }\n}\n\n/**\n * Create a new OR filter group\n */\nexport function createOrFilter(filters: Filter[] = []): GroupFilter {\n return {\n type: 'or',\n filters\n }\n}\n\n// ============================================================================\n// Filter transformation functions\n// ============================================================================\n\n/**\n * Transform filters from new GroupFilter format to legacy server format\n * Server expects { and: [...] } and { or: [...] } instead of { type: 'and', filters: [...] }\n */\nexport function transformFiltersForServer(filters: Filter[]): any[] {\n const transformFilter = (filter: Filter): any => {\n if (isSimpleFilter(filter)) {\n return filter\n } else if (isGroupFilter(filter)) {\n const transformedSubFilters = filter.filters.map(transformFilter)\n\n if (filter.type === 'and') {\n return { and: transformedSubFilters }\n } else {\n return { or: transformedSubFilters }\n }\n }\n return filter\n }\n\n return filters.map(transformFilter)\n}\n\n/**\n * Transform filters from server/API format to UI format\n * Converts {and: [...]} and {or: [...]} to {type: 'and', filters: [...]} format\n */\nexport function transformFiltersFromServer(filters: any[]): Filter[] {\n return filters.map(filter => {\n if (!filter || typeof filter !== 'object') {\n return filter\n }\n\n // Handle legacy {and: [...]} format\n if ('and' in filter && Array.isArray(filter.and)) {\n return {\n type: 'and',\n filters: transformFiltersFromServer(filter.and)\n } as GroupFilter\n }\n\n // Handle legacy {or: [...]} format\n if ('or' in filter && Array.isArray(filter.or)) {\n return {\n type: 'or',\n filters: transformFiltersFromServer(filter.or)\n } as GroupFilter\n }\n\n // Handle new format {type: 'and', filters: [...]} - process recursively\n if ('type' in filter && 'filters' in filter && Array.isArray(filter.filters)) {\n return {\n type: filter.type,\n filters: transformFiltersFromServer(filter.filters)\n } as GroupFilter\n }\n\n // Simple filter - pass through\n return filter as SimpleFilter\n }).filter(Boolean) // Remove any null/undefined values\n}\n\n// ============================================================================\n// Query utility functions\n// ============================================================================\n\n/**\n * Check if query has any content (measures, dimensions, or timeDimensions)\n */\nexport function hasQueryContent(query: CubeQuery): boolean {\n return Boolean(\n (query.measures && query.measures.length > 0) ||\n (query.dimensions && query.dimensions.length > 0) ||\n (query.timeDimensions && query.timeDimensions.length > 0)\n )\n}\n\n/**\n * Clean query object by removing empty arrays\n */\nexport function cleanQuery(query: CubeQuery): CubeQuery {\n const cleanedQuery: CubeQuery = {}\n\n if (query.measures && query.measures.length > 0) {\n cleanedQuery.measures = query.measures\n }\n\n if (query.dimensions && query.dimensions.length > 0) {\n cleanedQuery.dimensions = query.dimensions\n }\n\n if (query.timeDimensions && query.timeDimensions.length > 0) {\n cleanedQuery.timeDimensions = query.timeDimensions\n }\n\n if (query.filters && query.filters.length > 0) {\n cleanedQuery.filters = query.filters\n }\n\n if (query.order) {\n cleanedQuery.order = query.order\n }\n\n if (query.limit) {\n cleanedQuery.limit = query.limit\n }\n\n if (query.offset) {\n cleanedQuery.offset = query.offset\n }\n\n if (query.segments && query.segments.length > 0) {\n cleanedQuery.segments = query.segments\n }\n\n return cleanedQuery\n}\n\n/**\n * Clean a query and transform filters for server compatibility\n * This version transforms GroupFilter to legacy and/or format\n */\nexport function cleanQueryForServer(query: CubeQuery): CubeQuery {\n const cleanedQuery = cleanQuery(query)\n\n // Apply server transformation to filters\n if (cleanedQuery.filters && cleanedQuery.filters.length > 0) {\n cleanedQuery.filters = transformFiltersForServer(cleanedQuery.filters) as any\n }\n\n return cleanedQuery\n}\n\n/**\n * Transform a Cube.js query from external format to UI internal format\n * This handles format differences between server/API queries and QueryBuilder state\n */\nexport function transformQueryForUI(query: any): CubeQuery {\n if (!query || typeof query !== 'object') {\n return {}\n }\n\n const transformed: CubeQuery = {}\n\n // Copy simple fields if they exist\n if (query.measures) transformed.measures = Array.isArray(query.measures) ? query.measures : []\n if (query.dimensions) transformed.dimensions = Array.isArray(query.dimensions) ? query.dimensions : []\n if (query.timeDimensions) transformed.timeDimensions = Array.isArray(query.timeDimensions) ? query.timeDimensions : []\n if (query.order) transformed.order = query.order\n if (query.limit) transformed.limit = query.limit\n if (query.offset) transformed.offset = query.offset\n if (query.segments) transformed.segments = Array.isArray(query.segments) ? query.segments : []\n\n // Transform filters from server format to UI format\n if (query.filters && Array.isArray(query.filters)) {\n transformed.filters = transformFiltersFromServer(query.filters)\n }\n\n return cleanQuery(transformed)\n}\n\n// ============================================================================\n// Schema utility functions\n// ============================================================================\n\n/**\n * Get cube name from field name (e.g., \"Employees.count\" -> \"Employees\")\n */\nexport function getCubeNameFromField(fieldName: string): string {\n return fieldName.split('.')[0]\n}\n\n/**\n * Get field type from schema\n */\nexport function getFieldType(fieldName: string, schema: MetaResponse): string {\n for (const cube of schema.cubes) {\n // Check measures\n const measure = cube.measures.find(m => m.name === fieldName)\n if (measure) return measure.type\n\n // Check dimensions\n const dimension = cube.dimensions.find(d => d.name === fieldName)\n if (dimension) return dimension.type\n }\n\n return 'string' // Default fallback\n}\n\n/**\n * Get field title from schema metadata, falling back to field name\n */\nexport function getFieldTitle(fieldName: string, schema: MetaResponse | null): string {\n if (!schema) return fieldName\n\n for (const cube of schema.cubes) {\n // Check measures\n const measure = cube.measures.find(m => m.name === fieldName)\n if (measure) return measure.title || measure.shortTitle || fieldName\n\n // Check dimensions\n const dimension = cube.dimensions.find(d => d.name === fieldName)\n if (dimension) return dimension.title || dimension.shortTitle || fieldName\n }\n\n return fieldName // Fallback to field name if not found\n}\n\n/**\n * Get available operators for a field type\n */\nexport function getAvailableOperators(fieldType: string): Array<{operator: string, label: string}> {\n const operators: Array<{operator: string, label: string}> = []\n\n for (const [operator, meta] of Object.entries(FILTER_OPERATORS)) {\n if (meta.fieldTypes.includes(fieldType)) {\n operators.push({\n operator,\n label: meta.label\n })\n }\n }\n\n return operators\n}\n\n/**\n * Get ALL filterable fields from schema\n */\nexport function getAllFilterableFields(schema: MetaResponse): MetaField[] {\n const allFields: MetaField[] = []\n\n schema.cubes.forEach(cube => {\n allFields.push(...cube.measures)\n allFields.push(...cube.dimensions)\n })\n\n return allFields.sort((a, b) => a.name.localeCompare(b.name))\n}\n\n// ============================================================================\n// Date range utility functions\n// ============================================================================\n\n/**\n * Convert DateRangeType to Cube.js compatible date range format\n */\nexport function convertDateRangeTypeToValue(rangeType: string, number?: number): string {\n const typeMap: Record<string, string> = {\n 'today': 'today',\n 'yesterday': 'yesterday',\n 'this_week': 'this week',\n 'this_month': 'this month',\n 'this_quarter': 'this quarter',\n 'this_year': 'this year',\n 'last_7_days': 'last 7 days',\n 'last_30_days': 'last 30 days',\n 'last_week': 'last week',\n 'last_month': 'last month',\n 'last_quarter': 'last quarter',\n 'last_year': 'last year',\n 'last_12_months': 'last 12 months'\n }\n\n // Handle dynamic ranges with number input\n if (rangeType.startsWith('last_n_') && number !== undefined && number > 0) {\n const unit = rangeType.replace('last_n_', '')\n const unitSingular = unit.slice(0, -1) // Remove 's' for singular form\n return number === 1 ? `last ${unitSingular}` : `last ${number} ${unit}`\n }\n\n return typeMap[rangeType] || rangeType\n}\n\n/**\n * Check if a date range type requires a number input\n */\nexport function requiresNumberInput(rangeType: string): boolean {\n return rangeType.startsWith('last_n_')\n}\n\n/**\n * Format date for Cube.js (YYYY-MM-DD)\n */\nexport function formatDateForCube(date: Date): string {\n return date.toISOString().split('T')[0]\n}\n","/**\n * QueryAnalysisPanel Component\n * Displays query planning analysis for debugging and transparency\n */\n\nimport React from 'react'\nimport { getIcon } from '../../icons'\nimport type { QueryAnalysis } from '../types'\n\ninterface QueryAnalysisPanelProps {\n analysis: QueryAnalysis\n}\n\n/**\n * Format reason string for display\n */\nfunction formatReason(reason: string): string {\n return reason.replace(/_/g, ' ')\n}\n\n/**\n * Get badge color based on reason\n */\nfunction getReasonBadgeClasses(reason: string): string {\n switch (reason) {\n case 'most_dimensions':\n return 'bg-dc-info-bg text-dc-info'\n case 'most_connected':\n return 'bg-dc-accent-bg text-dc-accent'\n case 'alphabetical_fallback':\n return 'bg-dc-warning-bg text-dc-warning'\n case 'single_cube':\n return 'bg-dc-success-bg text-dc-success'\n default:\n return 'bg-dc-muted-bg text-dc-muted'\n }\n}\n\nconst QueryAnalysisPanel: React.FC<QueryAnalysisPanelProps> = ({ analysis }) => {\n const InfoIcon = getIcon('info')\n const ArrowRightIcon = getIcon('chevronRight')\n const WarningIcon = getIcon('warning')\n const TableIcon = getIcon('table')\n const LinkIcon = getIcon('link')\n const SuccessIcon = getIcon('success')\n const ErrorIcon = getIcon('error')\n\n return (\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded-lg p-4 space-y-4\">\n {/* Query Summary Section */}\n <div className=\"border-b border-dc-border pb-3\">\n <h4 className=\"text-sm font-semibold text-dc-text mb-2 flex items-center\">\n <InfoIcon className=\"w-4 h-4 mr-2\" />\n Query Summary\n </h4>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-2 text-xs\">\n <div className=\"bg-dc-surface p-2 rounded\">\n <span className=\"text-dc-text-muted\">Type:</span>\n <span className=\"ml-1 font-medium text-dc-text\">\n {formatReason(analysis.querySummary.queryType)}\n </span>\n </div>\n <div className=\"bg-dc-surface p-2 rounded\">\n <span className=\"text-dc-text-muted\">Cubes:</span>\n <span className=\"ml-1 font-medium text-dc-text\">{analysis.cubeCount}</span>\n </div>\n <div className=\"bg-dc-surface p-2 rounded\">\n <span className=\"text-dc-text-muted\">Joins:</span>\n <span className=\"ml-1 font-medium text-dc-text\">{analysis.querySummary.joinCount}</span>\n </div>\n <div className=\"bg-dc-surface p-2 rounded\">\n <span className=\"text-dc-text-muted\">CTEs:</span>\n <span className=\"ml-1 font-medium text-dc-text\">{analysis.querySummary.cteCount}</span>\n </div>\n </div>\n </div>\n\n {/* Primary Cube Section */}\n <div className=\"border-b border-dc-border pb-3\">\n <h4 className=\"text-sm font-semibold text-dc-text mb-2 flex items-center\">\n <TableIcon className=\"w-4 h-4 mr-2\" />\n Primary Cube (FROM table)\n </h4>\n <div className=\"bg-dc-surface p-3 rounded text-sm\">\n <div className=\"flex items-center gap-2 mb-2 flex-wrap\">\n <span className=\"font-mono font-medium text-dc-primary\">\n {analysis.primaryCube.selectedCube}\n </span>\n <span className={`text-xs px-2 py-0.5 rounded ${getReasonBadgeClasses(analysis.primaryCube.reason)}`}>\n {formatReason(analysis.primaryCube.reason)}\n </span>\n </div>\n <p className=\"text-dc-text-secondary text-xs\">\n {analysis.primaryCube.explanation}\n </p>\n {analysis.primaryCube.candidates && analysis.primaryCube.candidates.length > 1 && (\n <details className=\"mt-2\">\n <summary className=\"text-xs text-dc-text-muted cursor-pointer hover:text-dc-text\">\n Show candidates ({analysis.primaryCube.candidates.length})\n </summary>\n <div className=\"mt-2 space-y-1 ml-2\">\n {analysis.primaryCube.candidates.map((c, i) => (\n <div key={i} className=\"text-xs flex items-center gap-2 flex-wrap\">\n <span className={`font-mono ${c.cubeName === analysis.primaryCube.selectedCube ? 'font-bold text-dc-primary' : 'text-dc-text-muted'}`}>\n {c.cubeName}\n </span>\n <span className=\"text-dc-text-muted\">\n dims: {c.dimensionCount}, joins: {c.joinCount}\n </span>\n {c.canReachAll ? (\n <span className=\"text-dc-success flex items-center gap-0.5\">\n <SuccessIcon className=\"w-3 h-3\" />\n reachable\n </span>\n ) : (\n <span className=\"text-dc-error flex items-center gap-0.5\">\n <ErrorIcon className=\"w-3 h-3\" />\n cannot reach all\n </span>\n )}\n </div>\n ))}\n </div>\n </details>\n )}\n </div>\n </div>\n\n {/* Join Paths Section */}\n {analysis.joinPaths.length > 0 && (\n <div className=\"border-b border-dc-border pb-3\">\n <h4 className=\"text-sm font-semibold text-dc-text mb-2 flex items-center\">\n <LinkIcon className=\"w-4 h-4 mr-2\" />\n Join Paths\n </h4>\n <div className=\"space-y-2\">\n {analysis.joinPaths.map((jp, idx) => (\n <div key={idx} className=\"bg-dc-surface p-3 rounded text-sm\">\n <div className=\"flex items-center gap-2 mb-2 flex-wrap\">\n <span className=\"font-mono text-dc-text-secondary\">{analysis.primaryCube.selectedCube}</span>\n <ArrowRightIcon className=\"w-4 h-4 text-dc-text-muted\" />\n <span className=\"font-mono font-medium text-dc-text\">{jp.targetCube}</span>\n {jp.pathFound ? (\n <span className=\"text-xs px-2 py-0.5 bg-dc-success-bg text-dc-success rounded\">\n {jp.pathLength} step{jp.pathLength !== 1 ? 's' : ''}\n </span>\n ) : (\n <span className=\"text-xs px-2 py-0.5 bg-dc-error-bg text-dc-error rounded\">\n No path\n </span>\n )}\n </div>\n {jp.pathFound && jp.path && jp.path.length > 0 && (\n <div className=\"space-y-1 ml-2\">\n {jp.path.map((step, stepIdx) => (\n <div key={stepIdx} className=\"flex items-center gap-1 text-xs flex-wrap\">\n <span className=\"font-mono text-dc-text-secondary\">{step.fromCube}</span>\n <ArrowRightIcon className=\"w-3 h-3 text-dc-text-muted\" />\n <span className=\"font-mono text-dc-text\">{step.toCube}</span>\n <span className=\"text-dc-text-muted\">\n ({step.relationship}, {step.joinType} join)\n </span>\n {step.joinColumns.length > 0 && (\n <span className=\"text-dc-text-muted\">\n on {step.joinColumns.map(jc => `${jc.sourceColumn}=${jc.targetColumn}`).join(', ')}\n </span>\n )}\n </div>\n ))}\n </div>\n )}\n {!jp.pathFound && jp.error && (\n <p className=\"text-xs text-dc-error mt-1\">{jp.error}</p>\n )}\n {jp.visitedCubes && jp.visitedCubes.length > 0 && !jp.pathFound && (\n <details className=\"mt-1\">\n <summary className=\"text-xs text-dc-text-muted cursor-pointer hover:text-dc-text\">\n Cubes visited during search ({jp.visitedCubes.length})\n </summary>\n <div className=\"mt-1 text-xs text-dc-text-muted ml-2\">\n {jp.visitedCubes.join(' → ')}\n </div>\n </details>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Pre-Aggregations Section */}\n {analysis.preAggregations.length > 0 && (\n <div className=\"border-b border-dc-border pb-3\">\n <h4 className=\"text-sm font-semibold text-dc-text mb-2 flex items-center\">\n <TableIcon className=\"w-4 h-4 mr-2\" />\n Pre-Aggregation CTEs\n </h4>\n <div className=\"space-y-2\">\n {analysis.preAggregations.map((pa, idx) => (\n <div key={idx} className=\"bg-dc-surface p-3 rounded text-sm\">\n <div className=\"flex items-center gap-2 mb-1 flex-wrap\">\n <span className=\"font-mono font-medium text-dc-text\">{pa.cubeName}</span>\n <span className=\"text-xs text-dc-text-muted\">as</span>\n <code className=\"text-xs bg-dc-surface-secondary px-1 rounded font-mono\">{pa.cteAlias}</code>\n </div>\n <p className=\"text-xs text-dc-text-secondary\">{pa.reason}</p>\n <div className=\"mt-1 text-xs text-dc-text-muted\">\n <span className=\"font-medium\">Measures:</span> {pa.measures.join(', ')}\n </div>\n {pa.joinKeys.length > 0 && (\n <div className=\"mt-1 text-xs text-dc-text-muted\">\n <span className=\"font-medium\">Join keys:</span> {pa.joinKeys.map(jk => `${jk.sourceColumn}=${jk.targetColumn}`).join(', ')}\n </div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Warnings Section */}\n {analysis.warnings && analysis.warnings.length > 0 && (\n <div>\n <h4 className=\"text-sm font-semibold text-dc-warning mb-2 flex items-center\">\n <WarningIcon className=\"w-4 h-4 mr-2\" />\n Warnings\n </h4>\n <ul className=\"list-disc list-inside text-xs text-dc-warning space-y-1\">\n {analysis.warnings.map((w, i) => (\n <li key={i}>{w}</li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Cubes Involved */}\n {analysis.cubesInvolved.length > 0 && (\n <div className=\"text-xs text-dc-text-muted pt-2 border-t border-dc-border\">\n <span className=\"font-medium\">Cubes involved:</span> {analysis.cubesInvolved.join(', ')}\n </div>\n )}\n </div>\n )\n}\n\nexport default QueryAnalysisPanel\n","/* eslint-disable no-multi-assign */\n\nfunction deepFreeze(obj) {\n if (obj instanceof Map) {\n obj.clear =\n obj.delete =\n obj.set =\n function () {\n throw new Error('map is read-only');\n };\n } else if (obj instanceof Set) {\n obj.add =\n obj.clear =\n obj.delete =\n function () {\n throw new Error('set is read-only');\n };\n }\n\n // Freeze self\n Object.freeze(obj);\n\n Object.getOwnPropertyNames(obj).forEach((name) => {\n const prop = obj[name];\n const type = typeof prop;\n\n // Freeze prop if it is an object or function and also not already frozen\n if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) {\n deepFreeze(prop);\n }\n });\n\n return obj;\n}\n\n/** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */\n/** @typedef {import('highlight.js').CompiledMode} CompiledMode */\n/** @implements CallbackResponse */\n\nclass Response {\n /**\n * @param {CompiledMode} mode\n */\n constructor(mode) {\n // eslint-disable-next-line no-undefined\n if (mode.data === undefined) mode.data = {};\n\n this.data = mode.data;\n this.isMatchIgnored = false;\n }\n\n ignoreMatch() {\n this.isMatchIgnored = true;\n }\n}\n\n/**\n * @param {string} value\n * @returns {string}\n */\nfunction escapeHTML(value) {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#x27;');\n}\n\n/**\n * performs a shallow merge of multiple objects into one\n *\n * @template T\n * @param {T} original\n * @param {Record<string,any>[]} objects\n * @returns {T} a single new object\n */\nfunction inherit$1(original, ...objects) {\n /** @type Record<string,any> */\n const result = Object.create(null);\n\n for (const key in original) {\n result[key] = original[key];\n }\n objects.forEach(function(obj) {\n for (const key in obj) {\n result[key] = obj[key];\n }\n });\n return /** @type {T} */ (result);\n}\n\n/**\n * @typedef {object} Renderer\n * @property {(text: string) => void} addText\n * @property {(node: Node) => void} openNode\n * @property {(node: Node) => void} closeNode\n * @property {() => string} value\n */\n\n/** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */\n/** @typedef {{walk: (r: Renderer) => void}} Tree */\n/** */\n\nconst SPAN_CLOSE = '</span>';\n\n/**\n * Determines if a node needs to be wrapped in <span>\n *\n * @param {Node} node */\nconst emitsWrappingTags = (node) => {\n // rarely we can have a sublanguage where language is undefined\n // TODO: track down why\n return !!node.scope;\n};\n\n/**\n *\n * @param {string} name\n * @param {{prefix:string}} options\n */\nconst scopeToCSSClass = (name, { prefix }) => {\n // sub-language\n if (name.startsWith(\"language:\")) {\n return name.replace(\"language:\", \"language-\");\n }\n // tiered scope: comment.line\n if (name.includes(\".\")) {\n const pieces = name.split(\".\");\n return [\n `${prefix}${pieces.shift()}`,\n ...(pieces.map((x, i) => `${x}${\"_\".repeat(i + 1)}`))\n ].join(\" \");\n }\n // simple scope\n return `${prefix}${name}`;\n};\n\n/** @type {Renderer} */\nclass HTMLRenderer {\n /**\n * Creates a new HTMLRenderer\n *\n * @param {Tree} parseTree - the parse tree (must support `walk` API)\n * @param {{classPrefix: string}} options\n */\n constructor(parseTree, options) {\n this.buffer = \"\";\n this.classPrefix = options.classPrefix;\n parseTree.walk(this);\n }\n\n /**\n * Adds texts to the output stream\n *\n * @param {string} text */\n addText(text) {\n this.buffer += escapeHTML(text);\n }\n\n /**\n * Adds a node open to the output stream (if needed)\n *\n * @param {Node} node */\n openNode(node) {\n if (!emitsWrappingTags(node)) return;\n\n const className = scopeToCSSClass(node.scope,\n { prefix: this.classPrefix });\n this.span(className);\n }\n\n /**\n * Adds a node close to the output stream (if needed)\n *\n * @param {Node} node */\n closeNode(node) {\n if (!emitsWrappingTags(node)) return;\n\n this.buffer += SPAN_CLOSE;\n }\n\n /**\n * returns the accumulated buffer\n */\n value() {\n return this.buffer;\n }\n\n // helpers\n\n /**\n * Builds a span element\n *\n * @param {string} className */\n span(className) {\n this.buffer += `<span class=\"${className}\">`;\n }\n}\n\n/** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */\n/** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */\n/** @typedef {import('highlight.js').Emitter} Emitter */\n/** */\n\n/** @returns {DataNode} */\nconst newNode = (opts = {}) => {\n /** @type DataNode */\n const result = { children: [] };\n Object.assign(result, opts);\n return result;\n};\n\nclass TokenTree {\n constructor() {\n /** @type DataNode */\n this.rootNode = newNode();\n this.stack = [this.rootNode];\n }\n\n get top() {\n return this.stack[this.stack.length - 1];\n }\n\n get root() { return this.rootNode; }\n\n /** @param {Node} node */\n add(node) {\n this.top.children.push(node);\n }\n\n /** @param {string} scope */\n openNode(scope) {\n /** @type Node */\n const node = newNode({ scope });\n this.add(node);\n this.stack.push(node);\n }\n\n closeNode() {\n if (this.stack.length > 1) {\n return this.stack.pop();\n }\n // eslint-disable-next-line no-undefined\n return undefined;\n }\n\n closeAllNodes() {\n while (this.closeNode());\n }\n\n toJSON() {\n return JSON.stringify(this.rootNode, null, 4);\n }\n\n /**\n * @typedef { import(\"./html_renderer\").Renderer } Renderer\n * @param {Renderer} builder\n */\n walk(builder) {\n // this does not\n return this.constructor._walk(builder, this.rootNode);\n // this works\n // return TokenTree._walk(builder, this.rootNode);\n }\n\n /**\n * @param {Renderer} builder\n * @param {Node} node\n */\n static _walk(builder, node) {\n if (typeof node === \"string\") {\n builder.addText(node);\n } else if (node.children) {\n builder.openNode(node);\n node.children.forEach((child) => this._walk(builder, child));\n builder.closeNode(node);\n }\n return builder;\n }\n\n /**\n * @param {Node} node\n */\n static _collapse(node) {\n if (typeof node === \"string\") return;\n if (!node.children) return;\n\n if (node.children.every(el => typeof el === \"string\")) {\n // node.text = node.children.join(\"\");\n // delete node.children;\n node.children = [node.children.join(\"\")];\n } else {\n node.children.forEach((child) => {\n TokenTree._collapse(child);\n });\n }\n }\n}\n\n/**\n Currently this is all private API, but this is the minimal API necessary\n that an Emitter must implement to fully support the parser.\n\n Minimal interface:\n\n - addText(text)\n - __addSublanguage(emitter, subLanguageName)\n - startScope(scope)\n - endScope()\n - finalize()\n - toHTML()\n\n*/\n\n/**\n * @implements {Emitter}\n */\nclass TokenTreeEmitter extends TokenTree {\n /**\n * @param {*} options\n */\n constructor(options) {\n super();\n this.options = options;\n }\n\n /**\n * @param {string} text\n */\n addText(text) {\n if (text === \"\") { return; }\n\n this.add(text);\n }\n\n /** @param {string} scope */\n startScope(scope) {\n this.openNode(scope);\n }\n\n endScope() {\n this.closeNode();\n }\n\n /**\n * @param {Emitter & {root: DataNode}} emitter\n * @param {string} name\n */\n __addSublanguage(emitter, name) {\n /** @type DataNode */\n const node = emitter.root;\n if (name) node.scope = `language:${name}`;\n\n this.add(node);\n }\n\n toHTML() {\n const renderer = new HTMLRenderer(this, this.options);\n return renderer.value();\n }\n\n finalize() {\n this.closeAllNodes();\n return true;\n }\n}\n\n/**\n * @param {string} value\n * @returns {RegExp}\n * */\n\n/**\n * @param {RegExp | string } re\n * @returns {string}\n */\nfunction source(re) {\n if (!re) return null;\n if (typeof re === \"string\") return re;\n\n return re.source;\n}\n\n/**\n * @param {RegExp | string } re\n * @returns {string}\n */\nfunction lookahead(re) {\n return concat('(?=', re, ')');\n}\n\n/**\n * @param {RegExp | string } re\n * @returns {string}\n */\nfunction anyNumberOfTimes(re) {\n return concat('(?:', re, ')*');\n}\n\n/**\n * @param {RegExp | string } re\n * @returns {string}\n */\nfunction optional(re) {\n return concat('(?:', re, ')?');\n}\n\n/**\n * @param {...(RegExp | string) } args\n * @returns {string}\n */\nfunction concat(...args) {\n const joined = args.map((x) => source(x)).join(\"\");\n return joined;\n}\n\n/**\n * @param { Array<string | RegExp | Object> } args\n * @returns {object}\n */\nfunction stripOptionsFromArgs(args) {\n const opts = args[args.length - 1];\n\n if (typeof opts === 'object' && opts.constructor === Object) {\n args.splice(args.length - 1, 1);\n return opts;\n } else {\n return {};\n }\n}\n\n/** @typedef { {capture?: boolean} } RegexEitherOptions */\n\n/**\n * Any of the passed expresssions may match\n *\n * Creates a huge this | this | that | that match\n * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args\n * @returns {string}\n */\nfunction either(...args) {\n /** @type { object & {capture?: boolean} } */\n const opts = stripOptionsFromArgs(args);\n const joined = '('\n + (opts.capture ? \"\" : \"?:\")\n + args.map((x) => source(x)).join(\"|\") + \")\";\n return joined;\n}\n\n/**\n * @param {RegExp | string} re\n * @returns {number}\n */\nfunction countMatchGroups(re) {\n return (new RegExp(re.toString() + '|')).exec('').length - 1;\n}\n\n/**\n * Does lexeme start with a regular expression match at the beginning\n * @param {RegExp} re\n * @param {string} lexeme\n */\nfunction startsWith(re, lexeme) {\n const match = re && re.exec(lexeme);\n return match && match.index === 0;\n}\n\n// BACKREF_RE matches an open parenthesis or backreference. To avoid\n// an incorrect parse, it additionally matches the following:\n// - [...] elements, where the meaning of parentheses and escapes change\n// - other escape sequences, so we do not misparse escape sequences as\n// interesting elements\n// - non-matching or lookahead parentheses, which do not capture. These\n// follow the '(' with a '?'.\nconst BACKREF_RE = /\\[(?:[^\\\\\\]]|\\\\.)*\\]|\\(\\??|\\\\([1-9][0-9]*)|\\\\./;\n\n// **INTERNAL** Not intended for outside usage\n// join logically computes regexps.join(separator), but fixes the\n// backreferences so they continue to match.\n// it also places each individual regular expression into it's own\n// match group, keeping track of the sequencing of those match groups\n// is currently an exercise for the caller. :-)\n/**\n * @param {(string | RegExp)[]} regexps\n * @param {{joinWith: string}} opts\n * @returns {string}\n */\nfunction _rewriteBackreferences(regexps, { joinWith }) {\n let numCaptures = 0;\n\n return regexps.map((regex) => {\n numCaptures += 1;\n const offset = numCaptures;\n let re = source(regex);\n let out = '';\n\n while (re.length > 0) {\n const match = BACKREF_RE.exec(re);\n if (!match) {\n out += re;\n break;\n }\n out += re.substring(0, match.index);\n re = re.substring(match.index + match[0].length);\n if (match[0][0] === '\\\\' && match[1]) {\n // Adjust the backreference.\n out += '\\\\' + String(Number(match[1]) + offset);\n } else {\n out += match[0];\n if (match[0] === '(') {\n numCaptures++;\n }\n }\n }\n return out;\n }).map(re => `(${re})`).join(joinWith);\n}\n\n/** @typedef {import('highlight.js').Mode} Mode */\n/** @typedef {import('highlight.js').ModeCallback} ModeCallback */\n\n// Common regexps\nconst MATCH_NOTHING_RE = /\\b\\B/;\nconst IDENT_RE = '[a-zA-Z]\\\\w*';\nconst UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\\\w*';\nconst NUMBER_RE = '\\\\b\\\\d+(\\\\.\\\\d+)?';\nconst C_NUMBER_RE = '(-?)(\\\\b0[xX][a-fA-F0-9]+|(\\\\b\\\\d+(\\\\.\\\\d*)?|\\\\.\\\\d+)([eE][-+]?\\\\d+)?)'; // 0x..., 0..., decimal, float\nconst BINARY_NUMBER_RE = '\\\\b(0b[01]+)'; // 0b...\nconst RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\\\*|\\\\*=|\\\\+|\\\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\\\?|\\\\[|\\\\{|\\\\(|\\\\^|\\\\^=|\\\\||\\\\|=|\\\\|\\\\||~';\n\n/**\n* @param { Partial<Mode> & {binary?: string | RegExp} } opts\n*/\nconst SHEBANG = (opts = {}) => {\n const beginShebang = /^#![ ]*\\//;\n if (opts.binary) {\n opts.begin = concat(\n beginShebang,\n /.*\\b/,\n opts.binary,\n /\\b.*/);\n }\n return inherit$1({\n scope: 'meta',\n begin: beginShebang,\n end: /$/,\n relevance: 0,\n /** @type {ModeCallback} */\n \"on:begin\": (m, resp) => {\n if (m.index !== 0) resp.ignoreMatch();\n }\n }, opts);\n};\n\n// Common modes\nconst BACKSLASH_ESCAPE = {\n begin: '\\\\\\\\[\\\\s\\\\S]', relevance: 0\n};\nconst APOS_STRING_MODE = {\n scope: 'string',\n begin: '\\'',\n end: '\\'',\n illegal: '\\\\n',\n contains: [BACKSLASH_ESCAPE]\n};\nconst QUOTE_STRING_MODE = {\n scope: 'string',\n begin: '\"',\n end: '\"',\n illegal: '\\\\n',\n contains: [BACKSLASH_ESCAPE]\n};\nconst PHRASAL_WORDS_MODE = {\n begin: /\\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\\b/\n};\n/**\n * Creates a comment mode\n *\n * @param {string | RegExp} begin\n * @param {string | RegExp} end\n * @param {Mode | {}} [modeOptions]\n * @returns {Partial<Mode>}\n */\nconst COMMENT = function(begin, end, modeOptions = {}) {\n const mode = inherit$1(\n {\n scope: 'comment',\n begin,\n end,\n contains: []\n },\n modeOptions\n );\n mode.contains.push({\n scope: 'doctag',\n // hack to avoid the space from being included. the space is necessary to\n // match here to prevent the plain text rule below from gobbling up doctags\n begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',\n end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,\n excludeBegin: true,\n relevance: 0\n });\n const ENGLISH_WORD = either(\n // list of common 1 and 2 letter words in English\n \"I\",\n \"a\",\n \"is\",\n \"so\",\n \"us\",\n \"to\",\n \"at\",\n \"if\",\n \"in\",\n \"it\",\n \"on\",\n // note: this is not an exhaustive list of contractions, just popular ones\n /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc\n /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.\n /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences\n );\n // looking like plain text, more likely to be a comment\n mode.contains.push(\n {\n // TODO: how to include \", (, ) without breaking grammars that use these for\n // comment delimiters?\n // begin: /[ ]+([()\"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()\":]?([.][ ]|[ ]|\\))){3}/\n // ---\n\n // this tries to find sequences of 3 english words in a row (without any\n // \"programming\" type syntax) this gives us a strong signal that we've\n // TRULY found a comment - vs perhaps scanning with the wrong language.\n // It's possible to find something that LOOKS like the start of the\n // comment - but then if there is no readable text - good chance it is a\n // false match and not a comment.\n //\n // for a visual example please see:\n // https://github.com/highlightjs/highlight.js/issues/2827\n\n begin: concat(\n /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */\n '(',\n ENGLISH_WORD,\n /[.]?[:]?([.][ ]|[ ])/,\n '){3}') // look for 3 words in a row\n }\n );\n return mode;\n};\nconst C_LINE_COMMENT_MODE = COMMENT('//', '$');\nconst C_BLOCK_COMMENT_MODE = COMMENT('/\\\\*', '\\\\*/');\nconst HASH_COMMENT_MODE = COMMENT('#', '$');\nconst NUMBER_MODE = {\n scope: 'number',\n begin: NUMBER_RE,\n relevance: 0\n};\nconst C_NUMBER_MODE = {\n scope: 'number',\n begin: C_NUMBER_RE,\n relevance: 0\n};\nconst BINARY_NUMBER_MODE = {\n scope: 'number',\n begin: BINARY_NUMBER_RE,\n relevance: 0\n};\nconst REGEXP_MODE = {\n scope: \"regexp\",\n begin: /\\/(?=[^/\\n]*\\/)/,\n end: /\\/[gimuy]*/,\n contains: [\n BACKSLASH_ESCAPE,\n {\n begin: /\\[/,\n end: /\\]/,\n relevance: 0,\n contains: [BACKSLASH_ESCAPE]\n }\n ]\n};\nconst TITLE_MODE = {\n scope: 'title',\n begin: IDENT_RE,\n relevance: 0\n};\nconst UNDERSCORE_TITLE_MODE = {\n scope: 'title',\n begin: UNDERSCORE_IDENT_RE,\n relevance: 0\n};\nconst METHOD_GUARD = {\n // excludes method names from keyword processing\n begin: '\\\\.\\\\s*' + UNDERSCORE_IDENT_RE,\n relevance: 0\n};\n\n/**\n * Adds end same as begin mechanics to a mode\n *\n * Your mode must include at least a single () match group as that first match\n * group is what is used for comparison\n * @param {Partial<Mode>} mode\n */\nconst END_SAME_AS_BEGIN = function(mode) {\n return Object.assign(mode,\n {\n /** @type {ModeCallback} */\n 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; },\n /** @type {ModeCallback} */\n 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }\n });\n};\n\nvar MODES = /*#__PURE__*/Object.freeze({\n __proto__: null,\n APOS_STRING_MODE: APOS_STRING_MODE,\n BACKSLASH_ESCAPE: BACKSLASH_ESCAPE,\n BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,\n BINARY_NUMBER_RE: BINARY_NUMBER_RE,\n COMMENT: COMMENT,\n C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE,\n C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE,\n C_NUMBER_MODE: C_NUMBER_MODE,\n C_NUMBER_RE: C_NUMBER_RE,\n END_SAME_AS_BEGIN: END_SAME_AS_BEGIN,\n HASH_COMMENT_MODE: HASH_COMMENT_MODE,\n IDENT_RE: IDENT_RE,\n MATCH_NOTHING_RE: MATCH_NOTHING_RE,\n METHOD_GUARD: METHOD_GUARD,\n NUMBER_MODE: NUMBER_MODE,\n NUMBER_RE: NUMBER_RE,\n PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE,\n QUOTE_STRING_MODE: QUOTE_STRING_MODE,\n REGEXP_MODE: REGEXP_MODE,\n RE_STARTERS_RE: RE_STARTERS_RE,\n SHEBANG: SHEBANG,\n TITLE_MODE: TITLE_MODE,\n UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,\n UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE\n});\n\n/**\n@typedef {import('highlight.js').CallbackResponse} CallbackResponse\n@typedef {import('highlight.js').CompilerExt} CompilerExt\n*/\n\n// Grammar extensions / plugins\n// See: https://github.com/highlightjs/highlight.js/issues/2833\n\n// Grammar extensions allow \"syntactic sugar\" to be added to the grammar modes\n// without requiring any underlying changes to the compiler internals.\n\n// `compileMatch` being the perfect small example of now allowing a grammar\n// author to write `match` when they desire to match a single expression rather\n// than being forced to use `begin`. The extension then just moves `match` into\n// `begin` when it runs. Ie, no features have been added, but we've just made\n// the experience of writing (and reading grammars) a little bit nicer.\n\n// ------\n\n// TODO: We need negative look-behind support to do this properly\n/**\n * Skip a match if it has a preceding dot\n *\n * This is used for `beginKeywords` to prevent matching expressions such as\n * `bob.keyword.do()`. The mode compiler automatically wires this up as a\n * special _internal_ 'on:begin' callback for modes with `beginKeywords`\n * @param {RegExpMatchArray} match\n * @param {CallbackResponse} response\n */\nfunction skipIfHasPrecedingDot(match, response) {\n const before = match.input[match.index - 1];\n if (before === \".\") {\n response.ignoreMatch();\n }\n}\n\n/**\n *\n * @type {CompilerExt}\n */\nfunction scopeClassName(mode, _parent) {\n // eslint-disable-next-line no-undefined\n if (mode.className !== undefined) {\n mode.scope = mode.className;\n delete mode.className;\n }\n}\n\n/**\n * `beginKeywords` syntactic sugar\n * @type {CompilerExt}\n */\nfunction beginKeywords(mode, parent) {\n if (!parent) return;\n if (!mode.beginKeywords) return;\n\n // for languages with keywords that include non-word characters checking for\n // a word boundary is not sufficient, so instead we check for a word boundary\n // or whitespace - this does no harm in any case since our keyword engine\n // doesn't allow spaces in keywords anyways and we still check for the boundary\n // first\n mode.begin = '\\\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\\\.)(?=\\\\b|\\\\s)';\n mode.__beforeBegin = skipIfHasPrecedingDot;\n mode.keywords = mode.keywords || mode.beginKeywords;\n delete mode.beginKeywords;\n\n // prevents double relevance, the keywords themselves provide\n // relevance, the mode doesn't need to double it\n // eslint-disable-next-line no-undefined\n if (mode.relevance === undefined) mode.relevance = 0;\n}\n\n/**\n * Allow `illegal` to contain an array of illegal values\n * @type {CompilerExt}\n */\nfunction compileIllegal(mode, _parent) {\n if (!Array.isArray(mode.illegal)) return;\n\n mode.illegal = either(...mode.illegal);\n}\n\n/**\n * `match` to match a single expression for readability\n * @type {CompilerExt}\n */\nfunction compileMatch(mode, _parent) {\n if (!mode.match) return;\n if (mode.begin || mode.end) throw new Error(\"begin & end are not supported with match\");\n\n mode.begin = mode.match;\n delete mode.match;\n}\n\n/**\n * provides the default 1 relevance to all modes\n * @type {CompilerExt}\n */\nfunction compileRelevance(mode, _parent) {\n // eslint-disable-next-line no-undefined\n if (mode.relevance === undefined) mode.relevance = 1;\n}\n\n// allow beforeMatch to act as a \"qualifier\" for the match\n// the full match begin must be [beforeMatch][begin]\nconst beforeMatchExt = (mode, parent) => {\n if (!mode.beforeMatch) return;\n // starts conflicts with endsParent which we need to make sure the child\n // rule is not matched multiple times\n if (mode.starts) throw new Error(\"beforeMatch cannot be used with starts\");\n\n const originalMode = Object.assign({}, mode);\n Object.keys(mode).forEach((key) => { delete mode[key]; });\n\n mode.keywords = originalMode.keywords;\n mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));\n mode.starts = {\n relevance: 0,\n contains: [\n Object.assign(originalMode, { endsParent: true })\n ]\n };\n mode.relevance = 0;\n\n delete originalMode.beforeMatch;\n};\n\n// keywords that should have no default relevance value\nconst COMMON_KEYWORDS = [\n 'of',\n 'and',\n 'for',\n 'in',\n 'not',\n 'or',\n 'if',\n 'then',\n 'parent', // common variable name\n 'list', // common variable name\n 'value' // common variable name\n];\n\nconst DEFAULT_KEYWORD_SCOPE = \"keyword\";\n\n/**\n * Given raw keywords from a language definition, compile them.\n *\n * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords\n * @param {boolean} caseInsensitive\n */\nfunction compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {\n /** @type {import(\"highlight.js/private\").KeywordDict} */\n const compiledKeywords = Object.create(null);\n\n // input can be a string of keywords, an array of keywords, or a object with\n // named keys representing scopeName (which can then point to a string or array)\n if (typeof rawKeywords === 'string') {\n compileList(scopeName, rawKeywords.split(\" \"));\n } else if (Array.isArray(rawKeywords)) {\n compileList(scopeName, rawKeywords);\n } else {\n Object.keys(rawKeywords).forEach(function(scopeName) {\n // collapse all our objects back into the parent object\n Object.assign(\n compiledKeywords,\n compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)\n );\n });\n }\n return compiledKeywords;\n\n // ---\n\n /**\n * Compiles an individual list of keywords\n *\n * Ex: \"for if when while|5\"\n *\n * @param {string} scopeName\n * @param {Array<string>} keywordList\n */\n function compileList(scopeName, keywordList) {\n if (caseInsensitive) {\n keywordList = keywordList.map(x => x.toLowerCase());\n }\n keywordList.forEach(function(keyword) {\n const pair = keyword.split('|');\n compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];\n });\n }\n}\n\n/**\n * Returns the proper score for a given keyword\n *\n * Also takes into account comment keywords, which will be scored 0 UNLESS\n * another score has been manually assigned.\n * @param {string} keyword\n * @param {string} [providedScore]\n */\nfunction scoreForKeyword(keyword, providedScore) {\n // manual scores always win over common keywords\n // so you can force a score of 1 if you really insist\n if (providedScore) {\n return Number(providedScore);\n }\n\n return commonKeyword(keyword) ? 0 : 1;\n}\n\n/**\n * Determines if a given keyword is common or not\n *\n * @param {string} keyword */\nfunction commonKeyword(keyword) {\n return COMMON_KEYWORDS.includes(keyword.toLowerCase());\n}\n\n/*\n\nFor the reasoning behind this please see:\nhttps://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419\n\n*/\n\n/**\n * @type {Record<string, boolean>}\n */\nconst seenDeprecations = {};\n\n/**\n * @param {string} message\n */\nconst error = (message) => {\n console.error(message);\n};\n\n/**\n * @param {string} message\n * @param {any} args\n */\nconst warn = (message, ...args) => {\n console.log(`WARN: ${message}`, ...args);\n};\n\n/**\n * @param {string} version\n * @param {string} message\n */\nconst deprecated = (version, message) => {\n if (seenDeprecations[`${version}/${message}`]) return;\n\n console.log(`Deprecated as of ${version}. ${message}`);\n seenDeprecations[`${version}/${message}`] = true;\n};\n\n/* eslint-disable no-throw-literal */\n\n/**\n@typedef {import('highlight.js').CompiledMode} CompiledMode\n*/\n\nconst MultiClassError = new Error();\n\n/**\n * Renumbers labeled scope names to account for additional inner match\n * groups that otherwise would break everything.\n *\n * Lets say we 3 match scopes:\n *\n * { 1 => ..., 2 => ..., 3 => ... }\n *\n * So what we need is a clean match like this:\n *\n * (a)(b)(c) => [ \"a\", \"b\", \"c\" ]\n *\n * But this falls apart with inner match groups:\n *\n * (a)(((b)))(c) => [\"a\", \"b\", \"b\", \"b\", \"c\" ]\n *\n * Our scopes are now \"out of alignment\" and we're repeating `b` 3 times.\n * What needs to happen is the numbers are remapped:\n *\n * { 1 => ..., 2 => ..., 5 => ... }\n *\n * We also need to know that the ONLY groups that should be output\n * are 1, 2, and 5. This function handles this behavior.\n *\n * @param {CompiledMode} mode\n * @param {Array<RegExp | string>} regexes\n * @param {{key: \"beginScope\"|\"endScope\"}} opts\n */\nfunction remapScopeNames(mode, regexes, { key }) {\n let offset = 0;\n const scopeNames = mode[key];\n /** @type Record<number,boolean> */\n const emit = {};\n /** @type Record<number,string> */\n const positions = {};\n\n for (let i = 1; i <= regexes.length; i++) {\n positions[i + offset] = scopeNames[i];\n emit[i + offset] = true;\n offset += countMatchGroups(regexes[i - 1]);\n }\n // we use _emit to keep track of which match groups are \"top-level\" to avoid double\n // output from inside match groups\n mode[key] = positions;\n mode[key]._emit = emit;\n mode[key]._multi = true;\n}\n\n/**\n * @param {CompiledMode} mode\n */\nfunction beginMultiClass(mode) {\n if (!Array.isArray(mode.begin)) return;\n\n if (mode.skip || mode.excludeBegin || mode.returnBegin) {\n error(\"skip, excludeBegin, returnBegin not compatible with beginScope: {}\");\n throw MultiClassError;\n }\n\n if (typeof mode.beginScope !== \"object\" || mode.beginScope === null) {\n error(\"beginScope must be object\");\n throw MultiClassError;\n }\n\n remapScopeNames(mode, mode.begin, { key: \"beginScope\" });\n mode.begin = _rewriteBackreferences(mode.begin, { joinWith: \"\" });\n}\n\n/**\n * @param {CompiledMode} mode\n */\nfunction endMultiClass(mode) {\n if (!Array.isArray(mode.end)) return;\n\n if (mode.skip || mode.excludeEnd || mode.returnEnd) {\n error(\"skip, excludeEnd, returnEnd not compatible with endScope: {}\");\n throw MultiClassError;\n }\n\n if (typeof mode.endScope !== \"object\" || mode.endScope === null) {\n error(\"endScope must be object\");\n throw MultiClassError;\n }\n\n remapScopeNames(mode, mode.end, { key: \"endScope\" });\n mode.end = _rewriteBackreferences(mode.end, { joinWith: \"\" });\n}\n\n/**\n * this exists only to allow `scope: {}` to be used beside `match:`\n * Otherwise `beginScope` would necessary and that would look weird\n\n {\n match: [ /def/, /\\w+/ ]\n scope: { 1: \"keyword\" , 2: \"title\" }\n }\n\n * @param {CompiledMode} mode\n */\nfunction scopeSugar(mode) {\n if (mode.scope && typeof mode.scope === \"object\" && mode.scope !== null) {\n mode.beginScope = mode.scope;\n delete mode.scope;\n }\n}\n\n/**\n * @param {CompiledMode} mode\n */\nfunction MultiClass(mode) {\n scopeSugar(mode);\n\n if (typeof mode.beginScope === \"string\") {\n mode.beginScope = { _wrap: mode.beginScope };\n }\n if (typeof mode.endScope === \"string\") {\n mode.endScope = { _wrap: mode.endScope };\n }\n\n beginMultiClass(mode);\n endMultiClass(mode);\n}\n\n/**\n@typedef {import('highlight.js').Mode} Mode\n@typedef {import('highlight.js').CompiledMode} CompiledMode\n@typedef {import('highlight.js').Language} Language\n@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin\n@typedef {import('highlight.js').CompiledLanguage} CompiledLanguage\n*/\n\n// compilation\n\n/**\n * Compiles a language definition result\n *\n * Given the raw result of a language definition (Language), compiles this so\n * that it is ready for highlighting code.\n * @param {Language} language\n * @returns {CompiledLanguage}\n */\nfunction compileLanguage(language) {\n /**\n * Builds a regex with the case sensitivity of the current language\n *\n * @param {RegExp | string} value\n * @param {boolean} [global]\n */\n function langRe(value, global) {\n return new RegExp(\n source(value),\n 'm'\n + (language.case_insensitive ? 'i' : '')\n + (language.unicodeRegex ? 'u' : '')\n + (global ? 'g' : '')\n );\n }\n\n /**\n Stores multiple regular expressions and allows you to quickly search for\n them all in a string simultaneously - returning the first match. It does\n this by creating a huge (a|b|c) regex - each individual item wrapped with ()\n and joined by `|` - using match groups to track position. When a match is\n found checking which position in the array has content allows us to figure\n out which of the original regexes / match groups triggered the match.\n\n The match object itself (the result of `Regex.exec`) is returned but also\n enhanced by merging in any meta-data that was registered with the regex.\n This is how we keep track of which mode matched, and what type of rule\n (`illegal`, `begin`, end, etc).\n */\n class MultiRegex {\n constructor() {\n this.matchIndexes = {};\n // @ts-ignore\n this.regexes = [];\n this.matchAt = 1;\n this.position = 0;\n }\n\n // @ts-ignore\n addRule(re, opts) {\n opts.position = this.position++;\n // @ts-ignore\n this.matchIndexes[this.matchAt] = opts;\n this.regexes.push([opts, re]);\n this.matchAt += countMatchGroups(re) + 1;\n }\n\n compile() {\n if (this.regexes.length === 0) {\n // avoids the need to check length every time exec is called\n // @ts-ignore\n this.exec = () => null;\n }\n const terminators = this.regexes.map(el => el[1]);\n this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true);\n this.lastIndex = 0;\n }\n\n /** @param {string} s */\n exec(s) {\n this.matcherRe.lastIndex = this.lastIndex;\n const match = this.matcherRe.exec(s);\n if (!match) { return null; }\n\n // eslint-disable-next-line no-undefined\n const i = match.findIndex((el, i) => i > 0 && el !== undefined);\n // @ts-ignore\n const matchData = this.matchIndexes[i];\n // trim off any earlier non-relevant match groups (ie, the other regex\n // match groups that make up the multi-matcher)\n match.splice(0, i);\n\n return Object.assign(match, matchData);\n }\n }\n\n /*\n Created to solve the key deficiently with MultiRegex - there is no way to\n test for multiple matches at a single location. Why would we need to do\n that? In the future a more dynamic engine will allow certain matches to be\n ignored. An example: if we matched say the 3rd regex in a large group but\n decided to ignore it - we'd need to started testing again at the 4th\n regex... but MultiRegex itself gives us no real way to do that.\n\n So what this class creates MultiRegexs on the fly for whatever search\n position they are needed.\n\n NOTE: These additional MultiRegex objects are created dynamically. For most\n grammars most of the time we will never actually need anything more than the\n first MultiRegex - so this shouldn't have too much overhead.\n\n Say this is our search group, and we match regex3, but wish to ignore it.\n\n regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0\n\n What we need is a new MultiRegex that only includes the remaining\n possibilities:\n\n regex4 | regex5 ' ie, startAt = 3\n\n This class wraps all that complexity up in a simple API... `startAt` decides\n where in the array of expressions to start doing the matching. It\n auto-increments, so if a match is found at position 2, then startAt will be\n set to 3. If the end is reached startAt will return to 0.\n\n MOST of the time the parser will be setting startAt manually to 0.\n */\n class ResumableMultiRegex {\n constructor() {\n // @ts-ignore\n this.rules = [];\n // @ts-ignore\n this.multiRegexes = [];\n this.count = 0;\n\n this.lastIndex = 0;\n this.regexIndex = 0;\n }\n\n // @ts-ignore\n getMatcher(index) {\n if (this.multiRegexes[index]) return this.multiRegexes[index];\n\n const matcher = new MultiRegex();\n this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts));\n matcher.compile();\n this.multiRegexes[index] = matcher;\n return matcher;\n }\n\n resumingScanAtSamePosition() {\n return this.regexIndex !== 0;\n }\n\n considerAll() {\n this.regexIndex = 0;\n }\n\n // @ts-ignore\n addRule(re, opts) {\n this.rules.push([re, opts]);\n if (opts.type === \"begin\") this.count++;\n }\n\n /** @param {string} s */\n exec(s) {\n const m = this.getMatcher(this.regexIndex);\n m.lastIndex = this.lastIndex;\n let result = m.exec(s);\n\n // The following is because we have no easy way to say \"resume scanning at the\n // existing position but also skip the current rule ONLY\". What happens is\n // all prior rules are also skipped which can result in matching the wrong\n // thing. Example of matching \"booger\":\n\n // our matcher is [string, \"booger\", number]\n //\n // ....booger....\n\n // if \"booger\" is ignored then we'd really need a regex to scan from the\n // SAME position for only: [string, number] but ignoring \"booger\" (if it\n // was the first match), a simple resume would scan ahead who knows how\n // far looking only for \"number\", ignoring potential string matches (or\n // future \"booger\" matches that might be valid.)\n\n // So what we do: We execute two matchers, one resuming at the same\n // position, but the second full matcher starting at the position after:\n\n // /--- resume first regex match here (for [number])\n // |/---- full match here for [string, \"booger\", number]\n // vv\n // ....booger....\n\n // Which ever results in a match first is then used. So this 3-4 step\n // process essentially allows us to say \"match at this position, excluding\n // a prior rule that was ignored\".\n //\n // 1. Match \"booger\" first, ignore. Also proves that [string] does non match.\n // 2. Resume matching for [number]\n // 3. Match at index + 1 for [string, \"booger\", number]\n // 4. If #2 and #3 result in matches, which came first?\n if (this.resumingScanAtSamePosition()) {\n if (result && result.index === this.lastIndex) ; else { // use the second matcher result\n const m2 = this.getMatcher(0);\n m2.lastIndex = this.lastIndex + 1;\n result = m2.exec(s);\n }\n }\n\n if (result) {\n this.regexIndex += result.position + 1;\n if (this.regexIndex === this.count) {\n // wrap-around to considering all matches again\n this.considerAll();\n }\n }\n\n return result;\n }\n }\n\n /**\n * Given a mode, builds a huge ResumableMultiRegex that can be used to walk\n * the content and find matches.\n *\n * @param {CompiledMode} mode\n * @returns {ResumableMultiRegex}\n */\n function buildModeRegex(mode) {\n const mm = new ResumableMultiRegex();\n\n mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: \"begin\" }));\n\n if (mode.terminatorEnd) {\n mm.addRule(mode.terminatorEnd, { type: \"end\" });\n }\n if (mode.illegal) {\n mm.addRule(mode.illegal, { type: \"illegal\" });\n }\n\n return mm;\n }\n\n /** skip vs abort vs ignore\n *\n * @skip - The mode is still entered and exited normally (and contains rules apply),\n * but all content is held and added to the parent buffer rather than being\n * output when the mode ends. Mostly used with `sublanguage` to build up\n * a single large buffer than can be parsed by sublanguage.\n *\n * - The mode begin ands ends normally.\n * - Content matched is added to the parent mode buffer.\n * - The parser cursor is moved forward normally.\n *\n * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it\n * never matched) but DOES NOT continue to match subsequent `contains`\n * modes. Abort is bad/suboptimal because it can result in modes\n * farther down not getting applied because an earlier rule eats the\n * content but then aborts.\n *\n * - The mode does not begin.\n * - Content matched by `begin` is added to the mode buffer.\n * - The parser cursor is moved forward accordingly.\n *\n * @ignore - Ignores the mode (as if it never matched) and continues to match any\n * subsequent `contains` modes. Ignore isn't technically possible with\n * the current parser implementation.\n *\n * - The mode does not begin.\n * - Content matched by `begin` is ignored.\n * - The parser cursor is not moved forward.\n */\n\n /**\n * Compiles an individual mode\n *\n * This can raise an error if the mode contains certain detectable known logic\n * issues.\n * @param {Mode} mode\n * @param {CompiledMode | null} [parent]\n * @returns {CompiledMode | never}\n */\n function compileMode(mode, parent) {\n const cmode = /** @type CompiledMode */ (mode);\n if (mode.isCompiled) return cmode;\n\n [\n scopeClassName,\n // do this early so compiler extensions generally don't have to worry about\n // the distinction between match/begin\n compileMatch,\n MultiClass,\n beforeMatchExt\n ].forEach(ext => ext(mode, parent));\n\n language.compilerExtensions.forEach(ext => ext(mode, parent));\n\n // __beforeBegin is considered private API, internal use only\n mode.__beforeBegin = null;\n\n [\n beginKeywords,\n // do this later so compiler extensions that come earlier have access to the\n // raw array if they wanted to perhaps manipulate it, etc.\n compileIllegal,\n // default to 1 relevance if not specified\n compileRelevance\n ].forEach(ext => ext(mode, parent));\n\n mode.isCompiled = true;\n\n let keywordPattern = null;\n if (typeof mode.keywords === \"object\" && mode.keywords.$pattern) {\n // we need a copy because keywords might be compiled multiple times\n // so we can't go deleting $pattern from the original on the first\n // pass\n mode.keywords = Object.assign({}, mode.keywords);\n keywordPattern = mode.keywords.$pattern;\n delete mode.keywords.$pattern;\n }\n keywordPattern = keywordPattern || /\\w+/;\n\n if (mode.keywords) {\n mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);\n }\n\n cmode.keywordPatternRe = langRe(keywordPattern, true);\n\n if (parent) {\n if (!mode.begin) mode.begin = /\\B|\\b/;\n cmode.beginRe = langRe(cmode.begin);\n if (!mode.end && !mode.endsWithParent) mode.end = /\\B|\\b/;\n if (mode.end) cmode.endRe = langRe(cmode.end);\n cmode.terminatorEnd = source(cmode.end) || '';\n if (mode.endsWithParent && parent.terminatorEnd) {\n cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd;\n }\n }\n if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal));\n if (!mode.contains) mode.contains = [];\n\n mode.contains = [].concat(...mode.contains.map(function(c) {\n return expandOrCloneMode(c === 'self' ? mode : c);\n }));\n mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); });\n\n if (mode.starts) {\n compileMode(mode.starts, parent);\n }\n\n cmode.matcher = buildModeRegex(cmode);\n return cmode;\n }\n\n if (!language.compilerExtensions) language.compilerExtensions = [];\n\n // self is not valid at the top-level\n if (language.contains && language.contains.includes('self')) {\n throw new Error(\"ERR: contains `self` is not supported at the top-level of a language. See documentation.\");\n }\n\n // we need a null object, which inherit will guarantee\n language.classNameAliases = inherit$1(language.classNameAliases || {});\n\n return compileMode(/** @type Mode */ (language));\n}\n\n/**\n * Determines if a mode has a dependency on it's parent or not\n *\n * If a mode does have a parent dependency then often we need to clone it if\n * it's used in multiple places so that each copy points to the correct parent,\n * where-as modes without a parent can often safely be re-used at the bottom of\n * a mode chain.\n *\n * @param {Mode | null} mode\n * @returns {boolean} - is there a dependency on the parent?\n * */\nfunction dependencyOnParent(mode) {\n if (!mode) return false;\n\n return mode.endsWithParent || dependencyOnParent(mode.starts);\n}\n\n/**\n * Expands a mode or clones it if necessary\n *\n * This is necessary for modes with parental dependenceis (see notes on\n * `dependencyOnParent`) and for nodes that have `variants` - which must then be\n * exploded into their own individual modes at compile time.\n *\n * @param {Mode} mode\n * @returns {Mode | Mode[]}\n * */\nfunction expandOrCloneMode(mode) {\n if (mode.variants && !mode.cachedVariants) {\n mode.cachedVariants = mode.variants.map(function(variant) {\n return inherit$1(mode, { variants: null }, variant);\n });\n }\n\n // EXPAND\n // if we have variants then essentially \"replace\" the mode with the variants\n // this happens in compileMode, where this function is called from\n if (mode.cachedVariants) {\n return mode.cachedVariants;\n }\n\n // CLONE\n // if we have dependencies on parents then we need a unique\n // instance of ourselves, so we can be reused with many\n // different parents without issue\n if (dependencyOnParent(mode)) {\n return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null });\n }\n\n if (Object.isFrozen(mode)) {\n return inherit$1(mode);\n }\n\n // no special dependency issues, just return ourselves\n return mode;\n}\n\nvar version = \"11.11.1\";\n\nclass HTMLInjectionError extends Error {\n constructor(reason, html) {\n super(reason);\n this.name = \"HTMLInjectionError\";\n this.html = html;\n }\n}\n\n/*\nSyntax highlighting with language autodetection.\nhttps://highlightjs.org/\n*/\n\n\n\n/**\n@typedef {import('highlight.js').Mode} Mode\n@typedef {import('highlight.js').CompiledMode} CompiledMode\n@typedef {import('highlight.js').CompiledScope} CompiledScope\n@typedef {import('highlight.js').Language} Language\n@typedef {import('highlight.js').HLJSApi} HLJSApi\n@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin\n@typedef {import('highlight.js').PluginEvent} PluginEvent\n@typedef {import('highlight.js').HLJSOptions} HLJSOptions\n@typedef {import('highlight.js').LanguageFn} LanguageFn\n@typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement\n@typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext\n@typedef {import('highlight.js/private').MatchType} MatchType\n@typedef {import('highlight.js/private').KeywordData} KeywordData\n@typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch\n@typedef {import('highlight.js/private').AnnotatedError} AnnotatedError\n@typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult\n@typedef {import('highlight.js').HighlightOptions} HighlightOptions\n@typedef {import('highlight.js').HighlightResult} HighlightResult\n*/\n\n\nconst escape = escapeHTML;\nconst inherit = inherit$1;\nconst NO_MATCH = Symbol(\"nomatch\");\nconst MAX_KEYWORD_HITS = 7;\n\n/**\n * @param {any} hljs - object that is extended (legacy)\n * @returns {HLJSApi}\n */\nconst HLJS = function(hljs) {\n // Global internal variables used within the highlight.js library.\n /** @type {Record<string, Language>} */\n const languages = Object.create(null);\n /** @type {Record<string, string>} */\n const aliases = Object.create(null);\n /** @type {HLJSPlugin[]} */\n const plugins = [];\n\n // safe/production mode - swallows more errors, tries to keep running\n // even if a single syntax or parse hits a fatal error\n let SAFE_MODE = true;\n const LANGUAGE_NOT_FOUND = \"Could not find the language '{}', did you forget to load/include a language module?\";\n /** @type {Language} */\n const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };\n\n // Global options used when within external APIs. This is modified when\n // calling the `hljs.configure` function.\n /** @type HLJSOptions */\n let options = {\n ignoreUnescapedHTML: false,\n throwUnescapedHTML: false,\n noHighlightRe: /^(no-?highlight)$/i,\n languageDetectRe: /\\blang(?:uage)?-([\\w-]+)\\b/i,\n classPrefix: 'hljs-',\n cssSelector: 'pre code',\n languages: null,\n // beta configuration options, subject to change, welcome to discuss\n // https://github.com/highlightjs/highlight.js/issues/1086\n __emitter: TokenTreeEmitter\n };\n\n /* Utility functions */\n\n /**\n * Tests a language name to see if highlighting should be skipped\n * @param {string} languageName\n */\n function shouldNotHighlight(languageName) {\n return options.noHighlightRe.test(languageName);\n }\n\n /**\n * @param {HighlightedHTMLElement} block - the HTML element to determine language for\n */\n function blockLanguage(block) {\n let classes = block.className + ' ';\n\n classes += block.parentNode ? block.parentNode.className : '';\n\n // language-* takes precedence over non-prefixed class names.\n const match = options.languageDetectRe.exec(classes);\n if (match) {\n const language = getLanguage(match[1]);\n if (!language) {\n warn(LANGUAGE_NOT_FOUND.replace(\"{}\", match[1]));\n warn(\"Falling back to no-highlight mode for this block.\", block);\n }\n return language ? match[1] : 'no-highlight';\n }\n\n return classes\n .split(/\\s+/)\n .find((_class) => shouldNotHighlight(_class) || getLanguage(_class));\n }\n\n /**\n * Core highlighting function.\n *\n * OLD API\n * highlight(lang, code, ignoreIllegals, continuation)\n *\n * NEW API\n * highlight(code, {lang, ignoreIllegals})\n *\n * @param {string} codeOrLanguageName - the language to use for highlighting\n * @param {string | HighlightOptions} optionsOrCode - the code to highlight\n * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail\n *\n * @returns {HighlightResult} Result - an object that represents the result\n * @property {string} language - the language name\n * @property {number} relevance - the relevance score\n * @property {string} value - the highlighted HTML code\n * @property {string} code - the original raw code\n * @property {CompiledMode} top - top of the current mode stack\n * @property {boolean} illegal - indicates whether any illegal matches were found\n */\n function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) {\n let code = \"\";\n let languageName = \"\";\n if (typeof optionsOrCode === \"object\") {\n code = codeOrLanguageName;\n ignoreIllegals = optionsOrCode.ignoreIllegals;\n languageName = optionsOrCode.language;\n } else {\n // old API\n deprecated(\"10.7.0\", \"highlight(lang, code, ...args) has been deprecated.\");\n deprecated(\"10.7.0\", \"Please use highlight(code, options) instead.\\nhttps://github.com/highlightjs/highlight.js/issues/2277\");\n languageName = codeOrLanguageName;\n code = optionsOrCode;\n }\n\n // https://github.com/highlightjs/highlight.js/issues/3149\n // eslint-disable-next-line no-undefined\n if (ignoreIllegals === undefined) { ignoreIllegals = true; }\n\n /** @type {BeforeHighlightContext} */\n const context = {\n code,\n language: languageName\n };\n // the plugin can change the desired language or the code to be highlighted\n // just be changing the object it was passed\n fire(\"before:highlight\", context);\n\n // a before plugin can usurp the result completely by providing it's own\n // in which case we don't even need to call highlight\n const result = context.result\n ? context.result\n : _highlight(context.language, context.code, ignoreIllegals);\n\n result.code = context.code;\n // the plugin can change anything in result to suite it\n fire(\"after:highlight\", result);\n\n return result;\n }\n\n /**\n * private highlight that's used internally and does not fire callbacks\n *\n * @param {string} languageName - the language to use for highlighting\n * @param {string} codeToHighlight - the code to highlight\n * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail\n * @param {CompiledMode?} [continuation] - current continuation mode, if any\n * @returns {HighlightResult} - result of the highlight operation\n */\n function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {\n const keywordHits = Object.create(null);\n\n /**\n * Return keyword data if a match is a keyword\n * @param {CompiledMode} mode - current mode\n * @param {string} matchText - the textual match\n * @returns {KeywordData | false}\n */\n function keywordData(mode, matchText) {\n return mode.keywords[matchText];\n }\n\n function processKeywords() {\n if (!top.keywords) {\n emitter.addText(modeBuffer);\n return;\n }\n\n let lastIndex = 0;\n top.keywordPatternRe.lastIndex = 0;\n let match = top.keywordPatternRe.exec(modeBuffer);\n let buf = \"\";\n\n while (match) {\n buf += modeBuffer.substring(lastIndex, match.index);\n const word = language.case_insensitive ? match[0].toLowerCase() : match[0];\n const data = keywordData(top, word);\n if (data) {\n const [kind, keywordRelevance] = data;\n emitter.addText(buf);\n buf = \"\";\n\n keywordHits[word] = (keywordHits[word] || 0) + 1;\n if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance;\n if (kind.startsWith(\"_\")) {\n // _ implied for relevance only, do not highlight\n // by applying a class name\n buf += match[0];\n } else {\n const cssClass = language.classNameAliases[kind] || kind;\n emitKeyword(match[0], cssClass);\n }\n } else {\n buf += match[0];\n }\n lastIndex = top.keywordPatternRe.lastIndex;\n match = top.keywordPatternRe.exec(modeBuffer);\n }\n buf += modeBuffer.substring(lastIndex);\n emitter.addText(buf);\n }\n\n function processSubLanguage() {\n if (modeBuffer === \"\") return;\n /** @type HighlightResult */\n let result = null;\n\n if (typeof top.subLanguage === 'string') {\n if (!languages[top.subLanguage]) {\n emitter.addText(modeBuffer);\n return;\n }\n result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);\n continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top);\n } else {\n result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);\n }\n\n // Counting embedded language score towards the host language may be disabled\n // with zeroing the containing mode relevance. Use case in point is Markdown that\n // allows XML everywhere and makes every XML snippet to have a much larger Markdown\n // score.\n if (top.relevance > 0) {\n relevance += result.relevance;\n }\n emitter.__addSublanguage(result._emitter, result.language);\n }\n\n function processBuffer() {\n if (top.subLanguage != null) {\n processSubLanguage();\n } else {\n processKeywords();\n }\n modeBuffer = '';\n }\n\n /**\n * @param {string} text\n * @param {string} scope\n */\n function emitKeyword(keyword, scope) {\n if (keyword === \"\") return;\n\n emitter.startScope(scope);\n emitter.addText(keyword);\n emitter.endScope();\n }\n\n /**\n * @param {CompiledScope} scope\n * @param {RegExpMatchArray} match\n */\n function emitMultiClass(scope, match) {\n let i = 1;\n const max = match.length - 1;\n while (i <= max) {\n if (!scope._emit[i]) { i++; continue; }\n const klass = language.classNameAliases[scope[i]] || scope[i];\n const text = match[i];\n if (klass) {\n emitKeyword(text, klass);\n } else {\n modeBuffer = text;\n processKeywords();\n modeBuffer = \"\";\n }\n i++;\n }\n }\n\n /**\n * @param {CompiledMode} mode - new mode to start\n * @param {RegExpMatchArray} match\n */\n function startNewMode(mode, match) {\n if (mode.scope && typeof mode.scope === \"string\") {\n emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);\n }\n if (mode.beginScope) {\n // beginScope just wraps the begin match itself in a scope\n if (mode.beginScope._wrap) {\n emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap);\n modeBuffer = \"\";\n } else if (mode.beginScope._multi) {\n // at this point modeBuffer should just be the match\n emitMultiClass(mode.beginScope, match);\n modeBuffer = \"\";\n }\n }\n\n top = Object.create(mode, { parent: { value: top } });\n return top;\n }\n\n /**\n * @param {CompiledMode } mode - the mode to potentially end\n * @param {RegExpMatchArray} match - the latest match\n * @param {string} matchPlusRemainder - match plus remainder of content\n * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode\n */\n function endOfMode(mode, match, matchPlusRemainder) {\n let matched = startsWith(mode.endRe, matchPlusRemainder);\n\n if (matched) {\n if (mode[\"on:end\"]) {\n const resp = new Response(mode);\n mode[\"on:end\"](match, resp);\n if (resp.isMatchIgnored) matched = false;\n }\n\n if (matched) {\n while (mode.endsParent && mode.parent) {\n mode = mode.parent;\n }\n return mode;\n }\n }\n // even if on:end fires an `ignore` it's still possible\n // that we might trigger the end node because of a parent mode\n if (mode.endsWithParent) {\n return endOfMode(mode.parent, match, matchPlusRemainder);\n }\n }\n\n /**\n * Handle matching but then ignoring a sequence of text\n *\n * @param {string} lexeme - string containing full match text\n */\n function doIgnore(lexeme) {\n if (top.matcher.regexIndex === 0) {\n // no more regexes to potentially match here, so we move the cursor forward one\n // space\n modeBuffer += lexeme[0];\n return 1;\n } else {\n // no need to move the cursor, we still have additional regexes to try and\n // match at this very spot\n resumeScanAtSamePosition = true;\n return 0;\n }\n }\n\n /**\n * Handle the start of a new potential mode match\n *\n * @param {EnhancedMatch} match - the current match\n * @returns {number} how far to advance the parse cursor\n */\n function doBeginMatch(match) {\n const lexeme = match[0];\n const newMode = match.rule;\n\n const resp = new Response(newMode);\n // first internal before callbacks, then the public ones\n const beforeCallbacks = [newMode.__beforeBegin, newMode[\"on:begin\"]];\n for (const cb of beforeCallbacks) {\n if (!cb) continue;\n cb(match, resp);\n if (resp.isMatchIgnored) return doIgnore(lexeme);\n }\n\n if (newMode.skip) {\n modeBuffer += lexeme;\n } else {\n if (newMode.excludeBegin) {\n modeBuffer += lexeme;\n }\n processBuffer();\n if (!newMode.returnBegin && !newMode.excludeBegin) {\n modeBuffer = lexeme;\n }\n }\n startNewMode(newMode, match);\n return newMode.returnBegin ? 0 : lexeme.length;\n }\n\n /**\n * Handle the potential end of mode\n *\n * @param {RegExpMatchArray} match - the current match\n */\n function doEndMatch(match) {\n const lexeme = match[0];\n const matchPlusRemainder = codeToHighlight.substring(match.index);\n\n const endMode = endOfMode(top, match, matchPlusRemainder);\n if (!endMode) { return NO_MATCH; }\n\n const origin = top;\n if (top.endScope && top.endScope._wrap) {\n processBuffer();\n emitKeyword(lexeme, top.endScope._wrap);\n } else if (top.endScope && top.endScope._multi) {\n processBuffer();\n emitMultiClass(top.endScope, match);\n } else if (origin.skip) {\n modeBuffer += lexeme;\n } else {\n if (!(origin.returnEnd || origin.excludeEnd)) {\n modeBuffer += lexeme;\n }\n processBuffer();\n if (origin.excludeEnd) {\n modeBuffer = lexeme;\n }\n }\n do {\n if (top.scope) {\n emitter.closeNode();\n }\n if (!top.skip && !top.subLanguage) {\n relevance += top.relevance;\n }\n top = top.parent;\n } while (top !== endMode.parent);\n if (endMode.starts) {\n startNewMode(endMode.starts, match);\n }\n return origin.returnEnd ? 0 : lexeme.length;\n }\n\n function processContinuations() {\n const list = [];\n for (let current = top; current !== language; current = current.parent) {\n if (current.scope) {\n list.unshift(current.scope);\n }\n }\n list.forEach(item => emitter.openNode(item));\n }\n\n /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */\n let lastMatch = {};\n\n /**\n * Process an individual match\n *\n * @param {string} textBeforeMatch - text preceding the match (since the last match)\n * @param {EnhancedMatch} [match] - the match itself\n */\n function processLexeme(textBeforeMatch, match) {\n const lexeme = match && match[0];\n\n // add non-matched text to the current mode buffer\n modeBuffer += textBeforeMatch;\n\n if (lexeme == null) {\n processBuffer();\n return 0;\n }\n\n // we've found a 0 width match and we're stuck, so we need to advance\n // this happens when we have badly behaved rules that have optional matchers to the degree that\n // sometimes they can end up matching nothing at all\n // Ref: https://github.com/highlightjs/highlight.js/issues/2140\n if (lastMatch.type === \"begin\" && match.type === \"end\" && lastMatch.index === match.index && lexeme === \"\") {\n // spit the \"skipped\" character that our regex choked on back into the output sequence\n modeBuffer += codeToHighlight.slice(match.index, match.index + 1);\n if (!SAFE_MODE) {\n /** @type {AnnotatedError} */\n const err = new Error(`0 width match regex (${languageName})`);\n err.languageName = languageName;\n err.badRule = lastMatch.rule;\n throw err;\n }\n return 1;\n }\n lastMatch = match;\n\n if (match.type === \"begin\") {\n return doBeginMatch(match);\n } else if (match.type === \"illegal\" && !ignoreIllegals) {\n // illegal match, we do not continue processing\n /** @type {AnnotatedError} */\n const err = new Error('Illegal lexeme \"' + lexeme + '\" for mode \"' + (top.scope || '<unnamed>') + '\"');\n err.mode = top;\n throw err;\n } else if (match.type === \"end\") {\n const processed = doEndMatch(match);\n if (processed !== NO_MATCH) {\n return processed;\n }\n }\n\n // edge case for when illegal matches $ (end of line) which is technically\n // a 0 width match but not a begin/end match so it's not caught by the\n // first handler (when ignoreIllegals is true)\n if (match.type === \"illegal\" && lexeme === \"\") {\n // advance so we aren't stuck in an infinite loop\n modeBuffer += \"\\n\";\n return 1;\n }\n\n // infinite loops are BAD, this is a last ditch catch all. if we have a\n // decent number of iterations yet our index (cursor position in our\n // parsing) still 3x behind our index then something is very wrong\n // so we bail\n if (iterations > 100000 && iterations > match.index * 3) {\n const err = new Error('potential infinite loop, way more iterations than matches');\n throw err;\n }\n\n /*\n Why might be find ourselves here? An potential end match that was\n triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH.\n (this could be because a callback requests the match be ignored, etc)\n\n This causes no real harm other than stopping a few times too many.\n */\n\n modeBuffer += lexeme;\n return lexeme.length;\n }\n\n const language = getLanguage(languageName);\n if (!language) {\n error(LANGUAGE_NOT_FOUND.replace(\"{}\", languageName));\n throw new Error('Unknown language: \"' + languageName + '\"');\n }\n\n const md = compileLanguage(language);\n let result = '';\n /** @type {CompiledMode} */\n let top = continuation || md;\n /** @type Record<string,CompiledMode> */\n const continuations = {}; // keep continuations for sub-languages\n const emitter = new options.__emitter(options);\n processContinuations();\n let modeBuffer = '';\n let relevance = 0;\n let index = 0;\n let iterations = 0;\n let resumeScanAtSamePosition = false;\n\n try {\n if (!language.__emitTokens) {\n top.matcher.considerAll();\n\n for (;;) {\n iterations++;\n if (resumeScanAtSamePosition) {\n // only regexes not matched previously will now be\n // considered for a potential match\n resumeScanAtSamePosition = false;\n } else {\n top.matcher.considerAll();\n }\n top.matcher.lastIndex = index;\n\n const match = top.matcher.exec(codeToHighlight);\n // console.log(\"match\", match[0], match.rule && match.rule.begin)\n\n if (!match) break;\n\n const beforeMatch = codeToHighlight.substring(index, match.index);\n const processedCount = processLexeme(beforeMatch, match);\n index = match.index + processedCount;\n }\n processLexeme(codeToHighlight.substring(index));\n } else {\n language.__emitTokens(codeToHighlight, emitter);\n }\n\n emitter.finalize();\n result = emitter.toHTML();\n\n return {\n language: languageName,\n value: result,\n relevance,\n illegal: false,\n _emitter: emitter,\n _top: top\n };\n } catch (err) {\n if (err.message && err.message.includes('Illegal')) {\n return {\n language: languageName,\n value: escape(codeToHighlight),\n illegal: true,\n relevance: 0,\n _illegalBy: {\n message: err.message,\n index,\n context: codeToHighlight.slice(index - 100, index + 100),\n mode: err.mode,\n resultSoFar: result\n },\n _emitter: emitter\n };\n } else if (SAFE_MODE) {\n return {\n language: languageName,\n value: escape(codeToHighlight),\n illegal: false,\n relevance: 0,\n errorRaised: err,\n _emitter: emitter,\n _top: top\n };\n } else {\n throw err;\n }\n }\n }\n\n /**\n * returns a valid highlight result, without actually doing any actual work,\n * auto highlight starts with this and it's possible for small snippets that\n * auto-detection may not find a better match\n * @param {string} code\n * @returns {HighlightResult}\n */\n function justTextHighlightResult(code) {\n const result = {\n value: escape(code),\n illegal: false,\n relevance: 0,\n _top: PLAINTEXT_LANGUAGE,\n _emitter: new options.__emitter(options)\n };\n result._emitter.addText(code);\n return result;\n }\n\n /**\n Highlighting with language detection. Accepts a string with the code to\n highlight. Returns an object with the following properties:\n\n - language (detected language)\n - relevance (int)\n - value (an HTML string with highlighting markup)\n - secondBest (object with the same structure for second-best heuristically\n detected language, may be absent)\n\n @param {string} code\n @param {Array<string>} [languageSubset]\n @returns {AutoHighlightResult}\n */\n function highlightAuto(code, languageSubset) {\n languageSubset = languageSubset || options.languages || Object.keys(languages);\n const plaintext = justTextHighlightResult(code);\n\n const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name =>\n _highlight(name, code, false)\n );\n results.unshift(plaintext); // plaintext is always an option\n\n const sorted = results.sort((a, b) => {\n // sort base on relevance\n if (a.relevance !== b.relevance) return b.relevance - a.relevance;\n\n // always award the tie to the base language\n // ie if C++ and Arduino are tied, it's more likely to be C++\n if (a.language && b.language) {\n if (getLanguage(a.language).supersetOf === b.language) {\n return 1;\n } else if (getLanguage(b.language).supersetOf === a.language) {\n return -1;\n }\n }\n\n // otherwise say they are equal, which has the effect of sorting on\n // relevance while preserving the original ordering - which is how ties\n // have historically been settled, ie the language that comes first always\n // wins in the case of a tie\n return 0;\n });\n\n const [best, secondBest] = sorted;\n\n /** @type {AutoHighlightResult} */\n const result = best;\n result.secondBest = secondBest;\n\n return result;\n }\n\n /**\n * Builds new class name for block given the language name\n *\n * @param {HTMLElement} element\n * @param {string} [currentLang]\n * @param {string} [resultLang]\n */\n function updateClassName(element, currentLang, resultLang) {\n const language = (currentLang && aliases[currentLang]) || resultLang;\n\n element.classList.add(\"hljs\");\n element.classList.add(`language-${language}`);\n }\n\n /**\n * Applies highlighting to a DOM node containing code.\n *\n * @param {HighlightedHTMLElement} element - the HTML element to highlight\n */\n function highlightElement(element) {\n /** @type HTMLElement */\n let node = null;\n const language = blockLanguage(element);\n\n if (shouldNotHighlight(language)) return;\n\n fire(\"before:highlightElement\",\n { el: element, language });\n\n if (element.dataset.highlighted) {\n console.log(\"Element previously highlighted. To highlight again, first unset `dataset.highlighted`.\", element);\n return;\n }\n\n // we should be all text, no child nodes (unescaped HTML) - this is possibly\n // an HTML injection attack - it's likely too late if this is already in\n // production (the code has likely already done its damage by the time\n // we're seeing it)... but we yell loudly about this so that hopefully it's\n // more likely to be caught in development before making it to production\n if (element.children.length > 0) {\n if (!options.ignoreUnescapedHTML) {\n console.warn(\"One of your code blocks includes unescaped HTML. This is a potentially serious security risk.\");\n console.warn(\"https://github.com/highlightjs/highlight.js/wiki/security\");\n console.warn(\"The element with unescaped HTML:\");\n console.warn(element);\n }\n if (options.throwUnescapedHTML) {\n const err = new HTMLInjectionError(\n \"One of your code blocks includes unescaped HTML.\",\n element.innerHTML\n );\n throw err;\n }\n }\n\n node = element;\n const text = node.textContent;\n const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text);\n\n element.innerHTML = result.value;\n element.dataset.highlighted = \"yes\";\n updateClassName(element, language, result.language);\n element.result = {\n language: result.language,\n // TODO: remove with version 11.0\n re: result.relevance,\n relevance: result.relevance\n };\n if (result.secondBest) {\n element.secondBest = {\n language: result.secondBest.language,\n relevance: result.secondBest.relevance\n };\n }\n\n fire(\"after:highlightElement\", { el: element, result, text });\n }\n\n /**\n * Updates highlight.js global options with the passed options\n *\n * @param {Partial<HLJSOptions>} userOptions\n */\n function configure(userOptions) {\n options = inherit(options, userOptions);\n }\n\n // TODO: remove v12, deprecated\n const initHighlighting = () => {\n highlightAll();\n deprecated(\"10.6.0\", \"initHighlighting() deprecated. Use highlightAll() now.\");\n };\n\n // TODO: remove v12, deprecated\n function initHighlightingOnLoad() {\n highlightAll();\n deprecated(\"10.6.0\", \"initHighlightingOnLoad() deprecated. Use highlightAll() now.\");\n }\n\n let wantsHighlight = false;\n\n /**\n * auto-highlights all pre>code elements on the page\n */\n function highlightAll() {\n function boot() {\n // if a highlight was requested before DOM was loaded, do now\n highlightAll();\n }\n\n // if we are called too early in the loading process\n if (document.readyState === \"loading\") {\n // make sure the event listener is only added once\n if (!wantsHighlight) {\n window.addEventListener('DOMContentLoaded', boot, false);\n }\n wantsHighlight = true;\n return;\n }\n\n const blocks = document.querySelectorAll(options.cssSelector);\n blocks.forEach(highlightElement);\n }\n\n /**\n * Register a language grammar module\n *\n * @param {string} languageName\n * @param {LanguageFn} languageDefinition\n */\n function registerLanguage(languageName, languageDefinition) {\n let lang = null;\n try {\n lang = languageDefinition(hljs);\n } catch (error$1) {\n error(\"Language definition for '{}' could not be registered.\".replace(\"{}\", languageName));\n // hard or soft error\n if (!SAFE_MODE) { throw error$1; } else { error(error$1); }\n // languages that have serious errors are replaced with essentially a\n // \"plaintext\" stand-in so that the code blocks will still get normal\n // css classes applied to them - and one bad language won't break the\n // entire highlighter\n lang = PLAINTEXT_LANGUAGE;\n }\n // give it a temporary name if it doesn't have one in the meta-data\n if (!lang.name) lang.name = languageName;\n languages[languageName] = lang;\n lang.rawDefinition = languageDefinition.bind(null, hljs);\n\n if (lang.aliases) {\n registerAliases(lang.aliases, { languageName });\n }\n }\n\n /**\n * Remove a language grammar module\n *\n * @param {string} languageName\n */\n function unregisterLanguage(languageName) {\n delete languages[languageName];\n for (const alias of Object.keys(aliases)) {\n if (aliases[alias] === languageName) {\n delete aliases[alias];\n }\n }\n }\n\n /**\n * @returns {string[]} List of language internal names\n */\n function listLanguages() {\n return Object.keys(languages);\n }\n\n /**\n * @param {string} name - name of the language to retrieve\n * @returns {Language | undefined}\n */\n function getLanguage(name) {\n name = (name || '').toLowerCase();\n return languages[name] || languages[aliases[name]];\n }\n\n /**\n *\n * @param {string|string[]} aliasList - single alias or list of aliases\n * @param {{languageName: string}} opts\n */\n function registerAliases(aliasList, { languageName }) {\n if (typeof aliasList === 'string') {\n aliasList = [aliasList];\n }\n aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; });\n }\n\n /**\n * Determines if a given language has auto-detection enabled\n * @param {string} name - name of the language\n */\n function autoDetection(name) {\n const lang = getLanguage(name);\n return lang && !lang.disableAutodetect;\n }\n\n /**\n * Upgrades the old highlightBlock plugins to the new\n * highlightElement API\n * @param {HLJSPlugin} plugin\n */\n function upgradePluginAPI(plugin) {\n // TODO: remove with v12\n if (plugin[\"before:highlightBlock\"] && !plugin[\"before:highlightElement\"]) {\n plugin[\"before:highlightElement\"] = (data) => {\n plugin[\"before:highlightBlock\"](\n Object.assign({ block: data.el }, data)\n );\n };\n }\n if (plugin[\"after:highlightBlock\"] && !plugin[\"after:highlightElement\"]) {\n plugin[\"after:highlightElement\"] = (data) => {\n plugin[\"after:highlightBlock\"](\n Object.assign({ block: data.el }, data)\n );\n };\n }\n }\n\n /**\n * @param {HLJSPlugin} plugin\n */\n function addPlugin(plugin) {\n upgradePluginAPI(plugin);\n plugins.push(plugin);\n }\n\n /**\n * @param {HLJSPlugin} plugin\n */\n function removePlugin(plugin) {\n const index = plugins.indexOf(plugin);\n if (index !== -1) {\n plugins.splice(index, 1);\n }\n }\n\n /**\n *\n * @param {PluginEvent} event\n * @param {any} args\n */\n function fire(event, args) {\n const cb = event;\n plugins.forEach(function(plugin) {\n if (plugin[cb]) {\n plugin[cb](args);\n }\n });\n }\n\n /**\n * DEPRECATED\n * @param {HighlightedHTMLElement} el\n */\n function deprecateHighlightBlock(el) {\n deprecated(\"10.7.0\", \"highlightBlock will be removed entirely in v12.0\");\n deprecated(\"10.7.0\", \"Please use highlightElement now.\");\n\n return highlightElement(el);\n }\n\n /* Interface definition */\n Object.assign(hljs, {\n highlight,\n highlightAuto,\n highlightAll,\n highlightElement,\n // TODO: Remove with v12 API\n highlightBlock: deprecateHighlightBlock,\n configure,\n initHighlighting,\n initHighlightingOnLoad,\n registerLanguage,\n unregisterLanguage,\n listLanguages,\n getLanguage,\n registerAliases,\n autoDetection,\n inherit,\n addPlugin,\n removePlugin\n });\n\n hljs.debugMode = function() { SAFE_MODE = false; };\n hljs.safeMode = function() { SAFE_MODE = true; };\n hljs.versionString = version;\n\n hljs.regex = {\n concat: concat,\n lookahead: lookahead,\n either: either,\n optional: optional,\n anyNumberOfTimes: anyNumberOfTimes\n };\n\n for (const key in MODES) {\n // @ts-ignore\n if (typeof MODES[key] === \"object\") {\n // @ts-ignore\n deepFreeze(MODES[key]);\n }\n }\n\n // merge all the modes/regexes into our main object\n Object.assign(hljs, MODES);\n\n return hljs;\n};\n\n// Other names for the variable may break build script\nconst highlight = HLJS({});\n\n// returns a new instance of the highlighter to be used for extensions\n// check https://github.com/wooorm/lowlight/issues/47\nhighlight.newInstance = () => HLJS({});\n\nmodule.exports = highlight;\nhighlight.HighlightJS = highlight;\nhighlight.default = highlight;\n","/*\nLanguage: JSON\nDescription: JSON (JavaScript Object Notation) is a lightweight data-interchange format.\nAuthor: Ivan Sagalaev <maniac@softwaremaniacs.org>\nWebsite: http://www.json.org\nCategory: common, protocols, web\n*/\n\nfunction json(hljs) {\n const ATTRIBUTE = {\n className: 'attr',\n begin: /\"(\\\\.|[^\\\\\"\\r\\n])*\"(?=\\s*:)/,\n relevance: 1.01\n };\n const PUNCTUATION = {\n match: /[{}[\\],:]/,\n className: \"punctuation\",\n relevance: 0\n };\n const LITERALS = [\n \"true\",\n \"false\",\n \"null\"\n ];\n // NOTE: normally we would rely on `keywords` for this but using a mode here allows us\n // - to use the very tight `illegal: \\S` rule later to flag any other character\n // - as illegal indicating that despite looking like JSON we do not truly have\n // - JSON and thus improve false-positively greatly since JSON will try and claim\n // - all sorts of JSON looking stuff\n const LITERALS_MODE = {\n scope: \"literal\",\n beginKeywords: LITERALS.join(\" \"),\n };\n\n return {\n name: 'JSON',\n aliases: ['jsonc'],\n keywords:{\n literal: LITERALS,\n },\n contains: [\n ATTRIBUTE,\n PUNCTUATION,\n hljs.QUOTE_STRING_MODE,\n LITERALS_MODE,\n hljs.C_NUMBER_MODE,\n hljs.C_LINE_COMMENT_MODE,\n hljs.C_BLOCK_COMMENT_MODE\n ],\n illegal: '\\\\S'\n };\n}\n\nexport { json as default };\n","/*\n Language: SQL\n Website: https://en.wikipedia.org/wiki/SQL\n Category: common, database\n */\n\n/*\n\nGoals:\n\nSQL is intended to highlight basic/common SQL keywords and expressions\n\n- If pretty much every single SQL server includes supports, then it's a canidate.\n- It is NOT intended to include tons of vendor specific keywords (Oracle, MySQL,\n PostgreSQL) although the list of data types is purposely a bit more expansive.\n- For more specific SQL grammars please see:\n - PostgreSQL and PL/pgSQL - core\n - T-SQL - https://github.com/highlightjs/highlightjs-tsql\n - sql_more (core)\n\n */\n\nfunction sql(hljs) {\n const regex = hljs.regex;\n const COMMENT_MODE = hljs.COMMENT('--', '$');\n const STRING = {\n scope: 'string',\n variants: [\n {\n begin: /'/,\n end: /'/,\n contains: [ { match: /''/ } ]\n }\n ]\n };\n const QUOTED_IDENTIFIER = {\n begin: /\"/,\n end: /\"/,\n contains: [ { match: /\"\"/ } ]\n };\n\n const LITERALS = [\n \"true\",\n \"false\",\n // Not sure it's correct to call NULL literal, and clauses like IS [NOT] NULL look strange that way.\n // \"null\",\n \"unknown\"\n ];\n\n const MULTI_WORD_TYPES = [\n \"double precision\",\n \"large object\",\n \"with timezone\",\n \"without timezone\"\n ];\n\n const TYPES = [\n 'bigint',\n 'binary',\n 'blob',\n 'boolean',\n 'char',\n 'character',\n 'clob',\n 'date',\n 'dec',\n 'decfloat',\n 'decimal',\n 'float',\n 'int',\n 'integer',\n 'interval',\n 'nchar',\n 'nclob',\n 'national',\n 'numeric',\n 'real',\n 'row',\n 'smallint',\n 'time',\n 'timestamp',\n 'varchar',\n 'varying', // modifier (character varying)\n 'varbinary'\n ];\n\n const NON_RESERVED_WORDS = [\n \"add\",\n \"asc\",\n \"collation\",\n \"desc\",\n \"final\",\n \"first\",\n \"last\",\n \"view\"\n ];\n\n // https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#reserved-word\n const RESERVED_WORDS = [\n \"abs\",\n \"acos\",\n \"all\",\n \"allocate\",\n \"alter\",\n \"and\",\n \"any\",\n \"are\",\n \"array\",\n \"array_agg\",\n \"array_max_cardinality\",\n \"as\",\n \"asensitive\",\n \"asin\",\n \"asymmetric\",\n \"at\",\n \"atan\",\n \"atomic\",\n \"authorization\",\n \"avg\",\n \"begin\",\n \"begin_frame\",\n \"begin_partition\",\n \"between\",\n \"bigint\",\n \"binary\",\n \"blob\",\n \"boolean\",\n \"both\",\n \"by\",\n \"call\",\n \"called\",\n \"cardinality\",\n \"cascaded\",\n \"case\",\n \"cast\",\n \"ceil\",\n \"ceiling\",\n \"char\",\n \"char_length\",\n \"character\",\n \"character_length\",\n \"check\",\n \"classifier\",\n \"clob\",\n \"close\",\n \"coalesce\",\n \"collate\",\n \"collect\",\n \"column\",\n \"commit\",\n \"condition\",\n \"connect\",\n \"constraint\",\n \"contains\",\n \"convert\",\n \"copy\",\n \"corr\",\n \"corresponding\",\n \"cos\",\n \"cosh\",\n \"count\",\n \"covar_pop\",\n \"covar_samp\",\n \"create\",\n \"cross\",\n \"cube\",\n \"cume_dist\",\n \"current\",\n \"current_catalog\",\n \"current_date\",\n \"current_default_transform_group\",\n \"current_path\",\n \"current_role\",\n \"current_row\",\n \"current_schema\",\n \"current_time\",\n \"current_timestamp\",\n \"current_path\",\n \"current_role\",\n \"current_transform_group_for_type\",\n \"current_user\",\n \"cursor\",\n \"cycle\",\n \"date\",\n \"day\",\n \"deallocate\",\n \"dec\",\n \"decimal\",\n \"decfloat\",\n \"declare\",\n \"default\",\n \"define\",\n \"delete\",\n \"dense_rank\",\n \"deref\",\n \"describe\",\n \"deterministic\",\n \"disconnect\",\n \"distinct\",\n \"double\",\n \"drop\",\n \"dynamic\",\n \"each\",\n \"element\",\n \"else\",\n \"empty\",\n \"end\",\n \"end_frame\",\n \"end_partition\",\n \"end-exec\",\n \"equals\",\n \"escape\",\n \"every\",\n \"except\",\n \"exec\",\n \"execute\",\n \"exists\",\n \"exp\",\n \"external\",\n \"extract\",\n \"false\",\n \"fetch\",\n \"filter\",\n \"first_value\",\n \"float\",\n \"floor\",\n \"for\",\n \"foreign\",\n \"frame_row\",\n \"free\",\n \"from\",\n \"full\",\n \"function\",\n \"fusion\",\n \"get\",\n \"global\",\n \"grant\",\n \"group\",\n \"grouping\",\n \"groups\",\n \"having\",\n \"hold\",\n \"hour\",\n \"identity\",\n \"in\",\n \"indicator\",\n \"initial\",\n \"inner\",\n \"inout\",\n \"insensitive\",\n \"insert\",\n \"int\",\n \"integer\",\n \"intersect\",\n \"intersection\",\n \"interval\",\n \"into\",\n \"is\",\n \"join\",\n \"json_array\",\n \"json_arrayagg\",\n \"json_exists\",\n \"json_object\",\n \"json_objectagg\",\n \"json_query\",\n \"json_table\",\n \"json_table_primitive\",\n \"json_value\",\n \"lag\",\n \"language\",\n \"large\",\n \"last_value\",\n \"lateral\",\n \"lead\",\n \"leading\",\n \"left\",\n \"like\",\n \"like_regex\",\n \"listagg\",\n \"ln\",\n \"local\",\n \"localtime\",\n \"localtimestamp\",\n \"log\",\n \"log10\",\n \"lower\",\n \"match\",\n \"match_number\",\n \"match_recognize\",\n \"matches\",\n \"max\",\n \"member\",\n \"merge\",\n \"method\",\n \"min\",\n \"minute\",\n \"mod\",\n \"modifies\",\n \"module\",\n \"month\",\n \"multiset\",\n \"national\",\n \"natural\",\n \"nchar\",\n \"nclob\",\n \"new\",\n \"no\",\n \"none\",\n \"normalize\",\n \"not\",\n \"nth_value\",\n \"ntile\",\n \"null\",\n \"nullif\",\n \"numeric\",\n \"octet_length\",\n \"occurrences_regex\",\n \"of\",\n \"offset\",\n \"old\",\n \"omit\",\n \"on\",\n \"one\",\n \"only\",\n \"open\",\n \"or\",\n \"order\",\n \"out\",\n \"outer\",\n \"over\",\n \"overlaps\",\n \"overlay\",\n \"parameter\",\n \"partition\",\n \"pattern\",\n \"per\",\n \"percent\",\n \"percent_rank\",\n \"percentile_cont\",\n \"percentile_disc\",\n \"period\",\n \"portion\",\n \"position\",\n \"position_regex\",\n \"power\",\n \"precedes\",\n \"precision\",\n \"prepare\",\n \"primary\",\n \"procedure\",\n \"ptf\",\n \"range\",\n \"rank\",\n \"reads\",\n \"real\",\n \"recursive\",\n \"ref\",\n \"references\",\n \"referencing\",\n \"regr_avgx\",\n \"regr_avgy\",\n \"regr_count\",\n \"regr_intercept\",\n \"regr_r2\",\n \"regr_slope\",\n \"regr_sxx\",\n \"regr_sxy\",\n \"regr_syy\",\n \"release\",\n \"result\",\n \"return\",\n \"returns\",\n \"revoke\",\n \"right\",\n \"rollback\",\n \"rollup\",\n \"row\",\n \"row_number\",\n \"rows\",\n \"running\",\n \"savepoint\",\n \"scope\",\n \"scroll\",\n \"search\",\n \"second\",\n \"seek\",\n \"select\",\n \"sensitive\",\n \"session_user\",\n \"set\",\n \"show\",\n \"similar\",\n \"sin\",\n \"sinh\",\n \"skip\",\n \"smallint\",\n \"some\",\n \"specific\",\n \"specifictype\",\n \"sql\",\n \"sqlexception\",\n \"sqlstate\",\n \"sqlwarning\",\n \"sqrt\",\n \"start\",\n \"static\",\n \"stddev_pop\",\n \"stddev_samp\",\n \"submultiset\",\n \"subset\",\n \"substring\",\n \"substring_regex\",\n \"succeeds\",\n \"sum\",\n \"symmetric\",\n \"system\",\n \"system_time\",\n \"system_user\",\n \"table\",\n \"tablesample\",\n \"tan\",\n \"tanh\",\n \"then\",\n \"time\",\n \"timestamp\",\n \"timezone_hour\",\n \"timezone_minute\",\n \"to\",\n \"trailing\",\n \"translate\",\n \"translate_regex\",\n \"translation\",\n \"treat\",\n \"trigger\",\n \"trim\",\n \"trim_array\",\n \"true\",\n \"truncate\",\n \"uescape\",\n \"union\",\n \"unique\",\n \"unknown\",\n \"unnest\",\n \"update\",\n \"upper\",\n \"user\",\n \"using\",\n \"value\",\n \"values\",\n \"value_of\",\n \"var_pop\",\n \"var_samp\",\n \"varbinary\",\n \"varchar\",\n \"varying\",\n \"versioning\",\n \"when\",\n \"whenever\",\n \"where\",\n \"width_bucket\",\n \"window\",\n \"with\",\n \"within\",\n \"without\",\n \"year\",\n ];\n\n // these are reserved words we have identified to be functions\n // and should only be highlighted in a dispatch-like context\n // ie, array_agg(...), etc.\n const RESERVED_FUNCTIONS = [\n \"abs\",\n \"acos\",\n \"array_agg\",\n \"asin\",\n \"atan\",\n \"avg\",\n \"cast\",\n \"ceil\",\n \"ceiling\",\n \"coalesce\",\n \"corr\",\n \"cos\",\n \"cosh\",\n \"count\",\n \"covar_pop\",\n \"covar_samp\",\n \"cume_dist\",\n \"dense_rank\",\n \"deref\",\n \"element\",\n \"exp\",\n \"extract\",\n \"first_value\",\n \"floor\",\n \"json_array\",\n \"json_arrayagg\",\n \"json_exists\",\n \"json_object\",\n \"json_objectagg\",\n \"json_query\",\n \"json_table\",\n \"json_table_primitive\",\n \"json_value\",\n \"lag\",\n \"last_value\",\n \"lead\",\n \"listagg\",\n \"ln\",\n \"log\",\n \"log10\",\n \"lower\",\n \"max\",\n \"min\",\n \"mod\",\n \"nth_value\",\n \"ntile\",\n \"nullif\",\n \"percent_rank\",\n \"percentile_cont\",\n \"percentile_disc\",\n \"position\",\n \"position_regex\",\n \"power\",\n \"rank\",\n \"regr_avgx\",\n \"regr_avgy\",\n \"regr_count\",\n \"regr_intercept\",\n \"regr_r2\",\n \"regr_slope\",\n \"regr_sxx\",\n \"regr_sxy\",\n \"regr_syy\",\n \"row_number\",\n \"sin\",\n \"sinh\",\n \"sqrt\",\n \"stddev_pop\",\n \"stddev_samp\",\n \"substring\",\n \"substring_regex\",\n \"sum\",\n \"tan\",\n \"tanh\",\n \"translate\",\n \"translate_regex\",\n \"treat\",\n \"trim\",\n \"trim_array\",\n \"unnest\",\n \"upper\",\n \"value_of\",\n \"var_pop\",\n \"var_samp\",\n \"width_bucket\",\n ];\n\n // these functions can\n const POSSIBLE_WITHOUT_PARENS = [\n \"current_catalog\",\n \"current_date\",\n \"current_default_transform_group\",\n \"current_path\",\n \"current_role\",\n \"current_schema\",\n \"current_transform_group_for_type\",\n \"current_user\",\n \"session_user\",\n \"system_time\",\n \"system_user\",\n \"current_time\",\n \"localtime\",\n \"current_timestamp\",\n \"localtimestamp\"\n ];\n\n // those exist to boost relevance making these very\n // \"SQL like\" keyword combos worth +1 extra relevance\n const COMBOS = [\n \"create table\",\n \"insert into\",\n \"primary key\",\n \"foreign key\",\n \"not null\",\n \"alter table\",\n \"add constraint\",\n \"grouping sets\",\n \"on overflow\",\n \"character set\",\n \"respect nulls\",\n \"ignore nulls\",\n \"nulls first\",\n \"nulls last\",\n \"depth first\",\n \"breadth first\"\n ];\n\n const FUNCTIONS = RESERVED_FUNCTIONS;\n\n const KEYWORDS = [\n ...RESERVED_WORDS,\n ...NON_RESERVED_WORDS\n ].filter((keyword) => {\n return !RESERVED_FUNCTIONS.includes(keyword);\n });\n\n const VARIABLE = {\n scope: \"variable\",\n match: /@[a-z0-9][a-z0-9_]*/,\n };\n\n const OPERATOR = {\n scope: \"operator\",\n match: /[-+*/=%^~]|&&?|\\|\\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,\n relevance: 0,\n };\n\n const FUNCTION_CALL = {\n match: regex.concat(/\\b/, regex.either(...FUNCTIONS), /\\s*\\(/),\n relevance: 0,\n keywords: { built_in: FUNCTIONS }\n };\n\n // turns a multi-word keyword combo into a regex that doesn't\n // care about extra whitespace etc.\n // input: \"START QUERY\"\n // output: /\\bSTART\\s+QUERY\\b/\n function kws_to_regex(list) {\n return regex.concat(\n /\\b/,\n regex.either(...list.map((kw) => {\n return kw.replace(/\\s+/, \"\\\\s+\")\n })),\n /\\b/\n )\n }\n\n const MULTI_WORD_KEYWORDS = {\n scope: \"keyword\",\n match: kws_to_regex(COMBOS),\n relevance: 0,\n };\n\n // keywords with less than 3 letters are reduced in relevancy\n function reduceRelevancy(list, {\n exceptions, when\n } = {}) {\n const qualifyFn = when;\n exceptions = exceptions || [];\n return list.map((item) => {\n if (item.match(/\\|\\d+$/) || exceptions.includes(item)) {\n return item;\n } else if (qualifyFn(item)) {\n return `${item}|0`;\n } else {\n return item;\n }\n });\n }\n\n return {\n name: 'SQL',\n case_insensitive: true,\n // does not include {} or HTML tags `</`\n illegal: /[{}]|<\\//,\n keywords: {\n $pattern: /\\b[\\w\\.]+/,\n keyword:\n reduceRelevancy(KEYWORDS, { when: (x) => x.length < 3 }),\n literal: LITERALS,\n type: TYPES,\n built_in: POSSIBLE_WITHOUT_PARENS\n },\n contains: [\n {\n scope: \"type\",\n match: kws_to_regex(MULTI_WORD_TYPES)\n },\n MULTI_WORD_KEYWORDS,\n FUNCTION_CALL,\n VARIABLE,\n STRING,\n QUOTED_IDENTIFIER,\n hljs.C_NUMBER_MODE,\n hljs.C_BLOCK_COMMENT_MODE,\n COMMENT_MODE,\n OPERATOR\n ]\n };\n}\n\nexport { sql as default };\n","/**\n * CodeBlock Component\n * Displays syntax-highlighted code with copy-to-clipboard functionality\n */\n\nimport React, { useState, useEffect, useRef } from 'react'\nimport hljs from 'highlight.js/lib/core'\nimport json from 'highlight.js/lib/languages/json'\nimport sql from 'highlight.js/lib/languages/sql'\nimport { getIcon } from '../../icons'\nimport './CodeBlock.css'\n\n// Register languages\nhljs.registerLanguage('json', json)\nhljs.registerLanguage('sql', sql)\n\ninterface CodeBlockProps {\n code: string\n language: 'json' | 'sql'\n title?: string\n maxHeight?: string\n height?: string\n className?: string\n}\n\nexport const CodeBlock: React.FC<CodeBlockProps> = ({\n code,\n language,\n title,\n maxHeight = '16rem',\n height,\n className = ''\n}) => {\n const [copied, setCopied] = useState(false)\n const codeRef = useRef<HTMLElement>(null)\n const CopyIcon = getIcon('copy')\n const CheckIcon = getIcon('check')\n\n // Apply syntax highlighting\n useEffect(() => {\n if (codeRef.current && code) {\n codeRef.current.innerHTML = hljs.highlight(code, { language }).value\n }\n }, [code, language])\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Fallback for older browsers\n const textArea = document.createElement('textarea')\n textArea.value = code\n textArea.style.position = 'fixed'\n textArea.style.left = '-999999px'\n document.body.appendChild(textArea)\n textArea.select()\n document.execCommand('copy')\n document.body.removeChild(textArea)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n return (\n <div className={`relative ${className}`}>\n {/* Header with title and copy button */}\n <div className=\"flex items-center justify-between mb-2\">\n {title && (\n <h4 className=\"text-sm font-semibold text-dc-text\">{title}</h4>\n )}\n <button\n onClick={handleCopy}\n className=\"ml-auto px-2 py-1 text-xs rounded hover:bg-dc-surface-secondary border border-dc-border transition-colors flex items-center gap-1.5\"\n title={copied ? 'Copied!' : 'Copy to clipboard'}\n >\n {copied ? (\n <>\n <CheckIcon className=\"w-3.5 h-3.5 text-dc-success\" />\n <span className=\"text-dc-success\">Copied</span>\n </>\n ) : (\n <>\n <CopyIcon className=\"w-3.5 h-3.5 text-dc-text-secondary\" />\n <span className=\"text-dc-text-secondary\">Copy</span>\n </>\n )}\n </button>\n </div>\n\n {/* Code block with syntax highlighting */}\n <div\n className=\"bg-dc-surface-secondary border border-dc-border rounded overflow-auto\"\n style={height ? { height, minHeight: height, maxHeight: height } : { maxHeight }}\n >\n <pre className=\"p-3 text-xs m-0\">\n <code\n ref={codeRef}\n className={`hljs language-${language}`}\n >\n {code}\n </code>\n </pre>\n </div>\n </div>\n )\n}\n\nexport default CodeBlock\n","/**\n * Smart Chart Defaulting System\n *\n * Provides intelligent chart type selection and configuration based on\n * the user's current metrics and breakdowns selection.\n */\n\nimport type { ChartType, ChartAxisConfig } from '../types'\nimport type { MetricItem, BreakdownItem } from '../components/AnalysisBuilder/types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Result of smart chart defaults calculation\n */\nexport interface SmartChartDefaults {\n /** The recommended chart type */\n chartType: ChartType\n /** The auto-configured chart axis settings */\n chartConfig: ChartAxisConfig\n}\n\n/**\n * Availability status for a chart type\n */\nexport interface ChartAvailability {\n /** Whether the chart type can be used with current selections */\n available: boolean\n /** Reason why the chart is unavailable (for tooltip) */\n reason?: string\n}\n\n/**\n * Map of chart type availability statuses\n */\nexport type ChartAvailabilityMap = Record<ChartType, ChartAvailability>\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if a breakdown is a time dimension\n */\nfunction isTimeDimension(breakdown: BreakdownItem): boolean {\n return breakdown.isTimeDimension\n}\n\n/**\n * Get the first time dimension from breakdowns, if any\n */\nfunction getFirstTimeDimension(breakdowns: BreakdownItem[]): BreakdownItem | undefined {\n return breakdowns.find(isTimeDimension)\n}\n\n/**\n * Get the first non-time dimension from breakdowns, if any\n */\nfunction getFirstDimension(breakdowns: BreakdownItem[]): BreakdownItem | undefined {\n return breakdowns.find((b) => !b.isTimeDimension)\n}\n\n/**\n * Get all non-time dimensions\n */\nfunction getDimensions(breakdowns: BreakdownItem[]): BreakdownItem[] {\n return breakdowns.filter((b) => !b.isTimeDimension)\n}\n\n/**\n * Get all time dimensions\n */\nfunction getTimeDimensions(breakdowns: BreakdownItem[]): BreakdownItem[] {\n return breakdowns.filter(isTimeDimension)\n}\n\n// ============================================================================\n// Chart Availability\n// ============================================================================\n\n/**\n * Check if a specific chart type is available given current selections\n */\nexport function getChartAvailability(\n chartType: ChartType,\n metrics: MetricItem[],\n breakdowns: BreakdownItem[]\n): ChartAvailability {\n const measureCount = metrics.length\n const dimensionCount = getDimensions(breakdowns).length\n const timeDimensionCount = getTimeDimensions(breakdowns).length\n const totalBreakdowns = breakdowns.length\n\n switch (chartType) {\n // Always available charts\n case 'table':\n case 'markdown':\n return { available: true }\n\n // Measure-only charts (KPI Number, KPI Text)\n case 'kpiNumber':\n case 'kpiText':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n return { available: true }\n\n // Bar chart - needs dimension for categories + measure for values\n case 'bar':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (totalBreakdowns < 1) {\n return { available: false, reason: 'Requires at least 1 breakdown for categories' }\n }\n return { available: true }\n\n // KPI Delta - needs dimension for ordering + measure for values\n case 'kpiDelta':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (totalBreakdowns < 1) {\n return { available: false, reason: 'Requires at least 1 breakdown for ordering' }\n }\n return { available: true }\n\n // Line and area charts - need dimension/time + measure\n case 'line':\n case 'area':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (totalBreakdowns < 1) {\n return { available: false, reason: 'Requires a breakdown (dimension or time)' }\n }\n return { available: true }\n\n // Pie chart - needs dimension (not time) + measure\n case 'pie':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires 1 measure' }\n }\n if (dimensionCount < 1) {\n return { available: false, reason: 'Requires 1 dimension (not time dimension)' }\n }\n return { available: true }\n\n // Scatter - needs measure + any breakdown\n case 'scatter':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n // Scatter can work with just measures (x and y from different measures)\n // or with dimension + measure\n if (measureCount < 2 && totalBreakdowns < 1) {\n return { available: false, reason: 'Requires 2 measures or 1 measure + 1 breakdown' }\n }\n return { available: true }\n\n // Bubble - needs 2+ measures and 1+ breakdown (dimension or time dimension for series)\n case 'bubble':\n if (measureCount < 2) {\n return { available: false, reason: 'Requires at least 2 measures' }\n }\n if (totalBreakdowns < 1) {\n return { available: false, reason: 'Requires at least 1 breakdown for series grouping' }\n }\n return { available: true }\n\n // Radar - needs dimension + measure\n case 'radar':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (dimensionCount < 1) {\n return { available: false, reason: 'Requires at least 1 dimension' }\n }\n return { available: true }\n\n // Radial Bar - needs dimension + measure\n case 'radialBar':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (dimensionCount < 1) {\n return { available: false, reason: 'Requires at least 1 dimension' }\n }\n return { available: true }\n\n // Treemap - needs dimension + measure\n case 'treemap':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (dimensionCount < 1) {\n return { available: false, reason: 'Requires at least 1 dimension' }\n }\n return { available: true }\n\n // Activity Grid - needs time dimension + measure\n case 'activityGrid':\n if (measureCount < 1) {\n return { available: false, reason: 'Requires at least 1 measure' }\n }\n if (timeDimensionCount < 1) {\n return { available: false, reason: 'Requires a time dimension' }\n }\n return { available: true }\n\n default:\n // Unknown chart type - assume available\n return { available: true }\n }\n}\n\n/**\n * Get availability for all chart types\n */\nexport function getAllChartAvailability(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[]\n): ChartAvailabilityMap {\n // Chart types in alphabetical order (matching ChartTypeSelector display)\n const chartTypes: ChartType[] = [\n 'activityGrid',\n 'area',\n 'bar',\n 'bubble',\n 'kpiDelta',\n 'kpiNumber',\n 'kpiText',\n 'line',\n 'markdown',\n 'pie',\n 'radar',\n 'radialBar',\n 'scatter',\n 'table',\n 'treemap'\n ]\n\n const availability: Partial<ChartAvailabilityMap> = {}\n for (const chartType of chartTypes) {\n availability[chartType] = getChartAvailability(chartType, metrics, breakdowns)\n }\n\n return availability as ChartAvailabilityMap\n}\n\n// ============================================================================\n// Smart Chart Type Selection\n// ============================================================================\n\n/**\n * Select the best chart type based on current metrics and breakdowns\n *\n * Priority order:\n * 1. If current chart type is still valid, keep it (preserve user intent)\n * 2. If current chart becomes invalid, switch to best alternative:\n * - Has time dimension → line\n * - Has dimension + measure → bar\n * - Has measures only → bar (or kpiNumber if single measure + no breakdowns)\n * - No fields → keep current\n */\nexport function selectBestChartType(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n currentChartType: ChartType\n): ChartType {\n // Check if current chart type is still valid\n const currentAvailability = getChartAvailability(currentChartType, metrics, breakdowns)\n if (currentAvailability.available) {\n return currentChartType\n }\n\n // No fields selected - keep current\n if (metrics.length === 0 && breakdowns.length === 0) {\n return currentChartType\n }\n\n const hasTimeDimension = getTimeDimensions(breakdowns).length > 0\n const hasDimension = getDimensions(breakdowns).length > 0\n const hasMeasure = metrics.length > 0\n\n // Priority selection logic\n if (hasTimeDimension && hasMeasure) {\n // Time series data → line chart\n return 'line'\n }\n\n if (hasDimension && hasMeasure) {\n // Categorical data with measures → bar chart\n return 'bar'\n }\n\n if (hasMeasure && !hasDimension && !hasTimeDimension) {\n // Measures only, no breakdowns → KPI number (works with just measures)\n return 'kpiNumber'\n }\n\n // Fallback to table as most versatile (works with any combination)\n return 'table'\n}\n\n// ============================================================================\n// Smart Chart Config Defaults\n// ============================================================================\n\n/**\n * Get smart default chart configuration based on chart type and selections\n */\nexport function getSmartChartDefaults(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n currentChartType: ChartType\n): SmartChartDefaults {\n // First, determine the best chart type\n const chartType = selectBestChartType(metrics, breakdowns, currentChartType)\n\n // Then, auto-configure the chart axes based on chart type\n const chartConfig = buildChartConfig(chartType, metrics, breakdowns)\n\n return { chartType, chartConfig }\n}\n\n/**\n * Build optimal chart configuration for a given chart type\n */\nfunction buildChartConfig(\n chartType: ChartType,\n metrics: MetricItem[],\n breakdowns: BreakdownItem[]\n): ChartAxisConfig {\n const timeDimension = getFirstTimeDimension(breakdowns)\n const dimension = getFirstDimension(breakdowns)\n const dimensions = getDimensions(breakdowns)\n const allBreakdowns = breakdowns\n\n switch (chartType) {\n case 'line':\n case 'area':\n // Line/Area: xAxis = first time dimension (prefer) or dimension\n // yAxis = all measures, series = optional second dimension\n return {\n xAxis: timeDimension\n ? [timeDimension.field]\n : dimension\n ? [dimension.field]\n : [],\n yAxis: metrics.map((m) => m.field),\n series:\n dimensions.length > 1\n ? [dimensions[1].field]\n : dimension && timeDimension\n ? [dimension.field]\n : []\n }\n\n case 'bar':\n // Bar: xAxis = first dimension (prefer non-time), yAxis = all measures\n return {\n xAxis: dimension\n ? [dimension.field]\n : timeDimension\n ? [timeDimension.field]\n : [],\n yAxis: metrics.map((m) => m.field),\n series:\n dimensions.length > 1\n ? [dimensions[1].field]\n : timeDimension && dimension\n ? [timeDimension.field]\n : []\n }\n\n case 'pie':\n // Pie: xAxis = first dimension (exactly 1), yAxis = first measure (exactly 1)\n return {\n xAxis: dimension ? [dimension.field] : [],\n yAxis: metrics.length > 0 ? [metrics[0].field] : []\n }\n\n case 'scatter':\n // Scatter: xAxis = first dimension or measure, yAxis = first/second measure\n if (metrics.length >= 2) {\n return {\n xAxis: [metrics[0].field],\n yAxis: [metrics[1].field],\n series: dimension ? [dimension.field] : []\n }\n }\n return {\n xAxis: allBreakdowns.length > 0 ? [allBreakdowns[0].field] : [],\n yAxis: metrics.length > 0 ? [metrics[0].field] : [],\n series: dimensions.length > 1 ? [dimensions[1].field] : []\n }\n\n case 'bubble':\n // Bubble: xAxis = first measure, yAxis = second measure, sizeField = third measure (or second if only 2)\n // series = first breakdown (dimension or time dimension) for grouping/coloring\n return {\n xAxis: metrics.length > 0 ? [metrics[0].field] : [],\n yAxis: metrics.length > 1 ? [metrics[1].field] : [],\n sizeField: metrics.length > 2 ? metrics[2].field : metrics.length > 1 ? metrics[1].field : undefined,\n series: dimension ? [dimension.field] : timeDimension ? [timeDimension.field] : []\n }\n\n case 'radar':\n case 'radialBar':\n case 'treemap':\n // These all use dimension for categories and measure for values\n return {\n xAxis: dimension ? [dimension.field] : [],\n yAxis: metrics.length > 0 ? [metrics[0].field] : []\n }\n\n case 'activityGrid':\n // Activity Grid: dateField = time dimension, valueField = measure\n return {\n dateField: timeDimension ? [timeDimension.field] : [],\n valueField: metrics.length > 0 ? [metrics[0].field] : []\n }\n\n case 'kpiNumber':\n case 'kpiDelta':\n case 'kpiText':\n // KPI charts: just need the measure\n return {\n yAxis: metrics.length > 0 ? [metrics[0].field] : []\n }\n\n case 'table':\n // Table: include all fields\n return {\n xAxis: [\n ...breakdowns.map((b) => b.field),\n ...metrics.map((m) => m.field)\n ]\n }\n\n case 'markdown':\n // Markdown doesn't need chart config\n return {}\n\n default:\n // Default fallback - x = first breakdown, y = all measures\n return {\n xAxis: allBreakdowns.length > 0 ? [allBreakdowns[0].field] : [],\n yAxis: metrics.map((m) => m.field)\n }\n }\n}\n\n// ============================================================================\n// Update Logic for AnalysisBuilder\n// ============================================================================\n\n/**\n * Determine if chart type should be auto-switched based on selections change\n *\n * Returns the new chart type if a switch is recommended, or null if no change needed.\n *\n * @param metrics - Current metrics selection\n * @param breakdowns - Current breakdowns selection\n * @param currentChartType - Current chart type\n * @param userManuallySelected - Whether user manually selected the current chart type\n */\nexport function shouldAutoSwitchChartType(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n currentChartType: ChartType,\n userManuallySelected: boolean\n): ChartType | null {\n // If user manually selected this chart type, only switch if it becomes invalid\n if (userManuallySelected) {\n const availability = getChartAvailability(currentChartType, metrics, breakdowns)\n if (availability.available) {\n return null // Keep user's choice\n }\n }\n\n // Check if a better chart type should be used\n const recommendedType = selectBestChartType(metrics, breakdowns, currentChartType)\n\n // Only suggest switch if recommended type is different\n if (recommendedType !== currentChartType) {\n return recommendedType\n }\n\n return null\n}\n\n/**\n * Check if a chart config field references valid fields from metrics/breakdowns\n */\nfunction isValidConfigField(\n fieldValue: string | string[] | undefined,\n validFields: Set<string>\n): boolean {\n if (!fieldValue) return false\n if (Array.isArray(fieldValue)) {\n return fieldValue.length > 0 && fieldValue.every((f) => validFields.has(f))\n }\n return validFields.has(fieldValue)\n}\n\n/**\n * Merge existing chart config with smart defaults\n * Only fills in missing or invalid fields, preserves valid existing config\n */\nexport function mergeChartConfigWithDefaults(\n existingConfig: ChartAxisConfig,\n smartDefaults: ChartAxisConfig,\n metrics: MetricItem[],\n breakdowns: BreakdownItem[]\n): ChartAxisConfig {\n // Build set of valid field names\n const validFields = new Set<string>([\n ...metrics.map((m) => m.field),\n ...breakdowns.map((b) => b.field)\n ])\n\n const result: ChartAxisConfig = {}\n\n // For each key in smart defaults, use existing value if valid, otherwise use default\n const allKeys = new Set([\n ...Object.keys(existingConfig),\n ...Object.keys(smartDefaults)\n ]) as Set<keyof ChartAxisConfig>\n\n for (const key of allKeys) {\n const existingValue = existingConfig[key]\n const defaultValue = smartDefaults[key]\n\n // Check if existing value is valid\n if (isValidConfigField(existingValue as string | string[] | undefined, validFields)) {\n // Keep existing valid config\n result[key] = existingValue as any\n } else if (defaultValue !== undefined) {\n // Use smart default\n result[key] = defaultValue as any\n }\n // If neither exists or is valid, leave undefined\n }\n\n return result\n}\n","/**\n * Color Palette Selector Component\n * Allows users to select from predefined color palettes for their dashboard\n */\n\nimport { useState, useRef, useEffect } from 'react'\nimport { COLOR_PALETTES, getColorPalette } from '../utils/colorPalettes'\nimport { getIcon } from '../icons'\n\nconst ChevronDownIcon = getIcon('chevronDown')\n\ninterface ColorPaletteSelectorProps {\n currentPalette?: string\n onPaletteChange: (paletteName: string) => void\n className?: string\n}\n\nexport default function ColorPaletteSelector({\n currentPalette = 'default',\n onPaletteChange,\n className = ''\n}: ColorPaletteSelectorProps) {\n const [isOpen, setIsOpen] = useState(false)\n const dropdownRef = useRef<HTMLDivElement>(null)\n \n const currentPaletteObj = getColorPalette(currentPalette)\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false)\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [isOpen])\n\n const handlePaletteSelect = (paletteName: string) => {\n onPaletteChange(paletteName)\n setIsOpen(false)\n }\n\n return (\n <div className={`relative ${className}`} ref={dropdownRef}>\n {/* Trigger Button */}\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 bg-dc-surface border border-dc-border rounded-md shadow-xs text-sm font-medium text-dc-text-secondary hover:bg-dc-surface-hover focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-dc-accent\"\n >\n {/* Current Palette Preview - Hidden on mobile */}\n <div className=\"hidden md:flex items-center gap-1.5\">\n <div className=\"flex gap-0.5\">\n {currentPaletteObj.colors.slice(0, 4).map((color, index) => (\n <div\n key={index}\n className=\"w-3 h-3 rounded-xs border border-dc-border\"\n style={{ backgroundColor: color }}\n title={`Series Color ${index + 1}`}\n />\n ))}\n </div>\n <span className=\"text-xs text-dc-text-secondary\">|</span>\n <div className=\"flex gap-0.5\">\n {currentPaletteObj.gradient.slice(0, 3).map((color, index) => (\n <div\n key={index}\n className=\"w-2 h-3 border-r first:rounded-l-sm last:rounded-r-sm last:border-r-0\"\n style={{\n backgroundColor: color,\n borderColor: 'var(--dc-border)'\n }}\n title={`Gradient Color ${index + 1}`}\n />\n ))}\n </div>\n </div>\n <span>{currentPaletteObj.label}</span>\n <ChevronDownIcon \n className={`w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : ''}`} \n />\n </button>\n\n {/* Dropdown Menu - Responsive width */}\n {isOpen && (\n <div className=\"absolute top-full left-0 mt-1 w-72 md:w-80 lg:w-96 bg-dc-surface border border-dc-border rounded-md shadow-lg z-50 max-h-80 overflow-y-auto\">\n <div className=\"py-1\">\n {COLOR_PALETTES.slice().sort((a, b) => a.label.localeCompare(b.label)).map((palette) => (\n <button\n key={palette.name}\n type=\"button\"\n onClick={() => handlePaletteSelect(palette.name)}\n className={`w-full px-3 py-2 text-left text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover ${\n palette.name === currentPalette ? 'bg-dc-surface-secondary' : 'text-dc-text-secondary'\n }`}\n style={palette.name === currentPalette ? { color: 'var(--dc-primary)' } : undefined}\n >\n <div className=\"flex items-center gap-3\">\n {/* Palette Preview - Hidden on mobile */}\n <div className=\"hidden md:flex items-center gap-2\">\n {/* Series Colors */}\n <div className=\"flex gap-0.5\">\n {palette.colors.slice(0, 6).map((color, index) => (\n <div\n key={`series-${index}`}\n className=\"w-3 h-3 rounded-xs border border-dc-border\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n\n {/* Separator */}\n <div className=\"w-px h-4 bg-dc-border\" />\n \n {/* Gradient Colors */}\n <div className=\"flex\">\n {palette.gradient.map((color, index) => (\n <div\n key={`gradient-${index}`}\n className=\"w-2 h-4 first:rounded-l-sm last:rounded-r-sm\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n </div>\n \n {/* Palette Name */}\n <span className=\"font-medium\">{palette.label}</span>\n \n {/* Current Indicator */}\n {palette.name === currentPalette && (\n <div className=\"ml-auto\">\n <div className=\"w-2 h-2 rounded-full\" style={{ backgroundColor: 'var(--dc-primary)' }}></div>\n </div>\n )}\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}","/**\n * AnalysisResultsPanel Component\n *\n * Displays query execution results with chart and table views.\n * Used in the left panel of AnalysisBuilder.\n */\n\nimport { useState, useEffect, useMemo, memo } from 'react'\nimport type { AnalysisResultsPanelProps } from './types'\nimport { LazyChart, isValidChartType } from '../../charts/ChartLoader'\nimport { getIcon } from '../../icons'\nimport { QueryAnalysisPanel, CodeBlock } from '../../shared'\nimport ColorPaletteSelector from '../ColorPaletteSelector'\n\n/**\n * AnalysisResultsPanel displays query results with chart/table toggle.\n *\n * Features:\n * - Chart visualization with LazyChart\n * - Table view with DataTable\n * - Loading, error, and empty states\n * - Stale results indicator\n * - Display limit control for tables\n */\nconst AnalysisResultsPanel = memo(function AnalysisResultsPanel({\n executionStatus,\n executionResults,\n executionError,\n totalRowCount,\n resultsStale = false,\n chartType = 'line',\n chartConfig = {},\n displayConfig = {},\n colorPalette,\n currentPaletteName,\n onColorPaletteChange,\n allQueries,\n activeView = 'chart',\n onActiveViewChange,\n displayLimit = 100,\n onDisplayLimitChange,\n hasMetrics = false,\n // Debug props - per-query for multi-query mode\n debugDataPerQuery = [],\n // Share props\n onShareClick,\n canShare = false,\n shareButtonState = 'idle',\n // Clear functionality\n onClearClick,\n canClear = false,\n // AI functionality\n enableAI = false,\n isAIOpen = false,\n onAIToggle,\n // Multi-query props\n queryCount = 1,\n perQueryResults,\n activeTableIndex = 0,\n onActiveTableChange\n}: AnalysisResultsPanelProps) {\n // Debug view toggle state\n const [showDebug, setShowDebug] = useState(false)\n // Active debug query tab (independent of main query tabs)\n const [activeDebugIndex, setActiveDebugIndex] = useState(0)\n\n // Clamp activeDebugIndex when queries are removed\n useEffect(() => {\n if (debugDataPerQuery.length > 0 && activeDebugIndex >= debugDataPerQuery.length) {\n setActiveDebugIndex(debugDataPerQuery.length - 1)\n }\n }, [debugDataPerQuery.length, activeDebugIndex])\n\n // Get current debug data based on active index\n const currentDebugData = debugDataPerQuery[activeDebugIndex] || {\n sql: null,\n analysis: null,\n loading: false,\n error: null\n }\n const debugSql = currentDebugData.sql\n const debugAnalysis = currentDebugData.analysis\n const debugLoading = currentDebugData.loading\n const debugError = currentDebugData.error\n // Get the query for the active debug tab\n const debugQuery = allQueries?.[activeDebugIndex] || null\n // Force table view when no metrics are selected\n useEffect(() => {\n if (!hasMetrics && activeView === 'chart') {\n onActiveViewChange('table')\n }\n }, [hasMetrics, activeView, onActiveViewChange])\n\n // Create a combined query object for the chart (includes measures from ALL queries)\n const combinedQueryForChart = useMemo(() => {\n if (!allQueries || allQueries.length === 0) return undefined\n if (allQueries.length === 1) return allQueries[0]\n\n // Combine measures from all queries, dimensions are shared (from Q1)\n const allMeasures = allQueries.flatMap(q => q?.measures || [])\n return {\n ...allQueries[0],\n measures: allMeasures\n }\n }, [allQueries])\n\n // Icons\n const SuccessIcon = getIcon('success')\n const ErrorIcon = getIcon('error')\n const WarningIcon = getIcon('warning')\n const TableIcon = getIcon('table')\n const ChartIcon = getIcon('measure')\n const CodeIcon = getIcon('codeBracket')\n const ShareIcon = getIcon('share')\n const CheckIcon = getIcon('check')\n const TrashIcon = getIcon('delete')\n const SparklesIcon = getIcon('sparkles')\n\n // Loading state - initial load\n const renderLoading = () => (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center\">\n <div\n className=\"animate-spin rounded-full h-12 w-12 border-b-2 mx-auto mb-4\"\n style={{ borderBottomColor: 'var(--dc-primary)' }}\n />\n <div className=\"text-sm font-semibold text-dc-text-secondary mb-1\">\n Executing Query...\n </div>\n <div className=\"text-xs text-dc-text-muted\">\n Running your query against the cube API\n </div>\n </div>\n </div>\n )\n\n // Error state - no previous results\n const renderError = () => (\n <div className=\"h-full flex flex-col\">\n {renderHeader()}\n <div className=\"flex-1 flex items-center justify-center p-4\">\n {showDebug ? (\n <div className=\"w-full h-full overflow-auto\">\n {renderDebug()}\n </div>\n ) : (\n <div className=\"text-center max-w-md\">\n <ErrorIcon className=\"w-12 h-12 mx-auto text-dc-error mb-4\" />\n <div className=\"text-sm font-semibold text-dc-text mb-2\">\n Query Execution Failed\n </div>\n <div className=\"text-sm text-dc-text-secondary mb-4\">\n There was an error executing your query. Please check the query and try again.\n </div>\n {executionError && (\n <div className=\"bg-dc-danger-bg border border-dc-error rounded-lg p-3 text-left\">\n <div className=\"text-xs font-mono text-dc-error break-words\">\n {executionError}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )\n\n // Check if any query has content (pending execution)\n const hasQueryContent = !!(allQueries?.some(q =>\n (q?.measures && q.measures.length > 0) ||\n (q?.dimensions && q.dimensions.length > 0) ||\n (q?.timeDimensions && q.timeDimensions.length > 0)\n ))\n\n // Waiting state - query built but not yet executed (debounce period)\n const renderWaiting = () => (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center\">\n <div\n className=\"animate-spin rounded-full h-12 w-12 border-b-2 mx-auto mb-4\"\n style={{ borderBottomColor: 'var(--dc-primary)' }}\n />\n <div className=\"text-sm font-semibold text-dc-text-secondary mb-1\">\n Preparing Query...\n </div>\n <div className=\"text-xs text-dc-text-muted\">\n Your query will execute shortly\n </div>\n </div>\n </div>\n )\n\n // Empty state - no query built yet\n const renderEmpty = () => (\n <div className=\"h-full flex items-center justify-center pt-6\">\n <div className=\"text-center mb-16\">\n <ChartIcon className=\"w-12 h-12 mx-auto text-dc-text-muted mb-3\" />\n <div className=\"text-sm font-semibold text-dc-text-secondary mb-1\">\n No Results Yet\n </div>\n <div className=\"text-xs text-dc-text-muted mb-4\">\n Add metrics or breakdowns from the panel on the right to see results\n </div>\n {/* Prominent AI button when enabled */}\n {enableAI && onAIToggle && (\n <button\n onClick={onAIToggle}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-dc-accent hover:bg-dc-accent rounded-lg transition-colors shadow-sm\"\n >\n <SparklesIcon className=\"w-4 h-4\" />\n Analyse with AI\n </button>\n )}\n </div>\n </div>\n )\n\n // No data returned state\n const renderNoData = () => (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center\">\n <SuccessIcon className=\"w-12 h-12 mx-auto text-dc-success mb-3\" />\n <div className=\"text-sm font-semibold text-dc-text mb-1\">\n Query Successful\n </div>\n <div className=\"text-xs text-dc-text-muted\">\n No data returned from the query\n </div>\n </div>\n </div>\n )\n\n // Render chart\n const renderChart = () => {\n if (!executionResults || executionResults.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full text-dc-text-muted\">\n <div className=\"text-center\">\n <ChartIcon className=\"w-12 h-12 mx-auto mb-3 opacity-50\" />\n <div className=\"text-sm font-semibold mb-1\">No data to display</div>\n <div className=\"text-xs\">Run a query to see chart visualization</div>\n </div>\n </div>\n )\n }\n\n if (!isValidChartType(chartType)) {\n return (\n <div className=\"flex items-center justify-center h-full text-dc-text-muted\">\n <div className=\"text-center\">\n <WarningIcon className=\"w-12 h-12 mx-auto mb-3 opacity-50\" />\n <div className=\"text-sm font-semibold mb-1\">Unsupported chart type</div>\n <div className=\"text-xs\">{chartType}</div>\n </div>\n </div>\n )\n }\n\n return (\n <LazyChart\n chartType={chartType}\n data={executionResults}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n colorPalette={colorPalette}\n queryObject={combinedQueryForChart}\n height=\"100%\"\n fallback={\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"animate-pulse bg-dc-surface-secondary rounded w-full h-full\" />\n </div>\n }\n />\n )\n }\n\n // Render debug view\n const renderDebug = () => (\n <div className=\"p-4 space-y-4 overflow-auto h-full\">\n {/* Query tabs for multi-query mode */}\n {debugDataPerQuery.length > 1 && (\n <div className=\"flex items-center gap-1 mb-4\">\n <span className=\"text-xs font-medium text-dc-text-muted mr-2\">Query:</span>\n <div className=\"flex border border-dc-border rounded-md overflow-hidden\">\n {debugDataPerQuery.map((data, idx) => (\n <button\n key={idx}\n onClick={() => setActiveDebugIndex(idx)}\n className={`px-3 py-1 text-xs font-medium transition-colors border-r last:border-r-0 border-dc-border ${\n activeDebugIndex === idx\n ? 'bg-dc-accent text-white'\n : 'bg-dc-bg text-dc-text-secondary hover:bg-dc-bg-secondary'\n }`}\n >\n Q{idx + 1}\n {data.loading && (\n <span className=\"ml-1 opacity-70\">•</span>\n )}\n {data.error && (\n <span className=\"ml-1 text-dc-error\">!</span>\n )}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Execution Error Banner (if any) */}\n {executionError && (\n <div className=\"bg-dc-danger-bg dark:bg-dc-danger-bg border border-dc-error dark:border-dc-error rounded p-3\">\n <h4 className=\"text-sm font-semibold text-dc-error dark:text-dc-error mb-1\">\n Execution Error\n </h4>\n <p className=\"text-sm text-dc-error dark:text-dc-error\">{executionError}</p>\n </div>\n )}\n\n {/* Query Analysis - full width (at top for visibility) */}\n <div>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Query Analysis</h4>\n {debugLoading ? (\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm\">\n Loading...\n </div>\n ) : debugAnalysis ? (\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3\">\n <QueryAnalysisPanel analysis={debugAnalysis} />\n </div>\n ) : (\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm\">\n {debugError ? 'Analysis unavailable due to error' : 'Add metrics to see analysis'}\n </div>\n )}\n </div>\n\n {/* Cube Query and SQL Query in 2 columns */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {/* Cube Query */}\n <div>\n {debugQuery ? (\n <CodeBlock\n code={JSON.stringify(debugQuery, null, 2)}\n language=\"json\"\n title=\"Cube Query\"\n height=\"16rem\"\n />\n ) : (\n <>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Cube Query</h4>\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm h-64 overflow-auto\">\n No query\n </div>\n </>\n )}\n </div>\n\n {/* Generated SQL */}\n <div>\n {debugLoading ? (\n <>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Generated SQL</h4>\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm h-64 overflow-auto\">\n Loading...\n </div>\n </>\n ) : debugError ? (\n <>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Generated SQL</h4>\n <div className=\"text-dc-error text-sm bg-dc-danger-bg dark:bg-dc-danger-bg p-3 rounded border border-dc-error dark:border-dc-error h-64 overflow-auto\">\n {debugError}\n </div>\n </>\n ) : debugSql ? (\n <CodeBlock\n code={\n debugSql.sql +\n (debugSql.params && debugSql.params.length > 0\n ? '\\n\\n-- Parameters:\\n' + JSON.stringify(debugSql.params, null, 2)\n : '')\n }\n language=\"sql\"\n title=\"Generated SQL\"\n height=\"16rem\"\n />\n ) : (\n <>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Generated SQL</h4>\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm h-64 overflow-auto\">\n Add metrics to generate SQL\n </div>\n </>\n )}\n </div>\n </div>\n\n {/* Chart Config & Display Config in 2 columns */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {/* Chart Config */}\n <div>\n <CodeBlock\n code={JSON.stringify(chartConfig, null, 2)}\n language=\"json\"\n title=\"Chart Config\"\n height=\"16rem\"\n />\n </div>\n\n {/* Display Config */}\n <div>\n <CodeBlock\n code={JSON.stringify(displayConfig, null, 2)}\n language=\"json\"\n title=\"Display Config\"\n height=\"16rem\"\n />\n </div>\n </div>\n\n {/* Server Response - full width */}\n <div>\n {executionResults ? (\n <CodeBlock\n code={JSON.stringify(executionResults, null, 2)}\n language=\"json\"\n title={`Server Response (${executionResults.length} rows)`}\n maxHeight=\"24rem\"\n />\n ) : (\n <>\n <h4 className=\"text-sm font-semibold text-dc-text mb-2\">Server Response</h4>\n <div className=\"bg-dc-surface-secondary border border-dc-border rounded p-3 text-dc-text-muted text-sm\">\n No results yet\n </div>\n </>\n )}\n </div>\n </div>\n )\n\n // Determine if we're in multi-query mode\n const isMultiQuery = queryCount > 1 && perQueryResults && perQueryResults.length > 1\n\n // Render table - uses per-query results in multi-query mode\n const renderTable = (tableIndex?: number) => {\n // In multi-query mode, use specific query's results and query object\n // tableIndex: undefined = single query, -1 = merged view, 0+ = per-query view\n let tableData: any[] | null = null\n let tableQuery = allQueries?.[0] // Default to first query\n\n if (isMultiQuery && tableIndex !== undefined && tableIndex >= 0 && perQueryResults) {\n // Per-query table view\n tableData = perQueryResults[tableIndex] || null\n tableQuery = allQueries?.[tableIndex]\n } else {\n // Merged view (tableIndex === -1) or single query mode\n tableData = executionResults\n // For merged view, use combined query\n if (isMultiQuery) {\n tableQuery = combinedQueryForChart\n }\n }\n\n if (!tableData || tableData.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full text-dc-text-muted\">\n <div className=\"text-center\">\n <TableIcon className=\"w-12 h-12 mx-auto mb-3 opacity-50\" />\n <div className=\"text-sm font-semibold mb-1\">No data to display</div>\n <div className=\"text-xs\">Run a query to see table data</div>\n </div>\n </div>\n )\n }\n\n // Apply display limit\n const limitedData = tableData.slice(0, displayLimit)\n\n return (\n <LazyChart\n chartType=\"table\"\n data={limitedData}\n colorPalette={colorPalette}\n queryObject={tableQuery}\n height=\"100%\"\n fallback={\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"animate-pulse bg-dc-surface-secondary rounded w-full h-full\" />\n </div>\n }\n />\n )\n }\n\n // Overlay spinner for refreshing\n const renderOverlaySpinner = () => (\n <div className=\"absolute inset-0 flex items-center justify-center bg-dc-surface bg-opacity-75 z-10\">\n <div className=\"text-center\">\n <div\n className=\"animate-spin rounded-full h-10 w-10 border-b-2 mx-auto mb-2\"\n style={{ borderBottomColor: 'var(--dc-primary)' }}\n />\n <div className=\"text-xs text-dc-text-secondary\">Refreshing results...</div>\n </div>\n </div>\n )\n\n // Render header - shown whenever we have query content\n const renderHeader = () => {\n const hasResults = executionResults && executionResults.length > 0\n\n return (\n <div className=\"px-4 py-2 border-b border-dc-border bg-dc-surface-secondary flex-shrink-0\">\n <div className=\"flex items-center justify-between\">\n {/* Left side: Status and row count */}\n <div className=\"flex items-center\">\n {executionStatus === 'refreshing' ? (\n <div\n className=\"w-4 h-4 mr-2 rounded-full border-b-2 animate-spin\"\n style={{ borderBottomColor: 'var(--dc-primary)' }}\n />\n ) : hasResults ? (\n <SuccessIcon className=\"w-4 h-4 text-dc-success mr-2\" />\n ) : executionStatus === 'error' ? (\n <ErrorIcon className=\"w-4 h-4 text-dc-error mr-2\" />\n ) : (\n <WarningIcon className=\"w-4 h-4 text-dc-text-muted mr-2\" />\n )}\n <span className=\"text-sm text-dc-text-secondary\">\n {hasResults ? (\n <>\n {executionResults.length} row{executionResults.length !== 1 ? 's' : ''}\n {totalRowCount !== null && totalRowCount > executionResults.length && (\n <span className=\"text-dc-text-muted\"> of {totalRowCount.toLocaleString()}</span>\n )}\n {resultsStale && (\n <span className=\"text-dc-warning ml-2\">• Results may be outdated</span>\n )}\n </>\n ) : executionStatus === 'error' ? (\n 'Query failed'\n ) : executionStatus === 'loading' ? (\n 'Executing...'\n ) : (\n 'No results'\n )}\n </span>\n </div>\n\n {/* Right side: Display limit (table only) and Debug toggle */}\n <div className=\"flex items-center gap-2\">\n {/* Display Limit (only for table view) */}\n {hasResults && activeView === 'table' && !showDebug && onDisplayLimitChange && (\n <select\n value={displayLimit}\n onChange={(e) => onDisplayLimitChange(Number(e.target.value))}\n className=\"text-xs border border-dc-border rounded px-2 py-1 bg-dc-surface text-dc-text focus:outline-none focus:ring-1 focus:ring-dc-primary\"\n >\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n <option value={250}>250 rows</option>\n <option value={500}>500 rows</option>\n </select>\n )}\n\n {/* AI Button - positioned before palette selector */}\n {enableAI && onAIToggle && (\n <button\n onClick={onAIToggle}\n className={`flex items-center gap-1 px-2 py-1.5 text-xs font-medium rounded transition-colors ${\n isAIOpen\n ? 'text-white bg-dc-accent border border-dc-accent'\n : 'text-dc-accent dark:text-dc-accent bg-dc-accent-bg dark:bg-dc-accent-bg border border-dc-accent dark:border-dc-accent hover:bg-dc-accent-bg dark:hover:bg-dc-accent-bg'\n }`}\n title={isAIOpen ? 'Close AI assistant' : 'Analyse with AI'}\n >\n <SparklesIcon className=\"w-3 h-3\" />\n <span className=\"hidden sm:inline\">Analyse with AI</span>\n </button>\n )}\n\n {/* Color Palette Selector (only when callback is provided, i.e., standalone mode) */}\n {onColorPaletteChange && hasResults && (\n <ColorPaletteSelector\n currentPalette={currentPaletteName || 'default'}\n onPaletteChange={onColorPaletteChange}\n />\n )}\n\n {/* Share Button */}\n {onShareClick && (\n <button\n onClick={onShareClick}\n className={`flex items-center gap-1 px-2 py-1.5 text-xs font-medium rounded transition-colors ${\n shareButtonState === 'idle' && canShare\n ? 'text-dc-accent dark:text-dc-accent bg-dc-accent-bg dark:bg-dc-accent-bg border border-dc-accent dark:border-dc-accent hover:bg-dc-accent-bg dark:hover:bg-dc-accent-bg'\n : shareButtonState !== 'idle'\n ? 'text-dc-success dark:text-dc-success bg-dc-success-bg dark:bg-dc-success-bg border border-dc-success dark:border-dc-success'\n : 'text-dc-text-muted bg-dc-surface-secondary border border-dc-border cursor-not-allowed'\n }`}\n title={shareButtonState === 'idle' ? 'Share this analysis' : 'Link copied!'}\n disabled={!canShare || shareButtonState !== 'idle'}\n >\n {shareButtonState === 'idle' ? (\n <>\n <ShareIcon className=\"w-3 h-3\" />\n <span className=\"hidden sm:inline\">Share</span>\n </>\n ) : shareButtonState === 'copied' ? (\n <>\n <CheckIcon className=\"w-3 h-3\" />\n <span className=\"hidden sm:inline\">Copied!</span>\n </>\n ) : (\n <>\n <CheckIcon className=\"w-3 h-3\" />\n <span className=\"hidden sm:inline\">Copied!</span>\n <span className=\"hidden lg:inline text-[10px] opacity-75\">(no chart)</span>\n </>\n )}\n </button>\n )}\n\n {/* Clear Button */}\n {onClearClick && canClear && (\n <button\n onClick={onClearClick}\n className=\"flex items-center gap-1 px-2 py-1.5 text-xs font-medium text-dc-text-secondary hover:text-dc-text bg-dc-surface hover:bg-dc-surface-hover border border-dc-border rounded transition-colors\"\n title=\"Clear all query data\"\n >\n <TrashIcon className=\"w-3 h-3\" />\n <span className=\"hidden sm:inline\">Clear</span>\n </button>\n )}\n\n {/* Debug Toggle Button */}\n <button\n onClick={() => setShowDebug(!showDebug)}\n className={`p-1.5 rounded transition-colors relative ${\n showDebug\n ? 'bg-dc-primary text-white'\n : 'text-dc-text-secondary hover:text-dc-text hover:bg-dc-surface-hover'\n }`}\n title={showDebug ? 'Hide debug info' : 'Show debug info'}\n >\n <CodeIcon className=\"w-4 h-4\" />\n {/* Error indicator dot - show if ANY query has an error */}\n {(executionError || debugDataPerQuery.some(d => d.error)) && !showDebug && (\n <span className=\"absolute -top-0.5 -right-0.5 w-2 h-2 bg-dc-danger-bg0 rounded-full\" />\n )}\n </button>\n </div>\n </div>\n\n {/* Performance Warning */}\n {hasResults && totalRowCount !== null && totalRowCount > 1000 && (\n <div className=\"mt-2 bg-dc-warning-bg border border-dc-warning rounded-lg p-2 flex items-start\">\n <WarningIcon className=\"w-4 h-4 text-dc-warning mr-2 shrink-0 mt-0.5\" />\n <div className=\"text-xs text-dc-warning\">\n <span className=\"font-semibold\">Large dataset:</span> {totalRowCount.toLocaleString()} rows.\n Consider adding filters to improve performance.\n </div>\n </div>\n )}\n </div>\n )\n }\n\n // Success state with data\n const renderSuccess = () => {\n const hasResults = executionResults && executionResults.length > 0\n\n if (!hasResults) {\n return (\n <div className=\"h-full flex flex-col\">\n {renderHeader()}\n <div className=\"flex-1 min-h-0 relative overflow-auto\">\n {showDebug ? renderDebug() : renderNoData()}\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"h-full flex flex-col\">\n {renderHeader()}\n\n {/* Results Content */}\n <div className=\"flex-1 min-h-0 relative overflow-auto\">\n {showDebug ? (\n renderDebug()\n ) : activeView === 'chart' ? (\n <div className=\"p-4 h-full\">{renderChart()}</div>\n ) : isMultiQuery ? (\n <div className=\"h-full\">{renderTable(activeTableIndex)}</div>\n ) : (\n <div className=\"h-full\">{renderTable()}</div>\n )}\n </div>\n\n {/* View Toggle - Below content, centered */}\n {!showDebug && (\n <div className=\"px-4 py-3 border-t border-dc-border bg-dc-surface flex justify-center flex-shrink-0\">\n <div className=\"flex items-center bg-dc-surface-secondary border border-dc-border rounded-md overflow-hidden\">\n {/* Chart button */}\n <button\n onClick={() => hasMetrics && onActiveViewChange('chart')}\n disabled={!hasMetrics}\n className={`flex items-center gap-1.5 px-4 py-1.5 text-sm font-medium transition-colors ${\n activeView === 'chart'\n ? 'bg-dc-primary text-white'\n : !hasMetrics\n ? 'text-dc-text-disabled bg-dc-surface-tertiary cursor-not-allowed'\n : 'text-dc-text-secondary hover:bg-dc-surface-hover'\n }`}\n title={hasMetrics ? 'Chart view' : 'Add metrics to enable chart view'}\n >\n <ChartIcon className=\"w-4 h-4\" />\n Chart\n </button>\n\n {/* Table buttons - show multiple when in multi-query mode */}\n {isMultiQuery ? (\n <>\n {/* Per-query table buttons */}\n {Array.from({ length: queryCount }).map((_, index) => (\n <button\n key={`table-${index}`}\n onClick={() => {\n onActiveViewChange('table')\n onActiveTableChange?.(index)\n }}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium transition-colors ${\n activeView === 'table' && activeTableIndex === index\n ? 'bg-dc-primary text-white'\n : 'text-dc-text-secondary hover:bg-dc-surface-hover'\n }`}\n title={`Table Q${index + 1}`}\n >\n <TableIcon className=\"w-4 h-4\" />\n Q{index + 1}\n </button>\n ))}\n {/* Merged table button */}\n <button\n onClick={() => {\n onActiveViewChange('table')\n onActiveTableChange?.(-1) // -1 = merged view\n }}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium transition-colors ${\n activeView === 'table' && activeTableIndex === -1\n ? 'bg-dc-primary text-white'\n : 'text-dc-text-secondary hover:bg-dc-surface-hover'\n }`}\n title=\"Merged table view\"\n >\n <TableIcon className=\"w-4 h-4\" />\n Merged\n </button>\n </>\n ) : (\n <button\n onClick={() => onActiveViewChange('table')}\n className={`flex items-center gap-1.5 px-4 py-1.5 text-sm font-medium transition-colors ${\n activeView === 'table'\n ? 'bg-dc-primary text-white'\n : 'text-dc-text-secondary hover:bg-dc-surface-hover'\n }`}\n title=\"Table view\"\n >\n <TableIcon className=\"w-4 h-4\" />\n Table\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n )\n }\n\n // Determine what to render based on execution status\n const hasResults = executionResults !== null\n\n // Don't show results if we're in idle state with no query content (cleared state)\n const shouldShowResults = hasResults && (executionStatus !== 'idle' || hasQueryContent)\n\n return (\n <div className=\"h-full min-h-[400px] flex flex-col bg-dc-surface relative\">\n {/* Main content */}\n {executionStatus === 'idle' && !hasQueryContent && renderEmpty()}\n {executionStatus === 'idle' && hasQueryContent && !hasResults && renderWaiting()}\n {executionStatus === 'loading' && !hasResults && renderLoading()}\n {executionStatus === 'error' && !hasResults && renderError()}\n {(executionStatus === 'success' || shouldShowResults) && renderSuccess()}\n\n {/* Overlay states */}\n {(executionStatus === 'loading' || executionStatus === 'refreshing') && hasResults && renderOverlaySpinner()}\n </div>\n )\n})\n\nexport default AnalysisResultsPanel\n","/**\n * MetricItemCard Component\n *\n * Displays a single metric item with remove button.\n */\n\nimport { memo } from 'react'\nimport type { MetricItemCardProps } from './types'\nimport { getIcon, getMeasureTypeIcon } from '../../icons'\n\n/**\n * MetricItemCard displays a selected metric with:\n * - Field icon based on measure type\n * - Field title or full name\n * - Sort toggle button (visible on hover, or always visible when sorted)\n * - Remove button (visible on hover)\n * - Drag handle for reordering\n */\nconst MetricItemCard = memo(function MetricItemCard({\n metric,\n fieldMeta,\n onRemove,\n sortDirection,\n sortPriority,\n onToggleSort,\n index,\n isDragging,\n onDragStart,\n onDragEnd\n}: MetricItemCardProps) {\n const CloseIcon = getIcon('close')\n const ChevronUpIcon = getIcon('chevronUp')\n const ChevronDownIcon = getIcon('chevronDown')\n const ChevronUpDownIcon = getIcon('chevronUpDown')\n\n // Get the appropriate icon based on measure type\n const measureType = fieldMeta?.type || 'count'\n const MeasureIcon = getMeasureTypeIcon(measureType) || getIcon('measure')\n\n // Get display title - prefer shortTitle, then title, then field name\n const displayTitle = fieldMeta?.shortTitle || fieldMeta?.title || metric.field.split('.').pop() || metric.field\n\n // Get the cube name from the field\n const cubeName = metric.field.split('.')[0]\n\n // Get sort icon based on direction\n const getSortIcon = () => {\n switch (sortDirection) {\n case 'asc':\n return ChevronUpIcon ? <ChevronUpIcon className=\"w-4 h-4\" /> : '↑'\n case 'desc':\n return ChevronDownIcon ? <ChevronDownIcon className=\"w-4 h-4\" /> : '↓'\n default:\n return ChevronUpDownIcon ? <ChevronUpDownIcon className=\"w-4 h-4\" /> : '⇅'\n }\n }\n\n // Get sort tooltip\n const getSortTooltip = () => {\n switch (sortDirection) {\n case 'asc':\n return 'Sorted ascending (click for descending)'\n case 'desc':\n return 'Sorted descending (click to remove)'\n default:\n return 'Click to sort ascending'\n }\n }\n\n // Check if drag/drop is enabled\n const isDraggable = typeof index === 'number' && onDragStart && onDragEnd\n\n return (\n <div\n className={`flex items-center gap-2 p-2 bg-dc-surface-secondary rounded-lg group hover:bg-dc-surface-tertiary transition-all duration-150 ${\n isDraggable ? 'cursor-grab active:cursor-grabbing' : ''\n } ${isDragging ? 'opacity-30' : ''}`}\n draggable={isDraggable ? true : undefined}\n onDragStart={isDraggable ? (e) => onDragStart(e, index) : undefined}\n onDragEnd={isDraggable ? onDragEnd : undefined}\n >\n {/* Icon - colored background matching field selector */}\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-measure text-dc-measure-text flex-shrink-0\">\n {MeasureIcon && <MeasureIcon className=\"w-4 h-4\" />}\n </span>\n\n {/* Field Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\" title={metric.field}>\n {displayTitle}\n </div>\n <div className=\"text-xs text-dc-text-muted truncate\">\n {cubeName}\n </div>\n </div>\n\n {/* Sort Button */}\n {onToggleSort && (\n <button\n onClick={onToggleSort}\n className={`p-1 transition-opacity flex-shrink-0 flex items-center gap-0.5 ${\n sortDirection\n ? 'opacity-100 text-dc-primary'\n : 'opacity-100 sm:opacity-0 sm:group-hover:opacity-100 text-dc-text-muted hover:text-dc-primary'\n }`}\n title={getSortTooltip()}\n >\n {getSortIcon()}\n {sortDirection && sortPriority && (\n <span className=\"text-xs font-medium\">({sortPriority})</span>\n )}\n </button>\n )}\n\n {/* Remove Button */}\n <button\n onClick={onRemove}\n className=\"p-1 text-dc-text-muted hover:text-dc-danger opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity flex-shrink-0\"\n title=\"Remove metric\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n </div>\n )\n})\n\nexport default MetricItemCard\n","/**\n * MetricsSection Component\n *\n * Displays the Metrics section in the query panel with expandable list of metrics.\n */\n\nimport { useMemo, useState, useCallback, useRef, memo, DragEvent } from 'react'\nimport type { MetricsSectionProps } from './types'\nimport type { MetaField } from '../../shared/types'\nimport MetricItemCard from './MetricItemCard'\nimport SectionHeading from './SectionHeading'\nimport { getIcon } from '../../icons'\n\n// Get icon once at module level to avoid recreating\nconst AddIcon = getIcon('add')\n\n/**\n * Find field metadata by field name\n */\nfunction findFieldMeta(fieldName: string, schema: MetricsSectionProps['schema']): MetaField | null {\n if (!schema?.cubes) return null\n\n const [cubeName] = fieldName.split('.')\n const cube = schema.cubes.find((c) => c.name === cubeName)\n if (!cube) return null\n\n return cube.measures?.find((m) => m.name === fieldName) || null\n}\n\n/**\n * Get next sort direction in the cycle: null -> asc -> desc -> null\n */\nfunction getNextSortDirection(current: 'asc' | 'desc' | null): 'asc' | 'desc' | null {\n switch (current) {\n case null:\n return 'asc'\n case 'asc':\n return 'desc'\n case 'desc':\n return null\n default:\n return 'asc'\n }\n}\n\n/**\n * MetricsSection displays a collapsible section with:\n * - Header with title and add button\n * - List of selected metrics (using MetricItemCard)\n * - Drag/drop reordering support\n */\nconst MetricsSection = memo(function MetricsSection({\n metrics,\n schema,\n onAdd,\n onRemove,\n order,\n onOrderChange,\n onReorder\n}: MetricsSectionProps) {\n\n // Drag/drop state\n const [draggedIndex, setDraggedIndex] = useState<number | null>(null)\n const [dropTargetIndex, setDropTargetIndex] = useState<number | null>(null) // Index where item will be inserted\n\n // Use refs to track current values for use in drop handler (avoids stale closure issues)\n const draggedIndexRef = useRef<number | null>(null)\n const dropTargetIndexRef = useRef<number | null>(null)\n\n // Get the ordered keys to calculate priority\n const orderKeys = useMemo(() => order ? Object.keys(order) : [], [order])\n\n // Resolve field metadata for all metrics with sort info\n const metricsWithMeta = useMemo(() => {\n return metrics.map((metric, index) => {\n const sortDirection = order?.[metric.field] || null\n const sortPriority = sortDirection ? orderKeys.indexOf(metric.field) + 1 : undefined\n return {\n metric,\n fieldMeta: findFieldMeta(metric.field, schema),\n sortDirection,\n sortPriority,\n index\n }\n })\n }, [metrics, schema, order, orderKeys])\n\n // Track drag clone for cleanup\n const dragCloneRef = useRef<HTMLElement | null>(null)\n\n // Drag handlers\n const handleDragStart = useCallback((e: DragEvent, index: number) => {\n setDraggedIndex(index)\n draggedIndexRef.current = index\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', JSON.stringify({ type: 'metric', index, field: metrics[index].field }))\n\n // Create a semi-transparent, slightly tilted drag image\n const target = e.currentTarget as HTMLElement\n const clone = target.cloneNode(true) as HTMLElement\n clone.style.cssText = `\n position: absolute;\n top: -9999px;\n left: -9999px;\n width: ${target.offsetWidth}px;\n opacity: 0.7;\n transform: rotate(2deg);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n `\n document.body.appendChild(clone)\n dragCloneRef.current = clone\n\n // Calculate offset from click position\n const rect = target.getBoundingClientRect()\n const offsetX = e.clientX - rect.left\n const offsetY = e.clientY - rect.top\n e.dataTransfer.setDragImage(clone, offsetX, offsetY)\n }, [metrics])\n\n const handleDragEnd = useCallback(() => {\n setDraggedIndex(null)\n setDropTargetIndex(null)\n draggedIndexRef.current = null\n dropTargetIndexRef.current = null\n // Clean up the drag clone\n if (dragCloneRef.current) {\n document.body.removeChild(dragCloneRef.current)\n dragCloneRef.current = null\n }\n }, [])\n\n // Handle drag over an item - determine drop position based on mouse position\n const handleItemDragOver = useCallback((e: DragEvent, itemIndex: number) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Only process if we're dragging from this section\n const currentDraggedIndex = draggedIndexRef.current\n if (currentDraggedIndex === null) return\n\n // Determine if we're in the top or bottom half of the item\n const rect = e.currentTarget.getBoundingClientRect()\n const mouseY = e.clientY - rect.top\n const isTopHalf = mouseY < rect.height / 2\n\n // Calculate target index based on position\n let targetIndex = isTopHalf ? itemIndex : itemIndex + 1\n\n // Don't set drop target if it would result in no movement\n if (targetIndex === currentDraggedIndex || targetIndex === currentDraggedIndex + 1) {\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n } else {\n setDropTargetIndex(targetIndex)\n dropTargetIndexRef.current = targetIndex\n }\n }, [])\n\n // Handle drop on an item\n const handleItemDrop = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Use refs to get current values (avoids stale closure issues)\n const currentDraggedIndex = draggedIndexRef.current\n const currentDropTargetIndex = dropTargetIndexRef.current\n\n // Reset visual state immediately\n setDraggedIndex(null)\n setDropTargetIndex(null)\n draggedIndexRef.current = null\n dropTargetIndexRef.current = null\n\n // Validate and reorder - use refs directly, no dataTransfer parsing needed\n if (currentDraggedIndex === null || currentDropTargetIndex === null || !onReorder) {\n return\n }\n\n // Adjust target index when dragging down (after splice, indices shift)\n const adjustedTarget = currentDropTargetIndex > currentDraggedIndex\n ? currentDropTargetIndex - 1\n : currentDropTargetIndex\n\n if (adjustedTarget !== currentDraggedIndex) {\n onReorder(currentDraggedIndex, adjustedTarget)\n }\n }, [onReorder])\n\n // Clear drop target when leaving the section\n const handleSectionDragLeave = useCallback((e: DragEvent) => {\n const relatedTarget = e.relatedTarget as HTMLElement | null\n if (!relatedTarget || !e.currentTarget.contains(relatedTarget)) {\n setDropTargetIndex(null)\n }\n }, [])\n\n // Calculate if an item should be shifted to make room for the drop\n const getItemTransform = useCallback((itemIndex: number): string => {\n if (draggedIndex === null || dropTargetIndex === null) return ''\n\n // Gap size in pixels\n const gapSize = 40\n\n // If this is the dragged item, no transform needed (it's already faded)\n if (itemIndex === draggedIndex) return ''\n\n // Items at or after drop target need to shift down\n // But we need to account for the dragged item's position\n if (draggedIndex < dropTargetIndex) {\n // Dragging down: items between dragged+1 and dropTarget-1 shift up\n if (itemIndex > draggedIndex && itemIndex < dropTargetIndex) {\n return '' // No gap needed, item stays in place\n }\n // Item at dropTarget-1 position should show gap after it\n if (itemIndex === dropTargetIndex - 1) {\n return `translateY(-${gapSize / 2}px)` // Shift up to make room\n }\n if (itemIndex >= dropTargetIndex) {\n return `translateY(${gapSize / 2}px)` // Shift down\n }\n } else {\n // Dragging up: items from dropTarget to draggedIndex-1 shift down\n if (itemIndex >= dropTargetIndex && itemIndex < draggedIndex) {\n return `translateY(${gapSize / 2}px)` // Shift down to make room\n }\n }\n\n return ''\n }, [draggedIndex, dropTargetIndex])\n\n // Determine if gap indicator should show at a position\n const shouldShowGapIndicator = useCallback((itemIndex: number): boolean => {\n if (draggedIndex === null || dropTargetIndex === null) return false\n\n // Show indicator before the item that matches dropTargetIndex\n return itemIndex === dropTargetIndex\n }, [draggedIndex, dropTargetIndex])\n\n return (\n <div>\n {/* Section Header - entire row is clickable */}\n <button\n onClick={onAdd}\n className=\"flex items-center justify-between mb-3 w-full py-1 px-2 -ml-2 rounded-lg hover:bg-dc-primary/10 transition-colors group\"\n title=\"Add metric\"\n >\n <SectionHeading>Metrics</SectionHeading>\n <AddIcon className=\"w-5 h-5 text-dc-text-secondary group-hover:text-dc-primary transition-colors\" />\n </button>\n\n {/* Metrics List */}\n <div\n className=\"space-y-2\"\n onDragLeave={onReorder ? handleSectionDragLeave : undefined}\n onDragOver={onReorder ? (e) => e.preventDefault() : undefined}\n onDrop={onReorder ? handleItemDrop : undefined}\n >\n {metricsWithMeta.map(({ metric, fieldMeta, sortDirection, sortPriority, index }) => {\n const transform = getItemTransform(index)\n const showGapBefore = shouldShowGapIndicator(index)\n\n return (\n <div\n key={metric.id}\n className=\"relative\"\n style={{\n transform,\n transition: draggedIndex !== null ? 'transform 0.15s ease-out' : 'none'\n }}\n onDragOver={onReorder ? (e) => handleItemDragOver(e, index) : undefined}\n onDrop={onReorder ? handleItemDrop : undefined}\n >\n {/* Gap indicator line - shows where item will be inserted */}\n {showGapBefore && (\n <div className=\"absolute -top-5 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n )}\n <MetricItemCard\n metric={metric}\n fieldMeta={fieldMeta}\n onRemove={() => onRemove(metric.id)}\n sortDirection={sortDirection}\n sortPriority={sortPriority}\n onToggleSort={onOrderChange ? () => {\n const nextDirection = getNextSortDirection(sortDirection)\n onOrderChange(metric.field, nextDirection)\n } : undefined}\n index={index}\n isDragging={draggedIndex === index}\n onDragStart={onReorder ? handleDragStart : undefined}\n onDragEnd={onReorder ? handleDragEnd : undefined}\n />\n </div>\n )\n })}\n {/* Gap indicator after the last item - shows when dropping at end */}\n {onReorder && draggedIndex !== null && dropTargetIndex === metrics.length && (\n <div className=\"relative h-2\">\n <div className=\"absolute top-0 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n </div>\n )}\n {/* Handle drop at the end of the list */}\n {onReorder && metrics.length > 0 && draggedIndex !== null && (\n <div\n className=\"h-8\"\n onDragOver={(e) => {\n e.preventDefault()\n // Set drop target to end of list\n const lastIndex = metrics.length\n const currentDraggedIndex = draggedIndexRef.current\n if (dropTargetIndexRef.current !== lastIndex && currentDraggedIndex !== lastIndex - 1) {\n setDropTargetIndex(lastIndex)\n dropTargetIndexRef.current = lastIndex\n }\n }}\n onDrop={handleItemDrop}\n />\n )}\n </div>\n </div>\n )\n})\n\nexport default MetricsSection\n","/**\n * Type definitions for AnalysisBuilder components\n *\n * AnalysisBuilder is a redesigned query builder with:\n * - Results panel on the left (large)\n * - Query builder panel on the right\n * - Search-based field selection via modal\n * - Sections: Metrics (measures), Breakdown (dimensions), Filters\n */\n\nimport type { MouseEvent, DragEvent } from 'react'\nimport type {\n CubeQuery,\n Filter,\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n MultiQueryConfig\n} from '../../types'\nimport type { ColorPalette } from '../../utils/colorPalettes'\nimport type { MetaResponse, MetaField, MetaCube, QueryAnalysis } from '../../shared/types'\nimport type { ChartAvailabilityMap } from '../../shared/chartDefaults'\nimport type { MultiQueryValidationResult } from '../../utils/multiQueryValidation'\n\n// Re-export types from shared for convenience\nexport type { MetaResponse, MetaField, MetaCube, QueryAnalysis }\n\n// ============================================================================\n// Metric and Breakdown Items\n// ============================================================================\n\n/**\n * A selected metric (measure) with a letter label (A, B, C, ...)\n */\nexport interface MetricItem {\n /** Unique identifier for this metric selection */\n id: string\n /** Full field name, e.g., \"Employees.count\" */\n field: string\n /** Display label (A, B, C, ...) */\n label: string\n}\n\n/**\n * A selected breakdown (dimension or time dimension)\n */\nexport interface BreakdownItem {\n /** Unique identifier for this breakdown selection */\n id: string\n /** Full field name, e.g., \"Employees.departmentName\" */\n field: string\n /** Granularity for time dimensions (day, week, month, quarter, year) */\n granularity?: string\n /** Whether this is a time dimension */\n isTimeDimension: boolean\n /** Enable period comparison for time dimensions (compares current filter period vs prior period) */\n enableComparison?: boolean\n}\n\n// ============================================================================\n// State Types\n// ============================================================================\n\n/** Validation status for query building */\nexport type ValidationStatus = 'idle' | 'validating' | 'valid' | 'invalid'\n\n/** Execution status for query results */\nexport type ExecutionStatus = 'idle' | 'loading' | 'refreshing' | 'success' | 'error'\n\n/**\n * Main state for the AnalysisBuilder component\n */\nexport interface AnalysisBuilderState {\n /** Selected metrics (measures) */\n metrics: MetricItem[]\n /** Selected breakdowns (dimensions and time dimensions) */\n breakdowns: BreakdownItem[]\n /** Applied filters */\n filters: Filter[]\n /** Sort order for this query (field name -> 'asc' | 'desc') */\n order?: Record<string, 'asc' | 'desc'>\n\n // Validation state\n validationStatus: ValidationStatus\n validationError: string | null\n\n // Execution state\n executionStatus: ExecutionStatus\n executionResults: any[] | null\n executionError: string | null\n totalRowCount: number | null\n\n // Stale indicator (query changed since last execution)\n resultsStale: boolean\n}\n\n/**\n * State for the AI query generation panel\n */\nexport interface AIState {\n /** Whether the AI panel is open */\n isOpen: boolean\n /** User's natural language prompt */\n userPrompt: string\n /** Whether a query is being generated */\n isGenerating: boolean\n /** Error message from generation */\n error: string | null\n /** Whether the AI has generated a query that's been loaded */\n hasGeneratedQuery: boolean\n /** Snapshot of state before AI was opened (for undo) */\n previousState: {\n metrics: MetricItem[]\n breakdowns: BreakdownItem[]\n filters: Filter[]\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n } | null\n}\n\n// ============================================================================\n// Field Search Modal Types\n// ============================================================================\n\n/**\n * Mode for the field search modal - determines which field types are shown\n */\nexport type FieldSearchMode = 'metrics' | 'breakdown' | 'filter'\n\n/**\n * Field type categorization\n */\nexport type FieldType = 'measure' | 'dimension' | 'timeDimension'\n\n/**\n * A field option for display in the search modal\n */\nexport interface FieldOption {\n /** Full field name, e.g., \"Employees.count\" */\n name: string\n /** Display title */\n title: string\n /** Short title for compact display */\n shortTitle: string\n /** Field type (count, sum, avg, string, time, number, etc.) */\n type: string\n /** Optional description */\n description?: string\n /** Parent cube name */\n cubeName: string\n /** Categorized field type */\n fieldType: FieldType\n}\n\n/**\n * Props for the FieldSearchModal component\n */\nexport interface FieldSearchModalProps {\n /** Whether the modal is open */\n isOpen: boolean\n /** Callback to close the modal */\n onClose: () => void\n /** Callback when a field is selected. keepOpen=true when shift-click multi-selecting */\n onSelect: (field: MetaField, fieldType: FieldType, cubeName: string, keepOpen?: boolean) => void\n /** Mode determines which field types to show */\n mode: FieldSearchMode\n /** Schema metadata */\n schema: MetaResponse | null\n /** Already selected field names (to show checkmarks) */\n selectedFields: string[]\n /** Recently used field names */\n recentFields?: string[]\n}\n\n/**\n * Props for the FieldSearchItem component\n */\nexport interface FieldSearchItemProps {\n /** Field data */\n field: FieldOption\n /** Whether this field is selected */\n isSelected: boolean\n /** Whether this field is focused/highlighted */\n isFocused: boolean\n /** Click handler - receives mouse event for shift-click multi-select */\n onClick: (e: MouseEvent) => void\n /** Mouse enter handler (for detail panel) */\n onMouseEnter: () => void\n}\n\n/**\n * Props for the FieldDetailPanel component\n */\nexport interface FieldDetailPanelProps {\n /** Field to display details for */\n field: FieldOption | null\n}\n\n// ============================================================================\n// Panel Component Props\n// ============================================================================\n\n/**\n * Tab options for the query panel\n */\nexport type QueryPanelTab = 'query' | 'chart' | 'display'\n\n/**\n * Props for the AnalysisQueryPanel component\n */\nexport interface AnalysisQueryPanelProps {\n /** Selected metrics */\n metrics: MetricItem[]\n /** Selected breakdowns */\n breakdowns: BreakdownItem[]\n /** Applied filters */\n filters: Filter[]\n /** Schema metadata */\n schema: MetaResponse | null\n\n /** Currently active tab */\n activeTab: QueryPanelTab\n /** Callback when active tab changes */\n onActiveTabChange: (tab: QueryPanelTab) => void\n\n // Metric actions\n onAddMetric: () => void\n onRemoveMetric: (id: string) => void\n onReorderMetrics?: (fromIndex: number, toIndex: number) => void\n\n // Breakdown actions\n onAddBreakdown: () => void\n onRemoveBreakdown: (id: string) => void\n onBreakdownGranularityChange: (id: string, granularity: string) => void\n onBreakdownComparisonToggle?: (id: string) => void\n onReorderBreakdowns?: (fromIndex: number, toIndex: number) => void\n\n // Filter actions\n onFiltersChange: (filters: Filter[]) => void\n onDropFieldToFilter?: (field: string) => void\n\n // Sorting\n /** Current sort order */\n order?: Record<string, 'asc' | 'desc'>\n /** Callback when sort order changes */\n onOrderChange: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n\n // Chart configuration\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n /** Color palette for display config options */\n colorPalette?: ColorPalette\n /** Map of chart type availability for disabling unavailable chart types */\n chartAvailability?: ChartAvailabilityMap\n onChartTypeChange: (type: ChartType) => void\n onChartConfigChange: (config: ChartAxisConfig) => void\n onDisplayConfigChange: (config: ChartDisplayConfig) => void\n\n // Validation state (for showing errors)\n validationStatus: ValidationStatus\n validationError: string | null\n\n // Multi-query props\n /** Number of queries (determines single vs multi-query display) */\n queryCount?: number\n /** Index of the currently active query tab */\n activeQueryIndex?: number\n /** Strategy for merging results from multiple queries */\n mergeStrategy?: 'concat' | 'merge'\n /** Callback when active query tab changes */\n onActiveQueryChange?: (index: number) => void\n /** Callback to add a new query */\n onAddQuery?: () => void\n /** Callback to remove a query at specified index */\n onRemoveQuery?: (index: number) => void\n /** Callback when merge strategy changes */\n onMergeStrategyChange?: (strategy: 'concat' | 'merge') => void\n /** Whether breakdowns are locked (synced from Q1 in merge mode) */\n breakdownsLocked?: boolean\n /** Combined metrics from all queries (for chart config in multi-query mode) */\n combinedMetrics?: MetricItem[]\n /** Combined breakdowns from all queries (for chart config in multi-query mode) */\n combinedBreakdowns?: BreakdownItem[]\n /** Validation result for multi-query mode (errors and warnings) */\n multiQueryValidation?: MultiQueryValidationResult | null\n}\n\n/**\n * Props for the AnalysisResultsPanel component\n */\nexport interface AnalysisResultsPanelProps {\n /** Current execution status */\n executionStatus: ExecutionStatus\n /** Execution results (raw data) */\n executionResults: any[] | null\n /** Execution error message */\n executionError: string | null\n /** Total row count (before limit) */\n totalRowCount: number | null\n /** Whether results are stale (query changed) */\n resultsStale: boolean\n\n /** Chart type for visualization */\n chartType: ChartType\n /** Chart axis configuration */\n chartConfig: ChartAxisConfig\n /** Chart display configuration */\n displayConfig: ChartDisplayConfig\n /** Color palette for charts */\n colorPalette?: ColorPalette\n /** Current palette name (for selector) */\n currentPaletteName?: string\n /** Callback when color palette changes (shows selector when provided) */\n onColorPaletteChange?: (paletteName: string) => void\n\n /** All queries for multi-query mode (used for table column headers per-query) */\n allQueries?: CubeQuery[]\n /** Schema metadata */\n schema: MetaResponse | null\n\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Callback when active view changes */\n onActiveViewChange: (view: 'table' | 'chart') => void\n\n /** Display limit for table */\n displayLimit: number\n /** Callback when display limit changes */\n onDisplayLimitChange: (limit: number) => void\n\n /** Whether the query has metrics (measures) - needed to enable/disable chart view */\n hasMetrics: boolean\n\n // Debug information (from dry-run) - per-query for multi-query mode\n /** Debug data for each query (SQL, analysis, loading/error state) */\n debugDataPerQuery?: Array<{\n sql: { sql: string; params: any[] } | null\n analysis: QueryAnalysis | null\n loading: boolean\n error: string | null\n }>\n\n // Share functionality\n onShareClick?: () => void\n canShare?: boolean\n shareButtonState?: 'idle' | 'copied' | 'copied-no-chart'\n\n // Clear functionality\n onClearClick?: () => void\n canClear?: boolean\n\n // AI functionality\n enableAI?: boolean\n isAIOpen?: boolean\n onAIToggle?: () => void\n\n // Multi-query support\n /** Number of queries (for showing Table 1, Table 2 tabs) */\n queryCount?: number\n /** Per-query results (for table view in multi-query mode) */\n perQueryResults?: (any[] | null)[]\n /** Active table index in multi-query mode */\n activeTableIndex?: number\n /** Callback when active table changes */\n onActiveTableChange?: (index: number) => void\n}\n\n// ============================================================================\n// Section Component Props\n// ============================================================================\n\n/**\n * Props for the MetricsSection component\n */\nexport interface MetricsSectionProps {\n /** Selected metrics */\n metrics: MetricItem[]\n /** Schema for resolving field titles */\n schema: MetaResponse | null\n /** Add metric handler */\n onAdd: () => void\n /** Remove metric handler */\n onRemove: (id: string) => void\n /** Whether the section is expanded */\n isExpanded?: boolean\n /** Toggle expansion */\n onToggleExpanded?: () => void\n /** Current sort order */\n order?: Record<string, 'asc' | 'desc'>\n /** Callback when sort order changes */\n onOrderChange?: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n /** Callback when metrics are reordered via drag/drop */\n onReorder?: (fromIndex: number, toIndex: number) => void\n /** Callback when a metric is dragged to the filter section */\n onDragToFilter?: (field: string) => void\n}\n\n/**\n * Props for the BreakdownSection component\n */\nexport interface BreakdownSectionProps {\n /** Selected breakdowns */\n breakdowns: BreakdownItem[]\n /** Schema for resolving field titles */\n schema: MetaResponse | null\n /** Add breakdown handler */\n onAdd: () => void\n /** Remove breakdown handler */\n onRemove: (id: string) => void\n /** Change granularity for time dimension */\n onGranularityChange: (id: string, granularity: string) => void\n /** Toggle comparison for time dimension */\n onComparisonToggle?: (id: string) => void\n /** Whether the section is expanded */\n isExpanded?: boolean\n /** Toggle expansion */\n onToggleExpanded?: () => void\n /** Current sort order */\n order?: Record<string, 'asc' | 'desc'>\n /** Callback when sort order changes */\n onOrderChange?: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n /** Callback when breakdowns are reordered via drag/drop */\n onReorder?: (fromIndex: number, toIndex: number) => void\n /** Callback when a breakdown is dragged to the filter section */\n onDragToFilter?: (field: string) => void\n}\n\n/**\n * Props for MetricItemCard component\n */\nexport interface MetricItemCardProps {\n /** Metric item data */\n metric: MetricItem\n /** Field metadata (for title, description) */\n fieldMeta: MetaField | null\n /** Remove handler */\n onRemove: () => void\n /** Current sort direction for this field */\n sortDirection?: 'asc' | 'desc' | null\n /** Sort priority (1, 2, 3...) if sorted */\n sortPriority?: number\n /** Toggle sort handler */\n onToggleSort?: () => void\n /** Index in the list (for drag/drop) */\n index?: number\n /** Whether this item is being dragged */\n isDragging?: boolean\n /** Whether dragging over this item */\n isDragOver?: boolean\n /** Drag start handler */\n onDragStart?: (e: DragEvent, index: number) => void\n /** Drag over handler */\n onDragOver?: (e: DragEvent, index: number) => void\n /** Drop handler */\n onDrop?: (e: DragEvent, index: number) => void\n /** Drag end handler */\n onDragEnd?: () => void\n}\n\n/**\n * Props for BreakdownItemCard component\n */\nexport interface BreakdownItemCardProps {\n /** Breakdown item data */\n breakdown: BreakdownItem\n /** Field metadata (for title, description) */\n fieldMeta: MetaField | null\n /** Remove handler */\n onRemove: () => void\n /** Granularity change handler (for time dimensions) */\n onGranularityChange?: (granularity: string) => void\n /** Toggle comparison for time dimensions */\n onComparisonToggle?: () => void\n /** Whether another time dimension already has comparison enabled */\n comparisonDisabled?: boolean\n /** Current sort direction for this field */\n sortDirection?: 'asc' | 'desc' | null\n /** Sort priority (1, 2, 3...) if sorted */\n sortPriority?: number\n /** Toggle sort handler */\n onToggleSort?: () => void\n /** Index in the list (for drag/drop) */\n index?: number\n /** Whether this item is being dragged */\n isDragging?: boolean\n /** Whether dragging over this item */\n isDragOver?: boolean\n /** Drag start handler */\n onDragStart?: (e: DragEvent, index: number) => void\n /** Drag over handler */\n onDragOver?: (e: DragEvent, index: number) => void\n /** Drop handler */\n onDrop?: (e: DragEvent, index: number) => void\n /** Drag end handler */\n onDragEnd?: () => void\n}\n\n// ============================================================================\n// Main Component Props\n// ============================================================================\n\n/**\n * Props for the main AnalysisBuilder component\n */\nexport interface AnalysisBuilderProps {\n /** Additional CSS classes */\n className?: string\n /** Maximum height for the component (e.g., '800px', '100vh', 'calc(100vh - 64px)') */\n maxHeight?: string\n /**\n * Initial query configuration to load.\n * Accepts either a single CubeQuery or a MultiQueryConfig - the component handles both internally.\n * This keeps multi-query complexity contained within AnalysisBuilder.\n */\n initialQuery?: CubeQuery | MultiQueryConfig\n /** Initial chart configuration (for editing existing portlets) */\n initialChartConfig?: {\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n }\n /** Initial data to display (avoids re-fetching when editing existing portlets) */\n initialData?: any[]\n /** Color palette for chart visualization */\n colorPalette?: ColorPalette\n /** Disable localStorage persistence */\n disableLocalStorage?: boolean\n /** Hide settings button */\n hideSettings?: boolean\n /** Callback when query changes (for modal integration) */\n onQueryChange?: (query: CubeQuery) => void\n /** Callback when chart config changes */\n onChartConfigChange?: (config: { chartType: ChartType; chartConfig: ChartAxisConfig; displayConfig: ChartDisplayConfig }) => void\n}\n\n/**\n * Ref interface for AnalysisBuilder (for external access)\n */\nexport interface AnalysisBuilderRef {\n /**\n * Get the current query configuration.\n * Returns either a CubeQuery (single query) or MultiQueryConfig (multiple queries).\n * Consumers should just JSON.stringify the result - no need to check the type.\n */\n getQueryConfig: () => CubeQuery | MultiQueryConfig\n /** Get current chart configuration */\n getChartConfig: () => { chartType: ChartType; chartConfig: ChartAxisConfig; displayConfig: ChartDisplayConfig }\n /** Execute the current query */\n executeQuery: () => void\n /** Clear the current query */\n clearQuery: () => void\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Local storage state shape for persistence\n */\nexport interface AnalysisBuilderStorageState {\n // Legacy single-query format (for backward compatibility)\n metrics: MetricItem[]\n breakdowns: BreakdownItem[]\n filters: Filter[]\n order?: Record<string, 'asc' | 'desc'>\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n activeView: 'table' | 'chart'\n\n // Multi-query format (when multiple queries are configured)\n queryStates?: AnalysisBuilderState[]\n activeQueryIndex?: number\n mergeStrategy?: 'concat' | 'merge'\n /** Dimension keys used for merging in 'merge' strategy */\n mergeKeys?: string[]\n}\n\n/**\n * Recent fields storage shape\n */\nexport interface RecentFieldsStorage {\n metrics: string[]\n breakdowns: string[]\n}\n\n/**\n * Time granularity options\n */\nexport const TIME_GRANULARITIES = [\n { value: 'hour', label: 'Hour' },\n { value: 'day', label: 'Day' },\n { value: 'week', label: 'Week' },\n { value: 'month', label: 'Month' },\n { value: 'quarter', label: 'Quarter' },\n { value: 'year', label: 'Year' }\n] as const\n\nexport type TimeGranularity = typeof TIME_GRANULARITIES[number]['value']\n","/**\n * BreakdownItemCard Component\n *\n * Displays a single breakdown (dimension) item with optional granularity selector.\n */\n\nimport { memo } from 'react'\nimport type { BreakdownItemCardProps, TimeGranularity } from './types'\nimport { TIME_GRANULARITIES } from './types'\nimport { getIcon } from '../../icons'\n\n/**\n * BreakdownItemCard displays a selected breakdown with:\n * - Field icon (dimension or time dimension)\n * - Field title or full name\n * - Granularity dropdown (for time dimensions)\n * - Sort toggle button (visible on hover, or always visible when sorted)\n * - Remove button (visible on hover)\n * - Drag handle for reordering\n */\nconst BreakdownItemCard = memo(function BreakdownItemCard({\n breakdown,\n fieldMeta,\n onRemove,\n onGranularityChange,\n onComparisonToggle,\n comparisonDisabled,\n sortDirection,\n sortPriority,\n onToggleSort,\n index,\n isDragging,\n onDragStart,\n onDragEnd\n}: BreakdownItemCardProps) {\n const DimensionIcon = getIcon('dimension')\n const TimeIcon = getIcon('timeDimension')\n const CloseIcon = getIcon('close')\n const ChevronUpIcon = getIcon('chevronUp')\n const ChevronDownIcon = getIcon('chevronDown')\n const ChevronUpDownIcon = getIcon('chevronUpDown')\n\n // Get display title - prefer shortTitle, then title, then field name\n const displayTitle = fieldMeta?.shortTitle || fieldMeta?.title || breakdown.field.split('.').pop() || breakdown.field\n\n // Get the cube name from the field\n const cubeName = breakdown.field.split('.')[0]\n\n // Choose icon based on dimension type\n const Icon = breakdown.isTimeDimension ? TimeIcon : DimensionIcon\n\n // Get sort icon based on direction\n const getSortIcon = () => {\n switch (sortDirection) {\n case 'asc':\n return ChevronUpIcon ? <ChevronUpIcon className=\"w-4 h-4\" /> : '↑'\n case 'desc':\n return ChevronDownIcon ? <ChevronDownIcon className=\"w-4 h-4\" /> : '↓'\n default:\n return ChevronUpDownIcon ? <ChevronUpDownIcon className=\"w-4 h-4\" /> : '⇅'\n }\n }\n\n // Get sort tooltip\n const getSortTooltip = () => {\n switch (sortDirection) {\n case 'asc':\n return 'Sorted ascending (click for descending)'\n case 'desc':\n return 'Sorted descending (click to remove)'\n default:\n return 'Click to sort ascending'\n }\n }\n\n // Check if drag/drop is enabled\n const isDraggable = typeof index === 'number' && onDragStart && onDragEnd\n\n return (\n <div\n className={`flex items-center gap-2 p-2 bg-dc-surface-secondary rounded-lg group hover:bg-dc-surface-tertiary transition-all duration-150 ${\n isDraggable ? 'cursor-grab active:cursor-grabbing' : ''\n } ${isDragging ? 'opacity-30' : ''}`}\n draggable={isDraggable ? true : undefined}\n onDragStart={isDraggable ? (e) => onDragStart(e, index) : undefined}\n onDragEnd={isDraggable ? onDragEnd : undefined}\n >\n {/* Icon - colored background matching field selector */}\n <span className={`w-6 h-6 flex items-center justify-center rounded flex-shrink-0 ${\n breakdown.isTimeDimension\n ? 'bg-dc-time-dimension text-dc-time-dimension-text'\n : 'bg-dc-dimension text-dc-dimension-text'\n }`}>\n <Icon className=\"w-4 h-4\" />\n </span>\n\n {/* Field Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\" title={breakdown.field}>\n {displayTitle}\n </div>\n <div className=\"text-xs text-dc-text-muted truncate\">\n {cubeName}\n </div>\n </div>\n\n {/* Granularity Selector (for time dimensions) */}\n {breakdown.isTimeDimension && onGranularityChange && (\n <select\n value={breakdown.granularity || 'day'}\n onChange={(e) => onGranularityChange(e.target.value as TimeGranularity)}\n onClick={(e) => e.stopPropagation()}\n className=\"text-xs bg-dc-surface border border-dc-border rounded px-2 py-1 text-dc-text focus:outline-none focus:ring-1 focus:ring-dc-primary flex-shrink-0\"\n >\n {TIME_GRANULARITIES.map((g) => (\n <option key={g.value} value={g.value}>\n {g.label}\n </option>\n ))}\n </select>\n )}\n\n {/* Comparison Toggle (for time dimensions) */}\n {breakdown.isTimeDimension && onComparisonToggle && (\n <button\n onClick={(e) => {\n e.stopPropagation()\n onComparisonToggle()\n }}\n disabled={comparisonDisabled && !breakdown.enableComparison}\n className={`text-xs px-2 py-1 rounded flex-shrink-0 transition-colors ${\n breakdown.enableComparison\n ? 'bg-dc-accent text-white'\n : 'bg-dc-surface border border-dc-border text-dc-text-muted hover:text-dc-text hover:bg-dc-surface-hover'\n } ${comparisonDisabled && !breakdown.enableComparison ? 'opacity-50 cursor-not-allowed' : ''}`}\n title={\n comparisonDisabled && !breakdown.enableComparison\n ? 'Another time dimension already has comparison enabled'\n : breakdown.enableComparison\n ? 'Click to disable comparison'\n : 'Compare with previous period'\n }\n >\n vs prior\n </button>\n )}\n\n {/* Sort Button */}\n {onToggleSort && (\n <button\n onClick={onToggleSort}\n className={`p-1 transition-opacity flex-shrink-0 flex items-center gap-0.5 ${\n sortDirection\n ? 'opacity-100 text-dc-primary'\n : 'opacity-100 sm:opacity-0 sm:group-hover:opacity-100 text-dc-text-muted hover:text-dc-primary'\n }`}\n title={getSortTooltip()}\n >\n {getSortIcon()}\n {sortDirection && sortPriority && (\n <span className=\"text-xs font-medium\">({sortPriority})</span>\n )}\n </button>\n )}\n\n {/* Remove Button */}\n <button\n onClick={onRemove}\n className=\"p-1 text-dc-text-muted hover:text-dc-danger opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity flex-shrink-0\"\n title=\"Remove breakdown\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n </div>\n )\n})\n\nexport default BreakdownItemCard\n","/**\n * BreakdownSection Component\n *\n * Displays the Breakdown section in the query panel with expandable list of breakdowns.\n */\n\nimport { useMemo, useState, useCallback, useRef, memo, DragEvent } from 'react'\nimport type { BreakdownSectionProps } from './types'\nimport type { MetaField } from '../../shared/types'\nimport BreakdownItemCard from './BreakdownItemCard'\nimport SectionHeading from './SectionHeading'\nimport { getIcon } from '../../icons'\n\n// Get icon once at module level to avoid recreating\nconst AddIcon = getIcon('add')\n\n/**\n * Find field metadata by field name\n */\nfunction findFieldMeta(fieldName: string, schema: BreakdownSectionProps['schema']): MetaField | null {\n if (!schema?.cubes) return null\n\n const [cubeName] = fieldName.split('.')\n const cube = schema.cubes.find((c) => c.name === cubeName)\n if (!cube) return null\n\n // Check dimensions first, then try to find in other arrays\n return cube.dimensions?.find((d) => d.name === fieldName) || null\n}\n\n/**\n * Get next sort direction in the cycle: null -> asc -> desc -> null\n */\nfunction getNextSortDirection(current: 'asc' | 'desc' | null): 'asc' | 'desc' | null {\n switch (current) {\n case null:\n return 'asc'\n case 'asc':\n return 'desc'\n case 'desc':\n return null\n default:\n return 'asc'\n }\n}\n\n/**\n * BreakdownSection displays a collapsible section with:\n * - Header with title and add button\n * - List of selected breakdowns (using BreakdownItemCard)\n * - Drag/drop reordering support\n */\nconst BreakdownSection = memo(function BreakdownSection({\n breakdowns,\n schema,\n onAdd,\n onRemove,\n onGranularityChange,\n onComparisonToggle,\n order,\n onOrderChange,\n onReorder\n}: BreakdownSectionProps) {\n\n // Drag/drop state\n const [draggedIndex, setDraggedIndex] = useState<number | null>(null)\n const [dropTargetIndex, setDropTargetIndex] = useState<number | null>(null) // Index where item will be inserted\n\n // Use refs to track current values for use in drop handler (avoids stale closure issues)\n const draggedIndexRef = useRef<number | null>(null)\n const dropTargetIndexRef = useRef<number | null>(null)\n\n // Get the ordered keys to calculate priority\n const orderKeys = useMemo(() => order ? Object.keys(order) : [], [order])\n\n // Calculate which breakdown has comparison enabled (only one allowed at a time)\n const activeComparisonId = useMemo(() => {\n const withComparison = breakdowns.find(b => b.isTimeDimension && b.enableComparison)\n return withComparison?.id || null\n }, [breakdowns])\n\n // Resolve field metadata for all breakdowns with sort info\n const breakdownsWithMeta = useMemo(() => {\n return breakdowns.map((breakdown, index) => {\n const sortDirection = order?.[breakdown.field] || null\n const sortPriority = sortDirection ? orderKeys.indexOf(breakdown.field) + 1 : undefined\n return {\n breakdown,\n fieldMeta: findFieldMeta(breakdown.field, schema),\n sortDirection,\n sortPriority,\n index\n }\n })\n }, [breakdowns, schema, order, orderKeys])\n\n // Track drag clone for cleanup\n const dragCloneRef = useRef<HTMLElement | null>(null)\n\n // Drag handlers\n const handleDragStart = useCallback((e: DragEvent, index: number) => {\n setDraggedIndex(index)\n draggedIndexRef.current = index\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', JSON.stringify({ type: 'breakdown', index, field: breakdowns[index].field }))\n\n // Create a semi-transparent, slightly tilted drag image\n const target = e.currentTarget as HTMLElement\n const clone = target.cloneNode(true) as HTMLElement\n clone.style.cssText = `\n position: absolute;\n top: -9999px;\n left: -9999px;\n width: ${target.offsetWidth}px;\n opacity: 0.7;\n transform: rotate(2deg);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n `\n document.body.appendChild(clone)\n dragCloneRef.current = clone\n\n // Calculate offset from click position\n const rect = target.getBoundingClientRect()\n const offsetX = e.clientX - rect.left\n const offsetY = e.clientY - rect.top\n e.dataTransfer.setDragImage(clone, offsetX, offsetY)\n }, [breakdowns])\n\n const handleDragEnd = useCallback(() => {\n setDraggedIndex(null)\n setDropTargetIndex(null)\n draggedIndexRef.current = null\n dropTargetIndexRef.current = null\n // Clean up the drag clone\n if (dragCloneRef.current) {\n document.body.removeChild(dragCloneRef.current)\n dragCloneRef.current = null\n }\n }, [])\n\n // Handle drag over an item - determine drop position based on mouse position\n const handleItemDragOver = useCallback((e: DragEvent, itemIndex: number) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Only process if we're dragging from this section\n const currentDraggedIndex = draggedIndexRef.current\n if (currentDraggedIndex === null) return\n\n // Determine if we're in the top or bottom half of the item\n const rect = e.currentTarget.getBoundingClientRect()\n const mouseY = e.clientY - rect.top\n const isTopHalf = mouseY < rect.height / 2\n\n // Calculate target index based on position\n let targetIndex = isTopHalf ? itemIndex : itemIndex + 1\n\n // Don't set drop target if it would result in no movement\n if (targetIndex === currentDraggedIndex || targetIndex === currentDraggedIndex + 1) {\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n } else {\n setDropTargetIndex(targetIndex)\n dropTargetIndexRef.current = targetIndex\n }\n }, [])\n\n // Handle drop on an item\n const handleItemDrop = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Use refs to get current values (avoids stale closure issues)\n const currentDraggedIndex = draggedIndexRef.current\n const currentDropTargetIndex = dropTargetIndexRef.current\n\n // Reset visual state immediately\n setDraggedIndex(null)\n setDropTargetIndex(null)\n draggedIndexRef.current = null\n dropTargetIndexRef.current = null\n\n // Validate and reorder - use refs directly, no dataTransfer parsing needed\n if (currentDraggedIndex === null || currentDropTargetIndex === null || !onReorder) {\n return\n }\n\n // Adjust target index when dragging down (after splice, indices shift)\n const adjustedTarget = currentDropTargetIndex > currentDraggedIndex\n ? currentDropTargetIndex - 1\n : currentDropTargetIndex\n\n if (adjustedTarget !== currentDraggedIndex) {\n onReorder(currentDraggedIndex, adjustedTarget)\n }\n }, [onReorder])\n\n // Clear drop target when leaving the section\n const handleSectionDragLeave = useCallback((e: DragEvent) => {\n const relatedTarget = e.relatedTarget as HTMLElement | null\n if (!relatedTarget || !e.currentTarget.contains(relatedTarget)) {\n setDropTargetIndex(null)\n }\n }, [])\n\n // Calculate if an item should be shifted to make room for the drop\n const getItemTransform = useCallback((itemIndex: number): string => {\n if (draggedIndex === null || dropTargetIndex === null) return ''\n\n // Gap size in pixels\n const gapSize = 40\n\n // If this is the dragged item, no transform needed (it's already faded)\n if (itemIndex === draggedIndex) return ''\n\n // Items at or after drop target need to shift down\n // But we need to account for the dragged item's position\n if (draggedIndex < dropTargetIndex) {\n // Dragging down: items between dragged+1 and dropTarget-1 shift up\n if (itemIndex > draggedIndex && itemIndex < dropTargetIndex) {\n return '' // No gap needed, item stays in place\n }\n // Item at dropTarget-1 position should show gap after it\n if (itemIndex === dropTargetIndex - 1) {\n return `translateY(-${gapSize / 2}px)` // Shift up to make room\n }\n if (itemIndex >= dropTargetIndex) {\n return `translateY(${gapSize / 2}px)` // Shift down\n }\n } else {\n // Dragging up: items from dropTarget to draggedIndex-1 shift down\n if (itemIndex >= dropTargetIndex && itemIndex < draggedIndex) {\n return `translateY(${gapSize / 2}px)` // Shift down to make room\n }\n }\n\n return ''\n }, [draggedIndex, dropTargetIndex])\n\n // Determine if gap indicator should show at a position\n const shouldShowGapIndicator = useCallback((itemIndex: number): boolean => {\n if (draggedIndex === null || dropTargetIndex === null) return false\n\n // Show indicator before the item that matches dropTargetIndex\n return itemIndex === dropTargetIndex\n }, [draggedIndex, dropTargetIndex])\n\n return (\n <div>\n {/* Section Header - entire row is clickable */}\n <button\n onClick={onAdd}\n className=\"flex items-center justify-between mb-3 w-full py-1 px-2 -ml-2 rounded-lg hover:bg-dc-primary/10 transition-colors group\"\n title=\"Add breakdown\"\n >\n <SectionHeading>Breakdown</SectionHeading>\n <AddIcon className=\"w-5 h-5 text-dc-text-secondary group-hover:text-dc-primary transition-colors\" />\n </button>\n\n {/* Breakdowns List */}\n <div\n className=\"space-y-2\"\n onDragLeave={onReorder ? handleSectionDragLeave : undefined}\n onDragOver={onReorder ? (e) => e.preventDefault() : undefined}\n onDrop={onReorder ? handleItemDrop : undefined}\n >\n {breakdownsWithMeta.map(({ breakdown, fieldMeta, sortDirection, sortPriority, index }) => {\n const transform = getItemTransform(index)\n const showGapBefore = shouldShowGapIndicator(index)\n\n return (\n <div\n key={breakdown.id}\n className=\"relative\"\n style={{\n transform,\n transition: draggedIndex !== null ? 'transform 0.15s ease-out' : 'none'\n }}\n onDragOver={onReorder ? (e) => handleItemDragOver(e, index) : undefined}\n onDrop={onReorder ? handleItemDrop : undefined}\n >\n {/* Gap indicator line - shows where item will be inserted */}\n {showGapBefore && (\n <div className=\"absolute -top-5 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n )}\n <BreakdownItemCard\n breakdown={breakdown}\n fieldMeta={fieldMeta}\n onRemove={() => onRemove(breakdown.id)}\n onGranularityChange={\n breakdown.isTimeDimension\n ? (granularity) => onGranularityChange(breakdown.id, granularity)\n : undefined\n }\n onComparisonToggle={\n breakdown.isTimeDimension && onComparisonToggle\n ? () => onComparisonToggle(breakdown.id)\n : undefined\n }\n comparisonDisabled={activeComparisonId !== null && activeComparisonId !== breakdown.id}\n sortDirection={sortDirection}\n sortPriority={sortPriority}\n onToggleSort={onOrderChange ? () => {\n const nextDirection = getNextSortDirection(sortDirection)\n onOrderChange(breakdown.field, nextDirection)\n } : undefined}\n index={index}\n isDragging={draggedIndex === index}\n onDragStart={onReorder ? handleDragStart : undefined}\n onDragEnd={onReorder ? handleDragEnd : undefined}\n />\n </div>\n )\n })}\n {/* Gap indicator after the last item - shows when dropping at end */}\n {onReorder && draggedIndex !== null && dropTargetIndex === breakdowns.length && (\n <div className=\"relative h-2\">\n <div className=\"absolute top-0 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n </div>\n )}\n {/* Handle drop at the end of the list */}\n {onReorder && breakdowns.length > 0 && draggedIndex !== null && (\n <div\n className=\"h-8\"\n onDragOver={(e) => {\n e.preventDefault()\n // Set drop target to end of list\n const lastIndex = breakdowns.length\n const currentDraggedIndex = draggedIndexRef.current\n if (dropTargetIndexRef.current !== lastIndex && currentDraggedIndex !== lastIndex - 1) {\n setDropTargetIndex(lastIndex)\n dropTargetIndexRef.current = lastIndex\n }\n }}\n onDrop={handleItemDrop}\n />\n )}\n </div>\n </div>\n )\n})\n\nexport default BreakdownSection\n","/**\n * FilterConfigModal Component\n *\n * Modal for configuring filter settings with full UI for:\n * - Field selection with search\n * - Operator selection\n * - Value input (varies by operator and field type)\n * - Date range selection\n * - Multi-value support\n */\n\nimport React, { useState, useRef, useEffect, useCallback, ChangeEvent } from 'react'\nimport { getIcon } from '../../icons'\nimport type { SimpleFilter, FilterOperator } from '../../types'\nimport type { MetaResponse, DateRangeType } from '../../shared/types'\nimport {\n FILTER_OPERATORS,\n DATE_RANGE_OPTIONS\n} from '../../shared/types'\nimport {\n getAvailableOperators,\n convertDateRangeTypeToValue,\n requiresNumberInput\n} from '../../shared/utils'\nimport { findFieldInSchema, getFieldTitle } from './utils'\nimport { useFilterValues } from '../../hooks/useFilterValues'\nimport { useDebounce } from '../../hooks/useDebounce'\n\nconst CloseIcon = getIcon('close')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\nconst MeasureIcon = getIcon('measure')\n\ninterface FilterConfigModalProps {\n /** The filter being edited */\n filter: SimpleFilter\n /** Schema for field metadata */\n schema: MetaResponse | null\n /** Callback when user saves changes */\n onSave: (filter: SimpleFilter) => void\n /** Callback when user cancels */\n onCancel: () => void\n /** Element to position the modal near */\n anchorElement?: HTMLElement | null\n}\n\nexport default function FilterConfigModal({\n filter: initialFilter,\n schema,\n onSave,\n onCancel,\n anchorElement\n}: FilterConfigModalProps) {\n const [filter, setFilter] = useState<SimpleFilter>(initialFilter)\n const [isOperatorDropdownOpen, setIsOperatorDropdownOpen] = useState(false)\n const [isValueDropdownOpen, setIsValueDropdownOpen] = useState(false)\n const [isDateRangeDropdownOpen, setIsDateRangeDropdownOpen] = useState(false)\n const [rangeType, setRangeType] = useState<DateRangeType>('this_month')\n const [numberValue, setNumberValue] = useState(1)\n const [searchText, setSearchText] = useState('')\n const [modalPosition, setModalPosition] = useState<{ top?: number; bottom?: number; left: number } | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Debounce search text for API calls\n const debouncedSearchText = useDebounce(searchText, 300)\n\n // Get field info\n const fieldInfo = findFieldInSchema(filter.member, schema)\n const fieldType = fieldInfo?.field.type || 'string'\n const isTimeField = fieldType === 'time'\n const isMeasureField = fieldInfo?.fieldType === 'measure'\n const isDimensionField = fieldInfo?.fieldType === 'dimension'\n\n // Get display title for field\n const fieldTitle = getFieldTitle(filter.member, schema)\n\n // Get operator metadata\n const operatorMeta = FILTER_OPERATORS[filter.operator as FilterOperator]\n\n // Get available operators for this field type\n const availableOperators = getAvailableOperators(fieldType)\n\n // Should show date range selector\n const shouldShowDateRange = isTimeField && filter.operator === 'inDateRange'\n\n // Should use combo box for value selection\n const shouldShowComboBox = useCallback(() => {\n const comboOperators = ['equals', 'notEquals', 'in', 'notIn']\n return comboOperators.includes(filter.operator) && isDimensionField && !isTimeField\n }, [filter.operator, isDimensionField, isTimeField])()\n\n // Fetch distinct values for combo box\n const {\n values: distinctValues,\n loading: valuesLoading,\n error: valuesError,\n searchValues\n } = useFilterValues(filter.member, shouldShowComboBox)\n\n // Calculate modal position relative to anchor element\n useEffect(() => {\n if (!anchorElement) {\n setModalPosition(null)\n return\n }\n\n const rect = anchorElement.getBoundingClientRect()\n const modalHeight = 500 // Approximate modal height\n const spaceAbove = rect.top\n const spaceBelow = window.innerHeight - rect.bottom\n const modalWidth = 400 // Modal max-width\n\n // Determine if modal should appear above or below\n const shouldAppearAbove = spaceAbove > modalHeight || spaceAbove > spaceBelow\n\n // Calculate left position (try to align with anchor, but keep within viewport)\n const left = Math.max(16, Math.min(rect.left, window.innerWidth - modalWidth - 16))\n\n if (shouldAppearAbove) {\n // Position above the anchor\n setModalPosition({\n bottom: window.innerHeight - rect.top + 8,\n left\n })\n } else {\n // Position below the anchor\n setModalPosition({\n top: rect.bottom + 8,\n left\n })\n }\n }, [anchorElement])\n\n // Close dropdowns when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOperatorDropdownOpen(false)\n setIsValueDropdownOpen(false)\n setIsDateRangeDropdownOpen(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Load values when dropdown opens\n useEffect(() => {\n if (isValueDropdownOpen && shouldShowComboBox && searchValues) {\n searchValues('', true)\n }\n }, [isValueDropdownOpen, shouldShowComboBox, searchValues])\n\n // Search when debounced text changes\n useEffect(() => {\n if (isValueDropdownOpen && shouldShowComboBox && searchValues && debouncedSearchText !== undefined) {\n searchValues(debouncedSearchText)\n }\n }, [debouncedSearchText, isValueDropdownOpen, shouldShowComboBox, searchValues])\n\n // Sync rangeType state with filter.dateRange\n useEffect(() => {\n if (!shouldShowDateRange || !filter.dateRange) return\n\n if (Array.isArray(filter.dateRange)) {\n setRangeType('custom')\n } else {\n // Find matching range type - prioritize \"last N\" patterns\n // Match \"last N days/weeks/months/quarters/years\"\n const flexMatch = filter.dateRange.match(/^last (\\d+) (days|weeks|months|quarters|years)$/)\n // Match singular forms: \"last day/week/month/quarter/year\" (when N=1)\n const singularMatch = !flexMatch && filter.dateRange.match(/^last (day|week|month|quarter|year)$/)\n\n if (flexMatch) {\n const [, num, unit] = flexMatch\n setRangeType(`last_n_${unit}` as DateRangeType)\n setNumberValue(parseInt(num) || 1)\n } else if (singularMatch) {\n // Handle singular forms as \"last_n_*\" with value of 1\n const [, unit] = singularMatch\n const pluralUnit = unit === 'day' ? 'days' :\n unit === 'week' ? 'weeks' :\n unit === 'month' ? 'months' :\n unit === 'quarter' ? 'quarters' : 'years'\n setRangeType(`last_n_${pluralUnit}` as DateRangeType)\n setNumberValue(1)\n } else {\n // Check predefined ranges (only if not a \"last N\" pattern)\n let found = false\n for (const option of DATE_RANGE_OPTIONS) {\n if (option.value !== 'custom' && !requiresNumberInput(option.value)) {\n if (convertDateRangeTypeToValue(option.value) === filter.dateRange) {\n setRangeType(option.value)\n found = true\n break\n }\n }\n }\n if (!found) setRangeType('custom')\n }\n }\n }, [filter.dateRange, shouldShowDateRange])\n\n // Handle operator change\n const handleOperatorChange = useCallback((operator: FilterOperator) => {\n setFilter({\n member: filter.member,\n operator,\n values: []\n })\n setIsOperatorDropdownOpen(false)\n }, [filter.member])\n\n // Handle value selection from combo box\n const handleValueSelect = useCallback((value: unknown) => {\n const values = filter.values || []\n if (operatorMeta?.supportsMultipleValues) {\n if (!values.includes(value)) {\n setFilter({ ...filter, values: [...values, value] })\n }\n } else {\n setFilter({ ...filter, values: [value] })\n setIsValueDropdownOpen(false)\n }\n setSearchText('')\n }, [filter, operatorMeta?.supportsMultipleValues])\n\n // Handle value removal\n const handleValueRemove = useCallback((valueToRemove: unknown) => {\n const values = (filter.values || []).filter((v: unknown) => v !== valueToRemove)\n setFilter({ ...filter, values })\n }, [filter])\n\n // Handle direct text/number input\n const handleDirectInput = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n if (operatorMeta?.valueType === 'number') {\n const numValue = parseFloat(value)\n if (!isNaN(numValue)) {\n setFilter({ ...filter, values: [numValue] })\n } else if (value === '' || value === '-') {\n setFilter({ ...filter, values: [] })\n }\n } else {\n setFilter({ ...filter, values: value ? [value] : [] })\n }\n }, [filter, operatorMeta?.valueType])\n\n // Handle between range inputs\n const handleBetweenStartInput = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = parseFloat(e.target.value)\n const currentValues = filter.values?.length >= 2 ? filter.values : ['', '']\n const newValues = [!isNaN(value) ? value : '', currentValues[1]].filter(v => v !== '')\n setFilter({ ...filter, values: newValues })\n }, [filter])\n\n const handleBetweenEndInput = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = parseFloat(e.target.value)\n const currentValues = filter.values?.length >= 2 ? filter.values : ['', '']\n const newValues = [currentValues[0], !isNaN(value) ? value : ''].filter(v => v !== '')\n setFilter({ ...filter, values: newValues })\n }, [filter])\n\n // Handle date input\n const handleDateInput = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setFilter({ ...filter, values: value ? [value] : [] })\n }, [filter])\n\n // Handle date range type change\n const handleRangeTypeChange = useCallback((newRangeType: DateRangeType) => {\n setRangeType(newRangeType)\n setIsDateRangeDropdownOpen(false)\n\n let dateRange: string | string[]\n if (newRangeType === 'custom') {\n const today = new Date().toISOString().split('T')[0]\n dateRange = [today, today]\n } else if (requiresNumberInput(newRangeType)) {\n dateRange = convertDateRangeTypeToValue(newRangeType, numberValue)\n } else {\n dateRange = convertDateRangeTypeToValue(newRangeType)\n }\n\n setFilter({ ...filter, dateRange } as SimpleFilter)\n }, [filter, numberValue])\n\n // Handle number value change for \"last N days/weeks/etc\"\n const handleNumberValueChange = useCallback((value: number) => {\n setNumberValue(value)\n if (requiresNumberInput(rangeType)) {\n const dateRange = convertDateRangeTypeToValue(rangeType, value)\n setFilter({ ...filter, dateRange } as SimpleFilter)\n }\n }, [filter, rangeType])\n\n // Handle custom date range inputs\n const handleCustomStartDate = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const start = e.target.value\n const currentRange = Array.isArray(filter.dateRange) ? filter.dateRange : [filter.dateRange || '', '']\n const end = currentRange[1] || start\n setFilter({ ...filter, dateRange: [start, end] } as SimpleFilter)\n }, [filter])\n\n const handleCustomEndDate = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const end = e.target.value\n const currentRange = Array.isArray(filter.dateRange) ? filter.dateRange : ['', filter.dateRange || '']\n const start = currentRange[0] || end\n setFilter({ ...filter, dateRange: [start, end] } as SimpleFilter)\n }, [filter])\n\n // Get current operator label\n const operatorLabel = availableOperators.find(op => op.operator === filter.operator)?.label || filter.operator\n\n // Get current date range label\n const dateRangeLabel = DATE_RANGE_OPTIONS.find(opt => opt.value === rangeType)?.label || 'Select range'\n\n // Get icon for field type\n const FieldIcon = isTimeField ? TimeDimensionIcon : isMeasureField ? MeasureIcon : DimensionIcon\n\n // Render value input based on operator type\n const renderValueInput = () => {\n // No value required for set/notSet\n if (!operatorMeta?.requiresValues) {\n return (\n <div className=\"text-sm text-dc-text-muted italic py-2\">\n No value required\n </div>\n )\n }\n\n // Date range selector for inDateRange on time fields\n if (shouldShowDateRange) {\n return (\n <div className=\"space-y-2\">\n {/* Range type dropdown */}\n <div className=\"relative\">\n <button\n onClick={() => {\n setIsOperatorDropdownOpen(false)\n setIsValueDropdownOpen(false)\n setIsDateRangeDropdownOpen(!isDateRangeDropdownOpen)\n }}\n className=\"w-full flex items-center justify-between text-left text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text hover:bg-dc-surface-hover\"\n >\n <span className=\"truncate\">{dateRangeLabel}</span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-2 transition-transform ${\n isDateRangeDropdownOpen ? 'rotate-180' : ''\n }`} />\n </button>\n\n {isDateRangeDropdownOpen && (\n <div className=\"absolute z-[60] left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded shadow-lg max-h-48 overflow-y-auto\">\n {DATE_RANGE_OPTIONS.map((option) => (\n <button\n key={option.value}\n onClick={() => handleRangeTypeChange(option.value)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover ${\n option.value === rangeType ? 'bg-dc-primary/10 text-dc-primary' : 'text-dc-text'\n }`}\n >\n {option.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Number input for \"last N\" ranges */}\n {requiresNumberInput(rangeType) && (\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n min=\"1\"\n max=\"1000\"\n value={numberValue}\n onChange={(e) => handleNumberValueChange(Math.max(1, parseInt(e.target.value) || 1))}\n className=\"flex-1 text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text w-20\"\n />\n <span className=\"text-sm text-dc-text-muted\">\n {rangeType.replace('last_n_', '')}\n </span>\n </div>\n )}\n\n {/* Custom date inputs */}\n {rangeType === 'custom' && (\n <div className=\"flex items-center gap-2\">\n <input\n type=\"date\"\n value={Array.isArray(filter.dateRange) ? filter.dateRange[0] : ''}\n onChange={handleCustomStartDate}\n className=\"flex-1 text-sm border border-dc-border rounded px-2 py-2 bg-dc-surface text-dc-text\"\n />\n <span className=\"text-sm text-dc-text-muted\">to</span>\n <input\n type=\"date\"\n value={Array.isArray(filter.dateRange) ? filter.dateRange[1] : ''}\n onChange={handleCustomEndDate}\n className=\"flex-1 text-sm border border-dc-border rounded px-2 py-2 bg-dc-surface text-dc-text\"\n />\n </div>\n )}\n </div>\n )\n }\n\n // Between/notBetween range inputs\n if (filter.operator === 'between' || filter.operator === 'notBetween') {\n return (\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n value={filter.values?.[0] ?? ''}\n onChange={handleBetweenStartInput}\n placeholder=\"Min\"\n className=\"flex-1 text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text\"\n />\n <span className=\"text-sm text-dc-text-muted\">to</span>\n <input\n type=\"number\"\n value={filter.values?.[1] ?? ''}\n onChange={handleBetweenEndInput}\n placeholder=\"Max\"\n className=\"flex-1 text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text\"\n />\n </div>\n )\n }\n\n // Date picker for date operators\n if (operatorMeta?.valueType === 'date') {\n return (\n <input\n type=\"date\"\n value={filter.values?.[0] || ''}\n onChange={handleDateInput}\n className=\"w-full text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text\"\n />\n )\n }\n\n // Number input\n if (operatorMeta?.valueType === 'number') {\n return (\n <input\n type=\"number\"\n value={filter.values?.[0] ?? ''}\n onChange={handleDirectInput}\n placeholder=\"Enter number\"\n className=\"w-full text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text\"\n />\n )\n }\n\n // Combo box for equals/notEquals/in/notIn on dimensions\n if (shouldShowComboBox) {\n return (\n <div className=\"space-y-2\">\n {/* Selected values as tags */}\n {filter.values && filter.values.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {filter.values.map((value: unknown, index: number) => (\n <span\n key={index}\n className=\"inline-flex items-center gap-1 bg-dc-primary/10 text-dc-primary text-sm px-2 py-1 rounded\"\n >\n <span className=\"max-w-[150px] truncate\">{String(value)}</span>\n <button\n onClick={() => handleValueRemove(value)}\n className=\"hover:text-dc-danger\"\n >\n <CloseIcon className=\"w-3.5 h-3.5\" />\n </button>\n </span>\n ))}\n </div>\n )}\n\n {/* Dropdown trigger */}\n <div className=\"relative\">\n <button\n onClick={() => {\n setIsOperatorDropdownOpen(false)\n setIsDateRangeDropdownOpen(false)\n setIsValueDropdownOpen(!isValueDropdownOpen)\n }}\n className=\"w-full flex items-center justify-between text-left text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text hover:bg-dc-surface-hover\"\n >\n <span className=\"text-dc-text-muted truncate\">\n {valuesLoading ? 'Loading...' : 'Select value...'}\n </span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-2 transition-transform ${\n isValueDropdownOpen ? 'rotate-180' : ''\n }`} />\n </button>\n\n {isValueDropdownOpen && (\n <div className=\"absolute z-[60] left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded shadow-lg max-h-56 overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-dc-border\">\n <input\n type=\"text\"\n value={searchText}\n onChange={(e) => setSearchText(e.target.value)}\n placeholder=\"Search...\"\n className=\"w-full text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text\"\n autoFocus\n />\n </div>\n\n {/* Values list */}\n <div className=\"max-h-40 overflow-y-auto\">\n {valuesLoading ? (\n <div className=\"px-3 py-2 text-sm text-dc-text-muted\">Loading...</div>\n ) : valuesError ? (\n <div className=\"px-3 py-2 text-sm text-dc-error\">Error: {valuesError}</div>\n ) : distinctValues.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-dc-text-muted\">No values found</div>\n ) : (\n distinctValues.map((value, index) => {\n const isSelected = filter.values?.includes(value)\n return (\n <button\n key={`${value}-${index}`}\n onClick={() => handleValueSelect(value)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover ${\n isSelected ? 'bg-dc-primary/10 text-dc-primary' : 'text-dc-text'\n }`}\n >\n {String(value)}\n {isSelected && <span className=\"float-right\">✓</span>}\n </button>\n )\n })\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // Default: text input\n return (\n <input\n type=\"text\"\n value={filter.values?.[0] ?? ''}\n onChange={handleDirectInput}\n placeholder=\"Enter value...\"\n className=\"w-full text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text placeholder-dc-text-muted\"\n />\n )\n }\n\n // Determine modal positioning style\n const getModalStyle = (): React.CSSProperties => {\n if (modalPosition) {\n return {\n position: 'fixed',\n ...modalPosition,\n maxWidth: '400px',\n width: '100%'\n }\n }\n return {}\n }\n\n const modalClassName = modalPosition\n ? 'bg-dc-surface rounded-lg shadow-xl'\n : 'bg-dc-surface rounded-lg shadow-xl max-w-md w-full'\n\n return (\n <>\n {/* Modal overlay */}\n <div\n className={`fixed inset-0 bg-dc-overlay z-50 ${modalPosition ? '' : 'flex items-center justify-center p-4'}`}\n onClick={onCancel}\n >\n <div\n ref={containerRef}\n className={modalClassName}\n style={getModalStyle()}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-4 border-b border-dc-border\">\n <h2 className=\"text-lg font-semibold text-dc-text\">Edit Filter</h2>\n <button\n onClick={onCancel}\n className=\"p-1 text-dc-text-muted hover:text-dc-text transition-colors\"\n >\n <CloseIcon className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-4 space-y-4\">\n {/* Field display */}\n <div>\n <label className=\"block text-sm font-medium text-dc-text-secondary mb-2\">\n Field\n </label>\n <div className=\"flex items-center gap-2 p-3 bg-dc-surface-secondary rounded\">\n <FieldIcon className=\"w-5 h-5 text-dc-filter-text\" />\n <span className=\"text-sm font-medium text-dc-text\">{fieldTitle}</span>\n </div>\n </div>\n\n {/* Operator selector */}\n <div>\n <label className=\"block text-sm font-medium text-dc-text-secondary mb-2\">\n Operator\n </label>\n <div className=\"relative\">\n <button\n onClick={() => {\n setIsValueDropdownOpen(false)\n setIsDateRangeDropdownOpen(false)\n setIsOperatorDropdownOpen(!isOperatorDropdownOpen)\n }}\n className=\"w-full flex items-center justify-between text-left text-sm border border-dc-border rounded px-3 py-2 bg-dc-surface text-dc-text hover:bg-dc-surface-hover\"\n >\n <span className=\"truncate\">{operatorLabel}</span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-2 transition-transform ${\n isOperatorDropdownOpen ? 'rotate-180' : ''\n }`} />\n </button>\n\n {isOperatorDropdownOpen && (\n <div className=\"absolute z-[60] left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded shadow-lg max-h-48 overflow-y-auto\">\n {availableOperators.map((op) => (\n <button\n key={op.operator}\n onClick={() => handleOperatorChange(op.operator as FilterOperator)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover ${\n op.operator === filter.operator ? 'bg-dc-primary/10 text-dc-primary' : 'text-dc-text'\n }`}\n >\n {op.label}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Value input */}\n <div>\n <label className=\"block text-sm font-medium text-dc-text-secondary mb-2\">\n Value\n </label>\n {renderValueInput()}\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-2 p-4 border-t border-dc-border\">\n <button\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-dc-text-secondary hover:text-dc-text transition-colors\"\n >\n Cancel\n </button>\n <button\n onClick={() => onSave(filter)}\n className=\"px-4 py-2 text-sm font-medium text-dc-primary-content bg-dc-primary hover:bg-dc-primary-hover rounded transition-colors\"\n >\n Save\n </button>\n </div>\n </div>\n </div>\n </>\n )\n}\n","/**\n * AnalysisFilterItem Component\n *\n * Compact filter chip for the AnalysisBuilder's narrow column layout.\n * Displays filter as a chip with icon, field name, operator, and value.\n * Clicking the chip opens a modal for editing the filter configuration.\n */\n\nimport { useState, useRef } from 'react'\nimport { getIcon } from '../../icons'\nimport type { SimpleFilter } from '../../types'\nimport type { MetaResponse } from '../../shared/types'\nimport { FILTER_OPERATORS } from '../../shared/types'\nimport { getFieldTitle, findFieldInSchema } from './utils'\nimport FilterConfigModal from './FilterConfigModal'\n\nconst CloseIcon = getIcon('close')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\nconst MeasureIcon = getIcon('measure')\n\ninterface AnalysisFilterItemProps {\n /** The filter to display */\n filter: SimpleFilter\n /** Schema for field metadata */\n schema: MetaResponse | null\n /** Callback to remove this filter */\n onRemove: () => void\n /** Callback to update this filter */\n onUpdate: (filter: SimpleFilter) => void\n}\n\nexport default function AnalysisFilterItem({\n filter,\n schema,\n onRemove,\n onUpdate\n}: AnalysisFilterItemProps) {\n const [isModalOpen, setIsModalOpen] = useState(false)\n const buttonRef = useRef<HTMLButtonElement>(null)\n\n // Get field info to determine icon\n const fieldInfo = findFieldInSchema(filter.member, schema)\n const fieldType = fieldInfo?.field.type || 'string'\n const isTimeField = fieldType === 'time'\n const isMeasureField = fieldInfo?.fieldType === 'measure'\n\n // Get display title for field\n const fieldTitle = getFieldTitle(filter.member, schema)\n\n // Get operator metadata\n const operatorMeta = FILTER_OPERATORS[filter.operator]\n const operatorLabel = operatorMeta?.label || filter.operator\n\n // Format value display\n const valueDisplay = formatValueDisplay(filter, operatorMeta)\n\n // Get appropriate icon and colors based on field type\n const FieldIcon = isTimeField ? TimeDimensionIcon : isMeasureField ? MeasureIcon : DimensionIcon\n const iconBgClass = isTimeField ? 'bg-dc-time-dimension' : isMeasureField ? 'bg-dc-measure' : 'bg-dc-dimension'\n const iconTextClass = isTimeField ? 'text-dc-time-dimension-text' : isMeasureField ? 'text-dc-measure-text' : 'text-dc-dimension-text'\n\n return (\n <>\n <div\n className=\"flex items-start gap-2 px-2 py-1.5 bg-dc-surface-secondary rounded-lg group hover:bg-dc-surface-tertiary transition-all duration-150 w-full\"\n >\n {/* Field type icon with appropriate background color */}\n <span className={`w-6 h-6 flex items-center justify-center rounded ${iconBgClass} ${iconTextClass} flex-shrink-0 mt-0.5`}>\n {FieldIcon && <FieldIcon className=\"w-4 h-4\" />}\n </span>\n\n {/* Filter description - clickable to edit */}\n <button\n ref={buttonRef}\n onClick={() => setIsModalOpen(true)}\n className=\"flex-1 min-w-0 text-left\"\n title={`${fieldTitle} ${operatorLabel} ${valueDisplay}`}\n >\n <div className=\"text-sm text-dc-text break-words\">\n <span className=\"font-medium\">{fieldTitle}</span>\n <span className=\"text-dc-text-muted mx-1\">{operatorLabel}</span>\n <span className=\"text-dc-primary\">{valueDisplay}</span>\n </div>\n </button>\n\n {/* Remove button */}\n <button\n onClick={onRemove}\n className=\"p-1 text-dc-text-muted hover:text-dc-danger opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity flex-shrink-0 mt-0.5\"\n title=\"Remove filter\"\n >\n {CloseIcon && <CloseIcon className=\"w-4 h-4\" />}\n </button>\n </div>\n\n {/* Filter configuration modal */}\n {isModalOpen && (\n <FilterConfigModal\n filter={filter}\n schema={schema}\n onSave={(updatedFilter) => {\n onUpdate(updatedFilter)\n setIsModalOpen(false)\n }}\n onCancel={() => setIsModalOpen(false)}\n anchorElement={buttonRef.current}\n />\n )}\n </>\n )\n}\n\n/**\n * Formats the filter value(s) for display in the chip.\n * Handles various value types and multiple values.\n */\nfunction formatValueDisplay(filter: SimpleFilter, operatorMeta: any): string {\n // No value required for set/notSet operators\n if (!operatorMeta?.requiresValues) {\n return ''\n }\n\n // Handle date range\n if (filter.dateRange) {\n if (Array.isArray(filter.dateRange)) {\n return `${filter.dateRange[0]} to ${filter.dateRange[1]}`\n }\n return filter.dateRange\n }\n\n const values = filter.values || []\n\n // No values selected\n if (values.length === 0) {\n return '(empty)'\n }\n\n // Single value\n if (values.length === 1) {\n return String(values[0])\n }\n\n // Two values\n if (values.length === 2) {\n return `${values[0]}, ${values[1]}`\n }\n\n // More than two values - show first two plus count\n return `${values[0]}, ${values[1]}, +${values.length - 2} more`\n}\n","/**\n * AnalysisFilterGroup Component\n *\n * Renders a group of filters with AND/OR logic.\n * Supports infinite nesting for complex filter conditions.\n * Compact design for the AnalysisBuilder's narrow column.\n */\n\nimport { useState, useRef, useEffect, useCallback } from 'react'\nimport { getIcon } from '../../icons'\nimport type { Filter, SimpleFilter, GroupFilter } from '../../types'\nimport type { MetaResponse } from '../../shared/types'\nimport AnalysisFilterItem from './AnalysisFilterItem'\n\nconst AddIcon = getIcon('add')\nconst CloseIcon = getIcon('close')\n\ninterface AnalysisFilterGroupProps {\n /** The group filter to render */\n group: GroupFilter\n /** Schema for field metadata */\n schema: MetaResponse | null\n /** Callback when group changes */\n onUpdate: (group: GroupFilter) => void\n /** Callback to remove this group */\n onRemove: () => void\n /** Callback to add a new filter - receives path relative to this group */\n onAddFilter: (relativePath?: number[]) => void\n /** Depth level for styling */\n depth?: number\n /** Whether to hide the remove button (for top-level groups) */\n hideRemoveButton?: boolean\n}\n\n/**\n * Check if a filter is a simple filter\n */\nfunction isSimpleFilter(filter: Filter): filter is SimpleFilter {\n return 'member' in filter && typeof (filter as SimpleFilter).member === 'string'\n}\n\n/**\n * Check if a filter is a group filter\n */\nfunction isGroupFilter(filter: Filter): filter is GroupFilter {\n return 'type' in filter && ((filter as GroupFilter).type === 'and' || (filter as GroupFilter).type === 'or')\n}\n\nexport default function AnalysisFilterGroup({\n group,\n schema,\n onUpdate,\n onRemove,\n onAddFilter,\n depth = 0,\n hideRemoveButton = false\n}: AnalysisFilterGroupProps) {\n const [isAddMenuOpen, setIsAddMenuOpen] = useState(false)\n const addMenuRef = useRef<HTMLDivElement>(null)\n\n // Close add menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (addMenuRef.current && !addMenuRef.current.contains(event.target as Node)) {\n setIsAddMenuOpen(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Toggle group type (AND <-> OR)\n const handleToggleType = useCallback(() => {\n const newType = group.type === 'and' ? 'or' : 'and'\n onUpdate({ ...group, type: newType })\n }, [group, onUpdate])\n\n // Update a nested filter at a specific index\n const handleUpdateFilter = useCallback((index: number, newFilter: Filter) => {\n const newFilters = [...group.filters]\n newFilters[index] = newFilter\n onUpdate({ ...group, filters: newFilters })\n }, [group, onUpdate])\n\n // Remove a filter at a specific index\n const handleRemoveFilter = useCallback((index: number) => {\n const newFilters = group.filters.filter((_, i) => i !== index)\n\n // If only one filter remains, we might want to unwrap\n // But for now, just update with remaining filters\n if (newFilters.length === 0) {\n // If group is empty, remove the group itself\n onRemove()\n } else if (newFilters.length === 1 && depth > 0) {\n // Unwrap single-filter groups at non-root level by updating parent\n // This is handled by the parent component\n onUpdate({ ...group, filters: newFilters })\n } else {\n onUpdate({ ...group, filters: newFilters })\n }\n }, [group, onUpdate, onRemove, depth])\n\n // Add a nested group at a specific index\n const handleAddNestedGroup = useCallback((type: 'and' | 'or') => {\n const newGroup: GroupFilter = { type, filters: [] }\n onUpdate({ ...group, filters: [...group.filters, newGroup] })\n setIsAddMenuOpen(false)\n }, [group, onUpdate])\n\n // Handle add filter button - add to this group\n const handleAddFilterClick = useCallback(() => {\n onAddFilter([]) // Empty path means add to this group\n setIsAddMenuOpen(false)\n }, [onAddFilter])\n\n // Create handler for nested group to add filters\n const createNestedAddFilterHandler = useCallback((nestedIndex: number) => {\n return (relativePath: number[] = []) => {\n // Prepend this nested index to the relative path\n onAddFilter([nestedIndex, ...relativePath])\n }\n }, [onAddFilter])\n\n // Get border color based on depth\n const getBorderColor = () => {\n if (depth % 2 === 0) {\n return 'border-dc-border'\n }\n return 'border-dc-border dark:border-dc-border'\n }\n\n // Get background color based on group type\n const getGroupBgColor = () => {\n return group.type === 'and' ? 'bg-dc-info-bg/50' : 'bg-dc-warning-bg/50'\n }\n\n const conditionCount = group.filters.length\n const conditionLabel = conditionCount === 1 ? 'condition' : 'conditions'\n\n return (\n <div className={`border ${getBorderColor()} rounded-lg bg-dc-surface w-full`}>\n {/* Group Header */}\n <div className={`flex items-center justify-between px-2 py-1.5 border-b border-dc-border/50 rounded-t-lg ${getGroupBgColor()}`}>\n <div className=\"flex items-center gap-2\">\n {/* AND/OR Toggle Button */}\n <button\n onClick={handleToggleType}\n className={`px-2 py-0.5 text-xs font-semibold rounded transition-colors ${\n group.type === 'and'\n ? 'bg-dc-info-bg text-dc-info hover:opacity-80'\n : 'bg-dc-warning-bg text-dc-warning hover:opacity-80'\n }`}\n title={`Click to switch to ${group.type === 'and' ? 'OR' : 'AND'}`}\n >\n {group.type.toUpperCase()}\n </button>\n\n {/* Condition Count */}\n <span className=\"text-xs text-dc-text-muted\">\n {conditionCount} {conditionLabel}\n </span>\n </div>\n\n <div className=\"flex items-center gap-1\">\n {/* Add Button with Dropdown */}\n <div className=\"relative\" ref={addMenuRef}>\n <button\n onClick={() => setIsAddMenuOpen(!isAddMenuOpen)}\n className=\"p-1 text-dc-text-secondary hover:text-dc-primary hover:bg-dc-surface-hover rounded transition-colors\"\n title=\"Add condition\"\n >\n <AddIcon className=\"w-4 h-4\" />\n </button>\n\n {isAddMenuOpen && (\n <div className=\"absolute right-0 mt-1 z-40 bg-dc-surface border border-dc-border rounded shadow-lg py-1 min-w-[120px]\">\n <button\n onClick={handleAddFilterClick}\n className=\"w-full text-left px-3 py-1.5 text-xs text-dc-text hover:bg-dc-surface-hover\"\n >\n Add Filter\n </button>\n <button\n onClick={() => handleAddNestedGroup('and')}\n className=\"w-full text-left px-3 py-1.5 text-xs text-dc-text hover:bg-dc-surface-hover\"\n >\n Add AND Group\n </button>\n <button\n onClick={() => handleAddNestedGroup('or')}\n className=\"w-full text-left px-3 py-1.5 text-xs text-dc-text hover:bg-dc-surface-hover\"\n >\n Add OR Group\n </button>\n </div>\n )}\n </div>\n\n {/* Remove Group Button */}\n {!hideRemoveButton && (\n <button\n onClick={onRemove}\n className=\"p-1 text-dc-text-muted hover:text-dc-danger transition-colors\"\n title=\"Remove group\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* Group Body - Filter List */}\n <div className=\"p-1.5 flex flex-wrap gap-2\">\n {group.filters.length === 0 ? (\n <div className=\"text-center py-3\">\n <p className=\"text-xs text-dc-text-muted mb-1\">No conditions in this group</p>\n <button\n onClick={() => onAddFilter([])}\n className=\"text-xs text-dc-primary hover:underline\"\n >\n Add a filter\n </button>\n </div>\n ) : (\n group.filters.map((filter, index) => {\n if (isSimpleFilter(filter)) {\n return (\n <AnalysisFilterItem\n key={`filter-${index}`}\n filter={filter}\n schema={schema}\n onUpdate={(newFilter) => handleUpdateFilter(index, newFilter)}\n onRemove={() => handleRemoveFilter(index)}\n />\n )\n } else if (isGroupFilter(filter)) {\n return (\n <AnalysisFilterGroup\n key={`group-${index}`}\n group={filter}\n schema={schema}\n onUpdate={(newGroup) => handleUpdateFilter(index, newGroup)}\n onRemove={() => handleRemoveFilter(index)}\n onAddFilter={createNestedAddFilterHandler(index)}\n depth={depth + 1}\n />\n )\n }\n return null\n })\n )}\n </div>\n </div>\n )\n}\n","/**\n * AnalysisFilterSection Component\n *\n * Compact filter section for the AnalysisBuilder's narrow column layout.\n * Renders hierarchical filter structure with AND/OR groups.\n * Uses FieldSearchModal for field selection.\n */\n\nimport { useState, useCallback, useRef, DragEvent } from 'react'\nimport { getIcon } from '../../icons'\nimport SectionHeading from './SectionHeading'\nimport type { Filter, SimpleFilter, GroupFilter } from '../../types'\nimport type { MetaResponse, MetaField } from '../../shared/types'\nimport FieldSearchModal from './FieldSearchModal'\nimport AnalysisFilterItem from './AnalysisFilterItem'\nimport AnalysisFilterGroup from './AnalysisFilterGroup'\nimport { convertDateRangeTypeToValue } from '../../shared/utils'\n\nconst AddIcon = getIcon('add')\n\ninterface AnalysisFilterSectionProps {\n /** Current filters */\n filters: Filter[]\n /** Schema for field metadata */\n schema: MetaResponse | null\n /** Callback when filters change */\n onFiltersChange: (filters: Filter[]) => void\n /** Callback when a field is dropped from another section */\n onFieldDropped?: (field: string) => void\n}\n\n/**\n * Check if a filter is a simple filter (has member property)\n */\nfunction isSimpleFilter(filter: Filter): filter is SimpleFilter {\n return 'member' in filter && typeof (filter as SimpleFilter).member === 'string'\n}\n\n/**\n * Check if a filter is a group filter\n */\nfunction isGroupFilter(filter: Filter): filter is GroupFilter {\n return 'type' in filter && ((filter as GroupFilter).type === 'and' || (filter as GroupFilter).type === 'or')\n}\n\n/**\n * Count all simple filters in a filter tree\n */\nfunction countFilters(filters: Filter[]): number {\n let count = 0\n for (const filter of filters) {\n if (isSimpleFilter(filter)) {\n count++\n } else if (isGroupFilter(filter)) {\n count += countFilters(filter.filters)\n }\n }\n return count\n}\n\n/**\n * Get all simple filter member names from a filter tree\n */\nfunction getSelectedFields(filters: Filter[]): string[] {\n const fields: string[] = []\n for (const filter of filters) {\n if (isSimpleFilter(filter)) {\n fields.push(filter.member)\n } else if (isGroupFilter(filter)) {\n fields.push(...getSelectedFields(filter.filters))\n }\n }\n return fields\n}\n\n/**\n * Add a filter at a specific path in the filter tree\n * Path is an array of indices, e.g., [0, 2] means filters[0].filters[2]\n */\nfunction addFilterAtPath(filters: Filter[], path: number[], newFilter: SimpleFilter): Filter[] {\n if (path.length === 0) {\n // Add to root level\n if (filters.length === 0) {\n return [newFilter]\n } else if (filters.length === 1 && isSimpleFilter(filters[0])) {\n // Wrap in AND group\n return [{ type: 'and', filters: [filters[0], newFilter] }]\n } else if (filters.length === 1 && isGroupFilter(filters[0])) {\n // Add to existing group\n return [{\n ...filters[0],\n filters: [...filters[0].filters, newFilter]\n }]\n } else {\n // Wrap all in AND group\n return [{ type: 'and', filters: [...filters, newFilter] }]\n }\n }\n\n // Navigate to the target group and add\n const [firstIndex, ...restPath] = path\n const newFilters = [...filters]\n const targetFilter = newFilters[firstIndex]\n\n if (isGroupFilter(targetFilter)) {\n if (restPath.length === 0) {\n // Add to this group\n newFilters[firstIndex] = {\n ...targetFilter,\n filters: [...targetFilter.filters, newFilter]\n }\n } else {\n // Recurse deeper\n newFilters[firstIndex] = {\n ...targetFilter,\n filters: addFilterAtPath(targetFilter.filters, restPath, newFilter)\n }\n }\n }\n\n return newFilters\n}\n\nexport default function AnalysisFilterSection({\n filters,\n schema,\n onFiltersChange,\n onFieldDropped\n}: AnalysisFilterSectionProps) {\n const [showFieldModal, setShowFieldModal] = useState(false)\n const [isDragOver, setIsDragOver] = useState(false)\n // Track which group we're adding a filter to (path of indices, empty = root)\n const pendingAddPath = useRef<number[]>([])\n\n // Get total filter count for display\n const totalFilterCount = countFilters(filters)\n\n // Handle drag over for drop zone\n const handleDragOver = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(true)\n }, [])\n\n const handleDragLeave = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(false)\n }, [])\n\n const handleDrop = useCallback((e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(false)\n\n try {\n const data = JSON.parse(e.dataTransfer.getData('text/plain'))\n if (data.field && onFieldDropped) {\n onFieldDropped(data.field)\n }\n } catch {\n // Ignore invalid drop data\n }\n }, [onFieldDropped])\n\n // Get selected field names for the modal\n const selectedFields = getSelectedFields(filters)\n\n // Handle adding a new filter via field selection\n const handleFieldSelected = useCallback(\n (field: MetaField, _fieldType: 'measure' | 'dimension' | 'timeDimension', _cubeName: string) => {\n // Determine default operator based on field type\n const isTime = field.type === 'time'\n const defaultOperator = isTime ? 'inDateRange' : 'equals'\n\n // Create new filter with appropriate defaults\n const newFilter: SimpleFilter = {\n member: field.name,\n operator: defaultOperator,\n values: []\n }\n\n // For time fields with inDateRange, set a default dateRange so the filter is immediately active\n if (isTime && defaultOperator === 'inDateRange') {\n (newFilter as any).dateRange = convertDateRangeTypeToValue('this_month')\n }\n\n // Add filter at the pending path\n const updatedFilters = addFilterAtPath(filters, pendingAddPath.current, newFilter)\n onFiltersChange(updatedFilters)\n\n setShowFieldModal(false)\n pendingAddPath.current = []\n },\n [filters, onFiltersChange]\n )\n\n // Handle updating a top-level filter\n const handleUpdateTopLevelFilter = useCallback(\n (index: number, newFilter: Filter) => {\n const newFilters = [...filters]\n newFilters[index] = newFilter\n onFiltersChange(newFilters)\n },\n [filters, onFiltersChange]\n )\n\n // Handle removing a top-level filter\n const handleRemoveTopLevelFilter = useCallback(\n (index: number) => {\n const newFilters = filters.filter((_, i) => i !== index)\n\n // If we have a single group with one filter, unwrap it\n if (newFilters.length === 1 && isGroupFilter(newFilters[0])) {\n const group = newFilters[0]\n if (group.filters.length === 1) {\n onFiltersChange([group.filters[0]])\n return\n }\n }\n\n onFiltersChange(newFilters)\n },\n [filters, onFiltersChange]\n )\n\n // Handle clearing all filters\n const handleClearAll = useCallback(() => {\n onFiltersChange([])\n }, [onFiltersChange])\n\n // Handle add filter button at root level\n const handleAddFilterClick = useCallback(() => {\n pendingAddPath.current = []\n setShowFieldModal(true)\n }, [])\n\n // Create a handler for adding filters at a specific path\n // The handler receives an optional relativePath from nested groups\n const createAddFilterHandler = useCallback((basePath: number[]) => {\n return (relativePath: number[] = []) => {\n pendingAddPath.current = [...basePath, ...relativePath]\n setShowFieldModal(true)\n }\n }, [])\n\n // Render a single filter (SimpleFilter or GroupFilter)\n const renderFilter = (filter: Filter, index: number, parentPath: number[] = []) => {\n const currentPath = [...parentPath, index]\n\n if (isSimpleFilter(filter)) {\n return (\n <AnalysisFilterItem\n key={`filter-${currentPath.join('-')}`}\n filter={filter}\n schema={schema}\n onUpdate={(newFilter) => handleUpdateTopLevelFilter(index, newFilter)}\n onRemove={() => handleRemoveTopLevelFilter(index)}\n />\n )\n } else if (isGroupFilter(filter)) {\n return (\n <AnalysisFilterGroup\n key={`group-${currentPath.join('-')}`}\n group={filter}\n schema={schema}\n onUpdate={(newGroup) => handleUpdateTopLevelFilter(index, newGroup)}\n onRemove={() => handleRemoveTopLevelFilter(index)}\n onAddFilter={createAddFilterHandler(currentPath)}\n hideRemoveButton={filters.length === 1}\n />\n )\n }\n return null\n }\n\n return (\n <div>\n {/* Header - entire row is clickable to add filter */}\n <button\n onClick={handleAddFilterClick}\n className=\"flex items-center justify-between mb-3 w-full py-1 px-2 -ml-2 rounded-lg hover:bg-dc-primary/10 transition-colors group\"\n title=\"Add filter\"\n >\n <SectionHeading>\n Filter\n {totalFilterCount > 0 && (\n <span className=\"ml-1.5 text-xs font-normal text-dc-text-muted normal-case tracking-normal\">\n ({totalFilterCount})\n </span>\n )}\n </SectionHeading>\n <div className=\"flex items-center gap-2\">\n {totalFilterCount > 0 && (\n <span\n role=\"button\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation()\n handleClearAll()\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.stopPropagation()\n handleClearAll()\n }\n }}\n className=\"text-xs text-dc-text-muted hover:text-dc-error underline cursor-pointer\"\n >\n Clear all\n </span>\n )}\n <AddIcon className=\"w-5 h-5 text-dc-text-secondary group-hover:text-dc-primary transition-colors\" />\n </div>\n </button>\n\n {/* Drop Zone Container - Only wraps content, not header */}\n <div\n onDragOver={onFieldDropped ? handleDragOver : undefined}\n onDragLeave={onFieldDropped ? handleDragLeave : undefined}\n onDrop={onFieldDropped ? handleDrop : undefined}\n className={`p-2 -mx-2 rounded-lg border-2 border-dashed transition-all ${\n isDragOver\n ? 'border-dc-primary bg-dc-primary/5'\n : 'border-transparent'\n }`}\n >\n {/* Filter List - Hierarchical Rendering */}\n {filters.length === 0 ? (\n <p className={`text-sm ${isDragOver ? 'text-dc-primary font-medium' : 'text-dc-text-muted'}`}>\n {isDragOver ? 'Drop to add filter' : 'No filters applied'}\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-2\">\n {filters.map((filter, index) => renderFilter(filter, index))}\n </div>\n )}\n </div>\n\n {/* Field Search Modal - mode 'filter' shows all fields (measures + dimensions) */}\n <FieldSearchModal\n isOpen={showFieldModal}\n onClose={() => {\n setShowFieldModal(false)\n pendingAddPath.current = []\n }}\n onSelect={handleFieldSelected}\n mode=\"filter\"\n schema={schema}\n selectedFields={selectedFields}\n />\n </div>\n )\n}\n","/**\n * AnalysisAxisDropZone Component\n *\n * A styled version of AxisDropZone that matches the Query Panel card styling.\n * Used in the Analysis Builder's Chart tab for configuring chart axes.\n *\n * Key differences from AxisDropZone:\n * - Vertical card layout instead of inline chips\n * - Two-line display (title + cube name)\n * - Colored icon boxes for measures, plain icons for dimensions\n * - Hidden-on-hover remove buttons\n */\n\nimport { useState, useCallback, useRef, useEffect, DragEvent } from 'react'\nimport { getIcon, getMeasureTypeIcon } from '../../icons'\nimport type { AxisDropZoneConfig } from '../../charts/chartConfigs'\n\nconst CloseIcon = getIcon('close')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\nconst MeasureIcon = getIcon('measure')\n\ninterface FieldMeta {\n title?: string\n shortTitle?: string\n cubeName: string\n type: 'measure' | 'dimension' | 'timeDimension'\n measureType?: string\n}\n\ninterface AnalysisAxisDropZoneProps {\n config: AxisDropZoneConfig\n fields: string[]\n onDrop: (e: DragEvent<HTMLDivElement>, toKey: string) => void\n onRemove: (field: string, fromKey: string) => void\n onDragStart: (\n e: DragEvent<HTMLDivElement>,\n field: string,\n fromKey: string,\n fromIndex?: number\n ) => void\n onDragEnd?: (e: DragEvent<HTMLDivElement>) => void\n onDragOver: (e: DragEvent<HTMLDivElement>) => void\n onReorder?: (fromIndex: number, toIndex: number, axisKey: string) => void\n draggedItem?: { field: string; fromAxis: string; fromIndex?: number } | null\n getFieldMeta?: (field: string) => FieldMeta\n // Dual Y-axis support\n yAxisAssignment?: Record<string, 'left' | 'right'>\n onYAxisAssignmentChange?: (field: string, axis: 'left' | 'right') => void\n}\n\nexport default function AnalysisAxisDropZone({\n config,\n fields,\n onDrop,\n onRemove,\n onDragStart,\n onDragEnd,\n onDragOver,\n onReorder,\n draggedItem,\n getFieldMeta,\n yAxisAssignment,\n onYAxisAssignmentChange\n}: AnalysisAxisDropZoneProps) {\n const { key, label, description, mandatory, maxItems, emptyText } = config\n const [dropTargetIndex, setDropTargetIndex] = useState<number | null>(null)\n const [isDraggedOver, setIsDraggedOver] = useState(false)\n const [isReorderDraggedOver, setIsReorderDraggedOver] = useState(false)\n\n // Track the field being dragged from this axis for drag-out-to-remove\n const draggingFieldRef = useRef<string | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n // Keep fields in a ref to avoid stale closure issues\n const fieldsRef = useRef(fields)\n fieldsRef.current = fields\n // Keep dropTargetIndex in a ref to avoid stale closure issues in drop handler\n const dropTargetIndexRef = useRef<number | null>(null)\n\n // Calculate acceptance considering what's being dragged\n const getCanAcceptMore = () => {\n let effectiveCount = fields.length\n\n // If we're dragging FROM this axis, we effectively have one less item\n if (draggedItem && draggedItem.fromAxis === key) {\n effectiveCount = Math.max(0, fields.length - 1)\n }\n\n return !maxItems || effectiveCount < maxItems\n }\n\n const getIsFull = () => {\n let effectiveCount = fields.length\n\n // If we're dragging FROM this axis, we effectively have one less item\n if (draggedItem && draggedItem.fromAxis === key) {\n effectiveCount = Math.max(0, fields.length - 1)\n }\n\n return maxItems && effectiveCount >= maxItems\n }\n\n const canAcceptMore = getCanAcceptMore()\n const isFull = getIsFull()\n\n // Add a global drag end listener to reset visual state\n useEffect(() => {\n const handleGlobalDragEnd = () => {\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n draggingFieldRef.current = null\n }\n\n document.addEventListener('dragend', handleGlobalDragEnd)\n return () => {\n document.removeEventListener('dragend', handleGlobalDragEnd)\n }\n }, [])\n\n // Clear states when transitioning between different drag operations\n useEffect(() => {\n if (draggedItem) {\n // If we have a dragged item but it's not from this axis, clear reorder state\n if (draggedItem.fromAxis !== key) {\n setIsReorderDraggedOver(false)\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n }\n // If we have a dragged item from this axis, clear regular drag state\n else if (draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n setIsDraggedOver(false)\n }\n } else {\n // No dragged item, clear all states\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }\n }, [draggedItem, key])\n\n // Handle drag over an item - determine drop position based on mouse position\n const handleItemDragOver = useCallback((e: DragEvent<HTMLDivElement>, itemIndex: number) => {\n // Check if this is a reorder operation (same axis)\n if (!draggedItem || draggedItem.fromAxis !== key || draggedItem.fromIndex === undefined) return\n\n e.preventDefault()\n e.stopPropagation()\n\n // Determine if we're in the top or bottom half of the item\n const rect = e.currentTarget.getBoundingClientRect()\n const mouseY = e.clientY - rect.top\n const isTopHalf = mouseY < rect.height / 2\n\n // Calculate target index based on position\n const fromIndex = draggedItem.fromIndex\n let targetIndex = isTopHalf ? itemIndex : itemIndex + 1\n\n // Don't set drop target if it would result in no movement\n if (targetIndex === fromIndex || targetIndex === fromIndex + 1) {\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n } else {\n setDropTargetIndex(targetIndex)\n dropTargetIndexRef.current = targetIndex\n setIsReorderDraggedOver(true)\n }\n }, [draggedItem, key])\n\n // Handle drop on an item for reordering\n const handleItemDrop = useCallback((e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n // DON'T stopPropagation here yet - only stop if this is a reorder operation\n\n // Use ref to get current dropTargetIndex (avoids stale closure)\n const currentDropTargetIndex = dropTargetIndexRef.current\n\n // Check if this is a reorder operation (same axis with valid indices)\n const isReorderOperation = draggedItem &&\n draggedItem.fromAxis === key &&\n draggedItem.fromIndex !== undefined &&\n currentDropTargetIndex !== null\n\n if (!isReorderOperation) {\n // Let the event bubble up to container for external drops\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n setIsReorderDraggedOver(false)\n return // Don't stop propagation - container will handle external drops\n }\n\n // This IS a reorder operation - stop propagation and handle it\n e.stopPropagation()\n\n // Adjust target index when dragging down (after splice, indices shift)\n const fromIndex = draggedItem!.fromIndex!\n const adjustedTarget = currentDropTargetIndex > fromIndex\n ? currentDropTargetIndex - 1\n : currentDropTargetIndex\n\n if (onReorder && adjustedTarget !== fromIndex) {\n onReorder(fromIndex, adjustedTarget, key)\n }\n\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n setIsReorderDraggedOver(false)\n }, [draggedItem, key, onReorder])\n\n // Handle drag end - check if dropped outside container to remove\n const handleFieldDragEnd = useCallback((e: DragEvent<HTMLDivElement>, field: string) => {\n const container = containerRef.current\n if (container && draggingFieldRef.current === field) {\n const rect = container.getBoundingClientRect()\n const isInside =\n e.clientX >= rect.left &&\n e.clientX <= rect.right &&\n e.clientY >= rect.top &&\n e.clientY <= rect.bottom\n\n // If dropped outside the container\n if (!isInside) {\n // Use a small delay to let other drop handlers fire first\n // Then check if the field is still in this axis (wasn't moved elsewhere)\n setTimeout(() => {\n // Check using ref to get current fields, avoiding stale closure\n if (fieldsRef.current.includes(field)) {\n onRemove(field, key)\n }\n }, 0)\n }\n }\n\n draggingFieldRef.current = null\n setDropTargetIndex(null)\n dropTargetIndexRef.current = null\n setIsReorderDraggedOver(false)\n\n onDragEnd?.(e)\n }, [key, onRemove, onDragEnd])\n\n // Calculate transform for gap animation\n const getItemTransform = useCallback((itemIndex: number): string => {\n if (!draggedItem || draggedItem.fromAxis !== key || draggedItem.fromIndex === undefined || dropTargetIndex === null) {\n return ''\n }\n\n const fromIndex = draggedItem.fromIndex\n const gapSize = 40\n\n // If this is the dragged item, no transform needed\n if (itemIndex === fromIndex) return ''\n\n if (fromIndex < dropTargetIndex) {\n // Dragging down\n if (itemIndex >= dropTargetIndex) {\n return `translateY(${gapSize / 2}px)`\n }\n } else {\n // Dragging up\n if (itemIndex >= dropTargetIndex && itemIndex < fromIndex) {\n return `translateY(${gapSize / 2}px)`\n }\n }\n\n return ''\n }, [draggedItem, key, dropTargetIndex])\n\n // Determine if gap indicator should show\n const shouldShowGapIndicator = useCallback((itemIndex: number): boolean => {\n if (!draggedItem || draggedItem.fromAxis !== key || dropTargetIndex === null) return false\n return itemIndex === dropTargetIndex\n }, [draggedItem, key, dropTargetIndex])\n\n // Get default field meta from field name\n const getDefaultFieldMeta = (field: string): FieldMeta => {\n const parts = field.split('.')\n const cubeName = parts[0] || field\n const fieldName = parts[1] || field\n\n return {\n title: fieldName,\n shortTitle: fieldName,\n cubeName,\n type: 'dimension' // Default assumption\n }\n }\n\n // Render icon based on field type\n const renderFieldIcon = (meta: FieldMeta) => {\n if (meta.type === 'measure') {\n // Measures get colored icon box with type-specific icon\n const IconComponent = getMeasureTypeIcon(meta.measureType || 'count') || MeasureIcon\n return (\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-measure text-dc-measure-text flex-shrink-0\">\n <IconComponent className=\"w-4 h-4\" />\n </span>\n )\n } else if (meta.type === 'timeDimension') {\n // Time dimensions get colored background matching field selector\n return (\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-time-dimension text-dc-time-dimension-text flex-shrink-0\">\n <TimeDimensionIcon className=\"w-4 h-4\" />\n </span>\n )\n } else {\n // Regular dimensions get colored background matching field selector\n return (\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-dimension text-dc-dimension-text flex-shrink-0\">\n <DimensionIcon className=\"w-4 h-4\" />\n </span>\n )\n }\n }\n\n return (\n <div className=\"mb-3\">\n {/* Header */}\n <div className=\"mb-2\">\n <h4 className=\"text-sm font-medium text-dc-text flex items-center\">\n {label}\n {mandatory && <span className=\"text-dc-error ml-1\">*</span>}\n </h4>\n {description && <div className=\"text-xs text-dc-text-muted mt-0.5\">{description}</div>}\n </div>\n\n {/* Drop Zone Container */}\n <div\n ref={containerRef}\n data-axis-container={key}\n className={`min-h-[48px] border-2 border-dashed rounded-lg p-2 transition-all duration-200 ${\n (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'shadow-sm border-solid'\n : isFull\n ? 'bg-dc-surface-secondary'\n : 'bg-dc-surface-secondary hover:bg-dc-surface-hover'\n }`}\n style={{\n borderColor:\n (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'var(--dc-primary)'\n : 'var(--dc-border)',\n backgroundColor:\n (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'rgba(var(--dc-primary-rgb), 0.1)'\n : undefined\n }}\n onDragOver={(e) => {\n // Check if this is a reorder operation (same axis) - if so, don't interfere\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n return\n }\n\n // Simple acceptance check - either we have space OR it's a single-item replacement\n const canAccept = canAcceptMore || maxItems === 1\n\n if (canAccept) {\n setIsDraggedOver(true)\n onDragOver(e)\n } else {\n e.preventDefault()\n e.dataTransfer.dropEffect = 'none'\n }\n }}\n onDragLeave={(e) => {\n // Check if we're truly leaving the container\n const rect = e.currentTarget.getBoundingClientRect()\n const isLeavingContainer =\n e.clientX < rect.left ||\n e.clientX > rect.right ||\n e.clientY < rect.top ||\n e.clientY > rect.bottom\n\n // Also check if the related target is outside this container\n const relatedTarget = e.relatedTarget as Element | null\n const isRelatedTargetOutside = relatedTarget && !e.currentTarget.contains(relatedTarget)\n\n if (isLeavingContainer || isRelatedTargetOutside || e.currentTarget === e.target) {\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }\n }}\n onDrop={(e) => {\n // Check if this is a reorder operation (same axis) - if so, don't interfere\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n return\n }\n\n // Simple acceptance check - either we have space OR it's a single-item replacement\n const shouldAcceptDrop = canAcceptMore || maxItems === 1\n\n if (shouldAcceptDrop) {\n onDrop(e, key)\n } else {\n e.preventDefault()\n }\n\n // Reset drag state on drop\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }}\n >\n {fields.length === 0 ? (\n <div className=\"text-sm text-dc-text-muted text-center py-2\">\n {isFull ? 'Maximum items reached' : emptyText || `Drop fields here`}\n </div>\n ) : (\n <div\n className=\"space-y-2\"\n onDragOver={(e) => {\n // Allow dropping for reorder operations\n if (draggedItem && draggedItem.fromAxis === key) {\n e.preventDefault()\n }\n }}\n onDrop={(e) => {\n // Handle reorder drops at container level\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n handleItemDrop(e)\n }\n }}\n >\n {fields.map((field, index) => {\n const meta = getFieldMeta ? getFieldMeta(field) : getDefaultFieldMeta(field)\n const isBeingDragged =\n draggedItem && draggedItem.field === field && draggedItem.fromAxis === key\n const transform = getItemTransform(index)\n const showGapBefore = shouldShowGapIndicator(index)\n\n return (\n <div\n key={`${field}-${index}`}\n className=\"relative\"\n style={{\n transform,\n transition: draggedItem && draggedItem.fromAxis === key ? 'transform 0.15s ease-out' : 'none'\n }}\n >\n {/* Gap indicator line - shows where item will be inserted */}\n {showGapBefore && (\n <div className=\"absolute -top-5 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n )}\n\n <div\n draggable\n onDragStart={(e) => {\n draggingFieldRef.current = field\n onDragStart(e, field, key, index)\n }}\n onDragEnd={(e) => handleFieldDragEnd(e, field)}\n onDragOver={(e) => handleItemDragOver(e, index)}\n onDrop={handleItemDrop}\n className={`flex items-center gap-2 p-2 bg-dc-surface rounded-lg group hover:bg-dc-surface-tertiary transition-colors cursor-move ${\n isBeingDragged ? 'opacity-30 cursor-grabbing' : ''\n }`}\n >\n {/* Icon */}\n {renderFieldIcon(meta)}\n\n {/* Field Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\" title={field}>\n {meta.shortTitle || meta.title || field.split('.').pop()}\n </div>\n <div className=\"text-xs text-dc-text-muted truncate\">{meta.cubeName}</div>\n </div>\n\n {/* L/R Axis Toggle - only for yAxis with dual axis enabled */}\n {config.enableDualAxis && onYAxisAssignmentChange && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n const currentAxis = yAxisAssignment?.[field] || 'left'\n onYAxisAssignmentChange(field, currentAxis === 'left' ? 'right' : 'left')\n }}\n className={`px-1.5 py-0.5 text-xs font-medium rounded transition-colors flex-shrink-0 ${\n (yAxisAssignment?.[field] || 'left') === 'left'\n ? 'bg-dc-info-bg text-dc-info hover:opacity-80'\n : 'bg-dc-accent-bg text-dc-accent hover:opacity-80'\n }`}\n title={`Y-Axis: ${(yAxisAssignment?.[field] || 'left') === 'left' ? 'Left' : 'Right'} (click to toggle)`}\n >\n {(yAxisAssignment?.[field] || 'left') === 'left' ? 'L' : 'R'}\n </button>\n )}\n\n {/* Remove Button - hidden until hover */}\n <button\n type=\"button\"\n onClick={() => onRemove(field, key)}\n className=\"p-1 text-dc-text-muted hover:text-dc-danger opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\"\n title={`Remove from ${label}`}\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )\n })}\n {/* Gap indicator after the last item - shows when dropping at end */}\n {draggedItem && draggedItem.fromAxis === key && dropTargetIndex === fields.length && (\n <div className=\"relative h-2\">\n <div className=\"absolute top-0 left-0 right-0 flex items-center justify-center pointer-events-none z-10\">\n <div className=\"h-0.5 w-full bg-dc-primary rounded-full\" />\n </div>\n </div>\n )}\n {/* Handle drop at the end of the list for reordering */}\n {draggedItem && draggedItem.fromAxis === key && fields.length > 1 && (\n <div\n className=\"h-6\"\n onDragOver={(e) => {\n if (draggedItem.fromIndex !== undefined) {\n e.preventDefault()\n const lastIndex = fields.length\n if (dropTargetIndexRef.current !== lastIndex && draggedItem.fromIndex !== lastIndex - 1) {\n setDropTargetIndex(lastIndex)\n dropTargetIndexRef.current = lastIndex\n setIsReorderDraggedOver(true)\n }\n }\n }}\n onDrop={handleItemDrop}\n />\n )}\n </div>\n )}\n </div>\n\n {mandatory && fields.length === 0 && (\n <div className=\"text-xs text-dc-error mt-1\">This field is required</div>\n )}\n </div>\n )\n}\n","import { barChartConfig } from '../components/charts/BarChart.config'\nimport { lineChartConfig } from '../components/charts/LineChart.config'\nimport { areaChartConfig } from '../components/charts/AreaChart.config'\nimport { pieChartConfig } from '../components/charts/PieChart.config'\nimport { scatterChartConfig } from '../components/charts/ScatterChart.config'\nimport { bubbleChartConfig } from '../components/charts/BubbleChart.config'\nimport { radarChartConfig } from '../components/charts/RadarChart.config'\nimport { radialBarChartConfig } from '../components/charts/RadialBarChart.config'\nimport { treemapChartConfig } from '../components/charts/TreeMapChart.config'\nimport { dataTableConfig } from '../components/charts/DataTable.config'\nimport { activityGridChartConfig } from '../components/charts/ActivityGridChart.config'\nimport { kpiNumberConfig } from '../components/charts/KpiNumber.config'\nimport { kpiDeltaConfig } from '../components/charts/KpiDelta.config'\nimport { kpiTextConfig } from '../components/charts/KpiText.config'\nimport { markdownConfig } from '../components/charts/MarkdownChart.config'\nimport type { ChartConfigRegistry } from './chartConfigs'\n\n/**\n * Registry of all chart type configurations\n */\nexport const chartConfigRegistry: ChartConfigRegistry = {\n bar: barChartConfig,\n line: lineChartConfig,\n area: areaChartConfig,\n pie: pieChartConfig,\n scatter: scatterChartConfig,\n bubble: bubbleChartConfig,\n radar: radarChartConfig,\n radialBar: radialBarChartConfig,\n treemap: treemapChartConfig,\n table: dataTableConfig,\n activityGrid: activityGridChartConfig,\n kpiNumber: kpiNumberConfig,\n kpiDelta: kpiDeltaConfig,\n kpiText: kpiTextConfig,\n markdown: markdownConfig\n}","import { useState } from 'react'\nimport { chartConfigRegistry } from '../charts/chartConfigRegistry'\nimport type { ChartType } from '../types'\nimport type { ChartAvailabilityMap } from '../shared/chartDefaults'\n\ninterface ChartTypeSelectorProps {\n selectedType: ChartType\n onTypeChange: (type: ChartType) => void\n className?: string\n /** Compact mode for narrow containers - uses 2 columns and constrains width */\n compact?: boolean\n /** Map of chart type availability - when provided, unavailable charts are disabled */\n availability?: ChartAvailabilityMap\n}\n\n// Chart type display names (defined outside component to avoid recreation)\nconst chartTypeLabels: Record<ChartType, string> = {\n activityGrid: 'Activity Grid',\n area: 'Area Chart',\n bar: 'Bar Chart',\n bubble: 'Bubble Chart',\n kpiDelta: 'KPI Delta',\n kpiNumber: 'KPI Number',\n kpiText: 'KPI Text',\n line: 'Line Chart',\n markdown: 'Markdown',\n pie: 'Pie Chart',\n radar: 'Radar Chart',\n radialBar: 'Radial Bar Chart',\n scatter: 'Scatter Plot',\n table: 'Data Table',\n treemap: 'TreeMap'\n}\n\nexport default function ChartTypeSelector({\n selectedType,\n onTypeChange,\n className = '',\n compact = false,\n availability\n}: ChartTypeSelectorProps) {\n const [isOpen, setIsOpen] = useState(false)\n\n // Get chart types and sort alphabetically by label\n const chartTypes = (Object.entries(chartConfigRegistry) as [ChartType, typeof chartConfigRegistry[keyof typeof chartConfigRegistry]][])\n .sort((a, b) => {\n const labelA = chartTypeLabels[a[0]] || a[0]\n const labelB = chartTypeLabels[b[0]] || b[0]\n return labelA.localeCompare(labelB)\n })\n\n const selectedConfig = chartConfigRegistry[selectedType]\n const SelectedIcon = selectedConfig?.icon\n const selectedLabel = chartTypeLabels[selectedType]\n\n return (\n <div className={`${className} relative`}>\n {/* Dropdown Button */}\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"w-full flex items-center justify-between px-3 py-2 border border-dc-border rounded-md bg-dc-surface hover:bg-dc-surface-hover focus:outline-hidden focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n >\n <div className=\"flex items-center space-x-2\">\n {SelectedIcon && (\n <SelectedIcon className=\"h-5 w-5 text-dc-text-secondary\" />\n )}\n <span className=\"text-sm font-medium text-dc-text\">{selectedLabel}</span>\n </div>\n <svg\n className={`h-4 w-4 text-dc-text-muted transform transition-transform ${isOpen ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n\n {/* Dropdown Menu - Grid Layout */}\n {isOpen && (\n <div className={`absolute z-10 mt-1 w-full bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-80 overflow-auto ${compact ? '' : 'min-w-max'}`}>\n <div className=\"p-2\">\n <div className={`grid gap-1.5 ${compact ? 'grid-cols-2' : 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4'}`}>\n {chartTypes.map(([type, config]) => {\n const IconComponent = config.icon\n const label = chartTypeLabels[type]\n const isSelected = selectedType === type\n const description = config.description\n const useCase = config.useCase\n\n // Check availability if provided\n const chartAvailability = availability?.[type]\n const isAvailable = chartAvailability?.available ?? true\n const unavailableReason = chartAvailability?.reason\n\n // Build tooltip text - show unavailable reason if not available, otherwise show description\n const tooltipText = !isAvailable && unavailableReason\n ? unavailableReason\n : [description, useCase].filter(Boolean).join('. ')\n\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => {\n if (!isAvailable) return // Don't allow clicking disabled charts\n onTypeChange(type)\n setIsOpen(false)\n }}\n disabled={!isAvailable}\n className={`\n relative p-1.5 rounded border transition-colors duration-150\n text-left group min-h-[30px] flex items-center justify-start\n ${!isAvailable\n ? 'opacity-50 cursor-not-allowed bg-dc-surface'\n : isSelected\n ? 'bg-dc-surface-secondary'\n : 'bg-dc-surface hover:bg-dc-surface-hover'\n }\n `}\n style={{\n borderColor: isSelected && isAvailable ? 'var(--dc-primary)' : 'var(--dc-border)'\n }}\n title={tooltipText}\n >\n <div className=\"flex items-center space-x-1.5\">\n {/* Icon */}\n {IconComponent && (\n <IconComponent\n className={`h-4 w-4 shrink-0 ${\n !isAvailable\n ? 'text-dc-text-muted'\n : isSelected\n ? 'text-dc-text'\n : 'text-dc-text-secondary'\n }`}\n />\n )}\n\n {/* Chart name */}\n <span className={`text-xs font-medium leading-tight truncate ${\n !isAvailable\n ? 'text-dc-text-muted'\n : isSelected\n ? ''\n : 'text-dc-text'\n }`}\n style={isSelected && isAvailable ? { color: 'var(--dc-primary)' } : undefined}>\n {label}\n </span>\n </div>\n\n {/* Selected indicator - smaller dot */}\n {isSelected && isAvailable && (\n <div className=\"absolute top-0.5 right-0.5\">\n <div className=\"w-1.5 h-1.5 rounded-full\" style={{ backgroundColor: 'var(--dc-primary)' }}></div>\n </div>\n )}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}","/**\n * AnalysisChartConfigPanel Component\n *\n * A single-column chart configuration panel for the AnalysisBuilder.\n * Uses fields from the Query tab (metrics/breakdowns) as available fields.\n * Renders axis drop zones and display options based on chart type.\n */\n\nimport { useMemo, useEffect, useState, useCallback, DragEvent } from 'react'\nimport { getIcon, getMeasureTypeIcon } from '../../icons'\nimport SectionHeading from './SectionHeading'\nimport AnalysisAxisDropZone from './AnalysisAxisDropZone'\nimport ChartTypeSelector from '../ChartTypeSelector'\nimport { chartConfigRegistry } from '../../charts/chartConfigRegistry'\nimport { getChartConfig } from '../../charts/chartConfigs'\nimport type { ChartType, ChartAxisConfig } from '../../types'\nimport type { MetricItem, BreakdownItem } from './types'\nimport type { ChartAvailabilityMap } from '../../shared/chartDefaults'\nimport type { MetaResponse } from '../../shared/types'\n\nconst MeasureIcon = getIcon('measure')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\n\ninterface AnalysisChartConfigPanelProps {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n metrics: MetricItem[]\n breakdowns: BreakdownItem[]\n /** Schema metadata for resolving field titles */\n schema?: MetaResponse | null\n /** Map of chart type availability for disabling unavailable chart types */\n chartAvailability?: ChartAvailabilityMap\n onChartTypeChange: (type: ChartType) => void\n onChartConfigChange: (config: ChartAxisConfig) => void\n}\n\nexport default function AnalysisChartConfigPanel({\n chartType,\n chartConfig,\n metrics,\n breakdowns,\n schema,\n chartAvailability,\n onChartTypeChange,\n onChartConfigChange\n}: AnalysisChartConfigPanelProps) {\n // Track currently dragging item for immediate state updates\n const [draggedItem, setDraggedItem] = useState<{\n field: string\n fromAxis: string\n fromIndex?: number\n } | null>(null)\n\n // Derive available fields from metrics and breakdowns\n const availableFields = useMemo(\n () => ({\n measures: metrics.map((m) => m.field),\n dimensions: breakdowns.filter((b) => !b.isTimeDimension).map((b) => b.field),\n timeDimensions: breakdowns.filter((b) => b.isTimeDimension).map((b) => b.field)\n }),\n [metrics, breakdowns]\n )\n\n // Get configuration for current chart type\n const chartTypeConfig = useMemo(\n () => getChartConfig(chartType, chartConfigRegistry),\n [chartType]\n )\n\n // Check if this chart type skips queries\n const shouldSkipQuery = chartTypeConfig.skipQuery === true\n\n // Get fields for each drop zone\n const getFieldsForDropZone = (key: string): string[] => {\n const value = chartConfig[key as keyof ChartAxisConfig]\n const result = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? [value]\n : []\n return result\n }\n\n // Clean up chart config when available fields change\n useEffect(() => {\n const allAvailableFields = [\n ...availableFields.dimensions,\n ...availableFields.timeDimensions,\n ...availableFields.measures\n ]\n\n let hasChanges = false\n const newConfig = { ...chartConfig }\n\n // Check each axis and remove fields that are no longer available\n chartTypeConfig.dropZones.forEach((dropZone) => {\n const currentFields = getFieldsForDropZone(dropZone.key)\n const validFields = currentFields.filter((field) => allAvailableFields.includes(field))\n\n if (validFields.length !== currentFields.length) {\n hasChanges = true\n if (validFields.length === 0) {\n // Remove the axis property entirely if no valid fields remain\n delete newConfig[dropZone.key as keyof ChartAxisConfig]\n } else if (dropZone.maxItems === 1) {\n // Single field axis - always store as string\n newConfig[dropZone.key as keyof ChartAxisConfig] = validFields[0] as any\n } else {\n // Multi-field axis - always store as array\n newConfig[dropZone.key as keyof ChartAxisConfig] = validFields as any\n }\n }\n })\n\n if (hasChanges) {\n onChartConfigChange(newConfig)\n }\n }, [availableFields, chartConfig, chartTypeConfig.dropZones, onChartConfigChange])\n\n // Helper to determine field type and styling\n const getFieldType = (field: string): 'dimension' | 'timeDimension' | 'measure' => {\n if (availableFields.measures.includes(field)) return 'measure'\n if (availableFields.timeDimensions.includes(field)) return 'timeDimension'\n return 'dimension'\n }\n\n // Helper to find field metadata from schema\n const findFieldMeta = (fieldName: string) => {\n if (!schema?.cubes) return null\n\n const [cubeName] = fieldName.split('.')\n const cube = schema.cubes.find((c) => c.name === cubeName)\n if (!cube) return null\n\n // Check measures first, then dimensions\n const measure = cube.measures?.find((m) => m.name === fieldName)\n if (measure) return { ...measure, fieldType: 'measure' as const }\n\n const dimension = cube.dimensions?.find((d) => d.name === fieldName)\n if (dimension) return { ...dimension, fieldType: dimension.type === 'time' ? 'timeDimension' as const : 'dimension' as const }\n\n return null\n }\n\n // Get field metadata for display in AnalysisAxisDropZone\n const getFieldMeta = (field: string) => {\n const fieldType = getFieldType(field)\n const parts = field.split('.')\n const cubeName = parts[0] || field\n const fieldName = parts[1] || field\n\n // Look up field metadata from schema\n const schemaMeta = findFieldMeta(field)\n\n // Try to find the field in breakdowns for isTimeDimension flag\n const breakdownItem = breakdowns.find((b) => b.field === field)\n\n if (schemaMeta) {\n return {\n title: schemaMeta.title || fieldName,\n shortTitle: schemaMeta.shortTitle || schemaMeta.title || fieldName,\n cubeName,\n type: schemaMeta.fieldType,\n measureType: schemaMeta.fieldType === 'measure' ? schemaMeta.type : undefined\n }\n }\n\n // Fallback when schema lookup fails\n if (breakdownItem) {\n return {\n title: fieldName,\n shortTitle: fieldName,\n cubeName,\n type: breakdownItem.isTimeDimension ? ('timeDimension' as const) : ('dimension' as const)\n }\n }\n\n return {\n title: fieldName,\n shortTitle: fieldName,\n cubeName,\n type: fieldType\n }\n }\n\n // Drag and drop handlers\n const handleDragStart = (\n e: DragEvent<HTMLDivElement>,\n field: string,\n fromAxis: string,\n fromIndex?: number\n ) => {\n e.dataTransfer.setData('text/plain', JSON.stringify({ field, fromAxis, fromIndex }))\n setDraggedItem({ field, fromAxis, fromIndex })\n }\n\n const handleDragOver = (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n }\n\n const handleDragEnd = () => {\n setDraggedItem(null)\n }\n\n const handleDrop = (e: DragEvent<HTMLDivElement>, toAxis: string) => {\n e.preventDefault()\n const data = JSON.parse(e.dataTransfer.getData('text/plain'))\n const { field, fromAxis } = data\n\n const newConfig = { ...chartConfig }\n\n // Remove from old location if moving between axes\n if (fromAxis !== 'available' && fromAxis !== toAxis) {\n const fromValue = newConfig[fromAxis as keyof ChartAxisConfig]\n if (Array.isArray(fromValue)) {\n const filteredValue = fromValue.filter((f) => f !== field)\n if (filteredValue.length === 0) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n } else {\n newConfig[fromAxis as keyof ChartAxisConfig] = filteredValue as any\n }\n } else if (fromValue === field) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n }\n }\n\n // Add to new location\n const toValue = newConfig[toAxis as keyof ChartAxisConfig]\n const dropZoneConfig = chartTypeConfig.dropZones.find((dz) => dz.key === toAxis)\n\n if (dropZoneConfig?.maxItems === 1) {\n // Single field - always store as string\n newConfig[toAxis as keyof ChartAxisConfig] = field as any\n } else {\n // Multiple fields - always store as array\n if (Array.isArray(toValue)) {\n if (!toValue.includes(field)) {\n newConfig[toAxis as keyof ChartAxisConfig] = [...toValue, field] as any\n }\n } else {\n newConfig[toAxis as keyof ChartAxisConfig] = [field] as any\n }\n }\n\n // Apply default yAxisAssignment when adding to yAxis with dual axis enabled\n if (toAxis === 'yAxis' && dropZoneConfig?.enableDualAxis) {\n const currentYAxisFields = Array.isArray(newConfig.yAxis) ? newConfig.yAxis : [field]\n const fieldIndex = currentYAxisFields.indexOf(field)\n // Default: 1st field = left, 2nd field = right, 3rd+ = left\n if (!newConfig.yAxisAssignment?.[field]) {\n newConfig.yAxisAssignment = {\n ...newConfig.yAxisAssignment,\n [field]: fieldIndex === 1 ? 'right' : 'left'\n }\n }\n }\n\n setDraggedItem(null)\n onChartConfigChange(newConfig)\n }\n\n const handleRemoveFromAxis = (field: string, fromAxis: string) => {\n const newConfig = { ...chartConfig }\n const value = newConfig[fromAxis as keyof ChartAxisConfig]\n\n if (Array.isArray(value)) {\n const filteredValue = value.filter((f) => f !== field)\n if (filteredValue.length === 0) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n } else {\n newConfig[fromAxis as keyof ChartAxisConfig] = filteredValue as any\n }\n } else if (value === field) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n }\n\n // Clean up yAxisAssignment when removing from yAxis\n if (fromAxis === 'yAxis' && newConfig.yAxisAssignment?.[field]) {\n const { [field]: _removed, ...rest } = newConfig.yAxisAssignment\n newConfig.yAxisAssignment = Object.keys(rest).length > 0 ? rest : undefined\n }\n\n onChartConfigChange(newConfig)\n }\n\n const handleReorder = (fromIndex: number, toIndex: number, axisKey: string) => {\n const newConfig = { ...chartConfig }\n const value = newConfig[axisKey as keyof ChartAxisConfig]\n\n // Only reorder if we have an array with multiple items\n if (Array.isArray(value) && value.length > 1 && fromIndex !== toIndex) {\n const newArray = [...value]\n const [movedItem] = newArray.splice(fromIndex, 1)\n newArray.splice(toIndex, 0, movedItem)\n newConfig[axisKey as keyof ChartAxisConfig] = newArray as any\n\n setDraggedItem(null)\n onChartConfigChange(newConfig)\n }\n }\n\n // Handler for Y-axis assignment changes (dual Y-axis support)\n const handleYAxisAssignmentChange = useCallback(\n (field: string, axis: 'left' | 'right') => {\n onChartConfigChange({\n ...chartConfig,\n yAxisAssignment: {\n ...chartConfig.yAxisAssignment,\n [field]: axis\n }\n })\n },\n [chartConfig, onChartConfigChange]\n )\n\n // Get unassigned fields (fields selected in Query tab but not yet assigned to chart axes)\n const getUnassignedFields = () => {\n const assignedFields = new Set<string>()\n chartTypeConfig.dropZones.forEach((dz) => {\n getFieldsForDropZone(dz.key).forEach((field) => assignedFields.add(field))\n })\n\n // Exclude the currently dragged field only if it's being dragged FROM a configured axis\n if (draggedItem && draggedItem.fromAxis !== 'available') {\n assignedFields.add(draggedItem.field)\n }\n\n return {\n dimensions: availableFields.dimensions.filter((f) => !assignedFields.has(f)),\n timeDimensions: availableFields.timeDimensions.filter((f) => !assignedFields.has(f)),\n measures: availableFields.measures.filter((f) => !assignedFields.has(f))\n }\n }\n\n const unassignedFields = getUnassignedFields()\n const hasUnassignedFields =\n unassignedFields.dimensions.length > 0 ||\n unassignedFields.timeDimensions.length > 0 ||\n unassignedFields.measures.length > 0\n\n return (\n <div className=\"space-y-6\">\n {/* Chart Type Selector */}\n <div>\n <SectionHeading className=\"mb-2\">Chart Type</SectionHeading>\n <ChartTypeSelector\n selectedType={chartType}\n onTypeChange={onChartTypeChange}\n availability={chartAvailability}\n compact\n />\n </div>\n\n {/* Chart Axis Configuration - Dynamic Drop Zones */}\n {!shouldSkipQuery && chartTypeConfig.dropZones.length > 0 && (\n <div>\n <SectionHeading className=\"mb-2\">\n Chart Configuration\n </SectionHeading>\n <div className=\"space-y-1\">\n {chartTypeConfig.dropZones.map((dropZone) => (\n <AnalysisAxisDropZone\n key={dropZone.key}\n config={dropZone}\n fields={getFieldsForDropZone(dropZone.key)}\n onDrop={handleDrop}\n onRemove={handleRemoveFromAxis}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragOver={handleDragOver}\n onReorder={handleReorder}\n draggedItem={draggedItem}\n getFieldMeta={getFieldMeta}\n yAxisAssignment={chartConfig.yAxisAssignment}\n onYAxisAssignmentChange={\n dropZone.enableDualAxis ? handleYAxisAssignmentChange : undefined\n }\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Unassigned Fields - Show fields from Query tab that haven't been assigned yet */}\n {!shouldSkipQuery && hasUnassignedFields && (\n <div>\n <div className=\"mb-2\">\n <SectionHeading>Unassigned Fields</SectionHeading>\n <div className=\"text-xs text-dc-text-muted mt-0.5\">\n Drag fields to chart axes above\n </div>\n </div>\n <div className=\"border-2 border-dashed border-dc-border rounded-lg p-2 bg-dc-surface-secondary\">\n <div className=\"space-y-2\">\n {/* Measures */}\n {unassignedFields.measures.map((field) => {\n const meta = getFieldMeta(field)\n const isBeingDragged =\n draggedItem && draggedItem.field === field && draggedItem.fromAxis === 'available'\n const IconComponent = getMeasureTypeIcon(meta.measureType || 'count') || MeasureIcon\n return (\n <div\n key={field}\n draggable\n onDragStart={(e) => handleDragStart(e, field, 'available')}\n onDragEnd={handleDragEnd}\n className={`flex items-center gap-2 p-2 bg-dc-surface rounded-lg hover:bg-dc-surface-tertiary transition-colors cursor-move ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={field}\n >\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-measure text-dc-measure-text flex-shrink-0\">\n <IconComponent className=\"w-4 h-4\" />\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\">{meta.shortTitle}</div>\n <div className=\"text-xs text-dc-text-muted truncate\">{meta.cubeName}</div>\n </div>\n </div>\n )\n })}\n\n {/* Dimensions */}\n {unassignedFields.dimensions.map((field) => {\n const meta = getFieldMeta(field)\n const isBeingDragged =\n draggedItem && draggedItem.field === field && draggedItem.fromAxis === 'available'\n return (\n <div\n key={field}\n draggable\n onDragStart={(e) => handleDragStart(e, field, 'available')}\n onDragEnd={handleDragEnd}\n className={`flex items-center gap-2 p-2 bg-dc-surface rounded-lg hover:bg-dc-surface-tertiary transition-colors cursor-move ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={field}\n >\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-dimension text-dc-dimension-text flex-shrink-0\">\n <DimensionIcon className=\"w-4 h-4\" />\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\">{meta.shortTitle}</div>\n <div className=\"text-xs text-dc-text-muted truncate\">{meta.cubeName}</div>\n </div>\n </div>\n )\n })}\n\n {/* Time Dimensions */}\n {unassignedFields.timeDimensions.map((field) => {\n const meta = getFieldMeta(field)\n const isBeingDragged =\n draggedItem && draggedItem.field === field && draggedItem.fromAxis === 'available'\n return (\n <div\n key={field}\n draggable\n onDragStart={(e) => handleDragStart(e, field, 'available')}\n onDragEnd={handleDragEnd}\n className={`flex items-center gap-2 p-2 bg-dc-surface rounded-lg hover:bg-dc-surface-tertiary transition-colors cursor-move ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={field}\n >\n <span className=\"w-6 h-6 flex items-center justify-center rounded bg-dc-time-dimension text-dc-time-dimension-text flex-shrink-0\">\n <TimeDimensionIcon className=\"w-4 h-4\" />\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm text-dc-text truncate\">{meta.shortTitle}</div>\n <div className=\"text-xs text-dc-text-muted truncate\">{meta.cubeName}</div>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )}\n\n {/* Help text when no fields are available */}\n {!shouldSkipQuery &&\n availableFields.measures.length === 0 &&\n availableFields.dimensions.length === 0 &&\n availableFields.timeDimensions.length === 0 && (\n <div className=\"text-center text-dc-text-muted text-sm py-4\">\n <p>Add metrics and breakdowns in the Query tab to configure your chart.</p>\n </div>\n )}\n </div>\n )\n}\n","/**\n * AnalysisDisplayConfigPanel Component\n *\n * A panel for configuring chart display options (legend, grid, tooltip, etc.)\n * Extracted from AnalysisChartConfigPanel to be shown in its own tab.\n */\n\nimport { useMemo } from 'react'\nimport SectionHeading from './SectionHeading'\nimport { chartConfigRegistry } from '../../charts/chartConfigRegistry'\nimport { getChartConfig } from '../../charts/chartConfigs'\nimport type { ChartType, ChartDisplayConfig, ColorPalette, AxisFormatConfig } from '../../types'\nimport { AxisFormatControls } from '../charts/AxisFormatControls'\n\ninterface AnalysisDisplayConfigPanelProps {\n chartType: ChartType\n displayConfig: ChartDisplayConfig\n colorPalette?: ColorPalette\n onDisplayConfigChange: (config: ChartDisplayConfig) => void\n}\n\nexport default function AnalysisDisplayConfigPanel({\n chartType,\n displayConfig,\n colorPalette,\n onDisplayConfigChange\n}: AnalysisDisplayConfigPanelProps) {\n // Get configuration for current chart type\n const chartTypeConfig = useMemo(\n () => getChartConfig(chartType, chartConfigRegistry),\n [chartType]\n )\n\n // Check if we have any display options to show\n const hasDisplayOptions =\n (chartTypeConfig.displayOptions && chartTypeConfig.displayOptions.length > 0) ||\n (chartTypeConfig.displayOptionsConfig && chartTypeConfig.displayOptionsConfig.length > 0)\n\n if (!hasDisplayOptions) {\n return (\n <div className=\"text-center text-dc-text-muted text-sm py-4\">\n <p>No display options available for this chart type.</p>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-6\">\n <div>\n <SectionHeading className=\"mb-2\">Display Options</SectionHeading>\n <div className=\"space-y-2\">\n {/* Backward compatibility: Simple boolean display options */}\n {chartTypeConfig.displayOptions?.includes('showLegend') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showLegend ?? true}\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n showLegend: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Legend</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('showGrid') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showGrid ?? true}\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n showGrid: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Grid</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('showTooltip') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showTooltip ?? true}\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n showTooltip: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Tooltip</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('stacked') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.stacked ?? false}\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n stacked: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Stacked</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('hideHeader') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.hideHeader ?? false}\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n hideHeader: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Hide Header</span>\n </label>\n )}\n\n {/* New structured display options */}\n {chartTypeConfig.displayOptionsConfig?.map((option) => (\n <div key={option.key} className={`space-y-1 ${option.type === 'axisFormat' ? 'mt-6 pt-2' : ''}`}>\n {option.type === 'boolean' && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={\n (displayConfig[option.key as keyof ChartDisplayConfig] as boolean) ??\n option.defaultValue ??\n false\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.checked\n })\n }\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">{option.label}</span>\n </label>\n )}\n\n {option.type === 'string' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">\n {option.label}\n {option.key === 'content' && (\n <span className=\"text-xs text-dc-text-muted ml-1\">\n (only headers, lists and links)\n </span>\n )}\n </label>\n {option.key === 'content' ? (\n <textarea\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as string) ??\n option.defaultValue ??\n ''\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })\n }\n placeholder={option.placeholder}\n rows={8}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent font-mono resize-y bg-dc-surface text-dc-text\"\n />\n ) : (\n <input\n type=\"text\"\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as string) ??\n option.defaultValue ??\n ''\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })\n }\n placeholder={option.placeholder}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n )}\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'paletteColor' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <div className=\"flex flex-wrap gap-2\">\n {colorPalette?.colors.map((color, index) => {\n const isSelected =\n ((displayConfig[option.key as keyof ChartDisplayConfig] as number) ??\n option.defaultValue ??\n 0) === index\n return (\n <button\n key={index}\n type=\"button\"\n onClick={() =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: index\n })\n }\n className={`w-8 h-8 rounded border-2 transition-all duration-200 hover:scale-110 focus:outline-hidden focus:ring-2 focus:ring-dc-accent focus:ring-offset-1 ${\n isSelected\n ? 'ring-2 ring-offset-1 scale-110'\n : 'hover:border-dc-text-muted'\n }`}\n style={{\n backgroundColor: color,\n borderColor: isSelected ? 'var(--dc-primary)' : 'var(--dc-border)'\n }}\n title={`Color ${index + 1}: ${color}`}\n />\n )\n }) || [\n // Fallback if no palette available\n <button\n key={0}\n type=\"button\"\n onClick={() =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: 0\n })\n }\n className=\"w-8 h-8 rounded-sm border-2 ring-2 ring-offset-1\"\n style={{\n backgroundColor: '#8884d8',\n borderColor: 'var(--dc-primary)',\n boxShadow: '0 0 0 2px var(--dc-primary)'\n }}\n title=\"Default Color\"\n />\n ]}\n </div>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'number' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <input\n type=\"number\"\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as number) ??\n option.defaultValue ??\n 0\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value === '' ? undefined : Number(e.target.value)\n })\n }\n placeholder={option.placeholder}\n min={option.min}\n max={option.max}\n step={option.step}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'select' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <select\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as string) ??\n option.defaultValue ??\n ''\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })\n }\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n >\n {option.options?.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'color' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <div className=\"flex items-center space-x-2\">\n <input\n type=\"color\"\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as string) ??\n option.defaultValue ??\n '#8884d8'\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })\n }\n className=\"w-12 h-8 border border-dc-border rounded-sm cursor-pointer\"\n />\n <input\n type=\"text\"\n value={\n (displayConfig[option.key as keyof ChartDisplayConfig] as string) ??\n option.defaultValue ??\n '#8884d8'\n }\n onChange={(e) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })\n }\n placeholder={option.placeholder || '#8884d8'}\n className=\"flex-1 px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'axisFormat' && (\n <AxisFormatControls\n axisLabel={option.label}\n value={(displayConfig[option.key as keyof ChartDisplayConfig] as AxisFormatConfig) || {}}\n onChange={(config) =>\n onDisplayConfigChange({\n ...displayConfig,\n [option.key]: Object.keys(config).length > 0 ? config : undefined\n })\n }\n />\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","/**\n * AnalysisQueryPanel Component\n *\n * Right-side panel containing Query and Chart tabs with sections for\n * Metrics, Filters, and Breakdowns.\n */\n\nimport React, { useEffect, memo, useCallback, useMemo } from 'react'\nimport type { AnalysisQueryPanelProps, BreakdownItem } from './types'\nimport type { MetaField } from '../../shared/types'\nimport { getIcon } from '../../icons'\nimport MetricsSection from './MetricsSection'\nimport BreakdownSection from './BreakdownSection'\nimport BreakdownItemCard from './BreakdownItemCard'\nimport AnalysisFilterSection from './AnalysisFilterSection'\nimport AnalysisChartConfigPanel from './AnalysisChartConfigPanel'\nimport AnalysisDisplayConfigPanel from './AnalysisDisplayConfigPanel'\n\nconst AddIcon = getIcon('add')\nconst CloseIcon = getIcon('close')\nconst InfoIcon = getIcon('info')\nconst WarningIcon = getIcon('warning')\n\n/**\n * AnalysisQueryPanel displays the right-side query builder with:\n * - Query/Chart tab switcher (with multi-query support)\n * - Metrics section (measures)\n * - Filter section\n * - Breakdown section (dimensions)\n * - Chart configuration (in Chart tab)\n */\nconst AnalysisQueryPanel = memo(function AnalysisQueryPanel({\n metrics,\n breakdowns,\n filters,\n schema,\n activeTab,\n onActiveTabChange,\n onAddMetric,\n onRemoveMetric,\n onReorderMetrics,\n onAddBreakdown,\n onRemoveBreakdown,\n onBreakdownGranularityChange,\n onBreakdownComparisonToggle,\n onReorderBreakdowns,\n onFiltersChange,\n onDropFieldToFilter,\n // Sorting\n order,\n onOrderChange,\n // Chart configuration\n chartType,\n chartConfig,\n displayConfig,\n colorPalette,\n chartAvailability,\n onChartTypeChange,\n onChartConfigChange,\n onDisplayConfigChange,\n // Validation\n validationStatus: _validationStatus,\n validationError: _validationError,\n // Multi-query props\n queryCount = 1,\n activeQueryIndex = 0,\n mergeStrategy = 'concat',\n onActiveQueryChange,\n onAddQuery,\n onRemoveQuery,\n onMergeStrategyChange,\n breakdownsLocked = false,\n combinedMetrics,\n combinedBreakdowns,\n multiQueryValidation\n}: AnalysisQueryPanelProps) {\n // Mark unused props\n void _validationStatus\n void _validationError\n\n const isMultiQuery = queryCount > 1\n\n // Helper to find field metadata for a breakdown\n const getFieldMeta = useCallback((breakdown: BreakdownItem): MetaField | null => {\n if (!schema?.cubes) return null\n const [cubeName] = breakdown.field.split('.')\n const cube = schema.cubes.find(c => c.name === cubeName)\n if (!cube) return null\n // Check dimensions first, then time dimensions (which are in dimensions array)\n return cube.dimensions?.find(d => d.name === breakdown.field) || null\n }, [schema])\n\n // Check if another breakdown already has comparison enabled\n const comparisonEnabledBreakdown = useMemo(() => {\n return breakdowns.find(b => b.isTimeDimension && b.enableComparison)\n }, [breakdowns])\n\n // Force query tab when no metrics are selected\n useEffect(() => {\n if (metrics.length === 0 && (activeTab === 'chart' || activeTab === 'display')) {\n onActiveTabChange('query')\n }\n }, [metrics.length, activeTab, onActiveTabChange])\n\n // Handle query tab click\n const handleQueryTabClick = useCallback((index: number) => {\n onActiveQueryChange?.(index)\n // Ensure we're on the query tab when switching queries\n if (activeTab !== 'query') {\n onActiveTabChange('query')\n }\n }, [onActiveQueryChange, activeTab, onActiveTabChange])\n\n // Handle remove query\n const handleRemoveQuery = useCallback((e: React.MouseEvent, index: number) => {\n e.stopPropagation()\n onRemoveQuery?.(index)\n }, [onRemoveQuery])\n\n // Get tab label for query tabs\n const getQueryTabLabel = (index: number) => {\n if (!isMultiQuery) return 'Query'\n return `Q${index + 1}`\n }\n\n return (\n <div className=\"h-full flex flex-col bg-dc-surface\">\n {/* Tab Bar */}\n <div className=\"flex border-b border-dc-border flex-shrink-0\">\n {/* Query Tabs - show Q1, Q2, etc. when multi-query, or single \"Query\" tab */}\n {isMultiQuery ? (\n <>\n {Array.from({ length: queryCount }).map((_, index) => {\n const isActiveQuery = index === activeQueryIndex && activeTab === 'query'\n return (\n <button\n key={`q${index}`}\n onClick={() => handleQueryTabClick(index)}\n className={`flex items-center gap-1 px-3 py-3 text-sm font-medium transition-colors ${\n isActiveQuery\n ? 'text-dc-primary border-b-2 border-dc-primary'\n : 'text-dc-text-secondary hover:text-dc-text'\n }`}\n >\n {getQueryTabLabel(index)}\n <span\n role=\"button\"\n tabIndex={0}\n onClick={(e) => handleRemoveQuery(e, index)}\n onKeyDown={(e) => e.key === 'Enter' && handleRemoveQuery(e as unknown as React.MouseEvent, index)}\n className=\"p-0.5 rounded hover:bg-dc-danger-bg hover:text-dc-error transition-colors ml-0.5\"\n title=\"Remove query\"\n aria-label={`Remove ${getQueryTabLabel(index)}`}\n >\n <CloseIcon className=\"w-3 h-3\" />\n </span>\n </button>\n )\n })}\n {/* Add Query Button */}\n <button\n onClick={onAddQuery}\n className=\"flex items-center justify-center px-2 py-3 text-dc-text-secondary hover:text-dc-text transition-colors\"\n title=\"Add query\"\n aria-label=\"Add new query\"\n >\n <AddIcon className=\"w-4 h-4\" />\n </button>\n </>\n ) : (\n <button\n onClick={() => onActiveTabChange('query')}\n className={`flex-1 px-4 py-3 text-sm font-medium transition-colors ${\n activeTab === 'query'\n ? 'text-dc-primary border-b-2 border-dc-primary'\n : 'text-dc-text-secondary hover:text-dc-text'\n }`}\n >\n Query\n {/* Add button to convert to multi-query */}\n {onAddQuery && (\n <span\n role=\"button\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation()\n onAddQuery()\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.stopPropagation()\n onAddQuery()\n }\n }}\n className=\"ml-2 p-0.5 rounded hover:bg-dc-surface-hover transition-colors inline-flex items-center\"\n title=\"Add another query\"\n aria-label=\"Add another query\"\n >\n <AddIcon className=\"w-3 h-3\" />\n </span>\n )}\n </button>\n )}\n\n <button\n onClick={() => metrics.length > 0 && onActiveTabChange('chart')}\n disabled={metrics.length === 0}\n className={`flex-1 px-4 py-3 text-sm font-medium transition-colors ${\n activeTab === 'chart'\n ? 'text-dc-primary border-b-2 border-dc-primary'\n : metrics.length === 0\n ? 'text-dc-text-muted cursor-not-allowed opacity-50'\n : 'text-dc-text-secondary hover:text-dc-text'\n }`}\n title={metrics.length === 0 ? 'Add metrics to configure chart' : 'Chart configuration'}\n >\n Chart\n </button>\n <button\n onClick={() => metrics.length > 0 && onActiveTabChange('display')}\n disabled={metrics.length === 0}\n className={`flex-1 px-4 py-3 text-sm font-medium transition-colors ${\n activeTab === 'display'\n ? 'text-dc-primary border-b-2 border-dc-primary'\n : metrics.length === 0\n ? 'text-dc-text-muted cursor-not-allowed opacity-50'\n : 'text-dc-text-secondary hover:text-dc-text'\n }`}\n title={metrics.length === 0 ? 'Add metrics to configure display' : 'Display options'}\n >\n Display\n </button>\n </div>\n\n {/* Merge Strategy Controls (only shown when multiple queries and on query tab) */}\n {isMultiQuery && activeTab === 'query' && (\n <div className=\"flex items-center gap-3 px-4 py-2 text-sm bg-dc-surface-secondary border-b border-dc-border\">\n <label className=\"flex items-center gap-2\">\n <span className=\"text-dc-text-secondary text-xs\">Combine:</span>\n <select\n value={mergeStrategy}\n onChange={(e) => onMergeStrategyChange?.(e.target.value as 'concat' | 'merge')}\n className=\"px-2 py-1 text-xs bg-dc-surface border border-dc-border rounded text-dc-text focus:outline-none focus:ring-1 focus:ring-dc-primary\"\n >\n <option value=\"concat\">Separate series</option>\n <option value=\"merge\">Merge by dimension</option>\n </select>\n </label>\n\n </div>\n )}\n\n {/* Multi-Query Validation Warnings */}\n {multiQueryValidation && (multiQueryValidation.warnings.length > 0 || multiQueryValidation.errors.length > 0) && activeTab === 'query' && (\n <div className=\"px-4 py-2 border-b border-dc-border bg-dc-warning-bg\">\n {multiQueryValidation.errors.map((error, i) => (\n <div key={`error-${i}`} className=\"flex items-start gap-2 text-xs text-dc-error\">\n <WarningIcon className=\"w-3.5 h-3.5 mt-0.5 flex-shrink-0\" />\n <span>{error.message}</span>\n </div>\n ))}\n {multiQueryValidation.warnings.map((warning, i) => (\n <div key={`warning-${i}`} className=\"flex items-start gap-2 text-xs text-dc-warning\">\n <WarningIcon className=\"w-3.5 h-3.5 mt-0.5 flex-shrink-0\" />\n <span>{warning.message}</span>\n </div>\n ))}\n </div>\n )}\n\n {/* Tab Content */}\n <div className=\"flex-1 overflow-auto p-4\">\n {activeTab === 'query' ? (\n <div className=\"space-y-6\">\n {/* Metrics Section */}\n <MetricsSection\n metrics={metrics}\n schema={schema}\n onAdd={onAddMetric}\n onRemove={onRemoveMetric}\n order={order}\n onOrderChange={onOrderChange}\n onReorder={onReorderMetrics}\n />\n\n {/* Breakdown Section */}\n {breakdownsLocked ? (\n <div className=\"mb-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-sm font-medium text-dc-text\">Dimensions</h4>\n </div>\n {/* Explanation with link to switch mode */}\n <div className=\"flex items-start gap-2 px-3 py-2 mb-3 bg-dc-surface-secondary rounded border border-dc-border text-xs\">\n {InfoIcon && <InfoIcon className=\"w-4 h-4 text-dc-text-muted flex-shrink-0 mt-0.5\" />}\n <span className=\"text-dc-text-muted\">\n In merge mode, dimensions are shared from Q1.\n {onMergeStrategyChange && (\n <button\n onClick={() => onMergeStrategyChange('concat')}\n className=\"text-dc-primary hover:underline ml-1\"\n >\n Switch to separate series\n </button>\n )}\n </span>\n </div>\n {/* Show breakdown cards with granularity controls (but no remove) */}\n {breakdowns.length > 0 && (\n <div className=\"space-y-1\">\n {breakdowns.map((breakdown) => (\n <BreakdownItemCard\n key={breakdown.id}\n breakdown={breakdown}\n fieldMeta={getFieldMeta(breakdown)}\n onRemove={() => {}} // No-op - can't remove in locked mode\n onGranularityChange={breakdown.isTimeDimension ? (granularity) => onBreakdownGranularityChange(breakdown.id, granularity) : undefined}\n onComparisonToggle={breakdown.isTimeDimension && onBreakdownComparisonToggle ? () => onBreakdownComparisonToggle(breakdown.id) : undefined}\n comparisonDisabled={!!comparisonEnabledBreakdown && comparisonEnabledBreakdown.id !== breakdown.id}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <BreakdownSection\n breakdowns={breakdowns}\n schema={schema}\n onAdd={onAddBreakdown}\n onRemove={onRemoveBreakdown}\n onGranularityChange={onBreakdownGranularityChange}\n onComparisonToggle={onBreakdownComparisonToggle}\n order={order}\n onOrderChange={onOrderChange}\n onReorder={onReorderBreakdowns}\n />\n )}\n\n {/* Filter Section */}\n <AnalysisFilterSection\n filters={filters}\n schema={schema}\n onFiltersChange={onFiltersChange}\n onFieldDropped={onDropFieldToFilter}\n />\n </div>\n ) : activeTab === 'chart' ? (\n /* Chart Tab Content - use combined metrics/breakdowns in multi-query mode */\n <AnalysisChartConfigPanel\n chartType={chartType}\n chartConfig={chartConfig}\n metrics={isMultiQuery && combinedMetrics ? combinedMetrics : metrics}\n breakdowns={isMultiQuery && combinedBreakdowns ? combinedBreakdowns : breakdowns}\n schema={schema}\n chartAvailability={chartAvailability}\n onChartTypeChange={onChartTypeChange}\n onChartConfigChange={onChartConfigChange}\n />\n ) : activeTab === 'display' ? (\n /* Display Tab Content */\n <AnalysisDisplayConfigPanel\n chartType={chartType}\n displayConfig={displayConfig}\n colorPalette={colorPalette}\n onDisplayConfigChange={onDisplayConfigChange}\n />\n ) : null}\n </div>\n </div>\n )\n})\n\nexport default AnalysisQueryPanel\n","// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>\n// This work is free. You can redistribute it and/or modify it\n// under the terms of the WTFPL, Version 2\n// For more information see LICENSE.txt or http://www.wtfpl.net/\n//\n// For more information, the home page:\n// http://pieroxy.net/blog/pages/lz-string/testing.html\n//\n// LZ-based compression algorithm, version 1.4.5\nvar LZString = (function() {\n\n// private property\nvar f = String.fromCharCode;\nvar keyStrBase64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\nvar keyStrUriSafe = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$\";\nvar baseReverseDic = {};\n\nfunction getBaseValue(alphabet, character) {\n if (!baseReverseDic[alphabet]) {\n baseReverseDic[alphabet] = {};\n for (var i=0 ; i<alphabet.length ; i++) {\n baseReverseDic[alphabet][alphabet.charAt(i)] = i;\n }\n }\n return baseReverseDic[alphabet][character];\n}\n\nvar LZString = {\n compressToBase64 : function (input) {\n if (input == null) return \"\";\n var res = LZString._compress(input, 6, function(a){return keyStrBase64.charAt(a);});\n switch (res.length % 4) { // To produce valid Base64\n default: // When could this happen ?\n case 0 : return res;\n case 1 : return res+\"===\";\n case 2 : return res+\"==\";\n case 3 : return res+\"=\";\n }\n },\n\n decompressFromBase64 : function (input) {\n if (input == null) return \"\";\n if (input == \"\") return null;\n return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrBase64, input.charAt(index)); });\n },\n\n compressToUTF16 : function (input) {\n if (input == null) return \"\";\n return LZString._compress(input, 15, function(a){return f(a+32);}) + \" \";\n },\n\n decompressFromUTF16: function (compressed) {\n if (compressed == null) return \"\";\n if (compressed == \"\") return null;\n return LZString._decompress(compressed.length, 16384, function(index) { return compressed.charCodeAt(index) - 32; });\n },\n\n //compress into uint8array (UCS-2 big endian format)\n compressToUint8Array: function (uncompressed) {\n var compressed = LZString.compress(uncompressed);\n var buf=new Uint8Array(compressed.length*2); // 2 bytes per character\n\n for (var i=0, TotalLen=compressed.length; i<TotalLen; i++) {\n var current_value = compressed.charCodeAt(i);\n buf[i*2] = current_value >>> 8;\n buf[i*2+1] = current_value % 256;\n }\n return buf;\n },\n\n //decompress from uint8array (UCS-2 big endian format)\n decompressFromUint8Array:function (compressed) {\n if (compressed===null || compressed===undefined){\n return LZString.decompress(compressed);\n } else {\n var buf=new Array(compressed.length/2); // 2 bytes per character\n for (var i=0, TotalLen=buf.length; i<TotalLen; i++) {\n buf[i]=compressed[i*2]*256+compressed[i*2+1];\n }\n\n var result = [];\n buf.forEach(function (c) {\n result.push(f(c));\n });\n return LZString.decompress(result.join(''));\n\n }\n\n },\n\n\n //compress into a string that is already URI encoded\n compressToEncodedURIComponent: function (input) {\n if (input == null) return \"\";\n return LZString._compress(input, 6, function(a){return keyStrUriSafe.charAt(a);});\n },\n\n //decompress from an output of compressToEncodedURIComponent\n decompressFromEncodedURIComponent:function (input) {\n if (input == null) return \"\";\n if (input == \"\") return null;\n input = input.replace(/ /g, \"+\");\n return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); });\n },\n\n compress: function (uncompressed) {\n return LZString._compress(uncompressed, 16, function(a){return f(a);});\n },\n _compress: function (uncompressed, bitsPerChar, getCharFromInt) {\n if (uncompressed == null) return \"\";\n var i, value,\n context_dictionary= {},\n context_dictionaryToCreate= {},\n context_c=\"\",\n context_wc=\"\",\n context_w=\"\",\n context_enlargeIn= 2, // Compensate for the first entry which should not count\n context_dictSize= 3,\n context_numBits= 2,\n context_data=[],\n context_data_val=0,\n context_data_position=0,\n ii;\n\n for (ii = 0; ii < uncompressed.length; ii += 1) {\n context_c = uncompressed.charAt(ii);\n if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) {\n context_dictionary[context_c] = context_dictSize++;\n context_dictionaryToCreate[context_c] = true;\n }\n\n context_wc = context_w + context_c;\n if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) {\n context_w = context_wc;\n } else {\n if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {\n if (context_w.charCodeAt(0)<256) {\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n }\n value = context_w.charCodeAt(0);\n for (i=0 ; i<8 ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n } else {\n value = 1;\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1) | value;\n if (context_data_position ==bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = 0;\n }\n value = context_w.charCodeAt(0);\n for (i=0 ; i<16 ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n delete context_dictionaryToCreate[context_w];\n } else {\n value = context_dictionary[context_w];\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n\n\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n // Add wc to the dictionary.\n context_dictionary[context_wc] = context_dictSize++;\n context_w = String(context_c);\n }\n }\n\n // Output the code for w.\n if (context_w !== \"\") {\n if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {\n if (context_w.charCodeAt(0)<256) {\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n }\n value = context_w.charCodeAt(0);\n for (i=0 ; i<8 ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n } else {\n value = 1;\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1) | value;\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = 0;\n }\n value = context_w.charCodeAt(0);\n for (i=0 ; i<16 ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n delete context_dictionaryToCreate[context_w];\n } else {\n value = context_dictionary[context_w];\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n\n\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n }\n\n // Mark the end of the stream\n value = 2;\n for (i=0 ; i<context_numBits ; i++) {\n context_data_val = (context_data_val << 1) | (value&1);\n if (context_data_position == bitsPerChar-1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n\n // Flush the last char\n while (true) {\n context_data_val = (context_data_val << 1);\n if (context_data_position == bitsPerChar-1) {\n context_data.push(getCharFromInt(context_data_val));\n break;\n }\n else context_data_position++;\n }\n return context_data.join('');\n },\n\n decompress: function (compressed) {\n if (compressed == null) return \"\";\n if (compressed == \"\") return null;\n return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });\n },\n\n _decompress: function (length, resetValue, getNextValue) {\n var dictionary = [],\n next,\n enlargeIn = 4,\n dictSize = 4,\n numBits = 3,\n entry = \"\",\n result = [],\n i,\n w,\n bits, resb, maxpower, power,\n c,\n data = {val:getNextValue(0), position:resetValue, index:1};\n\n for (i = 0; i < 3; i += 1) {\n dictionary[i] = i;\n }\n\n bits = 0;\n maxpower = Math.pow(2,2);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n\n switch (next = bits) {\n case 0:\n bits = 0;\n maxpower = Math.pow(2,8);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n c = f(bits);\n break;\n case 1:\n bits = 0;\n maxpower = Math.pow(2,16);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n c = f(bits);\n break;\n case 2:\n return \"\";\n }\n dictionary[3] = c;\n w = c;\n result.push(c);\n while (true) {\n if (data.index > length) {\n return \"\";\n }\n\n bits = 0;\n maxpower = Math.pow(2,numBits);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n\n switch (c = bits) {\n case 0:\n bits = 0;\n maxpower = Math.pow(2,8);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n\n dictionary[dictSize++] = f(bits);\n c = dictSize-1;\n enlargeIn--;\n break;\n case 1:\n bits = 0;\n maxpower = Math.pow(2,16);\n power=1;\n while (power!=maxpower) {\n resb = data.val & data.position;\n data.position >>= 1;\n if (data.position == 0) {\n data.position = resetValue;\n data.val = getNextValue(data.index++);\n }\n bits |= (resb>0 ? 1 : 0) * power;\n power <<= 1;\n }\n dictionary[dictSize++] = f(bits);\n c = dictSize-1;\n enlargeIn--;\n break;\n case 2:\n return result.join('');\n }\n\n if (enlargeIn == 0) {\n enlargeIn = Math.pow(2, numBits);\n numBits++;\n }\n\n if (dictionary[c]) {\n entry = dictionary[c];\n } else {\n if (c === dictSize) {\n entry = w + w.charAt(0);\n } else {\n return null;\n }\n }\n result.push(entry);\n\n // Add w+entry[0] to the dictionary.\n dictionary[dictSize++] = w + entry.charAt(0);\n enlargeIn--;\n\n w = entry;\n\n if (enlargeIn == 0) {\n enlargeIn = Math.pow(2, numBits);\n numBits++;\n }\n\n }\n }\n};\n return LZString;\n})();\n\nif (typeof define === 'function' && define.amd) {\n define(function () { return LZString; });\n} else if( typeof module !== 'undefined' && module != null ) {\n module.exports = LZString\n} else if( typeof angular !== 'undefined' && angular != null ) {\n angular.module('LZString', [])\n .factory('LZString', function () {\n return LZString;\n });\n}\n","/**\n * Share utilities for QueryBuilder\n *\n * Handles compression, encoding, and URL generation for sharing analysis state.\n * Uses LZ-String for compression which produces URL-safe output.\n */\n\nimport { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string'\nimport type { CubeQuery, ChartType, ChartAxisConfig, ChartDisplayConfig, MultiQueryConfig } from '../types'\n\n/**\n * State that can be shared via URL\n * Query is required (can be single CubeQuery or MultiQueryConfig), chart config is optional (may be dropped if too large)\n */\nexport interface ShareableState {\n query: CubeQuery | MultiQueryConfig\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n activeView?: 'table' | 'chart'\n}\n\n/**\n * Result of compression with fallback\n */\nexport interface CompressionResult {\n encoded: string | null\n queryOnly: boolean\n}\n\n// Max safe URL hash length (conservative for browser compatibility)\nconst MAX_HASH_LENGTH = 1800\nconst SHARE_PREFIX = 'share='\n\n/**\n * Compress state to URL-safe encoded string\n */\nexport function compressAndEncode(state: ShareableState): string {\n const json = JSON.stringify(state)\n return compressToEncodedURIComponent(json)\n}\n\n/**\n * Decompress URL-safe encoded string back to state\n * Returns null if decompression or parsing fails\n */\nexport function decodeAndDecompress(encoded: string): ShareableState | null {\n try {\n const json = decompressFromEncodedURIComponent(encoded)\n if (!json) return null\n\n const state = JSON.parse(json) as ShareableState\n\n // Validate required field\n if (!state.query || typeof state.query !== 'object') {\n return null\n }\n\n return state\n } catch {\n return null\n }\n}\n\n/**\n * Check if compressed state fits within URL length limit\n */\nexport function isShareableSize(state: ShareableState): { ok: boolean; size: number; maxSize: number } {\n const encoded = compressAndEncode(state)\n return {\n ok: encoded.length <= MAX_HASH_LENGTH,\n size: encoded.length,\n maxSize: MAX_HASH_LENGTH\n }\n}\n\n/**\n * Compress state with automatic fallback\n * If full state is too large, tries with query only\n * Returns null encoded if even query-only is too large\n */\nexport function compressWithFallback(state: ShareableState): CompressionResult {\n // Try full state first\n const fullEncoded = compressAndEncode(state)\n if (fullEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: fullEncoded, queryOnly: false }\n }\n\n // Fall back to query only\n const queryOnlyState: ShareableState = { query: state.query }\n const queryOnlyEncoded = compressAndEncode(queryOnlyState)\n\n if (queryOnlyEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: queryOnlyEncoded, queryOnly: true }\n }\n\n // Even query-only is too large\n return { encoded: null, queryOnly: true }\n}\n\n/**\n * Generate full share URL with compressed state in hash\n */\nexport function generateShareUrl(state: ShareableState): string | null {\n const { encoded } = compressWithFallback(state)\n if (!encoded) return null\n\n return `${window.location.origin}${window.location.pathname}#${SHARE_PREFIX}${encoded}`\n}\n\n/**\n * Parse share hash from current URL\n * Returns encoded string if #share= is present, null otherwise\n */\nexport function parseShareHash(): string | null {\n if (typeof window === 'undefined') return null\n\n const hash = window.location.hash\n if (!hash || !hash.startsWith(`#${SHARE_PREFIX}`)) {\n return null\n }\n\n return hash.slice(SHARE_PREFIX.length + 1) // +1 for the #\n}\n\n/**\n * Clear share hash from URL without page reload\n */\nexport function clearShareHash(): void {\n if (typeof window === 'undefined') return\n\n const url = new URL(window.location.href)\n url.hash = ''\n window.history.replaceState(null, '', url.toString())\n}\n\n/**\n * Get the maximum allowed hash length\n */\nexport function getMaxHashLength(): number {\n return MAX_HASH_LENGTH\n}\n","/**\n * Utility functions for AI Assistant\n */\n\nimport type { \n AIQueryRequest,\n AIQueryResponse,\n AIConfig\n} from './types'\nimport { \n AI_STORAGE_KEY,\n DEFAULT_AI_CONFIG\n} from './constants'\n\n/**\n * Send a user prompt to AI proxy (server builds system prompt)\n */\nexport async function sendGeminiMessage(\n apiKey: string,\n userPrompt: string,\n endpoint: string = '/api/ai/generate'\n): Promise<AIQueryResponse> {\n const requestBody: AIQueryRequest = {\n text: userPrompt // Send only the user's prompt, server handles system prompt\n }\n\n // Only add API key header if provided (allow empty string for server key)\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json'\n }\n \n if (apiKey && apiKey.trim()) {\n headers['X-API-Key'] = apiKey\n }\n\n console.log('🤖 Client: Sending user prompt to AI proxy')\n console.log(' URL:', endpoint)\n console.log(' Headers:', headers)\n console.log(' User prompt length:', userPrompt.length)\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody)\n })\n\n console.log('📥 Client: Proxy response')\n console.log(' Status:', response.status)\n console.log(' Status Text:', response.statusText)\n\n if (!response.ok) {\n let errorMessage = `Failed to generate content: ${response.status} ${response.statusText}`\n \n try {\n // Try to parse JSON error response first\n const errorData = await response.json()\n console.error('❌ Client: Proxy error:', errorData)\n \n // Handle rate limit errors specially\n if (response.status === 429 && errorData.error === 'Daily quota exceeded') {\n throw new Error(\n `${errorData.message}\\n\\n${errorData.suggestion || 'Add your own Gemini API key for unlimited access.'}`\n )\n }\n \n // Handle other structured errors\n if (errorData.error) {\n errorMessage = errorData.message || errorData.error\n if (errorData.suggestion) {\n errorMessage += `\\n\\n💡 ${errorData.suggestion}`\n }\n }\n } catch {\n // Fallback to text if JSON parsing fails\n try {\n const errorText = await response.text()\n console.error('❌ Client: Proxy text error:', errorText)\n errorMessage = errorText || errorMessage\n } catch {\n console.error('❌ Client: Could not parse error response')\n }\n }\n \n throw new Error(errorMessage)\n }\n\n const data = await response.json()\n console.log('✅ Client: Successfully generated content')\n return data\n}\n\n// Removed: buildSystemPrompt and formatCubeSchemaForPrompt \n// These functions are now handled server-side for better security\n\n/**\n * Save AI configuration to localStorage\n */\nexport function saveAIConfig(config: AIConfig): void {\n try {\n localStorage.setItem(AI_STORAGE_KEY, JSON.stringify(config))\n } catch (error) {\n console.warn('Failed to save AI config to localStorage:', error)\n }\n}\n\n/**\n * Load AI configuration from localStorage\n */\nexport function loadAIConfig(): AIConfig {\n try {\n const saved = localStorage.getItem(AI_STORAGE_KEY)\n if (saved) {\n const parsed = JSON.parse(saved)\n return { ...DEFAULT_AI_CONFIG, ...parsed }\n }\n } catch (error) {\n console.warn('Failed to load AI config from localStorage:', error)\n }\n return { ...DEFAULT_AI_CONFIG }\n}\n\n/**\n * Extract query text from simplified AI response and clean up formatting\n */\nexport function extractTextFromResponse(response: AIQueryResponse): string {\n const rawText = response.query || ''\n\n // Clean up common markdown formatting that might appear\n return rawText\n .replace(/```json\\s*/g, '') // Remove ```json\n .replace(/```\\s*/g, '') // Remove ```\n .replace(/^\\s*```.*\\n/gm, '') // Remove any remaining code block markers\n .trim()\n}","/**\n * Multi-Query Validation Utilities\n *\n * Pure functions for validating multi-query configurations.\n * These help detect issues like measure collisions and granularity mismatches.\n */\n\nimport type { CubeQuery } from '../types'\n\n// TimeDimension type extracted from CubeQuery\ntype TimeDimension = NonNullable<CubeQuery['timeDimensions']>[number]\n\n/**\n * Validation error for multi-query configuration\n */\nexport interface MultiQueryValidationError {\n type: 'missing_time_dimension' | 'granularity_mismatch' | 'missing_merge_key'\n queryIndex: number\n message: string\n details?: {\n field?: string\n expectedGranularity?: string\n actualGranularity?: string\n }\n}\n\n/**\n * Validation warning for multi-query configuration\n */\nexport interface MultiQueryValidationWarning {\n type: 'measure_collision' | 'asymmetric_date_range'\n queryIndices: number[]\n message: string\n affectedMeasures?: string[]\n}\n\n/**\n * Result of multi-query validation\n */\nexport interface MultiQueryValidationResult {\n isValid: boolean\n errors: MultiQueryValidationError[]\n warnings: MultiQueryValidationWarning[]\n}\n\n/**\n * Extract time dimension info from a query\n */\nexport function extractTimeDimensions(query: CubeQuery): TimeDimension[] {\n return query.timeDimensions || []\n}\n\n/**\n * Validate that all queries have matching time dimension granularities\n * Only relevant for 'merge' strategy where data needs to align\n */\nexport function validateTimeDimensionAlignment(queries: CubeQuery[]): MultiQueryValidationError[] {\n const errors: MultiQueryValidationError[] = []\n\n if (queries.length < 2) return errors\n\n // Get time dimensions from first query as reference\n const q1TimeDims = extractTimeDimensions(queries[0])\n if (q1TimeDims.length === 0) return errors // No time dimensions to validate\n\n // Check each subsequent query\n for (let i = 1; i < queries.length; i++) {\n const qTimeDims = extractTimeDimensions(queries[i])\n\n // Check if query has time dimensions\n if (qTimeDims.length === 0 && q1TimeDims.length > 0) {\n errors.push({\n type: 'missing_time_dimension',\n queryIndex: i,\n message: `Query ${i + 1} is missing time dimension \"${q1TimeDims[0].dimension}\"`,\n details: { field: q1TimeDims[0].dimension }\n })\n continue\n }\n\n // Check granularity matches\n for (const refTimeDim of q1TimeDims) {\n const matchingDim = qTimeDims.find(td => td.dimension === refTimeDim.dimension)\n if (matchingDim && matchingDim.granularity !== refTimeDim.granularity) {\n errors.push({\n type: 'granularity_mismatch',\n queryIndex: i,\n message: `Query ${i + 1} uses \"${matchingDim.granularity}\" granularity but Query 1 uses \"${refTimeDim.granularity}\"`,\n details: {\n field: refTimeDim.dimension,\n expectedGranularity: refTimeDim.granularity,\n actualGranularity: matchingDim.granularity\n }\n })\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate that merge keys exist in all queries\n */\nexport function validateMergeKeys(queries: CubeQuery[], mergeKeys: string[]): MultiQueryValidationError[] {\n const errors: MultiQueryValidationError[] = []\n\n if (queries.length < 2 || mergeKeys.length === 0) return errors\n\n for (let i = 0; i < queries.length; i++) {\n const query = queries[i]\n const allFields = new Set([\n ...(query.dimensions || []),\n ...(query.timeDimensions?.map(td => td.dimension) || [])\n ])\n\n for (const key of mergeKeys) {\n if (!allFields.has(key)) {\n errors.push({\n type: 'missing_merge_key',\n queryIndex: i,\n message: `Query ${i + 1} is missing merge dimension \"${key}\"`,\n details: { field: key }\n })\n }\n }\n }\n\n return errors\n}\n\n/**\n * Detect when the same measure appears in multiple queries\n * This is a warning since the first value wins in merge mode\n */\nexport function detectMeasureCollisions(queries: CubeQuery[]): MultiQueryValidationWarning[] {\n const warnings: MultiQueryValidationWarning[] = []\n\n if (queries.length < 2) return warnings\n\n // Count occurrences of each measure\n const measureCounts = new Map<string, number[]>()\n\n queries.forEach((query, index) => {\n query.measures?.forEach(measure => {\n if (!measureCounts.has(measure)) {\n measureCounts.set(measure, [])\n }\n measureCounts.get(measure)!.push(index)\n })\n })\n\n // Find collisions\n const collisions: string[] = []\n const collisionIndices = new Set<number>()\n\n measureCounts.forEach((indices, measure) => {\n if (indices.length > 1) {\n collisions.push(measure)\n indices.forEach(i => collisionIndices.add(i))\n }\n })\n\n if (collisions.length > 0) {\n warnings.push({\n type: 'measure_collision',\n queryIndices: Array.from(collisionIndices).sort(),\n message: `Measure${collisions.length > 1 ? 's' : ''} \"${collisions.join('\", \"')}\" appear${collisions.length === 1 ? 's' : ''} in multiple queries - first value will be used`,\n affectedMeasures: collisions\n })\n }\n\n return warnings\n}\n\n/**\n * Check if queries have different date ranges\n */\nexport function detectAsymmetricDateRanges(queries: CubeQuery[]): MultiQueryValidationWarning[] {\n const warnings: MultiQueryValidationWarning[] = []\n\n if (queries.length < 2) return warnings\n\n // Get date ranges from each query's time dimensions\n const dateRanges = queries.map(q => {\n const timeDim = q.timeDimensions?.[0]\n return timeDim?.dateRange\n })\n\n // Check if any are different\n const uniqueRanges = new Set(dateRanges.map(r => JSON.stringify(r)))\n if (uniqueRanges.size > 1) {\n warnings.push({\n type: 'asymmetric_date_range',\n queryIndices: queries.map((_, i) => i),\n message: 'Queries have different date ranges - some data points may be missing in merged results'\n })\n }\n\n return warnings\n}\n\n/**\n * Validate a multi-query configuration\n * For 'merge' strategy: strict validation (errors block execution)\n * For 'concat' strategy: only warnings\n */\nexport function validateMultiQueryConfig(\n queries: CubeQuery[],\n mergeStrategy: 'concat' | 'merge',\n mergeKeys: string[] = []\n): MultiQueryValidationResult {\n const errors: MultiQueryValidationError[] = []\n const warnings: MultiQueryValidationWarning[] = []\n\n if (queries.length < 2) {\n return { isValid: true, errors, warnings }\n }\n\n // Always detect measure collisions (warning)\n warnings.push(...detectMeasureCollisions(queries))\n\n // Always detect asymmetric date ranges (warning)\n warnings.push(...detectAsymmetricDateRanges(queries))\n\n // For merge strategy, validate alignment\n if (mergeStrategy === 'merge') {\n errors.push(...validateTimeDimensionAlignment(queries))\n if (mergeKeys.length > 0) {\n errors.push(...validateMergeKeys(queries, mergeKeys))\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n }\n}\n\n/**\n * Check if a multi-query configuration is valid for execution\n */\nexport function isMultiQueryValid(queries: CubeQuery[]): boolean {\n return queries.filter(q =>\n (q.measures?.length || 0) +\n (q.dimensions?.length || 0) +\n (q.timeDimensions?.length || 0) > 0\n ).length >= 2\n}\n\n/**\n * Get human-readable validation summary\n */\nexport function getValidationSummary(result: MultiQueryValidationResult): string {\n if (result.isValid && result.warnings.length === 0) {\n return 'Configuration is valid'\n }\n\n const parts: string[] = []\n\n if (result.errors.length > 0) {\n parts.push(`${result.errors.length} error${result.errors.length > 1 ? 's' : ''}`)\n }\n\n if (result.warnings.length > 0) {\n parts.push(`${result.warnings.length} warning${result.warnings.length > 1 ? 's' : ''}`)\n }\n\n return parts.join(', ')\n}\n","/**\n * AnalysisAIPanel Component\n *\n * A collapsible panel for AI-powered query generation.\n * Appears above the results panel when activated.\n */\n\nimport { useCallback, KeyboardEvent } from 'react'\nimport { getIcon } from '../../icons'\n\nconst SparklesIcon = getIcon('sparkles')\nconst ErrorIcon = getIcon('error')\n\nexport interface AnalysisAIPanelProps {\n /** User's natural language prompt */\n userPrompt: string\n /** Callback when prompt changes */\n onPromptChange: (prompt: string) => void\n /** Whether a query is being generated */\n isGenerating: boolean\n /** Error message from generation */\n error: string | null\n /** Whether the AI has generated a query */\n hasGeneratedQuery: boolean\n /** Callback to generate query */\n onGenerate: () => void\n /** Callback to accept the generated query */\n onAccept: () => void\n /** Callback to cancel and restore previous state */\n onCancel: () => void\n}\n\nexport default function AnalysisAIPanel({\n userPrompt,\n onPromptChange,\n isGenerating,\n error,\n hasGeneratedQuery,\n onGenerate,\n onAccept,\n onCancel\n}: AnalysisAIPanelProps) {\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n onGenerate()\n }\n },\n [onGenerate]\n )\n\n return (\n <div\n className=\"border-b border-dc-border\"\n style={{ background: 'linear-gradient(to right, var(--dc-ai-gradient-start), var(--dc-ai-gradient-end))' }}\n >\n {/* Header */}\n <div className=\"px-4 py-2 flex items-center justify-between border-b border-dc-border bg-dc-surface-secondary\">\n <div className=\"flex items-center gap-2\">\n <SparklesIcon className=\"w-4 h-4 text-dc-accent\" />\n <span className=\"text-sm font-medium text-dc-text\">AI Query Generator</span>\n {isGenerating && (\n <span className=\"text-xs text-dc-accent animate-pulse\">\n Generating...\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {hasGeneratedQuery && (\n <button\n onClick={onAccept}\n className=\"px-3 py-1 text-xs font-medium text-white bg-dc-success hover:opacity-80 rounded transition-colors\"\n >\n Accept\n </button>\n )}\n <button\n onClick={onCancel}\n className=\"px-3 py-1 text-xs font-medium text-dc-text-secondary hover:text-dc-text bg-dc-surface hover:bg-dc-surface-hover border border-dc-border rounded transition-colors\"\n >\n {hasGeneratedQuery ? 'Cancel' : 'Close'}\n </button>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"p-4\">\n <div className=\"flex gap-3\">\n {/* Prompt input */}\n <div className=\"flex-1\">\n <textarea\n value={userPrompt}\n onChange={(e) => onPromptChange(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Describe your query in natural language... (e.g., 'Show total sales by month for the last year')\"\n className=\"w-full px-3 py-2 text-sm border border-dc-border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-dc-accent focus:border-dc-accent resize-none bg-dc-surface text-dc-text placeholder-dc-text-muted\"\n rows={2}\n disabled={isGenerating}\n />\n <div className=\"mt-1 text-xs text-dc-text-muted\">\n Press Enter to generate, Shift+Enter for new line\n </div>\n </div>\n\n {/* Generate button */}\n <div className=\"flex-shrink-0\">\n <button\n onClick={onGenerate}\n disabled={isGenerating || !userPrompt.trim()}\n className={`px-4 py-2 text-sm font-medium rounded-md transition-colors flex items-center gap-2 ${\n isGenerating || !userPrompt.trim()\n ? 'bg-dc-surface-tertiary text-dc-text-disabled cursor-not-allowed'\n : 'bg-dc-accent hover:bg-dc-accent-hover text-white'\n }`}\n >\n {isGenerating ? (\n <>\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin\" />\n <span>Generating...</span>\n </>\n ) : (\n <>\n <SparklesIcon className=\"w-4 h-4\" />\n <span>Generate</span>\n </>\n )}\n </button>\n </div>\n </div>\n\n {/* Error message */}\n {error && (\n <div className=\"mt-3 flex items-start gap-2 p-3 bg-dc-error-bg border border-dc-error-border rounded-md\">\n <ErrorIcon className=\"w-4 h-4 text-dc-error mt-0.5 flex-shrink-0\" />\n <div className=\"text-sm text-dc-error\">{error}</div>\n </div>\n )}\n\n {/* Success message */}\n {hasGeneratedQuery && !error && (\n <div className=\"mt-3 p-3 bg-dc-success-bg border border-dc-success-border rounded-md\">\n <div className=\"text-sm text-dc-success\">\n Query generated and loaded! Check the results below, then click{' '}\n <strong>Accept</strong> to keep or <strong>Cancel</strong> to revert.\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * AnalysisBuilder Component\n *\n * A redesigned query builder with a modern UX:\n * - Results panel on the left (large)\n * - Query builder panel on the right\n * - Search-based field selection via modal\n * - Sections: Metrics (measures), Breakdown (dimensions), Filters\n * - Auto-execute queries on field changes\n */\n\nimport { useState, useCallback, useEffect, useRef, useMemo, forwardRef, useImperativeHandle } from 'react'\nimport { useCubeContext } from '../../providers/CubeProvider'\nimport { useCubeQuery } from '../../hooks/useCubeQuery'\nimport { useMultiCubeQuery } from '../../hooks/useMultiCubeQuery'\nimport type {\n AnalysisBuilderProps,\n AnalysisBuilderRef,\n AnalysisBuilderState,\n AIState,\n MetricItem,\n BreakdownItem,\n QueryPanelTab,\n ExecutionStatus,\n AnalysisBuilderStorageState,\n QueryAnalysis\n} from './types'\nimport type { CubeQuery, Filter, ChartType, ChartAxisConfig, ChartDisplayConfig, QueryMergeStrategy, MultiQueryConfig } from '../../types'\nimport { isMultiQueryConfig } from '../../types'\nimport { parseDateRange, calculatePriorPeriod, formatDateForCube } from '../../../shared/date-utils'\nimport FieldSearchModal from './FieldSearchModal'\nimport AnalysisResultsPanel from './AnalysisResultsPanel'\nimport AnalysisQueryPanel from './AnalysisQueryPanel'\nimport type { MetaField, MetaResponse } from '../../shared/types'\nimport { cleanQueryForServer, convertDateRangeTypeToValue } from '../../shared/utils'\nimport { getAllChartAvailability, getSmartChartDefaults, shouldAutoSwitchChartType } from '../../shared/chartDefaults'\nimport { compressWithFallback, parseShareHash, decodeAndDecompress, clearShareHash } from '../../utils/shareUtils'\nimport { getColorPalette } from '../../utils/colorPalettes'\nimport { sendGeminiMessage, extractTextFromResponse } from '../AIAssistant/utils'\nimport { validateMultiQueryConfig, type MultiQueryValidationResult } from '../../utils/multiQueryValidation'\nimport AnalysisAIPanel from './AnalysisAIPanel'\n\n// Storage key for localStorage persistence\nconst STORAGE_KEY = 'drizzle-cube-analysis-builder-state'\n\n// Debounce delay for auto-execute (ms)\nconst AUTO_EXECUTE_DELAY = 300\n\n/**\n * Generate a unique ID for items\n */\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n}\n\n/**\n * Generate letter label for metrics (A, B, C, ..., AA, AB, ...)\n */\nfunction generateMetricLabel(index: number): string {\n let label = ''\n let n = index\n do {\n label = String.fromCharCode(65 + (n % 26)) + label\n n = Math.floor(n / 26) - 1\n } while (n >= 0)\n return label\n}\n\n/**\n * Find date filter for a specific time dimension field\n * Recursively searches filters (including nested and/or groups)\n * Handles both UI format ({type: 'and'/'or', filters: [...]}) and simple filters\n */\nfunction findDateFilterForField(\n filters: Filter[],\n field: string\n): { dateRange: string | string[] } | undefined {\n for (const filter of filters) {\n // Check for UI GroupFilter format: {type: 'and'/'or', filters: [...]}\n if ('type' in filter && 'filters' in filter) {\n const groupFilter = filter as { type: 'and' | 'or'; filters: Filter[] }\n const nested = findDateFilterForField(groupFilter.filters, field)\n if (nested) return nested\n } else if ('member' in filter) {\n // Simple filter with member, operator, dateRange\n const simple = filter as { member: string; operator?: string; dateRange?: string | string[] }\n if (simple.member === field && simple.operator === 'inDateRange' && simple.dateRange) {\n return { dateRange: simple.dateRange }\n }\n }\n }\n return undefined\n}\n\n/**\n * Build compareDateRange for a time dimension based on its date filter\n * When comparison is enabled, returns [[currentStart, currentEnd], [priorStart, priorEnd]]\n */\nfunction buildCompareDateRangeFromFilter(\n timeDimensionField: string,\n filters: Filter[]\n): [string, string][] | undefined {\n // Find the date filter for this time dimension\n const dateFilter = findDateFilterForField(filters, timeDimensionField)\n if (!dateFilter?.dateRange) return undefined\n\n // Parse the current range using shared utility\n const currentPeriod = parseDateRange(dateFilter.dateRange)\n if (!currentPeriod) return undefined\n\n // Calculate prior period using shared utility\n const priorPeriod = calculatePriorPeriod(currentPeriod.start, currentPeriod.end)\n\n return [\n [formatDateForCube(currentPeriod.start), formatDateForCube(currentPeriod.end)],\n [formatDateForCube(priorPeriod.start), formatDateForCube(priorPeriod.end)]\n ]\n}\n\n/**\n * Remove date filter for a specific field from filters array\n * Returns a new array with the filter removed (immutable)\n */\nfunction removeComparisonDateFilter(filters: Filter[], field: string): Filter[] {\n return filters.reduce<Filter[]>((acc, filter) => {\n // Check for UI GroupFilter format: {type: 'and'/'or', filters: [...]}\n if ('type' in filter && 'filters' in filter) {\n const groupFilter = filter as { type: 'and' | 'or'; filters: Filter[] }\n const cleanedSubFilters = removeComparisonDateFilter(groupFilter.filters, field)\n // Only keep the group if it still has filters\n if (cleanedSubFilters.length > 0) {\n acc.push({ type: groupFilter.type, filters: cleanedSubFilters } as Filter)\n }\n } else if ('member' in filter) {\n // Simple filter - skip if it's the date filter for this field\n const simple = filter as { member: string; operator?: string; dateRange?: string | string[] }\n if (!(simple.member === field && simple.operator === 'inDateRange')) {\n acc.push(filter)\n }\n } else {\n acc.push(filter)\n }\n return acc\n }, [])\n}\n\n/**\n * Convert metrics and breakdowns to CubeQuery format\n */\nfunction buildCubeQuery(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n filters: Filter[],\n order?: Record<string, 'asc' | 'desc'>\n): CubeQuery {\n // Find time dimensions with comparison enabled\n const comparisonFields = breakdowns\n .filter((b) => b.isTimeDimension && b.enableComparison)\n .map((b) => b.field)\n\n // Remove date filters for comparison-enabled time dimensions\n // (compareDateRange will handle the date ranges instead)\n let filteredFilters = filters\n for (const field of comparisonFields) {\n filteredFilters = removeComparisonDateFilter(filteredFilters, field)\n }\n\n const query: CubeQuery = {\n measures: metrics.map((m) => m.field),\n dimensions: breakdowns.filter((b) => !b.isTimeDimension).map((b) => b.field),\n timeDimensions: breakdowns\n .filter((b) => b.isTimeDimension)\n .map((b) => {\n const td: {\n dimension: string\n granularity: string\n compareDateRange?: [string, string][]\n } = {\n dimension: b.field,\n granularity: b.granularity || 'day'\n }\n\n // If comparison is enabled, build compareDateRange from the ORIGINAL filter\n if (b.enableComparison) {\n const compareDateRange = buildCompareDateRangeFromFilter(b.field, filters)\n if (compareDateRange) {\n td.compareDateRange = compareDateRange\n }\n }\n\n return td\n }),\n filters: filteredFilters.length > 0 ? filteredFilters : undefined,\n order: order && Object.keys(order).length > 0 ? order : undefined\n }\n\n // Clean up empty arrays\n if (query.measures?.length === 0) delete query.measures\n if (query.dimensions?.length === 0) delete query.dimensions\n if (query.timeDimensions?.length === 0) delete query.timeDimensions\n\n return query\n}\n\n/**\n * Create initial empty state\n */\nfunction createInitialState(): AnalysisBuilderState {\n return {\n metrics: [],\n breakdowns: [],\n filters: [],\n order: undefined,\n validationStatus: 'idle',\n validationError: null,\n executionStatus: 'idle',\n executionResults: null,\n executionError: null,\n totalRowCount: null,\n resultsStale: false\n }\n}\n\n/**\n * Load all state from localStorage once (to avoid repeated parsing)\n */\nfunction loadInitialStateFromStorage(\n disableLocalStorage: boolean\n): AnalysisBuilderStorageState | null {\n if (disableLocalStorage) return null\n\n try {\n const saved = localStorage.getItem(STORAGE_KEY)\n if (saved) {\n return JSON.parse(saved) as AnalysisBuilderStorageState\n }\n } catch {\n // Ignore parse errors\n }\n return null\n}\n\nconst AnalysisBuilder = forwardRef<AnalysisBuilderRef, AnalysisBuilderProps>(\n (\n {\n className = '',\n maxHeight,\n initialQuery,\n initialChartConfig,\n initialData,\n colorPalette: externalColorPalette,\n disableLocalStorage: disableLocalStorageProp = false,\n hideSettings: _hideSettings = false,\n onQueryChange,\n onChartConfigChange\n },\n ref\n ) => {\n // Mark unused props for future use\n void _hideSettings\n\n // Disable localStorage when initialQuery is provided (parent manages state)\n const disableLocalStorage = disableLocalStorageProp || !!initialQuery\n\n // Get context - metaLoading and metaError used by FieldSearchModal internally\n const { meta, cubeApi } = useCubeContext()\n\n // Load localStorage once on mount (before useState calls) to avoid repeated parsing\n const cachedStorage = useMemo(\n () => loadInitialStateFromStorage(disableLocalStorageProp),\n [] // Only run once on mount\n )\n\n // Helper to convert a CubeQuery to AnalysisBuilderState\n const queryToState = (query: CubeQuery): AnalysisBuilderState => ({\n ...createInitialState(),\n metrics: (query.measures || []).map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index)\n })),\n breakdowns: [\n ...(query.dimensions || []).map((field) => ({\n id: generateId(),\n field,\n isTimeDimension: false\n })),\n ...(query.timeDimensions || []).map((td) => ({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true\n }))\n ],\n filters: query.filters || [],\n order: query.order\n })\n\n // Multi-query state management\n // queryStates holds an array of query configurations (one per tab)\n // For single-query mode, this is an array with one element\n const [queryStates, setQueryStates] = useState<AnalysisBuilderState[]>(() => {\n // If initialQuery is provided, detect if it's multi-query or single query internally\n if (initialQuery) {\n if (isMultiQueryConfig(initialQuery)) {\n // Multi-query config - parse each query\n const multiConfig = initialQuery as MultiQueryConfig\n return multiConfig.queries.map(queryToState)\n }\n // Single query - wrap in array\n const singleQuery = initialQuery as CubeQuery\n return [queryToState(singleQuery)]\n }\n\n // Use cached localStorage data if available\n if (cachedStorage) {\n // Support legacy single-query format and new multi-query format\n const queries = cachedStorage.queryStates || [{\n ...createInitialState(),\n metrics: cachedStorage.metrics || [],\n breakdowns: cachedStorage.breakdowns || [],\n filters: cachedStorage.filters || [],\n order: cachedStorage.order\n }]\n return queries\n }\n\n return [createInitialState()]\n })\n\n // Index of the currently active query tab\n const [activeQueryIndex, setActiveQueryIndex] = useState<number>(() => {\n if (cachedStorage?.activeQueryIndex !== undefined) {\n return cachedStorage.activeQueryIndex\n }\n return 0\n })\n\n // Merge strategy for combining multiple query results\n const [mergeStrategy, setMergeStrategy] = useState<QueryMergeStrategy>(() => {\n // Priority: initialQuery (if multi-query) > cached localStorage > default\n if (initialQuery && isMultiQueryConfig(initialQuery)) {\n const multiConfig = initialQuery as MultiQueryConfig\n if (multiConfig.mergeStrategy) {\n return multiConfig.mergeStrategy\n }\n }\n if (cachedStorage?.mergeStrategy) {\n return cachedStorage.mergeStrategy\n }\n return 'concat'\n })\n\n // Dimension keys to align data on for 'merge' strategy - auto-computed from Q1 breakdowns\n const mergeKeys = useMemo(() => {\n if (mergeStrategy !== 'merge' || queryStates.length === 0) return undefined\n const q1Breakdowns = queryStates[0].breakdowns\n if (q1Breakdowns.length === 0) return undefined\n return q1Breakdowns.map(b => b.field)\n }, [mergeStrategy, queryStates])\n\n // Derive the active query state (convenience accessor)\n const state = queryStates[activeQueryIndex] || createInitialState()\n\n // Helper to update the active query state\n const setState = useCallback((updater: AnalysisBuilderState | ((prev: AnalysisBuilderState) => AnalysisBuilderState)) => {\n setQueryStates(prevStates => {\n const newStates = [...prevStates]\n if (typeof updater === 'function') {\n newStates[activeQueryIndex] = updater(prevStates[activeQueryIndex] || createInitialState())\n } else {\n newStates[activeQueryIndex] = updater\n }\n return newStates\n })\n }, [activeQueryIndex])\n\n // Sync breakdowns from Q1 to other queries when in merge mode\n useEffect(() => {\n if (mergeStrategy !== 'merge' || queryStates.length <= 1) return\n\n const q1Breakdowns = queryStates[0].breakdowns\n\n // Check if other queries need syncing\n let needsSync = false\n for (let i = 1; i < queryStates.length; i++) {\n if (JSON.stringify(queryStates[i].breakdowns) !== JSON.stringify(q1Breakdowns)) {\n needsSync = true\n break\n }\n }\n\n if (needsSync) {\n setQueryStates(prev => prev.map((qs, i) =>\n i === 0 ? qs : { ...qs, breakdowns: [...q1Breakdowns] }\n ))\n }\n }, [mergeStrategy, queryStates])\n\n // Chart configuration state - load from initialChartConfig, cached localStorage, or defaults\n const [chartType, setChartType] = useState<ChartType>(() => {\n // Priority: initialChartConfig > cached localStorage > default\n if (initialChartConfig?.chartType) {\n return initialChartConfig.chartType\n }\n if (!initialQuery && cachedStorage?.chartType) {\n return cachedStorage.chartType\n }\n return 'line'\n })\n\n const [chartConfig, setChartConfig] = useState<ChartAxisConfig>(() => {\n // Priority: initialChartConfig > cached localStorage > default\n if (initialChartConfig?.chartConfig) {\n return initialChartConfig.chartConfig\n }\n if (!initialQuery && cachedStorage?.chartConfig) {\n return cachedStorage.chartConfig\n }\n return {}\n })\n\n const [displayConfig, setDisplayConfig] = useState<ChartDisplayConfig>(() => {\n // Priority: initialChartConfig > cached localStorage > default\n if (initialChartConfig?.displayConfig) {\n return initialChartConfig.displayConfig\n }\n if (!initialQuery && cachedStorage?.displayConfig) {\n return cachedStorage.displayConfig\n }\n return { showLegend: true, showGrid: true, showTooltip: true }\n })\n\n // Local color palette state (only used when externalColorPalette is not provided)\n const [localPaletteName, setLocalPaletteName] = useState<string>('default')\n\n // Compute effective color palette\n const effectiveColorPalette = useMemo(() => {\n if (externalColorPalette) return externalColorPalette\n return getColorPalette(localPaletteName)\n }, [externalColorPalette, localPaletteName])\n\n // Order is now stored per-query in queryStates[index].order\n // Access current query's order via state.order\n\n // UI state\n const [activeTab, setActiveTab] = useState<QueryPanelTab>('query')\n const [activeView, setActiveView] = useState<'table' | 'chart'>(() => {\n if (!initialQuery && cachedStorage?.activeView) {\n return cachedStorage.activeView\n }\n return 'chart'\n })\n const [displayLimit, setDisplayLimit] = useState<number>(100)\n\n // Track whether user manually selected a chart type (vs auto-selection)\n // If initialChartConfig is provided, treat it as a manual selection to prevent auto-switching\n const [userManuallySelectedChart, setUserManuallySelectedChart] = useState(\n () => !!initialChartConfig?.chartType\n )\n\n // Debug data state (from dry-run API) - one entry per query in multi-query mode\n interface DebugDataEntry {\n sql: { sql: string; params: any[] } | null\n analysis: QueryAnalysis | null\n loading: boolean\n error: string | null\n }\n const [debugDataPerQuery, setDebugDataPerQuery] = useState<DebugDataEntry[]>([])\n\n // Field search modal state\n const [showFieldModal, setShowFieldModal] = useState(false)\n const [fieldModalMode, setFieldModalMode] = useState<'metrics' | 'breakdown'>('metrics')\n\n // Share state\n const [shareButtonState, setShareButtonState] = useState<'idle' | 'copied' | 'copied-no-chart'>('idle')\n\n // AI state\n const { features } = useCubeContext()\n const [aiState, setAIState] = useState<AIState>({\n isOpen: false,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: null\n })\n\n // Load shared state from URL on mount\n useEffect(() => {\n // Skip if initialQuery is provided (parent manages state)\n if (initialQuery) return\n\n const encoded = parseShareHash()\n if (!encoded) return\n\n const sharedState = decodeAndDecompress(encoded)\n if (!sharedState || !sharedState.query) return\n\n const queryConfig = sharedState.query\n\n // Check if this is a multi-query config\n if (isMultiQueryConfig(queryConfig)) {\n // Multi-query: set all query states\n const multiConfig = queryConfig as MultiQueryConfig\n setQueryStates(multiConfig.queries.map(queryToState))\n setActiveQueryIndex(0)\n if (multiConfig.mergeStrategy) {\n setMergeStrategy(multiConfig.mergeStrategy)\n }\n } else {\n // Single query: set as the only query state\n // queryToState already includes order from query.order\n const query = queryConfig as CubeQuery\n setQueryStates([queryToState(query)])\n setActiveQueryIndex(0)\n }\n\n // Apply chart config if present\n if (sharedState.chartType) {\n setChartType(sharedState.chartType)\n setUserManuallySelectedChart(true)\n }\n if (sharedState.chartConfig) {\n setChartConfig(sharedState.chartConfig)\n }\n if (sharedState.displayConfig) {\n setDisplayConfig(sharedState.displayConfig)\n }\n if (sharedState.activeView) {\n setActiveView(sharedState.activeView)\n }\n\n // Clear the share hash from URL\n clearShareHash()\n }, []) // Run once on mount\n\n // Build current query for the active tab - memoized to prevent infinite loops\n const currentQuery = useMemo(\n () => buildCubeQuery(state.metrics, state.breakdowns, state.filters, state.order),\n [state.metrics, state.breakdowns, state.filters, state.order]\n )\n\n // Build ALL queries from all queryStates (for multi-query execution)\n // Each query uses its own order from its state\n const allQueries = useMemo(() => {\n return queryStates.map(qs => buildCubeQuery(qs.metrics, qs.breakdowns, qs.filters, qs.order))\n }, [queryStates])\n\n // Check if we're in multi-query mode (more than one query with content)\n const isMultiQueryMode = useMemo(() => {\n if (queryStates.length <= 1) return false\n // Check if at least 2 queries have content\n const queriesWithContent = queryStates.filter(qs =>\n qs.metrics.length > 0 || qs.breakdowns.length > 0\n )\n return queriesWithContent.length > 1\n }, [queryStates])\n\n // Validate multi-query configuration and get warnings/errors\n const multiQueryValidation = useMemo((): MultiQueryValidationResult | null => {\n if (!isMultiQueryMode) return null\n return validateMultiQueryConfig(allQueries, mergeStrategy, mergeKeys || [])\n }, [isMultiQueryMode, allQueries, mergeStrategy, mergeKeys])\n\n // Combined metrics from ALL queries (for chart config in multi-query mode)\n const allMetrics = useMemo(() => {\n if (!isMultiQueryMode) return state.metrics\n return queryStates.flatMap(qs => qs.metrics)\n }, [isMultiQueryMode, queryStates, state.metrics])\n\n // Combined breakdowns from ALL queries (for chart config in multi-query mode)\n // In merge mode, breakdowns are synced from Q1 so we use Q1's breakdowns\n // In concat mode, we also use Q1's breakdowns as the reference (they're usually shared)\n const allBreakdowns = useMemo(() => {\n if (!isMultiQueryMode) return state.breakdowns\n // Use Q1's breakdowns as the canonical source\n return queryStates[0]?.breakdowns || []\n }, [isMultiQueryMode, queryStates, state.breakdowns])\n\n // Build MultiQueryConfig for multi-query execution\n const multiQueryConfig = useMemo(() => {\n if (!isMultiQueryMode) return null\n\n // Filter to only valid queries (have measures or dimensions)\n const validQueries = allQueries.filter(q =>\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n\n if (validQueries.length < 2) return null\n\n return {\n queries: validQueries.map(q => cleanQueryForServer(q)),\n mergeStrategy,\n mergeKeys,\n queryLabels: validQueries.map((_, i) => `Q${i + 1}`)\n }\n }, [allQueries, isMultiQueryMode, mergeStrategy, mergeKeys])\n\n // Serialize query for comparison (prevents object reference issues)\n // For multi-query mode, serialize all queries\n const currentQueryString = useMemo(() => {\n if (isMultiQueryMode) {\n return JSON.stringify({ queries: allQueries, mergeStrategy, mergeKeys })\n }\n return JSON.stringify(currentQuery)\n }, [currentQuery, allQueries, isMultiQueryMode, mergeStrategy, mergeKeys])\n\n // Debounced query for auto-execution\n const [debouncedQuery, setDebouncedQuery] = useState<CubeQuery | null>(null)\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const lastQueryStringRef = useRef<string>('')\n\n // Track if we should skip the first auto-execute (when initialData is provided)\n const hasInitialDataRef = useRef<boolean>(!!initialData && initialData.length > 0)\n const initialQueryStringRef = useRef<string>(initialQuery ? JSON.stringify(initialQuery) : '')\n\n // Track previous metrics/breakdowns for smart chart defaulting (avoid re-runs when chartConfig changes)\n const prevMetricsBreakdownsRef = useRef<string>('')\n const chartConfigRef = useRef<ChartAxisConfig>(chartConfig)\n\n // Determine if query is valid (has at least one measure OR one dimension)\n const isValidQuery =\n (currentQuery.measures && currentQuery.measures.length > 0) ||\n (currentQuery.dimensions && currentQuery.dimensions.length > 0) ||\n (currentQuery.timeDimensions && currentQuery.timeDimensions.length > 0)\n\n // In multi-query mode, check if we have 2+ valid queries (for debounce purposes)\n const hasValidMultiQuery = useMemo(() => {\n if (!isMultiQueryMode) return false\n const validQueries = allQueries.filter(q =>\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n return validQueries.length >= 2\n }, [isMultiQueryMode, allQueries])\n\n // Debounce query changes - use string comparison to avoid infinite loops\n useEffect(() => {\n // Skip if query hasn't actually changed\n if (currentQueryString === lastQueryStringRef.current) {\n console.log('[DEBUG] Debounce: skipped - query unchanged')\n return\n }\n console.log('[DEBUG] Debounce: query changed, will execute', { isMultiQueryMode, hasValidMultiQuery })\n\n // Skip initial auto-execution if initialData was provided and query hasn't changed from initial\n // This prevents re-fetching data that was already provided\n if (hasInitialDataRef.current && currentQueryString === initialQueryStringRef.current) {\n // Mark the query as \"seen\" so we don't skip future executions\n lastQueryStringRef.current = currentQueryString\n // Clear the flag so subsequent changes will execute\n hasInitialDataRef.current = false\n return\n }\n\n // Clear existing timer\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current)\n }\n\n // Only debounce if we have a valid query (single or multi-query mode)\n const shouldExecute = isValidQuery || hasValidMultiQuery\n if (shouldExecute) {\n debounceTimerRef.current = setTimeout(() => {\n lastQueryStringRef.current = currentQueryString\n // For multi-query, debouncedQuery just needs to be truthy to trigger execution\n // The actual value isn't used - multiQueryConfig is used instead\n // Using allQueries[0] provides stability - doesn't change on tab switch\n setDebouncedQuery(hasValidMultiQuery ? allQueries[0] : currentQuery)\n }, AUTO_EXECUTE_DELAY)\n } else {\n // Clear debounced query if no valid query\n lastQueryStringRef.current = currentQueryString\n setDebouncedQuery(null)\n }\n\n return () => {\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current)\n }\n }\n }, [currentQueryString, isValidQuery, hasValidMultiQuery, allQueries])\n\n // Transform debounced query to server format (converts filter groups)\n const serverQuery = useMemo(() => {\n if (!debouncedQuery) return null\n return cleanQueryForServer(debouncedQuery)\n }, [debouncedQuery])\n\n // Debounced multi-query config for auto-execution\n // This syncs with debouncedQuery - when debouncedQuery fires, we also fire multi-query\n const debouncedMultiConfig = useMemo(() => {\n // Only create multi-query config when:\n // 1. In multi-query mode (2+ queries with content)\n // 2. A debounced query has fired (indicating user finished typing)\n if (!isMultiQueryMode || !multiQueryConfig || !debouncedQuery) {\n return null\n }\n return multiQueryConfig\n }, [isMultiQueryMode, multiQueryConfig, debouncedQuery])\n\n // Execute SINGLE query using useCubeQuery hook (when not in multi-query mode)\n // Reset resultSet when query changes to avoid showing stale data after clearing\n const singleQueryResult = useCubeQuery(serverQuery, {\n skip: !serverQuery || isMultiQueryMode,\n resetResultSetOnChange: true\n })\n\n // Execute MULTI query using useMultiCubeQuery hook (when in multi-query mode)\n const multiQueryResult = useMultiCubeQuery(debouncedMultiConfig, {\n skip: !debouncedMultiConfig || !isMultiQueryMode,\n resetResultSetOnChange: true\n })\n\n // Unify results from single or multi query\n const resultSet = isMultiQueryMode ? null : singleQueryResult.resultSet\n const isLoading = isMultiQueryMode ? multiQueryResult.isLoading : singleQueryResult.isLoading\n const error = isMultiQueryMode ? multiQueryResult.error : singleQueryResult.error\n\n // Derive execution status - show success with initialData even before first query\n const executionStatus: ExecutionStatus = useMemo(() => {\n // If we have initialData and haven't started querying yet, show success\n const hasResults = isMultiQueryMode ? multiQueryResult.data : resultSet\n if (initialData && initialData.length > 0 && !debouncedQuery && !hasResults) {\n return 'success'\n }\n if (!debouncedQuery && !debouncedMultiConfig) return 'idle'\n // If results are stale (query changed but debounce hasn't fired yet), show refreshing\n // This prevents flash when toggling comparison mode\n // In multi-query mode, don't use per-tab resultsStale - the chart shows shared merged\n // data that doesn't change on tab switch. We rely on isLoading for actual refreshes.\n if (!isMultiQueryMode && state.resultsStale && hasResults) return 'refreshing'\n if (isLoading && !hasResults) return 'loading'\n if (isLoading && hasResults) return 'refreshing'\n if (error) return 'error'\n if (hasResults) return 'success'\n return 'idle'\n }, [debouncedQuery, debouncedMultiConfig, isLoading, error, resultSet, multiQueryResult.data, initialData, state.resultsStale, isMultiQueryMode])\n\n // Get execution results - use initialData if no resultSet yet\n // For chart: use merged results from all queries\n const executionResults = useMemo(() => {\n // Multi-query mode: use merged data from useMultiCubeQuery\n if (isMultiQueryMode && multiQueryResult.data) {\n console.log('[DEBUG] executionResults: multi-query', multiQueryResult.data?.length)\n return multiQueryResult.data as any[]\n }\n\n // Single query mode: use resultSet\n if (resultSet) {\n try {\n const data = resultSet.rawData()\n console.log('[DEBUG] executionResults: single-query', data?.length)\n return data\n } catch {\n return null\n }\n }\n // Use initialData if provided and no resultSet yet\n if (initialData && initialData.length > 0) {\n return initialData\n }\n console.log('[DEBUG] executionResults: null')\n return null\n }, [resultSet, initialData, isMultiQueryMode, multiQueryResult.data])\n\n // Get per-query results for table view in multi-query mode\n const perQueryResults = useMemo(() => {\n if (!isMultiQueryMode || !multiQueryResult.resultSets) {\n console.log('[DEBUG] perQueryResults: no results', { isMultiQueryMode, resultSets: multiQueryResult.resultSets })\n return undefined\n }\n const results = multiQueryResult.resultSets.map(rs => {\n if (!rs) return null\n try {\n return rs.rawData()\n } catch {\n return null\n }\n })\n console.log('[DEBUG] perQueryResults:', results.map(r => r?.length || 0))\n return results\n }, [isMultiQueryMode, multiQueryResult.resultSets])\n\n // Active table index for multi-query table view\n const [activeTableIndex, setActiveTableIndex] = useState(0)\n\n // Note: We pass executionStatus, executionResults, error directly to PortletResultsPanel\n // instead of storing in state, to avoid render loops\n\n // Clear resultsStale flag when new results arrive\n useEffect(() => {\n if (resultSet && state.resultsStale) {\n setState((prev) => ({ ...prev, resultsStale: false }))\n }\n }, [resultSet, state.resultsStale])\n\n // Compute chart availability based on current metrics and breakdowns\n // Use allMetrics/allBreakdowns for consistency in multi-query mode\n const chartAvailability = useMemo(\n () => getAllChartAvailability(allMetrics, allBreakdowns),\n [allMetrics, allBreakdowns]\n )\n\n // Helper to check if chart config is completely empty (no axes configured)\n const isChartConfigEmpty = useCallback((config: ChartAxisConfig): boolean => {\n const keys: (keyof ChartAxisConfig)[] = ['xAxis', 'yAxis', 'series', 'sizeField', 'colorField', 'dateField', 'valueField']\n return keys.every(key => {\n const val = config[key]\n if (val === undefined || val === null) return true\n if (Array.isArray(val)) return val.length === 0\n if (typeof val === 'string') return val === ''\n return false\n })\n }, [])\n\n // Keep chartConfigRef in sync with chartConfig state\n chartConfigRef.current = chartConfig\n\n // Smart chart defaulting - auto-configure chart type and axes when debouncedQuery changes\n // This runs AFTER the debounce fires, so chart config changes are synchronized with data updates\n // This prevents the \"double refresh\" visual where chart updates before data arrives\n useEffect(() => {\n // Only run when we have a debounced query (after debounce timer fires)\n if (!debouncedQuery) {\n return\n }\n\n if (allMetrics.length === 0 && allBreakdowns.length === 0) {\n return // Nothing to configure\n }\n\n // Create a key from metrics/breakdowns fields to detect actual changes\n // Use allMetrics and allBreakdowns to track changes across all queries\n const currentKey = JSON.stringify({\n metrics: allMetrics.map(m => m.field),\n breakdowns: allBreakdowns.map(b => ({ field: b.field, isTime: b.isTimeDimension }))\n })\n\n // Skip if metrics/breakdowns haven't actually changed\n if (currentKey === prevMetricsBreakdownsRef.current) {\n return\n }\n prevMetricsBreakdownsRef.current = currentKey\n\n // Check if we should auto-switch chart type (use allMetrics/allBreakdowns for multi-query)\n const newChartType = shouldAutoSwitchChartType(\n allMetrics,\n allBreakdowns,\n chartType,\n userManuallySelectedChart\n )\n\n if (newChartType) {\n // Chart type is changing - get smart defaults for the new chart type\n const { chartConfig: newChartConfig } = getSmartChartDefaults(\n allMetrics,\n allBreakdowns,\n newChartType\n )\n setChartType(newChartType)\n setChartConfig(newChartConfig)\n // Reset user selection flag since we auto-switched\n setUserManuallySelectedChart(false)\n } else if (allMetrics.length > 0 || allBreakdowns.length > 0) {\n // Only apply smart defaults if the chart config is COMPLETELY empty\n // Once user has configured ANY axis, don't auto-fill (respects user removals)\n // Use ref to get current value without adding to dependencies\n if (isChartConfigEmpty(chartConfigRef.current)) {\n const { chartConfig: smartDefaults } = getSmartChartDefaults(\n allMetrics,\n allBreakdowns,\n chartType\n )\n setChartConfig(smartDefaults)\n }\n }\n }, [debouncedQuery, allMetrics, allBreakdowns, chartType, userManuallySelectedChart, isChartConfigEmpty])\n\n // Save state to localStorage whenever it changes (if not disabled)\n // Deferred to avoid blocking renders\n useEffect(() => {\n if (disableLocalStorage) return\n\n // Defer to next tick to avoid blocking renders\n const timeoutId = setTimeout(() => {\n try {\n // Store both legacy format (for backward compatibility) and multi-query format\n const activeState = queryStates[activeQueryIndex] || createInitialState()\n const storageState: AnalysisBuilderStorageState = {\n // Legacy format (for backward compatibility with single-query)\n metrics: activeState.metrics,\n breakdowns: activeState.breakdowns,\n filters: activeState.filters,\n order: activeState.order,\n chartType,\n chartConfig,\n displayConfig,\n activeView,\n // Multi-query format (mergeKeys is computed from Q1 breakdowns, not stored)\n // queryStates already includes order per query\n queryStates: queryStates.length > 1 ? queryStates : undefined,\n activeQueryIndex: queryStates.length > 1 ? activeQueryIndex : undefined,\n mergeStrategy: queryStates.length > 1 ? mergeStrategy : undefined\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(storageState))\n } catch {\n // Failed to save to localStorage\n }\n }, 0)\n\n return () => clearTimeout(timeoutId)\n }, [\n queryStates,\n activeQueryIndex,\n mergeStrategy,\n chartType,\n chartConfig,\n displayConfig,\n activeView,\n disableLocalStorage\n ])\n\n // Call onQueryChange callback when query changes\n useEffect(() => {\n if (onQueryChange && isValidQuery) {\n onQueryChange(currentQuery)\n }\n }, [currentQuery, isValidQuery, onQueryChange])\n\n // Call onChartConfigChange callback when chart config changes\n useEffect(() => {\n if (onChartConfigChange) {\n onChartConfigChange({ chartType, chartConfig, displayConfig })\n }\n }, [chartType, chartConfig, displayConfig, onChartConfigChange])\n\n // Fetch dry-run data for debug tab\n // In multi-query mode, fetch debug data for ALL queries\n useEffect(() => {\n // Determine which queries to fetch debug for\n const queriesToFetch = isMultiQueryMode && multiQueryConfig\n ? multiQueryConfig.queries\n : (isValidQuery && serverQuery) ? [serverQuery] : []\n\n if (queriesToFetch.length === 0) {\n setDebugDataPerQuery([])\n return\n }\n\n let isCancelled = false\n\n const fetchDebugData = async () => {\n // Initialize loading state for all queries\n setDebugDataPerQuery(queriesToFetch.map(() => ({\n sql: null,\n analysis: null,\n loading: true,\n error: null\n })))\n\n // Fetch debug data for each query in parallel\n const results = await Promise.all(\n queriesToFetch.map(async (query) => {\n try {\n const result = await cubeApi.dryRun(query)\n return {\n sql: result.sql,\n analysis: result.analysis,\n loading: false,\n error: null\n }\n } catch (err) {\n return {\n sql: null,\n analysis: null,\n loading: false,\n error: err instanceof Error ? err.message : 'Failed to fetch debug info'\n }\n }\n })\n )\n\n if (!isCancelled) {\n setDebugDataPerQuery(results)\n }\n }\n\n fetchDebugData()\n\n return () => {\n isCancelled = true\n }\n }, [serverQuery, multiQueryConfig, cubeApi, isValidQuery, isMultiQueryMode])\n\n // ========================================================================\n // Metric Handlers\n // ========================================================================\n\n const handleAddMetric = useCallback(() => {\n setFieldModalMode('metrics')\n setShowFieldModal(true)\n }, [])\n\n const handleRemoveMetric = useCallback((id: string) => {\n setState((prev) => {\n // Find the field name before removing\n const fieldToRemove = prev.metrics.find((m) => m.id === id)?.field\n const newMetrics = prev.metrics.filter((m) => m.id !== id)\n\n // Clean up any sort order for the removed field\n let newOrder = prev.order\n if (fieldToRemove && newOrder && newOrder[fieldToRemove]) {\n newOrder = { ...newOrder }\n delete newOrder[fieldToRemove]\n if (Object.keys(newOrder).length === 0) {\n newOrder = undefined\n }\n }\n\n return {\n ...prev,\n metrics: newMetrics,\n order: newOrder,\n resultsStale: true\n }\n })\n }, [setState])\n\n const handleFieldSelected = useCallback(\n (field: MetaField, fieldType: 'measure' | 'dimension' | 'timeDimension', _cubeName: string, keepOpen?: boolean) => {\n if (fieldModalMode === 'metrics' && fieldType === 'measure') {\n // Toggle metric - add if not present, remove if already added\n setState((prev) => {\n const existingIndex = prev.metrics.findIndex((m) => m.field === field.name)\n if (existingIndex >= 0) {\n // Remove existing metric\n return {\n ...prev,\n metrics: prev.metrics.filter((_, i) => i !== existingIndex),\n resultsStale: true\n }\n }\n // Add new metric\n const newMetric: MetricItem = {\n id: generateId(),\n field: field.name,\n label: generateMetricLabel(prev.metrics.length)\n }\n return {\n ...prev,\n metrics: [...prev.metrics, newMetric],\n resultsStale: true\n }\n })\n } else if (fieldModalMode === 'breakdown') {\n // Toggle breakdown - add if not present, remove if already added\n const isTimeDimension = fieldType === 'timeDimension'\n setState((prev) => {\n const existingIndex = prev.breakdowns.findIndex((b) => b.field === field.name)\n if (existingIndex >= 0) {\n // Remove existing breakdown\n return {\n ...prev,\n breakdowns: prev.breakdowns.filter((_, i) => i !== existingIndex),\n resultsStale: true\n }\n }\n\n // Check if we already have a time dimension breakdown (only allow one)\n if (isTimeDimension) {\n const hasExistingTimeDimension = prev.breakdowns.some((b) => b.isTimeDimension)\n if (hasExistingTimeDimension) {\n // Don't add - already have a time dimension breakdown\n // Could show a notification here in the future\n return prev\n }\n }\n\n // Add new breakdown\n const newBreakdown: BreakdownItem = {\n id: generateId(),\n field: field.name,\n isTimeDimension,\n granularity: isTimeDimension ? 'month' : undefined\n }\n return {\n ...prev,\n breakdowns: [...prev.breakdowns, newBreakdown],\n resultsStale: true\n }\n })\n }\n // Only close modal if not doing shift-click multi-select\n if (!keepOpen) {\n setShowFieldModal(false)\n }\n },\n [fieldModalMode, setState]\n )\n\n // ========================================================================\n // Breakdown Handlers\n // ========================================================================\n\n const handleAddBreakdown = useCallback(() => {\n setFieldModalMode('breakdown')\n setShowFieldModal(true)\n }, [])\n\n const handleRemoveBreakdown = useCallback((id: string) => {\n setState((prev) => {\n // Find the field name before removing\n const fieldToRemove = prev.breakdowns.find((b) => b.id === id)?.field\n const newBreakdowns = prev.breakdowns.filter((b) => b.id !== id)\n\n // Clean up any sort order for the removed field\n let newOrder = prev.order\n if (fieldToRemove && newOrder && newOrder[fieldToRemove]) {\n newOrder = { ...newOrder }\n delete newOrder[fieldToRemove]\n if (Object.keys(newOrder).length === 0) {\n newOrder = undefined\n }\n }\n\n return {\n ...prev,\n breakdowns: newBreakdowns,\n order: newOrder,\n resultsStale: true\n }\n })\n }, [setState])\n\n const handleBreakdownGranularityChange = useCallback(\n (id: string, granularity: string) => {\n // In merge mode, granularity changes should update Q1's breakdowns (source of truth)\n // since the sync effect copies Q1 → other queries\n if (mergeStrategy === 'merge' && activeQueryIndex > 0) {\n // Update Q1's breakdowns directly\n setQueryStates(prev => {\n const newStates = [...prev]\n newStates[0] = {\n ...newStates[0],\n breakdowns: newStates[0].breakdowns.map((b) =>\n b.id === id ? { ...b, granularity } : b\n ),\n resultsStale: true\n }\n return newStates\n })\n } else {\n // Normal case: update active query's breakdowns\n setState((prev) => ({\n ...prev,\n breakdowns: prev.breakdowns.map((b) =>\n b.id === id ? { ...b, granularity } : b\n ),\n resultsStale: true\n }))\n }\n },\n [mergeStrategy, activeQueryIndex, setState]\n )\n\n const handleBreakdownComparisonToggle = useCallback(\n (breakdownId: string) => {\n // Check if we're enabling comparison (the breakdown currently doesn't have it)\n // In merge mode, use Q1's breakdowns as the source of truth\n const sourceBreakdowns = (mergeStrategy === 'merge' && activeQueryIndex > 0)\n ? queryStates[0]?.breakdowns || []\n : state.breakdowns\n const targetBreakdown = sourceBreakdowns.find(b => b.id === breakdownId)\n const isEnabling = targetBreakdown && !targetBreakdown.enableComparison\n\n // If enabling comparison and no date filter exists, auto-add one (last 30 days)\n if (isEnabling && targetBreakdown) {\n const currentFilters = (mergeStrategy === 'merge' && activeQueryIndex > 0)\n ? queryStates[0]?.filters || []\n : state.filters\n const hasDateFilter = findDateFilterForField(currentFilters, targetBreakdown.field)\n\n if (!hasDateFilter) {\n // Auto-add a date filter with 'last 30 days' range\n const newFilter: Filter = {\n member: targetBreakdown.field,\n operator: 'inDateRange',\n values: [],\n dateRange: convertDateRangeTypeToValue('last_30_days')\n } as Filter\n\n // Add the filter to the appropriate query's filters\n if (mergeStrategy === 'merge' && activeQueryIndex > 0) {\n setQueryStates(prev => {\n const newStates = [...prev]\n newStates[0] = {\n ...newStates[0],\n filters: [...newStates[0].filters, newFilter]\n }\n return newStates\n })\n } else {\n setState((prev) => ({\n ...prev,\n filters: [...prev.filters, newFilter]\n }))\n }\n }\n }\n\n // If enabling comparison and chart type is not 'line', switch to line chart first\n // (comparison only works well with line charts)\n if (isEnabling && chartType !== 'line') {\n setChartType('line')\n // Update chart config for line chart\n const { chartConfig: newChartConfig } = getSmartChartDefaults(\n state.metrics,\n state.breakdowns,\n 'line'\n )\n setChartConfig(newChartConfig)\n }\n\n // Helper to update breakdowns with comparison toggle\n const updateBreakdowns = (breakdowns: typeof state.breakdowns) =>\n breakdowns.map((b) => {\n if (b.id === breakdownId) {\n // Toggle this breakdown's comparison\n return { ...b, enableComparison: !b.enableComparison }\n }\n // Clear comparison from other time dimensions when enabling (only one allowed)\n if (b.isTimeDimension && b.enableComparison) {\n return { ...b, enableComparison: false }\n }\n return b\n })\n\n // In merge mode, update Q1's breakdowns (source of truth)\n if (mergeStrategy === 'merge' && activeQueryIndex > 0) {\n setQueryStates(prev => {\n const newStates = [...prev]\n newStates[0] = {\n ...newStates[0],\n breakdowns: updateBreakdowns(newStates[0].breakdowns),\n resultsStale: true\n }\n return newStates\n })\n } else {\n // Normal case: update active query's breakdowns\n setState((prev) => ({\n ...prev,\n breakdowns: updateBreakdowns(prev.breakdowns),\n resultsStale: true\n }))\n }\n },\n [chartType, state.breakdowns, state.filters, state.metrics, mergeStrategy, activeQueryIndex, queryStates, setState]\n )\n\n // ========================================================================\n // Reorder Handlers\n // ========================================================================\n\n const handleReorderMetrics = useCallback(\n (fromIndex: number, toIndex: number) => {\n setState((prev) => {\n const newMetrics = [...prev.metrics]\n const [movedItem] = newMetrics.splice(fromIndex, 1)\n newMetrics.splice(toIndex, 0, movedItem)\n return {\n ...prev,\n metrics: newMetrics,\n resultsStale: true\n }\n })\n },\n [setState]\n )\n\n const handleReorderBreakdowns = useCallback(\n (fromIndex: number, toIndex: number) => {\n setState((prev) => {\n const newBreakdowns = [...prev.breakdowns]\n const [movedItem] = newBreakdowns.splice(fromIndex, 1)\n newBreakdowns.splice(toIndex, 0, movedItem)\n return {\n ...prev,\n breakdowns: newBreakdowns,\n resultsStale: true\n }\n })\n },\n [setState]\n )\n\n // ========================================================================\n // Filter Handlers\n // ========================================================================\n\n // Filter change handler - connected to PortletQueryPanel\n const handleFiltersChange = useCallback((filters: Filter[]) => {\n setState((prev) => ({\n ...prev,\n filters,\n resultsStale: true\n }))\n }, [setState])\n\n // Handle dropping a field from metrics/breakdowns onto the filter section\n const handleDropFieldToFilter = useCallback((field: string) => {\n // Create a new filter with 'set' operator (checks if field exists/is not null)\n const newFilter: Filter = {\n member: field,\n operator: 'set',\n values: []\n }\n\n setState((prev) => {\n // Add to existing filters or create new array\n const existingFilters = prev.filters || []\n\n // Check if we already have a filter for this field\n const hasFilterForField = existingFilters.some((f) =>\n 'member' in f && f.member === field\n )\n\n if (hasFilterForField) {\n // Don't add duplicate filter\n return prev\n }\n\n // If we have existing filters, wrap in an AND group or add to existing group\n let updatedFilters: Filter[]\n if (existingFilters.length === 0) {\n updatedFilters = [newFilter]\n } else if (existingFilters.length === 1 && 'type' in existingFilters[0]) {\n // Already a group, add to it\n const group = existingFilters[0] as { type: 'and' | 'or'; filters: Filter[] }\n updatedFilters = [{\n ...group,\n filters: [...group.filters, newFilter]\n }]\n } else {\n // Wrap all in AND group\n updatedFilters = [{\n type: 'and' as const,\n filters: [...existingFilters, newFilter]\n }]\n }\n\n return {\n ...prev,\n filters: updatedFilters,\n resultsStale: true\n }\n })\n }, [setState])\n\n // ========================================================================\n // Order Handlers\n // ========================================================================\n\n const handleOrderChange = useCallback(\n (fieldName: string, direction: 'asc' | 'desc' | null) => {\n setState((prev) => {\n const newOrder = { ...(prev.order || {}) }\n\n if (direction === null) {\n // Remove sort for this field\n delete newOrder[fieldName]\n } else {\n // Set or update sort direction\n newOrder[fieldName] = direction\n }\n\n return {\n ...prev,\n order: Object.keys(newOrder).length > 0 ? newOrder : undefined,\n resultsStale: true\n }\n })\n },\n [setState]\n )\n\n // ========================================================================\n // Multi-Query Handlers\n // ========================================================================\n\n // Add a new query tab - copies current query's metrics, breakdowns, filters\n const handleAddQuery = useCallback(() => {\n const currentState = queryStates[activeQueryIndex] || createInitialState()\n const newState: AnalysisBuilderState = {\n ...createInitialState(),\n metrics: [...currentState.metrics],\n breakdowns: [...currentState.breakdowns],\n filters: [...currentState.filters]\n }\n setQueryStates(prev => [...prev, newState])\n // Switch to the new tab\n setActiveQueryIndex(queryStates.length)\n }, [queryStates, activeQueryIndex])\n\n // Remove a query tab at specified index\n const handleRemoveQuery = useCallback((index: number) => {\n setQueryStates(prev => {\n // Don't allow removing the last query\n if (prev.length <= 1) return prev\n return prev.filter((_, i) => i !== index)\n })\n // Adjust active index if needed\n if (index === activeQueryIndex) {\n // If removing active tab, switch to previous (or first if removing first)\n setActiveQueryIndex(Math.max(0, activeQueryIndex - 1))\n } else if (index < activeQueryIndex) {\n // Shift active index down if removing a tab before it\n setActiveQueryIndex(activeQueryIndex - 1)\n }\n }, [activeQueryIndex])\n\n // Change active query tab\n const handleActiveQueryChange = useCallback((index: number) => {\n setActiveQueryIndex(index)\n }, [])\n\n // Update merge strategy\n const handleMergeStrategyChange = useCallback((strategy: QueryMergeStrategy) => {\n setMergeStrategy(strategy)\n }, [])\n\n // Compute combined metrics from ALL queries (for chart config in multi-query mode)\n // Always returns an array (never undefined) for consistent prop passing\n const combinedMetrics = useMemo(() => {\n if (!isMultiQueryMode) return state.metrics\n\n const seen = new Set<string>()\n const combined: MetricItem[] = []\n\n for (let qIndex = 0; qIndex < queryStates.length; qIndex++) {\n const qs = queryStates[qIndex]\n for (const metric of qs.metrics) {\n // In multi-query mode, prefix with query label to distinguish\n const key = `Q${qIndex + 1}:${metric.field}`\n if (!seen.has(key)) {\n seen.add(key)\n combined.push({\n ...metric,\n // Keep original field but update label to show query source\n label: `${metric.label} (Q${qIndex + 1})`\n })\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, state.metrics])\n\n // Compute combined breakdowns from ALL queries (for chart config in multi-query mode)\n // Always returns an array (never undefined) for consistent prop passing\n const combinedBreakdowns = useMemo(() => {\n if (!isMultiQueryMode) return state.breakdowns\n\n const seen = new Set<string>()\n const combined: BreakdownItem[] = []\n\n for (const qs of queryStates) {\n for (const breakdown of qs.breakdowns) {\n // Deduplicate by field (breakdowns are usually shared across queries)\n if (!seen.has(breakdown.field)) {\n seen.add(breakdown.field)\n combined.push(breakdown)\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, state.breakdowns])\n\n // ========================================================================\n // Clear Query\n // ========================================================================\n\n const handleClearQuery = useCallback(() => {\n // In multi-query mode, only clear the active query\n // If user wants to clear all queries, they should remove tabs\n // createInitialState() already sets order: undefined\n setState(createInitialState())\n setUserManuallySelectedChart(false)\n // Also reset chart type, config, and display config\n setChartType('line')\n setChartConfig({})\n setDisplayConfig({ showLegend: true, showGrid: true, showTooltip: true })\n // Clear the debounced query immediately to stop showing old results\n setDebouncedQuery(null)\n // Also clear any pending debounce timer\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current)\n debounceTimerRef.current = null\n }\n }, [setState])\n\n // ========================================================================\n // AI Query Generation\n // ========================================================================\n\n const handleOpenAI = useCallback(() => {\n // Snapshot current state for undo\n setAIState({\n isOpen: true,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: {\n metrics: [...state.metrics],\n breakdowns: [...state.breakdowns],\n filters: [...state.filters],\n chartType,\n chartConfig: { ...chartConfig },\n displayConfig: { ...displayConfig }\n }\n })\n }, [state.metrics, state.breakdowns, state.filters, chartType, chartConfig, displayConfig])\n\n const handleCloseAI = useCallback(() => {\n setAIState(prev => ({\n ...prev,\n isOpen: false,\n userPrompt: '',\n error: null,\n hasGeneratedQuery: false\n }))\n }, [])\n\n const handleAIPromptChange = useCallback((prompt: string) => {\n setAIState(prev => ({ ...prev, userPrompt: prompt }))\n }, [])\n\n const handleGenerateAI = useCallback(async () => {\n if (!aiState.userPrompt.trim()) return\n\n setAIState(prev => ({ ...prev, isGenerating: true, error: null }))\n\n try {\n const response = await sendGeminiMessage(\n '', // API key not needed for server-side AI\n aiState.userPrompt,\n features?.aiEndpoint || '/api/ai'\n )\n\n const responseText = extractTextFromResponse(response)\n const parsed = JSON.parse(responseText) as {\n query?: CubeQuery\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n } | CubeQuery\n\n // Support both new format (with query/chartType/chartConfig) and legacy format (just query)\n const query = ('query' in parsed && parsed.query) ? parsed.query : parsed as CubeQuery\n const aiChartType = ('chartType' in parsed) ? parsed.chartType : undefined\n const aiChartConfig = ('chartConfig' in parsed) ? parsed.chartConfig : undefined\n\n // Load query into builder state (same pattern as initialQuery)\n setState(prev => ({\n ...prev,\n metrics: (query.measures || []).map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index)\n })),\n breakdowns: [\n ...(query.dimensions || []).map((field) => ({\n id: generateId(),\n field,\n isTimeDimension: false\n })),\n ...(query.timeDimensions || []).map((td) => ({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true\n }))\n ],\n filters: query.filters || []\n }))\n\n // Apply chart type if provided by AI\n if (aiChartType) {\n setChartType(aiChartType)\n setUserManuallySelectedChart(true) // Prevent auto-switching\n }\n\n // Apply chart config if provided by AI\n if (aiChartConfig) {\n setChartConfig(aiChartConfig)\n }\n\n // Switch to chart view so user can see the visualization\n setActiveView('chart')\n\n setAIState(prev => ({\n ...prev,\n isGenerating: false,\n hasGeneratedQuery: true\n }))\n } catch (error) {\n setAIState(prev => ({\n ...prev,\n isGenerating: false,\n error: error instanceof Error ? error.message : 'Failed to generate query'\n }))\n }\n }, [aiState.userPrompt, features?.aiEndpoint])\n\n const handleAcceptAI = useCallback(() => {\n // Close panel and clear previous state (keep the changes)\n setAIState({\n isOpen: false,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: null\n })\n }, [])\n\n const handleCancelAI = useCallback(() => {\n // Restore previous state\n if (aiState.previousState) {\n setState(prev => ({\n ...prev,\n metrics: aiState.previousState!.metrics,\n breakdowns: aiState.previousState!.breakdowns,\n filters: aiState.previousState!.filters\n }))\n setChartType(aiState.previousState.chartType)\n setChartConfig(aiState.previousState.chartConfig)\n setDisplayConfig(aiState.previousState.displayConfig)\n }\n\n // Close panel\n setAIState({\n isOpen: false,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: null\n })\n }, [aiState.previousState])\n\n // Handle chart type change - track that user manually selected this\n const handleChartTypeChange = useCallback((type: ChartType) => {\n // If switching away from 'line', clear any comparison from time dimensions first\n // (comparison only works with line charts)\n // Do this before other updates so React 18 batches them together\n if (type !== 'line') {\n const hasComparison = state.breakdowns.some(b => b.isTimeDimension && b.enableComparison)\n if (hasComparison) {\n setState((prev) => ({\n ...prev,\n breakdowns: prev.breakdowns.map((b) =>\n b.isTimeDimension && b.enableComparison\n ? { ...b, enableComparison: false }\n : b\n ),\n resultsStale: true\n }))\n }\n }\n\n setChartType(type)\n setUserManuallySelectedChart(true)\n\n // Update chart config for the new chart type\n const { chartConfig: newChartConfig } = getSmartChartDefaults(\n state.metrics,\n state.breakdowns,\n type\n )\n setChartConfig(newChartConfig)\n // Switch to chart view so user can see the changes\n setActiveView('chart')\n }, [state.metrics, state.breakdowns])\n\n // Handle chart config change - also switch to chart view\n const handleChartConfigChange = useCallback((config: ChartAxisConfig) => {\n setChartConfig(config)\n // Switch to chart view so user can see the changes\n setActiveView('chart')\n }, [])\n\n // Handle display config change - also switch to chart view\n const handleDisplayConfigChange = useCallback((config: ChartDisplayConfig) => {\n setDisplayConfig(config)\n // Switch to chart view so user can see the changes\n setActiveView('chart')\n }, [])\n\n // ========================================================================\n // Share Handler\n // ========================================================================\n\n const handleShare = useCallback(async () => {\n if (!isValidQuery) return\n\n // Build the query config - use multi-query format if multiple queries exist\n const queryConfig = queryStates.length > 1\n ? {\n queries: allQueries,\n mergeStrategy,\n mergeKeys,\n queryLabels: queryStates.map((_, i) => `Q${i + 1}`)\n }\n : currentQuery\n\n const shareableState = {\n query: queryConfig,\n chartType,\n chartConfig,\n displayConfig,\n activeView\n }\n\n // Try full state first, fall back to query-only if too large\n const { encoded, queryOnly } = compressWithFallback(shareableState)\n\n // If even query-only is too large, don't share\n if (!encoded) {\n return\n }\n\n const url = `${window.location.origin}${window.location.pathname}#share=${encoded}`\n\n try {\n await navigator.clipboard.writeText(url)\n } catch {\n // Fallback for older browsers\n const textArea = document.createElement('textarea')\n textArea.value = url\n document.body.appendChild(textArea)\n textArea.select()\n document.execCommand('copy')\n document.body.removeChild(textArea)\n }\n\n // Update button state\n setShareButtonState(queryOnly ? 'copied-no-chart' : 'copied')\n\n // Reset button state after 2 seconds\n setTimeout(() => {\n setShareButtonState('idle')\n }, 2000)\n }, [isValidQuery, queryStates.length, allQueries, mergeStrategy, mergeKeys, currentQuery, chartType, chartConfig, displayConfig, activeView])\n\n // ========================================================================\n // Expose API via ref\n // ========================================================================\n\n useImperativeHandle(\n ref,\n () => ({\n getQueryConfig: () => {\n // If multiple queries, return MultiQueryConfig format\n if (queryStates.length > 1) {\n return {\n queries: allQueries,\n mergeStrategy,\n mergeKeys,\n queryLabels: queryStates.map((_, i) => `Q${i + 1}`)\n }\n }\n // Single query, return CubeQuery format\n return currentQuery\n },\n getChartConfig: () => ({ chartType, chartConfig, displayConfig }),\n executeQuery: () => {\n // TODO: Implement manual execute\n },\n clearQuery: handleClearQuery\n }),\n [currentQuery, allQueries, queryStates.length, mergeStrategy, mergeKeys, chartType, chartConfig, displayConfig, handleClearQuery]\n )\n\n // ========================================================================\n // Render\n // ========================================================================\n\n return (\n <div\n className={`flex flex-col lg:flex-row bg-dc-surface border-x border-b border-dc-border ${maxHeight ? 'lg:h-[var(--dc-max-h)] lg:max-h-[var(--dc-max-h)] lg:overflow-hidden' : 'lg:h-full'} ${className}`}\n style={maxHeight ? { ['--dc-max-h' as string]: maxHeight } : undefined}\n >\n {/* Top/Left Panel - Results */}\n <div className=\"h-[60vh] lg:h-auto lg:flex-1 min-w-0 border-b lg:border-b-0 lg:border-r border-dc-border overflow-auto flex flex-col\">\n {/* AI Panel - expands above results when open */}\n {aiState.isOpen && (\n <AnalysisAIPanel\n userPrompt={aiState.userPrompt}\n onPromptChange={handleAIPromptChange}\n isGenerating={aiState.isGenerating}\n error={aiState.error}\n hasGeneratedQuery={aiState.hasGeneratedQuery}\n onGenerate={handleGenerateAI}\n onAccept={handleAcceptAI}\n onCancel={handleCancelAI}\n />\n )}\n\n {/* Results Panel */}\n <div className=\"flex-1 overflow-auto\">\n <AnalysisResultsPanel\n executionStatus={executionStatus}\n executionResults={executionResults}\n executionError={error?.message || null}\n totalRowCount={null}\n resultsStale={isLoading && executionResults !== null}\n chartType={chartType}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n colorPalette={effectiveColorPalette}\n // Only show palette selector in standalone mode (not when editing portlet)\n currentPaletteName={!externalColorPalette ? localPaletteName : undefined}\n onColorPaletteChange={!externalColorPalette ? setLocalPaletteName : undefined}\n allQueries={allQueries}\n schema={meta as MetaResponse | null}\n activeView={activeView}\n onActiveViewChange={setActiveView}\n displayLimit={displayLimit}\n onDisplayLimitChange={setDisplayLimit}\n hasMetrics={state.metrics.length > 0}\n // Debug props - per-query debug data for multi-query mode\n debugDataPerQuery={debugDataPerQuery}\n // Share props\n onShareClick={handleShare}\n canShare={isValidQuery}\n shareButtonState={shareButtonState}\n // Clear props\n onClearClick={handleClearQuery}\n canClear={state.metrics.length > 0 || state.breakdowns.length > 0 || state.filters.length > 0}\n // AI props\n enableAI={features?.enableAI !== false}\n isAIOpen={aiState.isOpen}\n onAIToggle={aiState.isOpen ? handleCloseAI : handleOpenAI}\n // Multi-query props\n queryCount={queryStates.length}\n perQueryResults={perQueryResults}\n activeTableIndex={activeTableIndex}\n onActiveTableChange={setActiveTableIndex}\n />\n </div>\n </div>\n\n {/* Bottom/Right Panel - Query Builder */}\n <div className=\"w-full lg:w-96 flex-shrink-0 lg:h-full overflow-auto lg:overflow-hidden\">\n <AnalysisQueryPanel\n metrics={state.metrics}\n breakdowns={state.breakdowns}\n filters={state.filters}\n schema={meta as MetaResponse | null}\n activeTab={activeTab}\n onActiveTabChange={setActiveTab}\n onAddMetric={handleAddMetric}\n onRemoveMetric={handleRemoveMetric}\n onReorderMetrics={handleReorderMetrics}\n onAddBreakdown={handleAddBreakdown}\n onRemoveBreakdown={handleRemoveBreakdown}\n onBreakdownGranularityChange={handleBreakdownGranularityChange}\n onBreakdownComparisonToggle={handleBreakdownComparisonToggle}\n onReorderBreakdowns={handleReorderBreakdowns}\n onFiltersChange={handleFiltersChange}\n onDropFieldToFilter={handleDropFieldToFilter}\n order={state.order}\n onOrderChange={handleOrderChange}\n chartType={chartType}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n colorPalette={effectiveColorPalette}\n chartAvailability={chartAvailability}\n onChartTypeChange={handleChartTypeChange}\n onChartConfigChange={handleChartConfigChange}\n onDisplayConfigChange={handleDisplayConfigChange}\n validationStatus={state.validationStatus}\n validationError={state.validationError}\n // Multi-query props\n queryCount={queryStates.length}\n activeQueryIndex={activeQueryIndex}\n mergeStrategy={mergeStrategy}\n onActiveQueryChange={handleActiveQueryChange}\n onAddQuery={handleAddQuery}\n onRemoveQuery={handleRemoveQuery}\n onMergeStrategyChange={handleMergeStrategyChange}\n breakdownsLocked={mergeStrategy === 'merge' && activeQueryIndex > 0}\n combinedMetrics={combinedMetrics}\n combinedBreakdowns={combinedBreakdowns}\n multiQueryValidation={multiQueryValidation}\n />\n </div>\n\n {/* Field Search Modal */}\n <FieldSearchModal\n isOpen={showFieldModal}\n onClose={() => setShowFieldModal(false)}\n onSelect={handleFieldSelected}\n mode={fieldModalMode}\n schema={meta as MetaResponse | null}\n selectedFields={[\n ...state.metrics.map((m) => m.field),\n ...state.breakdowns.map((b) => b.field)\n ]}\n />\n </div>\n )\n }\n)\n\nAnalysisBuilder.displayName = 'AnalysisBuilder'\n\nexport default AnalysisBuilder\n","/**\n * QueryBuilder Shim\n *\n * Backward compatibility wrapper that provides the QueryBuilder interface\n * while using AnalysisBuilder internally.\n *\n * This allows existing code importing QueryBuilder to seamlessly use the new\n * AnalysisBuilder component without any code changes.\n */\nimport { forwardRef, useImperativeHandle, useRef } from 'react'\nimport AnalysisBuilder from './AnalysisBuilder'\nimport type { AnalysisBuilderRef } from './AnalysisBuilder/types'\nimport type { QueryBuilderProps, QueryBuilderRef } from './QueryBuilder/types'\n\nconst QueryBuilderShim = forwardRef<QueryBuilderRef, QueryBuilderProps>(\n (props, ref) => {\n const analysisBuilderRef = useRef<AnalysisBuilderRef>(null)\n\n // Map QueryBuilder ref interface to AnalysisBuilder ref\n useImperativeHandle(ref, () => ({\n getCurrentQuery: () => {\n const config = analysisBuilderRef.current?.getQueryConfig()\n if (!config) {\n return { measures: [], dimensions: [] }\n }\n // If multi-query, return first query for backward compatibility\n if ('queries' in config) {\n return config.queries[0] || { measures: [], dimensions: [] }\n }\n return config\n },\n\n getValidationState: () => {\n // AnalysisBuilder doesn't expose validation state\n // Return a basic \"valid\" state since AnalysisBuilder auto-validates\n return {\n status: 'valid' as const\n }\n },\n\n getValidationResult: () => {\n // AnalysisBuilder doesn't expose validation results\n // Return null as it's an optional field\n return null\n }\n }), [])\n\n // Map QueryBuilder props to AnalysisBuilder props\n return (\n <AnalysisBuilder\n ref={analysisBuilderRef}\n className={props.className}\n initialQuery={props.initialQuery}\n disableLocalStorage={props.disableLocalStorage}\n hideSettings={props.hideSettings}\n // Note: enableSharing and onShare props are not supported by AnalysisBuilder\n // The AnalysisBuilder has its own sharing mechanism\n />\n )\n }\n)\n\nQueryBuilderShim.displayName = 'QueryBuilder'\n\nexport default QueryBuilderShim\n","import React, { useState } from 'react'\nimport { getIcon } from '../icons'\nimport type { AxisDropZoneConfig } from '../charts/chartConfigs'\n\nconst CloseIcon = getIcon('close')\n\ninterface FieldStyling {\n IconComponent: React.ComponentType<{ className?: string }>\n baseClasses: string\n hoverClasses: string\n}\n\ninterface AxisDropZoneProps {\n config: AxisDropZoneConfig\n fields: string[]\n onDrop: (e: React.DragEvent<HTMLDivElement>, toKey: string) => void\n onRemove: (field: string, fromKey: string) => void\n onDragStart: (e: React.DragEvent<HTMLDivElement>, field: string, fromKey: string, fromIndex?: number) => void\n onDragEnd?: (e: React.DragEvent<HTMLDivElement>) => void\n onDragOver: (e: React.DragEvent<HTMLDivElement>) => void\n getFieldStyling: (field: string) => FieldStyling\n onReorder?: (fromIndex: number, toIndex: number, axisKey: string) => void\n draggedItem?: { field: string; fromAxis: string; fromIndex?: number } | null\n}\n\nexport default function AxisDropZone({\n config,\n fields,\n onDrop,\n onRemove,\n onDragStart,\n onDragEnd,\n onDragOver,\n getFieldStyling,\n onReorder,\n draggedItem\n}: AxisDropZoneProps) {\n const { key, label, description, mandatory, maxItems, emptyText, icon: IconComponent } = config\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null)\n const [isDraggedOver, setIsDraggedOver] = useState(false)\n const [isReorderDraggedOver, setIsReorderDraggedOver] = useState(false)\n \n // Calculate acceptance considering what's being dragged\n const getCanAcceptMore = () => {\n let effectiveCount = fields.length\n \n // If we're dragging FROM this axis, we effectively have one less item\n if (draggedItem && draggedItem.fromAxis === key) {\n effectiveCount = Math.max(0, fields.length - 1)\n }\n \n return !maxItems || effectiveCount < maxItems\n }\n \n const getIsFull = () => {\n let effectiveCount = fields.length\n \n // If we're dragging FROM this axis, we effectively have one less item\n if (draggedItem && draggedItem.fromAxis === key) {\n effectiveCount = Math.max(0, fields.length - 1)\n }\n \n return maxItems && effectiveCount >= maxItems\n }\n \n const canAcceptMore = getCanAcceptMore()\n const isFull = getIsFull()\n \n\n // Add a global drag end listener to reset visual state\n React.useEffect(() => {\n const handleGlobalDragEnd = () => {\n setDragOverIndex(null)\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }\n\n document.addEventListener('dragend', handleGlobalDragEnd)\n return () => {\n document.removeEventListener('dragend', handleGlobalDragEnd)\n }\n }, [])\n\n // Clear states when transitioning between different drag operations\n React.useEffect(() => {\n if (draggedItem) {\n // If we have a dragged item but it's not from this axis, clear reorder state\n if (draggedItem.fromAxis !== key) {\n setIsReorderDraggedOver(false)\n setDragOverIndex(null)\n }\n // If we have a dragged item from this axis, clear regular drag state\n else if (draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n setIsDraggedOver(false)\n }\n } else {\n // No dragged item, clear all states\n setDragOverIndex(null)\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }\n }, [draggedItem, key])\n\n const handleReorderDragOver = (e: React.DragEvent<HTMLDivElement>, targetIndex: number) => {\n // Check if this is a reorder operation (same axis) using the draggedItem prop\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n e.preventDefault()\n e.stopPropagation()\n setDragOverIndex(targetIndex)\n setIsReorderDraggedOver(true)\n }\n }\n\n const handleReorderDragLeave = () => {\n // Clear the individual item drag over index\n setDragOverIndex(null)\n // Note: Don't clear isReorderDraggedOver here as it causes flickering\n // Let the global drag end handler clear it when the drag is truly complete\n }\n\n const handleReorderDrop = (e: React.DragEvent<HTMLDivElement>, targetIndex: number) => {\n e.preventDefault()\n e.stopPropagation()\n setDragOverIndex(null)\n setIsReorderDraggedOver(false)\n \n // Handle reordering using either drag data or the draggedItem prop\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined && onReorder) {\n onReorder(draggedItem.fromIndex, targetIndex, key)\n return\n }\n \n // Fallback to parsing drag data\n try {\n const data = JSON.parse(e.dataTransfer.getData('text/plain'))\n if (data.fromAxis === key && onReorder && data.fromIndex !== undefined) {\n onReorder(data.fromIndex, targetIndex, key)\n }\n } catch {\n // If we can't parse the data, ignore\n }\n }\n \n return (\n <div className=\"mb-2\">\n <div className=\"flex items-center gap-2 mb-1\">\n <h4 className=\"text-xs font-semibold text-dc-text-secondary flex items-center\">\n {IconComponent && <IconComponent className=\"w-3 h-3 mr-1 text-dc-text-muted\" />}\n {label}\n {mandatory && <span className=\"text-dc-error ml-1\">*</span>}\n {maxItems && (\n <span className=\"text-dc-text-muted ml-1 font-normal\">\n ({fields.length}/{maxItems})\n </span>\n )}\n </h4>\n {description && (\n <span className=\"text-xs text-dc-text-muted\">\n {description}\n </span>\n )}\n </div>\n \n <div\n data-axis-container={key}\n className={`min-h-[40px] sm:min-h-[32px] border-2 border-dashed rounded-lg p-3 sm:p-1.5 transition-all duration-300 flex items-center ${\n (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'shadow-lg scale-110 border-solid animate-pulse'\n : isFull\n ? 'bg-dc-surface-secondary'\n : 'bg-dc-surface-secondary hover:bg-dc-surface-hover'\n }`}\n style={{\n borderColor: (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'var(--dc-primary)'\n : 'var(--dc-border)',\n backgroundColor: (isDraggedOver && (canAcceptMore || maxItems === 1)) || isReorderDraggedOver\n ? 'rgba(var(--dc-primary-rgb), 0.1)'\n : undefined\n }}\n onDragOver={(e) => {\n // Check if this is a reorder operation (same axis) - if so, don't interfere\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n return\n }\n \n // Simple acceptance check - either we have space OR it's a single-item replacement\n const canAccept = canAcceptMore || (maxItems === 1)\n \n if (canAccept) {\n setIsDraggedOver(true)\n onDragOver(e)\n } else {\n e.preventDefault()\n e.dataTransfer.dropEffect = 'none'\n }\n }}\n onDragLeave={(e) => {\n // Check if we're truly leaving the container\n const rect = e.currentTarget.getBoundingClientRect()\n const isLeavingContainer = (\n e.clientX < rect.left || \n e.clientX > rect.right || \n e.clientY < rect.top || \n e.clientY > rect.bottom\n )\n \n // Also check if the related target is outside this container\n const relatedTarget = e.relatedTarget as Element | null\n const isRelatedTargetOutside = relatedTarget && !e.currentTarget.contains(relatedTarget)\n \n if (isLeavingContainer || isRelatedTargetOutside || e.currentTarget === e.target) {\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }\n }}\n onDrop={(e) => {\n // Check if this is a reorder operation (same axis) - if so, don't interfere\n if (draggedItem && draggedItem.fromAxis === key && draggedItem.fromIndex !== undefined) {\n return\n }\n \n // Simple acceptance check - either we have space OR it's a single-item replacement\n const shouldAcceptDrop = canAcceptMore || (maxItems === 1)\n \n if (shouldAcceptDrop) {\n onDrop(e, key)\n } else {\n e.preventDefault()\n }\n \n // Reset drag state on drop\n setIsDraggedOver(false)\n setIsReorderDraggedOver(false)\n }}\n >\n {fields.length === 0 ? (\n <div className=\"text-xs text-dc-text-muted text-center w-full\">\n {isFull ? 'Maximum items reached' : (emptyText || `Drop fields here`)}\n </div>\n ) : (\n <div className=\"flex flex-wrap gap-1\">\n {fields.map((field, index) => {\n const { IconComponent: FieldIcon, baseClasses, hoverClasses } = getFieldStyling(field)\n const isDragOver = dragOverIndex === index\n const isBeingDragged = draggedItem && draggedItem.field === field && draggedItem.fromAxis === key\n \n return (\n <div\n key={`${field}-${index}`}\n className={`relative ${isDragOver ? 'transform scale-105' : ''}`}\n >\n {/* Drop indicator line for reordering */}\n {isDragOver && (\n <div className=\"absolute -left-1 top-0 bottom-0 w-1 rounded-full z-10\" style={{ backgroundColor: 'var(--dc-primary)' }} />\n )}\n \n <div\n draggable\n onDragStart={(e) => {\n // Let parent handle drag data with index\n onDragStart(e, field, key, index)\n }}\n onDragEnd={onDragEnd}\n onDragOver={(e) => handleReorderDragOver(e, index)}\n onDragLeave={handleReorderDragLeave}\n onDrop={(e) => handleReorderDrop(e, index)}\n className={`rounded text-xs cursor-move px-3 py-0.5 sm:px-2 sm:py-1 flex items-center transition-transform h-[28px] sm:h-auto ${baseClasses} ${hoverClasses} ${\n isDragOver ? 'bg-opacity-75' : ''\n } ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n >\n <FieldIcon className=\"w-3 h-3 mr-1 shrink-0\" />\n <span className=\"leading-none\">{field}</span>\n <button\n type=\"button\"\n onClick={() => onRemove(field, key)}\n className=\"text-dc-text-secondary hover:text-dc-danger ml-1.5 leading-none\"\n title={`Remove from ${label}`}\n >\n <CloseIcon className=\"w-3 h-3\" />\n </button>\n </div>\n </div>\n )\n })}\n </div>\n )}\n </div>\n \n {mandatory && fields.length === 0 && (\n <div className=\"text-xs text-dc-error mt-0.5\">\n This field is required\n </div>\n )}\n </div>\n )\n}","import React, { useMemo, useEffect, useState } from 'react'\nimport { getIcon } from '../icons'\nimport AxisDropZone from './AxisDropZone'\n\nconst MeasureIcon = getIcon('measure')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\nimport { chartConfigRegistry } from '../charts/chartConfigRegistry'\nimport { getChartConfig } from '../charts/chartConfigs'\nimport type { ChartType, ChartAxisConfig, ChartDisplayConfig, ColorPalette } from '../types'\n\ninterface ChartConfigPanelProps {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n availableFields: {\n dimensions: string[]\n timeDimensions: string[]\n measures: string[]\n } | null\n colorPalette?: ColorPalette\n onChartConfigChange: (config: ChartAxisConfig) => void\n onDisplayConfigChange: (config: ChartDisplayConfig) => void\n}\n\nexport default function ChartConfigPanel({\n chartType,\n chartConfig,\n displayConfig,\n availableFields,\n colorPalette,\n onChartConfigChange,\n onDisplayConfigChange\n}: ChartConfigPanelProps) {\n \n // Track currently dragging item for immediate state updates\n const [draggedItem, setDraggedItem] = useState<{\n field: string\n fromAxis: string\n fromIndex?: number\n } | null>(null)\n \n // Get configuration for current chart type\n const chartTypeConfig = useMemo(() => \n getChartConfig(chartType, chartConfigRegistry),\n [chartType]\n )\n \n // Check if this chart type skips queries\n const shouldSkipQuery = chartTypeConfig.skipQuery === true\n\n // Get fields for each drop zone\n const getFieldsForDropZone = (key: string): string[] => {\n const value = chartConfig[key as keyof ChartAxisConfig]\n const result = Array.isArray(value) ? value : (typeof value === 'string' ? [value] : [])\n return result\n }\n\n // Clean up chart config when available fields change\n useEffect(() => {\n if (!availableFields) return\n\n const allAvailableFields = [\n ...availableFields.dimensions,\n ...availableFields.timeDimensions,\n ...availableFields.measures\n ]\n\n let hasChanges = false\n const newConfig = { ...chartConfig }\n\n // Check each axis and remove fields that are no longer available\n chartTypeConfig.dropZones.forEach(dropZone => {\n const currentFields = getFieldsForDropZone(dropZone.key)\n const validFields = currentFields.filter(field => allAvailableFields.includes(field))\n \n if (validFields.length !== currentFields.length) {\n hasChanges = true\n if (validFields.length === 0) {\n // Remove the axis property entirely if no valid fields remain\n delete newConfig[dropZone.key as keyof ChartAxisConfig]\n } else if (dropZone.maxItems === 1) {\n // Single field axis - always store as string\n newConfig[dropZone.key as keyof ChartAxisConfig] = validFields[0] as any\n } else {\n // Multi-field axis - always store as array\n newConfig[dropZone.key as keyof ChartAxisConfig] = validFields as any\n }\n }\n })\n\n if (hasChanges) {\n onChartConfigChange(newConfig)\n }\n }, [availableFields, chartConfig, chartTypeConfig.dropZones, onChartConfigChange])\n\n // Helper to determine field type and styling\n const getFieldType = (field: string): 'dimension' | 'timeDimension' | 'measure' => {\n if (!availableFields) return 'dimension'\n if (availableFields.measures.includes(field)) return 'measure'\n if (availableFields.timeDimensions.includes(field)) return 'timeDimension'\n return 'dimension'\n }\n\n const getFieldStyling = (field: string) => {\n const fieldType = getFieldType(field)\n\n switch (fieldType) {\n case 'measure':\n return {\n IconComponent: MeasureIcon,\n baseClasses: 'bg-dc-measure text-dc-measure border border-dc-measure',\n hoverClasses: 'hover:opacity-80'\n }\n case 'timeDimension':\n return {\n IconComponent: TimeDimensionIcon,\n baseClasses: 'bg-dc-time-dimension text-dc-time-dimension border border-dc-time-dimension',\n hoverClasses: 'hover:opacity-80'\n }\n default:\n return {\n IconComponent: DimensionIcon,\n baseClasses: 'bg-dc-dimension text-dc-dimension border border-dc-dimension',\n hoverClasses: 'hover:opacity-80'\n }\n }\n }\n\n // Drag and drop handlers\n const handleDragStart = (e: React.DragEvent<HTMLDivElement>, field: string, fromAxis: string, fromIndex?: number) => {\n e.dataTransfer.setData('text/plain', JSON.stringify({ field, fromAxis, fromIndex }))\n \n // Just track the dragged item - don't remove it yet\n setDraggedItem({ field, fromAxis, fromIndex })\n }\n\n const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n }\n\n const handleDragEnd = () => {\n // Just clear the dragged item tracking - no need to restore since we didn't remove it\n setDraggedItem(null)\n }\n\n const handleDrop = (e: React.DragEvent<HTMLDivElement>, toAxis: string) => {\n e.preventDefault()\n const data = JSON.parse(e.dataTransfer.getData('text/plain'))\n const { field, fromAxis } = data\n \n const newConfig = { ...chartConfig }\n \n // Remove from old location if moving between axes\n if (fromAxis !== 'available' && fromAxis !== toAxis) {\n const fromValue = newConfig[fromAxis as keyof ChartAxisConfig]\n if (Array.isArray(fromValue)) {\n const filteredValue = fromValue.filter(f => f !== field)\n if (filteredValue.length === 0) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n } else {\n newConfig[fromAxis as keyof ChartAxisConfig] = filteredValue as any\n }\n } else if (fromValue === field) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n }\n }\n \n // Add to new location\n const toValue = newConfig[toAxis as keyof ChartAxisConfig]\n const dropZoneConfig = chartTypeConfig.dropZones.find(dz => dz.key === toAxis)\n \n if (dropZoneConfig?.maxItems === 1) {\n // Single field - always store as string\n newConfig[toAxis as keyof ChartAxisConfig] = field as any\n } else {\n // Multiple fields - always store as array\n if (Array.isArray(toValue)) {\n if (!toValue.includes(field)) {\n newConfig[toAxis as keyof ChartAxisConfig] = [...toValue, field] as any\n }\n } else {\n newConfig[toAxis as keyof ChartAxisConfig] = [field] as any\n }\n }\n \n // Clear the dragged item tracking\n setDraggedItem(null)\n onChartConfigChange(newConfig)\n }\n\n const handleRemoveFromAxis = (field: string, fromAxis: string) => {\n const newConfig = { ...chartConfig }\n const value = newConfig[fromAxis as keyof ChartAxisConfig]\n \n if (Array.isArray(value)) {\n const filteredValue = value.filter(f => f !== field)\n if (filteredValue.length === 0) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n } else {\n newConfig[fromAxis as keyof ChartAxisConfig] = filteredValue as any\n }\n } else if (value === field) {\n delete newConfig[fromAxis as keyof ChartAxisConfig]\n }\n \n onChartConfigChange(newConfig)\n }\n\n const handleReorder = (fromIndex: number, toIndex: number, axisKey: string) => {\n const newConfig = { ...chartConfig }\n const value = newConfig[axisKey as keyof ChartAxisConfig]\n \n // Only reorder if we have an array with multiple items\n if (Array.isArray(value) && value.length > 1 && fromIndex !== toIndex) {\n const newArray = [...value]\n const [movedItem] = newArray.splice(fromIndex, 1)\n newArray.splice(toIndex, 0, movedItem)\n newConfig[axisKey as keyof ChartAxisConfig] = newArray as any\n \n // Clear the dragged item tracking\n setDraggedItem(null)\n onChartConfigChange(newConfig)\n }\n }\n\n // Get unassigned fields\n const getUnassignedFields = () => {\n if (!availableFields) return { dimensions: [], timeDimensions: [], measures: [] }\n \n const assignedFields = new Set<string>()\n chartTypeConfig.dropZones.forEach(dz => {\n getFieldsForDropZone(dz.key).forEach(field => assignedFields.add(field))\n })\n \n // Exclude the currently dragged field only if it's being dragged FROM a configured axis\n // (not from available fields, where it should remain visible)\n if (draggedItem && draggedItem.fromAxis !== 'available') {\n assignedFields.add(draggedItem.field)\n }\n \n return {\n dimensions: availableFields.dimensions.filter(f => !assignedFields.has(f)),\n timeDimensions: availableFields.timeDimensions.filter(f => !assignedFields.has(f)),\n measures: availableFields.measures.filter(f => !assignedFields.has(f))\n }\n }\n\n const unassignedFields = getUnassignedFields()\n\n\n return (\n <div>\n {/* Available Fields - Hidden for skipQuery charts */}\n {!shouldSkipQuery && availableFields && (\n <div className=\"mb-4\">\n <h4 className=\"text-xs font-semibold text-dc-text-secondary mb-2\">Available Fields</h4>\n <div className=\"border border-dc-border rounded-lg p-2 bg-dc-surface-secondary\">\n {(unassignedFields.dimensions.length > 0 ||\n unassignedFields.timeDimensions.length > 0 ||\n unassignedFields.measures.length > 0) ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-2 gap-y-4 sm:gap-y-2\">\n {/* Dimensions Column */}\n <div className=\"pb-2 sm:pb-0\">\n <div className=\"text-xs text-dc-text-secondary mb-2 sm:mb-1 flex items-center\">\n <DimensionIcon className=\"w-3 h-3 mr-1 text-dc-text-muted\" />\n Dimensions\n </div>\n <div className=\"space-y-1\">\n {unassignedFields.dimensions.map(dim => {\n const isBeingDragged = draggedItem && draggedItem.field === dim && draggedItem.fromAxis === 'available'\n return (\n <div\n key={dim}\n draggable\n onDragStart={(e) => handleDragStart(e, dim, 'available')}\n onDragEnd={handleDragEnd}\n className={`bg-dc-dimension text-dc-dimension border border-dc-dimension hover:opacity-80 rounded-sm text-xs cursor-move px-3 py-2 sm:px-2 sm:py-1 truncate ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={dim}\n >\n {dim}\n </div>\n )\n })}\n {unassignedFields.dimensions.length === 0 && (\n <div className=\"text-xs text-dc-text-muted italic\">None</div>\n )}\n </div>\n </div>\n \n {/* Time Dimensions Column */}\n <div className=\"pb-2 sm:pb-0\">\n <div className=\"text-xs text-dc-text-secondary mb-2 sm:mb-1 flex items-center\">\n <TimeDimensionIcon className=\"w-3 h-3 mr-1 text-dc-text-muted\" />\n Time Dimensions\n </div>\n <div className=\"space-y-1\">\n {unassignedFields.timeDimensions.map(dim => {\n const isBeingDragged = draggedItem && draggedItem.field === dim && draggedItem.fromAxis === 'available'\n return (\n <div\n key={dim}\n draggable\n onDragStart={(e) => handleDragStart(e, dim, 'available')}\n onDragEnd={handleDragEnd}\n className={`bg-dc-time-dimension text-dc-time-dimension border border-dc-time-dimension hover:opacity-80 rounded-sm text-xs cursor-move px-3 py-2 sm:px-2 sm:py-1 truncate ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={dim}\n >\n {dim}\n </div>\n )\n })}\n {unassignedFields.timeDimensions.length === 0 && (\n <div className=\"text-xs text-dc-text-muted italic\">None</div>\n )}\n </div>\n </div>\n \n {/* Measures Column */}\n <div className=\"pb-2 sm:pb-0\">\n <div className=\"text-xs text-dc-text-secondary mb-2 sm:mb-1 flex items-center\">\n <MeasureIcon className=\"w-3 h-3 mr-1 text-dc-text-muted\" />\n Measures\n </div>\n <div className=\"space-y-1\">\n {unassignedFields.measures.map(measure => {\n const isBeingDragged = draggedItem && draggedItem.field === measure && draggedItem.fromAxis === 'available'\n return (\n <div\n key={measure}\n draggable\n onDragStart={(e) => handleDragStart(e, measure, 'available')}\n onDragEnd={handleDragEnd}\n className={`bg-dc-measure text-dc-measure border border-dc-measure hover:opacity-80 rounded-sm text-xs cursor-move px-3 py-2 sm:px-2 sm:py-1 truncate ${isBeingDragged ? 'opacity-50 cursor-grabbing' : ''}`}\n title={measure}\n >\n {measure}\n </div>\n )\n })}\n {unassignedFields.measures.length === 0 && (\n <div className=\"text-xs text-dc-text-muted italic\">None</div>\n )}\n </div>\n </div>\n </div>\n ) : (\n <div className=\"text-xs text-dc-text-muted text-center py-2\">\n All fields have been assigned\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Chart Axis Configuration - Dynamic Drop Zones, Hidden for skipQuery charts */}\n {!shouldSkipQuery && (\n <div className=\"mb-4\">\n <h4 className=\"text-xs font-semibold text-dc-text-secondary mb-2\">Chart Configuration</h4>\n <div className=\"space-y-1\">\n {chartTypeConfig.dropZones.map(dropZone => (\n <AxisDropZone\n key={dropZone.key}\n config={dropZone}\n fields={getFieldsForDropZone(dropZone.key)}\n onDrop={handleDrop}\n onRemove={handleRemoveFromAxis}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragOver={handleDragOver}\n getFieldStyling={getFieldStyling}\n onReorder={handleReorder}\n draggedItem={draggedItem}\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Display Options */}\n {((chartTypeConfig.displayOptions && chartTypeConfig.displayOptions.length > 0) ||\n (chartTypeConfig.displayOptionsConfig && chartTypeConfig.displayOptionsConfig.length > 0)) && (\n <div className=\"mb-4\">\n <h4 className=\"text-xs font-semibold text-dc-text-secondary mb-2\">Display Options</h4>\n <div className=\"space-y-2\">\n {/* Backward compatibility: Simple boolean display options */}\n {chartTypeConfig.displayOptions?.includes('showLegend') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showLegend ?? true}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n showLegend: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Legend</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('showGrid') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showGrid ?? true}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n showGrid: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Grid</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('showTooltip') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.showTooltip ?? true}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n showTooltip: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Show Tooltip</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('stacked') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.stacked ?? false}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n stacked: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Stacked</span>\n </label>\n )}\n\n {chartTypeConfig.displayOptions?.includes('hideHeader') && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig.hideHeader ?? false}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n hideHeader: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">Hide Header</span>\n </label>\n )}\n\n {/* New structured display options */}\n {chartTypeConfig.displayOptionsConfig?.map((option) => (\n <div key={option.key} className=\"space-y-1\">\n {option.type === 'boolean' && (\n <label className=\"flex items-center space-x-2\">\n <input\n type=\"checkbox\"\n checked={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? false}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.checked\n })}\n className=\"rounded border-dc-border focus:ring-dc-accent\"\n style={{ color: 'var(--dc-primary)' }}\n />\n <span className=\"text-sm text-dc-text\">{option.label}</span>\n </label>\n )}\n\n {option.type === 'string' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">\n {option.label}\n {option.key === 'content' && (\n <span className=\"text-xs text-dc-text-muted ml-1\">(only headers, lists and links)</span>\n )}\n </label>\n {option.key === 'content' ? (\n <textarea\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? ''}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })}\n placeholder={option.placeholder}\n rows={8}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent font-mono resize-y bg-dc-surface text-dc-text\"\n />\n ) : (\n <input\n type=\"text\"\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? ''}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })}\n placeholder={option.placeholder}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n )}\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'paletteColor' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <div className=\"flex flex-wrap gap-2\">\n {colorPalette?.colors.map((color, index) => {\n const isSelected = (displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? 0) === index\n return (\n <button\n key={index}\n type=\"button\"\n onClick={() => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: index\n })}\n className={`w-8 h-8 rounded border-2 transition-all duration-200 hover:scale-110 focus:outline-hidden focus:ring-2 focus:ring-dc-accent focus:ring-offset-1 ${\n isSelected\n ? 'ring-2 ring-offset-1 scale-110'\n : 'hover:border-dc-text-muted'\n }`}\n style={{\n backgroundColor: color,\n borderColor: isSelected ? 'var(--dc-primary)' : 'var(--dc-border)'\n }}\n title={`Color ${index + 1}: ${color}`}\n />\n )\n }) || [\n // Fallback if no palette available\n <button\n key={0}\n type=\"button\"\n onClick={() => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: 0\n })}\n className=\"w-8 h-8 rounded-sm border-2 ring-2 ring-offset-1\"\n style={{\n backgroundColor: '#8884d8',\n borderColor: 'var(--dc-primary)',\n boxShadow: '0 0 0 2px var(--dc-primary)'\n }}\n title=\"Default Color\"\n />\n ]}\n </div>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'number' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <input\n type=\"number\"\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? 0}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value === '' ? undefined : Number(e.target.value)\n })}\n placeholder={option.placeholder}\n min={option.min}\n max={option.max}\n step={option.step}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'select' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <select\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? ''}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })}\n className=\"w-full px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n >\n {option.options?.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n\n {option.type === 'color' && (\n <div className=\"space-y-1\">\n <label className=\"text-sm text-dc-text-secondary\">{option.label}</label>\n <div className=\"flex items-center space-x-2\">\n <input\n type=\"color\"\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? '#8884d8'}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })}\n className=\"w-12 h-8 border border-dc-border rounded-sm cursor-pointer\"\n />\n <input\n type=\"text\"\n value={displayConfig[option.key as keyof ChartDisplayConfig] ?? option.defaultValue ?? '#8884d8'}\n onChange={(e) => onDisplayConfigChange({\n ...displayConfig,\n [option.key]: e.target.value\n })}\n placeholder={option.placeholder || '#8884d8'}\n className=\"flex-1 px-2 py-1 text-sm border border-dc-border rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n {option.description && (\n <p className=\"text-xs text-dc-text-muted\">{option.description}</p>\n )}\n </div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}","import React, { useState, useEffect, useRef } from 'react'\nimport Modal from './Modal'\nimport QueryBuilder from './QueryBuilderShim'\nimport ChartConfigPanel from './ChartConfigPanel'\nimport ChartTypeSelector from './ChartTypeSelector'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport { chartConfigRegistry } from '../charts/chartConfigRegistry'\nimport { getChartConfig } from '../charts/chartConfigs'\nimport type { PortletConfig, ChartAxisConfig, ChartDisplayConfig, ChartType, ColorPalette } from '../types'\n\ninterface PortletEditModalProps {\n isOpen: boolean\n onClose: () => void\n onSave: (portlet: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'>) => void\n portlet?: PortletConfig | null\n title: string\n submitText: string\n colorPalette?: ColorPalette\n}\n\n\nconst SAMPLE_QUERIES = [\n {\n name: 'Employee Count by Department',\n query: JSON.stringify({\n \"measures\": [\"Employees.count\"],\n \"dimensions\": [\"Departments.name\"],\n \"order\": { \"Employees.count\": \"desc\" }\n }, null, 2)\n },\n {\n name: 'Employee Hiring Trends',\n query: JSON.stringify({\n \"measures\": [\"Employees.count\"],\n \"timeDimensions\": [{\n \"dimension\": \"Employees.createdAt\",\n \"granularity\": \"month\"\n }],\n \"order\": { \"Employees.createdAt\": \"asc\" }\n }, null, 2)\n },\n {\n name: 'Department Budget Analysis',\n query: JSON.stringify({\n \"measures\": [\"Departments.totalBudget\", \"Departments.avgBudget\"],\n \"dimensions\": [\"Departments.name\"],\n \"order\": { \"Departments.totalBudget\": \"desc\" }\n }, null, 2)\n },\n {\n name: 'Daily Productivity Trends',\n query: JSON.stringify({\n \"measures\": [\"Productivity.avgLinesOfCode\", \"Productivity.totalPullRequests\"],\n \"timeDimensions\": [{\n \"dimension\": \"Productivity.date\",\n \"granularity\": \"day\"\n }],\n \"order\": { \"Productivity.date\": \"asc\" }\n }, null, 2)\n },\n {\n name: 'Happiness by Department',\n query: JSON.stringify({\n \"measures\": [\"Productivity.avgHappinessIndex\", \"Productivity.workingDaysCount\"],\n \"dimensions\": [\"Departments.name\"],\n \"order\": { \"Productivity.avgHappinessIndex\": \"desc\" }\n }, null, 2)\n },\n {\n name: 'Employee Salary Overview',\n query: JSON.stringify({\n \"measures\": [\"Employees.count\", \"Employees.avgSalary\", \"Employees.totalSalary\"],\n \"dimensions\": [\"Employees.isActive\"],\n \"order\": { \"Employees.avgSalary\": \"desc\" }\n }, null, 2)\n }\n]\n\nexport default function PortletEditModal({\n isOpen,\n onClose,\n onSave,\n portlet,\n title,\n submitText,\n colorPalette\n}: PortletEditModalProps) {\n // Get cube client from context\n const { cubeApi } = useCubeContext()\n const [formTitle, setFormTitle] = useState('')\n const [query, setQuery] = useState('')\n const [chartType, setChartType] = useState<ChartType>('bar')\n const [dashboardFilterMapping, setDashboardFilterMapping] = useState<string[]>([])\n const [isValidating, setIsValidating] = useState(false)\n const [validationResult, setValidationResult] = useState<{ isValid: boolean; message: string } | null>(null)\n const [lastValidatedQuery, setLastValidatedQuery] = useState<string>('')\n const [dryRunData, setDryRunData] = useState<any>(null)\n const [chartConfig, setChartConfig] = useState<ChartAxisConfig>({ xAxis: [], yAxis: [], series: [] })\n const [displayConfig, setDisplayConfig] = useState<ChartDisplayConfig>({ showLegend: true, showGrid: true, showTooltip: true, stacked: false })\n const [showQueryBuilder, setShowQueryBuilder] = useState(false)\n const [queryBuilderInitialQuery, setQueryBuilderInitialQuery] = useState<any>(null)\n const queryBuilderRef = useRef<any>(null)\n\n // Check if current chart type skips queries\n const chartTypeConfig = getChartConfig(chartType, chartConfigRegistry)\n const shouldSkipQuery = chartTypeConfig.skipQuery === true\n\n // Validation only - no automatic chart config changes\n const autoPopulateChartConfig = (_result: any) => {\n // Do nothing - let the chart configuration panel handle all axis assignments manually\n // This preserves any existing user configuration and doesn't auto-assign fields\n }\n \n // Sensible defaults: slightly larger than 1/3 width with good aspect ratio\n const defaultWidth = 5\n const defaultHeight = 4\n\n\n // Initialize form values when modal opens or portlet changes\n useEffect(() => {\n if (isOpen) {\n if (portlet) {\n // Edit mode - populate with existing data\n setFormTitle(portlet.title)\n const formattedQuery = (() => {\n try {\n return JSON.stringify(JSON.parse(portlet.query), null, 2)\n } catch {\n return portlet.query\n }\n })()\n setQuery(formattedQuery)\n setChartType(portlet.chartType)\n setChartConfig(portlet.chartConfig || { xAxis: [], yAxis: [], series: [] })\n setDisplayConfig(portlet.displayConfig || {})\n setDashboardFilterMapping(portlet.dashboardFilterMapping || [])\n setLastValidatedQuery(formattedQuery)\n setValidationResult({ isValid: true, message: 'Loaded query (assumed valid)' })\n setDryRunData(null)\n\n // Auto-run dry-run validation for edit mode to enable chart configuration (skip for skipQuery charts)\n if (!shouldSkipQuery) {\n setTimeout(() => {\n runDryRunValidation(formattedQuery, true, true)\n }, 100)\n }\n } else {\n // Create mode - clear form\n setFormTitle('')\n setQuery('')\n setChartType('bar')\n setChartConfig({ xAxis: [], yAxis: [], series: [] })\n setDisplayConfig({ showLegend: true, showGrid: true, showTooltip: true, stacked: false })\n setDashboardFilterMapping([])\n setLastValidatedQuery('')\n setValidationResult(null)\n setDryRunData(null)\n }\n setIsValidating(false)\n }\n }, [isOpen, portlet])\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n \n // For skipQuery charts, only validate title\n if (shouldSkipQuery) {\n if (!formTitle.trim()) {\n return\n }\n } else {\n // For normal charts, validate both title and query\n if (!formTitle.trim() || !query.trim()) {\n return\n }\n\n // Require validation before saving only if query has changed\n if (hasQueryChanged || (lastValidatedQuery === '' && query.trim() !== '')) {\n alert('Please validate your query before saving.')\n return\n }\n\n // Validate JSON\n try {\n JSON.parse(query)\n } catch {\n alert('Invalid JSON in query. Please check your syntax.')\n return\n }\n }\n\n // Prepare query - use minimal query for skipQuery charts\n const queryToSave = shouldSkipQuery ? '{\"measures\":[]}' : query.trim()\n\n if (portlet) {\n // Edit mode - return full portlet config\n onSave({\n ...portlet,\n title: formTitle.trim(),\n query: queryToSave,\n chartType,\n chartConfig: Object.keys(chartConfig).length > 0 ? chartConfig : undefined,\n displayConfig: displayConfig,\n dashboardFilterMapping: dashboardFilterMapping.length > 0 ? dashboardFilterMapping : undefined,\n w: portlet.w || defaultWidth,\n h: portlet.h || defaultHeight\n })\n } else {\n // Create mode - return partial config\n onSave({\n title: formTitle.trim(),\n query: queryToSave,\n chartType,\n chartConfig: Object.keys(chartConfig).length > 0 ? chartConfig : undefined,\n displayConfig: displayConfig,\n dashboardFilterMapping: dashboardFilterMapping.length > 0 ? dashboardFilterMapping : undefined,\n w: defaultWidth,\n h: defaultHeight\n })\n }\n }\n\n const handleSampleQuery = (sampleQuery: string) => {\n setQuery(sampleQuery)\n setValidationResult(null)\n setLastValidatedQuery('')\n setDryRunData(null)\n // Sample queries always clear chart config since they're completely different\n setChartConfig({ xAxis: [], yAxis: [], series: [] })\n }\n\n const handleQueryChange = (value: string) => {\n setQuery(value)\n setValidationResult(null)\n setDryRunData(null)\n // Only clear chart config for new portlets, preserve existing config for edits\n if (!portlet) {\n setChartConfig({ xAxis: [], yAxis: [], series: [] })\n }\n }\n\n const runDryRunValidation = async (queryToValidate: string, silent = false, isEditModeLoad = false) => {\n if (!queryToValidate.trim()) {\n if (!silent) {\n setValidationResult({ isValid: false, message: 'Query cannot be empty' })\n }\n return\n }\n\n let parsedQuery\n try {\n parsedQuery = JSON.parse(queryToValidate)\n } catch {\n if (!silent) {\n setValidationResult({ isValid: false, message: 'Invalid JSON syntax' })\n }\n return\n }\n\n if (!silent) {\n setIsValidating(true)\n setValidationResult(null)\n }\n\n try {\n const result = await cubeApi.dryRun(parsedQuery)\n\n // Check if validation is successful:\n // 1. Must have queryType (always present in successful Cube.js responses) \n // 2. Must not have an error\n const isValid = !result.error && result.queryType\n \n if (isValid) {\n setDryRunData(result)\n \n if (!silent) {\n const details = []\n \n if (result.pivotQuery?.query) {\n if (result.pivotQuery.query.measures?.length > 0) {\n details.push(`${result.pivotQuery.query.measures.length} measure${result.pivotQuery.query.measures.length > 1 ? 's' : ''}`)\n }\n if (result.pivotQuery.query.dimensions?.length > 0) {\n details.push(`${result.pivotQuery.query.dimensions.length} dimension${result.pivotQuery.query.dimensions.length > 1 ? 's' : ''}`)\n }\n if (result.pivotQuery.query.filters?.length > 0) {\n details.push(`${result.pivotQuery.query.filters.length} filter${result.pivotQuery.query.filters.length > 1 ? 's' : ''}`)\n }\n if (result.pivotQuery.query.timeDimensions?.length > 0) {\n details.push(`${result.pivotQuery.query.timeDimensions.length} time dimension${result.pivotQuery.query.timeDimensions.length > 1 ? 's' : ''}`)\n }\n }\n\n if (result.complexity) {\n details.push(`${result.complexity} complexity`)\n }\n if (result.sql?.sql) {\n details.push('SQL generated')\n }\n if (result.cubesUsed?.length > 0) {\n details.push(`Cubes: ${result.cubesUsed.join(', ')}`)\n }\n \n const message = details.length > 0 ? `Query validated successfully (${details.join(', ')})` : 'Query validated successfully'\n setValidationResult({ isValid: true, message })\n setLastValidatedQuery(queryToValidate)\n }\n\n // Auto-populate chart config with sensible defaults on successful validation\n if (!isEditModeLoad) {\n autoPopulateChartConfig(result)\n }\n } else {\n if (!silent) {\n const errorMsg = result.error || 'Query validation failed'\n const details = result.details ? ` - ${Array.isArray(result.details) ? result.details.join(', ') : result.details}` : ''\n setValidationResult({ \n isValid: false, \n message: errorMsg + details\n })\n setLastValidatedQuery(queryToValidate)\n }\n }\n } catch (error) {\n if (!silent) {\n setValidationResult({ \n isValid: false, \n message: error instanceof Error ? error.message : 'Network error during validation' \n })\n setLastValidatedQuery(queryToValidate)\n }\n } finally {\n if (!silent) {\n setIsValidating(false)\n }\n }\n }\n\n const handleValidateQuery = async () => {\n await runDryRunValidation(query)\n }\n\n const handleOpenQueryBuilder = () => {\n // Parse the current query and set it as the initial query for QueryBuilder\n const initialQuery = query ? (() => {\n try {\n return JSON.parse(query)\n } catch {\n return {}\n }\n })() : {}\n \n setQueryBuilderInitialQuery(initialQuery)\n setShowQueryBuilder(true)\n }\n\n\n const handleApplyQueryBuilderQuery = (e?: React.MouseEvent) => {\n e?.preventDefault()\n e?.stopPropagation()\n \n if (!queryBuilderRef.current) return\n \n // Get current query and validation state from QueryBuilder\n const currentQuery = queryBuilderRef.current.getCurrentQuery()\n const validationState = queryBuilderRef.current.getValidationState()\n const validationResult = queryBuilderRef.current.getValidationResult()\n \n // Apply the query to the form\n const formattedQuery = JSON.stringify(currentQuery, null, 2)\n setQuery(formattedQuery)\n \n // If QueryBuilder had a valid query, transfer the validation state and dry-run data\n if (validationState?.status === 'valid' && validationResult) {\n setValidationResult({ \n isValid: true, \n message: 'Query validated in Query Builder' \n })\n setLastValidatedQuery(formattedQuery)\n \n // Transfer the dry-run data from QueryBuilder validation result\n setDryRunData(validationResult)\n \n // Auto-populate chart config using the same logic as form validation\n autoPopulateChartConfig(validationResult)\n } else {\n // Reset validation state if query wasn't validated in QueryBuilder\n setValidationResult(null)\n setLastValidatedQuery('')\n setDryRunData(null)\n }\n \n // Return to form view to continue editing\n setShowQueryBuilder(false)\n }\n\n const handleBackToForm = () => {\n setShowQueryBuilder(false)\n setQueryBuilderInitialQuery(null)\n }\n\n const handleClose = () => {\n setFormTitle('')\n setQuery('')\n setChartType('bar')\n setChartConfig({ xAxis: [], yAxis: [], series: [] })\n setDisplayConfig({ showLegend: true, showGrid: true, showTooltip: true, stacked: false })\n setValidationResult(null)\n setIsValidating(false)\n setLastValidatedQuery('')\n setDryRunData(null)\n setShowQueryBuilder(false)\n setQueryBuilderInitialQuery(null)\n onClose()\n }\n\n const isEditMode = !!portlet\n const hasQueryChanged = query.trim() !== lastValidatedQuery.trim() && lastValidatedQuery !== ''\n const isQueryValidAndCurrent = validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n\n\n const availableFields = dryRunData?.pivotQuery?.query ? {\n dimensions: dryRunData.pivotQuery.query.dimensions || [],\n timeDimensions: dryRunData.pivotQuery.query.timeDimensions?.map((td: any) => td.dimension) || [],\n measures: dryRunData.pivotQuery.query.measures || []\n } : null\n\n\n const footer = showQueryBuilder ? (\n <>\n <button\n type=\"button\"\n onClick={handleBackToForm}\n className=\"px-4 py-2 text-sm font-medium text-dc-text-secondary bg-dc-surface border border-dc-border rounded-md hover:bg-dc-surface-hover focus:outline-none focus:ring-2 focus:ring-dc-primary\"\n >\n Back to Form\n </button>\n <button\n type=\"button\"\n onClick={handleApplyQueryBuilderQuery}\n className=\"px-4 py-2 text-sm font-medium border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-dc-accent\"\n style={{ backgroundColor: 'var(--dc-primary)', color: '#ffffff' }}\n title=\"Apply query to form\"\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-primary-hover)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-primary)'}\n >\n Apply Query\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"px-4 py-2 text-sm font-medium text-dc-text-secondary bg-dc-surface border border-dc-border rounded-md hover:bg-dc-surface-hover focus:outline-none focus:ring-2 focus:ring-dc-primary\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n form=\"portlet-form\"\n className=\"px-4 py-2 text-sm font-medium border border-transparent rounded-md disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-dc-accent\"\n style={{ backgroundColor: 'var(--dc-primary)', color: '#ffffff' }}\n disabled={shouldSkipQuery ? !formTitle.trim() : (!formTitle.trim() || !query.trim() || (hasQueryChanged || (lastValidatedQuery === '' && query.trim() !== '')))}\n title={!shouldSkipQuery && (hasQueryChanged || (lastValidatedQuery === '' && query.trim() !== '')) ? \"Please validate your query before saving\" : \"\"}\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-primary-hover)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-primary)'}\n >\n {submitText}\n </button>\n </>\n )\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={handleClose}\n title={showQueryBuilder ? \"Query Builder\" : title}\n size=\"fullscreen-mobile\"\n footer={footer}\n noPadding={showQueryBuilder}\n >\n {showQueryBuilder ? (\n <QueryBuilder\n ref={queryBuilderRef}\n initialQuery={queryBuilderInitialQuery}\n disableLocalStorage={true}\n hideSettings={true}\n className=\"flex-1 w-full\"\n />\n ) : (\n <form id=\"portlet-form\" onSubmit={handleSubmit} className=\"space-y-4\">\n {/* Main layout - Responsive: single column on mobile, two columns on desktop */}\n <div className=\"flex flex-col lg:flex-row gap-4\">\n {/* Left side - Title, Chart Type, Query */}\n <div className=\"flex-1 flex flex-col gap-4\">\n {/* Title */}\n <div>\n <label className=\"block text-sm font-semibold text-dc-text-secondary mb-1\">\n Title\n </label>\n <input\n type=\"text\"\n value={formTitle}\n onChange={(e) => setFormTitle(e.target.value)}\n className=\"w-full px-3 py-2 border border-dc-border rounded-md bg-dc-surface text-dc-text focus:outline-none focus:ring-2 focus:ring-dc-primary focus:border-dc-primary\"\n placeholder=\"Enter portlet title...\"\n required\n />\n </div>\n\n {/* Chart Type */}\n <div>\n <label className=\"block text-sm font-semibold text-dc-text-secondary mb-3\">\n Chart Type\n </label>\n <ChartTypeSelector\n selectedType={chartType}\n onTypeChange={setChartType}\n />\n </div>\n\n\n {/* Query Editor - Hidden for skipQuery charts */}\n {!shouldSkipQuery && (\n <div className=\"flex-1 flex flex-col\">\n <div className=\"flex justify-between items-center mb-1\">\n <label className=\"block text-sm font-semibold text-dc-text-secondary\">\n Cube.js Query (JSON)\n </label>\n <div className=\"flex items-center space-x-2\">\n <button\n type=\"button\"\n onClick={handleOpenQueryBuilder}\n className=\"text-xs px-2 py-1 text-dc-accent bg-dc-surface hover:bg-dc-accent-bg rounded-sm border border-dc-accent hover:opacity-80 focus:outline-none focus:ring-2 focus:ring-dc-accent\"\n >\n Edit in Query Builder\n </button>\n </div>\n </div>\n <textarea\n value={query}\n onChange={(e) => handleQueryChange(e.target.value)}\n className=\"flex-1 w-full min-h-64 px-3 py-2 border border-dc-border rounded-md bg-dc-surface text-dc-text focus:outline-none focus:ring-2 focus:ring-dc-primary focus:border-dc-primary font-mono text-xs resize-y\"\n placeholder={`{\n \"measures\": [\"People.count\"],\n \"dimensions\": [\"People.active\"]\n}`}\n required\n />\n </div>\n )}\n </div>\n\n {/* Right side - Chart Configuration */}\n <div className=\"flex-1 flex flex-col\">\n <label className=\"block text-sm font-semibold text-dc-text-secondary mb-1\">\n {shouldSkipQuery ? 'Chart Configuration' : 'Chart Axis Configuration'}\n </label>\n\n {shouldSkipQuery ? (\n <div className=\"rounded-lg bg-dc-surface p-3 border border-dc-border\">\n <ChartConfigPanel\n chartType={chartType}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n availableFields={null}\n colorPalette={colorPalette}\n onChartConfigChange={setChartConfig}\n onDisplayConfigChange={setDisplayConfig}\n />\n </div>\n ) : (!dryRunData || !isQueryValidAndCurrent) ? (\n <div className=\"flex-1 flex items-center justify-center border-2 border-dashed border-dc-border rounded-lg bg-dc-surface-secondary\">\n <div className=\"text-center text-dc-text-muted\">\n <svg className=\"h-8 w-8 mx-auto mb-2\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" />\n </svg>\n <p className=\"text-sm\">Validate query first to configure chart axes</p>\n </div>\n </div>\n ) : (\n <div className=\"rounded-lg bg-dc-surface p-3 border border-dc-border\">\n <ChartConfigPanel\n chartType={chartType}\n chartConfig={chartConfig}\n displayConfig={displayConfig}\n availableFields={availableFields}\n colorPalette={colorPalette}\n onChartConfigChange={setChartConfig}\n onDisplayConfigChange={setDisplayConfig}\n />\n </div>\n )}\n </div>\n </div>\n\n {/* Validation section - Hidden for skipQuery charts */}\n {!shouldSkipQuery && (hasQueryChanged || (lastValidatedQuery === '' && query.trim() !== '') || (validationResult && query.trim() === lastValidatedQuery.trim() && validationResult.message !== 'Loaded query (assumed valid)')) && (\n <div className={`rounded-lg p-4 ${\n validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n ? 'bg-dc-success-bg'\n : validationResult && !validationResult.isValid\n ? 'bg-dc-error-bg'\n : hasQueryChanged\n ? 'bg-dc-warning-bg'\n : 'bg-dc-surface-secondary'\n }`}>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-3\">\n <div className={`w-2 h-2 rounded-full ${\n validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n ? 'bg-dc-success'\n : validationResult && !validationResult.isValid\n ? 'bg-dc-error'\n : hasQueryChanged\n ? 'bg-dc-warning'\n : 'bg-dc-muted'\n }`}></div>\n <div>\n <h3 className={`text-sm font-medium ${\n validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n ? 'text-dc-success'\n : validationResult && !validationResult.isValid\n ? 'text-dc-error'\n : hasQueryChanged\n ? 'text-dc-warning'\n : 'text-dc-text-secondary'\n }`}>\n {validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n ? 'Query validated successfully'\n : validationResult && !validationResult.isValid\n ? 'Query validation failed'\n : hasQueryChanged\n ? 'Query modified - validation required'\n : 'Query validation required'\n }\n </h3>\n {validationResult && (\n <p className={`text-xs mt-1 ${\n validationResult.isValid ? 'text-dc-success' : 'text-dc-error'\n }`}>\n {validationResult.message}\n </p>\n )}\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={handleValidateQuery}\n disabled={isValidating || !query.trim()}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors flex items-center space-x-1.5 ${\n validationResult?.isValid && query.trim() === lastValidatedQuery.trim()\n ? 'bg-dc-success text-white hover:opacity-80'\n : validationResult && !validationResult.isValid\n ? 'bg-dc-error text-white hover:opacity-80'\n : 'bg-dc-primary text-white hover:bg-dc-primary-hover'\n } disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-dc-primary`}\n >\n {isValidating ? (\n <>\n <svg className=\"animate-spin h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\"></circle>\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n <span>Validating</span>\n </>\n ) : validationResult?.isValid && query.trim() === lastValidatedQuery.trim() ? (\n <>\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>Validated</span>\n </>\n ) : (\n <>\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>Validate</span>\n </>\n )}\n </button>\n </div>\n </div>\n )}\n\n {/* Sample Queries - only show for create mode */}\n {!isEditMode && (\n <div>\n <label className=\"block text-sm text-dc-text-muted mb-2\">Sample Queries (click to use)</label>\n <div className=\"flex flex-wrap gap-2 mb-2\">\n {SAMPLE_QUERIES.map((sample, index) => (\n <button\n key={index}\n type=\"button\"\n onClick={() => handleSampleQuery(sample.query)}\n className=\"px-2 py-1 text-xs text-dc-text-secondary bg-dc-surface-secondary border border-dc-border rounded-sm cursor-pointer transition-all duration-200 ease-in-out hover:bg-dc-surface-hover hover:border-dc-border m-0.5\"\n >\n {sample.name}\n </button>\n ))}\n </div>\n </div>\n )}\n </form>\n )}\n </Modal>\n )\n}","import React, { useState, useEffect, useRef, useCallback } from 'react'\nimport Modal from './Modal'\nimport AnalysisBuilder from './AnalysisBuilder'\nimport type { AnalysisBuilderRef } from './AnalysisBuilder/types'\nimport type { PortletConfig, ColorPalette, CubeQuery, MultiQueryConfig } from '../types'\n\ninterface PortletAnalysisModalProps {\n isOpen: boolean\n onClose: () => void\n onSave: (portlet: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'>) => void\n portlet?: PortletConfig | null\n /** Initial data to display (avoids re-fetching when editing) */\n initialData?: any[]\n title: string\n submitText: string\n colorPalette?: ColorPalette\n}\n\n/**\n * PortletAnalysisModal - A modal wrapper around AnalysisBuilder for portlet editing\n *\n * This replaces PortletEditModal with the modern AnalysisBuilder interface.\n * Features:\n * - Two-panel layout with results and query builder\n * - Auto-execution of queries\n * - Smart chart defaults\n * - Title input in header\n * - Initial data support (no re-fetch when editing)\n */\nexport default function PortletAnalysisModal({\n isOpen,\n onClose,\n onSave,\n portlet,\n initialData,\n title: modalTitle,\n submitText,\n colorPalette\n}: PortletAnalysisModalProps) {\n\n // Ref to AnalysisBuilder for getting current query and chart config\n const builderRef = useRef<AnalysisBuilderRef>(null)\n\n // Title state\n const [formTitle, setFormTitle] = useState('')\n\n // Parse initial query from portlet\n // AnalysisBuilder handles both single CubeQuery and MultiQueryConfig internally\n const initialQuery = React.useMemo<CubeQuery | MultiQueryConfig | undefined>(() => {\n if (!portlet?.query) return undefined\n try {\n return JSON.parse(portlet.query)\n } catch {\n return undefined\n }\n }, [portlet?.query])\n\n // Initial chart config from portlet\n const initialChartConfig = React.useMemo(() => {\n if (!portlet) return undefined\n return {\n chartType: portlet.chartType,\n chartConfig: portlet.chartConfig,\n displayConfig: portlet.displayConfig\n }\n }, [portlet])\n\n // Reset form state when modal opens/closes or portlet changes\n useEffect(() => {\n if (isOpen) {\n setFormTitle(portlet?.title || '')\n }\n }, [isOpen, portlet])\n\n // Handle save\n const handleSave = useCallback(() => {\n if (!formTitle.trim()) {\n alert('Please enter a title for the portlet.')\n return\n }\n\n // Get query config and chart config from AnalysisBuilder\n // AnalysisBuilder returns either CubeQuery or MultiQueryConfig - we just stringify it\n const queryConfig = builderRef.current?.getQueryConfig()\n const chartConfig = builderRef.current?.getChartConfig()\n\n if (!queryConfig) {\n alert('Please configure a query before saving.')\n return\n }\n\n // Check if config has content - works for both single and multi-query\n // For multi-query, check the first query; for single query, check directly\n const firstQuery = 'queries' in queryConfig ? queryConfig.queries[0] : queryConfig\n const hasContent =\n (firstQuery?.measures && firstQuery.measures.length > 0) ||\n (firstQuery?.dimensions && firstQuery.dimensions.length > 0) ||\n (firstQuery?.timeDimensions && firstQuery.timeDimensions.length > 0)\n\n if (!hasContent) {\n alert('Please add at least one metric or breakdown to your query.')\n return\n }\n\n // Build portlet config - just stringify whatever AnalysisBuilder returned\n const portletData: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'> = {\n ...(portlet || {}),\n title: formTitle.trim(),\n query: JSON.stringify(queryConfig),\n chartType: chartConfig?.chartType || 'line',\n chartConfig: chartConfig?.chartConfig || {},\n displayConfig: chartConfig?.displayConfig || {},\n // Preserve existing position or use defaults for new portlets\n w: portlet?.w || 5,\n h: portlet?.h || 4\n } as PortletConfig\n\n onSave(portletData)\n onClose()\n }, [formTitle, portlet, onSave, onClose])\n\n // Handle cancel\n const handleCancel = useCallback(() => {\n onClose()\n }, [onClose])\n\n // Footer with save/cancel buttons\n const footer = (\n <>\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"px-4 py-2 text-sm font-medium text-dc-text-secondary hover:text-dc-text bg-dc-surface border border-dc-border rounded-md hover:bg-dc-surface-hover transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n className=\"px-4 py-2 text-sm font-medium text-white bg-dc-accent hover:bg-dc-accent-hover rounded-md transition-colors\"\n >\n {submitText}\n </button>\n </>\n )\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={modalTitle}\n size=\"fullscreen-mobile\"\n showCloseButton={true}\n closeOnBackdropClick={false}\n closeOnEscape={true}\n noPadding={true}\n footer={footer}\n >\n {/* Custom content with title input */}\n <div className=\"flex flex-col h-full\">\n {/* Title input section */}\n <div className=\"shrink-0 px-4 py-3 border-b border-dc-border bg-dc-surface-secondary\">\n <div className=\"flex items-center gap-3\">\n <label htmlFor=\"portlet-title\" className=\"text-sm font-medium text-dc-text-secondary shrink-0\">\n Title\n </label>\n <input\n id=\"portlet-title\"\n type=\"text\"\n value={formTitle}\n onChange={(e) => setFormTitle(e.target.value)}\n placeholder=\"Enter portlet title...\"\n autoComplete=\"off\"\n className=\"flex-1 px-3 py-1.5 text-sm bg-dc-surface border border-dc-border rounded-md text-dc-text placeholder-dc-text-muted focus:outline-none focus:ring-2 focus:ring-dc-accent focus:border-transparent\"\n autoFocus\n />\n </div>\n </div>\n\n {/* AnalysisBuilder content */}\n <div className=\"flex-1 min-h-0\">\n <AnalysisBuilder\n ref={builderRef}\n maxHeight=\"100%\"\n initialQuery={initialQuery}\n initialChartConfig={initialChartConfig}\n initialData={initialData}\n colorPalette={colorPalette}\n disableLocalStorage={true}\n className=\"h-full\"\n />\n </div>\n </div>\n </Modal>\n )\n}\n","/**\n * Portlet Filter Configuration Modal\n * Allows users to configure which dashboard filters apply to a specific portlet\n */\n\nimport { useState, useEffect } from 'react'\nimport type { DashboardFilter } from '../types'\n\ninterface PortletFilterConfigModalProps {\n isOpen: boolean\n onClose: () => void\n dashboardFilters: DashboardFilter[]\n currentMapping: string[]\n onSave: (mapping: string[]) => void\n portletTitle: string\n}\n\nexport default function PortletFilterConfigModal({\n isOpen,\n onClose,\n dashboardFilters = [],\n currentMapping = [],\n onSave,\n portletTitle\n}: PortletFilterConfigModalProps) {\n const [selectedFilters, setSelectedFilters] = useState<string[]>(currentMapping)\n\n // Update local state when props change\n useEffect(() => {\n setSelectedFilters(currentMapping)\n }, [currentMapping, isOpen])\n\n const handleToggleFilter = (filterId: string) => {\n setSelectedFilters(prev => {\n if (prev.includes(filterId)) {\n return prev.filter(id => id !== filterId)\n } else {\n return [...prev, filterId]\n }\n })\n }\n\n const handleSave = () => {\n onSave(selectedFilters)\n onClose()\n }\n\n const handleCancel = () => {\n setSelectedFilters(currentMapping) // Reset to original\n onClose()\n }\n\n // Format filter preview text\n const formatFilterPreview = (filter: DashboardFilter): string => {\n if (!filter.filter) return ''\n\n // Handle simple filters\n if ('member' in filter.filter && filter.filter.member) {\n const values = filter.filter.values || []\n const valuesText = values.length > 0 ? values.join(', ') : 'no value'\n return `${filter.filter.member} ${filter.filter.operator} ${valuesText}`\n }\n\n // Handle group filters (AND/OR)\n if ('type' in filter.filter && filter.filter.type) {\n const filterCount = filter.filter.filters?.length || 0\n return `${filter.filter.type.toUpperCase()} group with ${filterCount} filter${filterCount !== 1 ? 's' : ''}`\n }\n\n return 'Complex filter'\n }\n\n if (!isOpen) return null\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50\" onClick={handleCancel}>\n <div\n className=\"bg-dc-surface border border-dc-border rounded-lg max-w-2xl w-full mx-4 max-h-[80vh] flex flex-col\"\n style={{ boxShadow: 'var(--dc-shadow-lg)' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"px-6 py-4 border-b border-dc-border bg-dc-surface-secondary rounded-t-lg\">\n <h2 className=\"text-lg font-semibold text-dc-text\">Configure Dashboard Filters</h2>\n <p className=\"text-sm text-dc-text-secondary mt-1\">\n Choose which dashboard filters apply to \"{portletTitle}\"\n </p>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {dashboardFilters.length === 0 ? (\n <div className=\"text-center py-8 text-dc-text-muted\">\n <svg\n className=\"mx-auto h-12 w-12 mb-3\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\"\n />\n </svg>\n <p className=\"text-sm font-medium\">No dashboard filters available</p>\n <p className=\"text-xs mt-1\">Add filters at the dashboard level first</p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between mb-4 pb-2 border-b border-dc-border\">\n <span className=\"text-sm font-medium text-dc-text\">Available Filters</span>\n <span className=\"text-xs text-dc-text-secondary\">\n {selectedFilters.length} of {dashboardFilters.length} selected\n </span>\n </div>\n\n {dashboardFilters.map(filter => {\n const isSelected = selectedFilters.includes(filter.id)\n\n return (\n <label\n key={filter.id}\n className={`flex items-start p-3 rounded-md border cursor-pointer transition-colors ${\n isSelected\n ? 'border-dc-primary bg-dc-surface-secondary'\n : 'border-dc-border hover:bg-dc-surface-hover'\n }`}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n onChange={() => handleToggleFilter(filter.id)}\n className=\"mt-0.5 mr-3 h-4 w-4 rounded border-dc-border focus:ring-2 focus:ring-dc-primary\"\n style={{\n accentColor: 'var(--dc-primary)'\n }}\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-sm text-dc-text truncate\">\n {filter.label}\n </span>\n {isSelected && (\n <span\n className=\"px-2 py-0.5 text-xs rounded-full\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n Applied\n </span>\n )}\n </div>\n <div className=\"mt-1 text-xs text-dc-text-secondary break-words\">\n {formatFilterPreview(filter)}\n </div>\n </div>\n </label>\n )\n })}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"px-6 py-4 border-t border-dc-border bg-dc-surface-secondary rounded-b-lg flex justify-end gap-3\">\n <button\n onClick={handleCancel}\n className=\"px-4 py-2 text-sm font-medium rounded-md border border-dc-border bg-dc-surface hover:bg-dc-surface-hover transition-colors text-dc-text\"\n >\n Cancel\n </button>\n <button\n onClick={handleSave}\n className=\"px-4 py-2 text-sm font-medium rounded-md text-white transition-colors\"\n style={{\n backgroundColor: 'var(--dc-primary)'\n }}\n >\n Apply Filters\n </button>\n </div>\n </div>\n </div>\n )\n}\n","/**\n * FilterValueSelector Component\n * \n * Smart input component that adapts to operator type:\n * - Combo box for equals/notEquals with API-fetched values\n * - Number input for numeric operators\n * - Date picker for date operators\n * - No input for set/notSet operators\n */\n\nimport React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'\nimport { getIcon } from '../../icons'\nimport { useFilterValues } from '../../hooks/useFilterValues'\nimport { useDebounce } from '../../hooks/useDebounce'\nimport type { FilterValueSelectorProps } from '../QueryBuilder/types'\nimport { FILTER_OPERATORS } from '../QueryBuilder/types'\n\nconst ChevronDownIcon = getIcon('chevronDown')\nconst CloseIcon = getIcon('close')\n\nconst FilterValueSelector: React.FC<FilterValueSelectorProps> = ({\n fieldName,\n operator,\n values,\n onValuesChange,\n schema\n}) => {\n const operatorMeta = FILTER_OPERATORS[operator]\n const [isOpen, setIsOpen] = useState(false)\n const [searchText, setSearchText] = useState('')\n const [hasLoadedInitial, setHasLoadedInitial] = useState(false)\n const dropdownRef = useRef<HTMLDivElement>(null)\n const lastSearchedTerm = useRef<string>('')\n \n // Debounce the search text\n const debouncedSearchText = useDebounce(searchText, 300)\n \n // Check if the field is a dimension (not a measure)\n const isDimension = useMemo(() => schema ? schema.cubes.some(cube => \n cube.dimensions.some(dim => dim.name === fieldName)\n ) : false, [schema, fieldName])\n \n // Check if the field is a time dimension\n const isTimeDimension = useMemo(() => schema ? schema.cubes.some(cube => \n cube.dimensions.some(dim => dim.name === fieldName && dim.type === 'time')\n ) : false, [schema, fieldName])\n \n // Fetch distinct values for combo box (only for equals/notEquals/in/notIn on non-time dimensions)\n const shouldFetchValues = useMemo(() => \n (['equals', 'notEquals', 'in', 'notIn'].includes(operator)) && isDimension && !isTimeDimension,\n [operator, isDimension, isTimeDimension]\n )\n const shouldShowComboBox = shouldFetchValues\n \n const { \n values: distinctValues, \n loading: valuesLoading, \n error: valuesError,\n searchValues\n } = useFilterValues(fieldName, shouldFetchValues)\n \n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false)\n }\n }\n \n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n \n // Load initial values when dropdown opens\n useEffect(() => {\n if (isOpen && shouldFetchValues && searchValues) {\n searchValues('', true) // Force load with empty search\n setHasLoadedInitial(true)\n lastSearchedTerm.current = ''\n }\n }, [isOpen, shouldFetchValues, searchValues])\n \n // Trigger search when debounced search text changes\n useEffect(() => {\n if (hasLoadedInitial && shouldFetchValues && searchValues && debouncedSearchText !== lastSearchedTerm.current) {\n lastSearchedTerm.current = debouncedSearchText\n searchValues(debouncedSearchText)\n }\n }, [debouncedSearchText, hasLoadedInitial, shouldFetchValues, searchValues])\n \n // Handle dropdown toggle\n const handleDropdownToggle = useCallback(() => {\n const newIsOpen = !isOpen\n setIsOpen(newIsOpen)\n \n // Reset search when closing dropdown\n if (!newIsOpen) {\n setSearchText('')\n lastSearchedTerm.current = ''\n }\n }, [isOpen])\n \n // Handle search input change\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const newSearchText = e.target.value\n setSearchText(newSearchText)\n }, [])\n \n // Handle value selection for combo box\n const handleValueSelect = useCallback((value: any) => {\n if (operatorMeta.supportsMultipleValues) {\n // Add to selection if not already selected\n if (!values.includes(value)) {\n onValuesChange([...values, value])\n }\n } else {\n // Replace current value\n onValuesChange([value])\n setIsOpen(false)\n }\n // Clear search after selection\n setSearchText('')\n }, [operatorMeta.supportsMultipleValues, values, onValuesChange])\n \n // Handle value removal for multi-select\n const handleValueRemove = useCallback((valueToRemove: any) => {\n onValuesChange(values.filter(v => v !== valueToRemove))\n }, [values, onValuesChange])\n \n // Handle direct text input for non-combo operators\n const handleDirectInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n if (operatorMeta.valueType === 'number') {\n const numValue = parseFloat(value)\n // Accept valid numbers including zero\n if (!isNaN(numValue)) {\n onValuesChange([numValue])\n } else if (value === '' || value === '-') {\n // Allow empty string or just a minus sign for negative numbers being typed\n onValuesChange([])\n }\n } else {\n onValuesChange(value ? [value] : [])\n }\n }, [operatorMeta.valueType, onValuesChange])\n \n // Handle date input\n const handleDateInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n if (operator === 'inDateRange') {\n // For date range, we need two values\n const currentValues = values.length >= 2 ? values : ['', '']\n onValuesChange([value, currentValues[1]])\n } else {\n // Single date value\n onValuesChange(value ? [value] : [])\n }\n }, [operator, values, onValuesChange])\n \n const handleDateRangeEndInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n const currentValues = values.length >= 2 ? values : ['', '']\n onValuesChange([currentValues[0], value])\n }, [values, onValuesChange])\n\n // Handle between/notBetween range inputs (must be defined at top level, not inside conditionals)\n const handleBetweenStartInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = parseFloat(e.target.value)\n const currentValues = values.length >= 2 ? values : ['', '']\n const newValues = [!isNaN(value) ? value : e.target.value === '' ? '' : currentValues[0], currentValues[1]]\n onValuesChange(newValues.filter(v => v !== ''))\n }, [values, onValuesChange])\n\n const handleBetweenEndInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = parseFloat(e.target.value)\n const currentValues = values.length >= 2 ? values : ['', '']\n const newValues = [currentValues[0], !isNaN(value) ? value : e.target.value === '' ? '' : currentValues[1]]\n onValuesChange(newValues.filter(v => v !== ''))\n }, [values, onValuesChange])\n\n // Render based on operator type\n if (!operatorMeta.requiresValues) {\n // No input needed for set/notSet\n return (\n <div className=\"text-sm text-dc-text-muted italic\">\n No value required\n </div>\n )\n }\n \n if (operator === 'inDateRange') {\n // Date range picker\n return (\n <div className=\"flex items-center space-x-2\">\n <input\n type=\"date\"\n value={values[0] || ''}\n onChange={handleDateInput}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n <span className=\"text-sm text-dc-text-muted\">to</span>\n <input\n type=\"date\"\n value={values[1] || ''}\n onChange={handleDateRangeEndInput}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n )\n }\n \n if (operator === 'between' || operator === 'notBetween') {\n // Between range picker (for numbers)\n return (\n <div className=\"flex items-center space-x-2\">\n <input\n type=\"number\"\n value={values[0] !== undefined && values[0] !== null ? values[0] : ''}\n onChange={handleBetweenStartInput}\n placeholder=\"Min\"\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n <span className=\"text-sm text-dc-text-muted\">to</span>\n <input\n type=\"number\"\n value={values[1] !== undefined && values[1] !== null ? values[1] : ''}\n onChange={handleBetweenEndInput}\n placeholder=\"Max\"\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n )\n }\n \n if (operatorMeta.valueType === 'date') {\n // Single date picker\n return (\n <input\n type=\"date\"\n value={values[0] || ''}\n onChange={handleDateInput}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n )\n }\n \n if (operatorMeta.valueType === 'number') {\n // Number input\n return (\n <input\n type=\"number\"\n value={values[0] !== undefined && values[0] !== null ? values[0] : ''}\n onChange={handleDirectInput}\n placeholder=\"Enter number\"\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n )\n }\n \n // Time dimension with equals/notEquals/in/notIn - use date picker\n if (isTimeDimension && (['equals', 'notEquals', 'in', 'notIn'].includes(operator))) {\n if (operatorMeta.supportsMultipleValues) {\n // Multi-select date picker (for notEquals that supports multiple values)\n return (\n <div className=\"space-y-2 min-w-0 max-w-full\">\n {/* Selected dates display */}\n {values.length > 0 && (\n <div className=\"flex flex-wrap gap-1 max-w-full\">\n {values.map((value, index) => (\n <div\n key={index}\n className=\"inline-flex items-center bg-dc-time-dimension text-dc-time-dimension text-xs px-2 py-1 rounded-sm border border-dc-time-dimension\"\n >\n <span className=\"mr-1\">{String(value)}</span>\n <button\n onClick={() => handleValueRemove(value)}\n className=\"text-dc-accent hover:text-dc-accent focus:outline-hidden\"\n >\n <CloseIcon className=\"w-3 h-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n \n {/* Add new date */}\n <input\n type=\"date\"\n onChange={(e) => {\n if (e.target.value && !values.includes(e.target.value)) {\n onValuesChange([...values, e.target.value])\n e.target.value = '' // Clear the input\n }\n }}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n placeholder=\"Add date...\"\n />\n </div>\n )\n } else {\n // Single date picker\n return (\n <input\n type=\"date\"\n value={values[0] || ''}\n onChange={handleDateInput}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n )\n }\n }\n \n if (shouldShowComboBox) {\n // Combo box with API-fetched values\n return (\n <div className=\"relative min-w-0 max-w-full\" ref={dropdownRef}>\n {/* Selected values display (for multi-select) */}\n {operatorMeta.supportsMultipleValues && values.length > 0 && (\n <div className=\"flex flex-wrap gap-1 mb-2 max-w-full\">\n {values.map((value, index) => (\n <div\n key={index}\n className=\"inline-flex items-center bg-dc-time-dimension text-dc-time-dimension text-xs px-2 py-1 rounded-sm border border-dc-time-dimension\"\n >\n <span className=\"mr-1\">{String(value)}</span>\n <button\n onClick={() => handleValueRemove(value)}\n className=\"text-dc-accent hover:text-dc-accent focus:outline-hidden\"\n >\n <CloseIcon className=\"w-3 h-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n \n {/* Single value display (for single-select) */}\n {!operatorMeta.supportsMultipleValues && values.length > 0 && (\n <div className=\"mb-2\">\n <div className=\"inline-flex items-center bg-dc-time-dimension text-dc-time-dimension text-xs px-2 py-1 rounded-sm border border-dc-time-dimension\">\n <span className=\"mr-1\">{String(values[0])}</span>\n <button\n onClick={() => onValuesChange([])}\n className=\"text-dc-accent hover:text-dc-accent focus:outline-hidden\"\n >\n <CloseIcon className=\"w-3 h-3\" />\n </button>\n </div>\n </div>\n )}\n \n {/* Dropdown trigger */}\n <button\n onClick={handleDropdownToggle}\n className=\"w-full text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent flex items-center justify-between min-w-0\"\n >\n <span className=\"text-dc-text-muted truncate\">\n {valuesLoading && !hasLoadedInitial ? 'Loading values...' : 'Select value...'}\n </span>\n <ChevronDownIcon className=\"w-4 h-4 text-dc-text-muted\" />\n </button>\n\n {/* Dropdown menu */}\n {isOpen && (\n <div className=\"absolute z-30 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-60 overflow-y-auto\">\n {/* Search input */}\n <div className=\"p-2 border-b border-dc-border\">\n <input\n type=\"text\"\n value={searchText}\n onChange={handleSearchChange}\n placeholder=\"Search values...\"\n className=\"w-full text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n autoFocus\n />\n </div>\n\n {/* Values list */}\n <div className=\"max-h-48 overflow-y-auto\">\n {valuesLoading ? (\n <div className=\"p-2 text-sm text-dc-text-muted\">\n {searchText ? 'Searching...' : 'Loading values...'}\n </div>\n ) : valuesError ? (\n <div className=\"p-2 text-sm text-dc-error\">\n Error loading values: {valuesError}\n </div>\n ) : distinctValues.length === 0 ? (\n <div className=\"p-2 text-sm text-dc-text-muted\">\n {searchText ? 'No matching values' : 'No values available'}\n </div>\n ) : (\n distinctValues.map((value, index) => {\n const isSelected = values.includes(value)\n\n return (\n <button\n key={`${value}-${index}`}\n onClick={() => handleValueSelect(value)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover ${\n isSelected ? 'bg-dc-accent-bg text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n {String(value)}\n {isSelected && (\n <span className=\"float-right text-dc-accent\">✓</span>\n )}\n </button>\n )\n })\n )}\n </div>\n </div>\n )}\n </div>\n )\n }\n \n // Fallback to text input\n return (\n <input\n type=\"text\"\n value={values[0] !== undefined && values[0] !== null ? values[0] : ''}\n onChange={handleDirectInput}\n placeholder={`Enter ${operatorMeta.valueType} value`}\n className=\"text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n )\n}\n\nexport default FilterValueSelector","/**\n * Utility functions for QueryBuilder components\n */\n\nimport type { CubeQuery, Filter, SimpleFilter, GroupFilter } from '../../types'\nimport type { MetaField, MetaResponse } from '../QueryBuilder/types'\nimport { FILTER_OPERATORS } from '../QueryBuilder/types'\n\n/**\n * Check if a field is selected in the current query\n */\nexport function isFieldSelected(\n fieldName: string, \n fieldType: 'measures' | 'dimensions' | 'timeDimensions',\n query: CubeQuery\n): boolean {\n switch (fieldType) {\n case 'measures':\n return query.measures?.includes(fieldName) || false\n case 'dimensions':\n return query.dimensions?.includes(fieldName) || false\n case 'timeDimensions':\n return query.timeDimensions?.some(td => td.dimension === fieldName) || false\n default:\n return false\n }\n}\n\n/**\n * Get all time dimension fields from schema\n */\nexport function getTimeDimensionFields(schema: MetaResponse): MetaField[] {\n const timeDimensions: MetaField[] = []\n \n schema.cubes.forEach(cube => {\n cube.dimensions.forEach(dimension => {\n if (dimension.type === 'time') {\n timeDimensions.push(dimension)\n }\n })\n })\n \n return timeDimensions\n}\n\n/**\n * Get all non-time dimension fields from schema\n */\nexport function getRegularDimensionFields(schema: MetaResponse): MetaField[] {\n const dimensions: MetaField[] = []\n \n schema.cubes.forEach(cube => {\n cube.dimensions.forEach(dimension => {\n if (dimension.type !== 'time') {\n dimensions.push(dimension)\n }\n })\n })\n \n return dimensions\n}\n\n/**\n * Get all measure fields from schema\n */\nexport function getMeasureFields(schema: MetaResponse): MetaField[] {\n const measures: MetaField[] = []\n \n schema.cubes.forEach(cube => {\n cube.measures.forEach(measure => {\n measures.push(measure)\n })\n })\n \n return measures\n}\n\n/**\n * Check if query has any content (measures, dimensions, or timeDimensions)\n */\nexport function hasQueryContent(query: CubeQuery): boolean {\n return Boolean(\n (query.measures && query.measures.length > 0) ||\n (query.dimensions && query.dimensions.length > 0) ||\n (query.timeDimensions && query.timeDimensions.length > 0)\n )\n}\n\n/**\n * Get count of selected fields across all types\n */\nexport function getSelectedFieldsCount(query: CubeQuery): number {\n let count = 0\n if (query.measures) count += query.measures.length\n if (query.dimensions) count += query.dimensions.length\n if (query.timeDimensions) count += query.timeDimensions.length\n return count\n}\n\n/**\n * Get cube name from field name (e.g., \"Employees.count\" -> \"Employees\")\n */\nexport function getCubeNameFromField(fieldName: string): string {\n return fieldName.split('.')[0]\n}\n\n/**\n * Group fields by cube name\n */\nexport function groupFieldsByCube(fields: MetaField[]): Record<string, MetaField[]> {\n return fields.reduce((groups, field) => {\n const cubeName = getCubeNameFromField(field.name)\n if (!groups[cubeName]) {\n groups[cubeName] = []\n }\n groups[cubeName].push(field)\n return groups\n }, {} as Record<string, MetaField[]>)\n}\n\n/**\n * Clean query object by removing empty arrays\n */\nexport function cleanQuery(query: CubeQuery): CubeQuery {\n const cleanedQuery: CubeQuery = {}\n \n if (query.measures && query.measures.length > 0) {\n cleanedQuery.measures = query.measures\n }\n \n if (query.dimensions && query.dimensions.length > 0) {\n cleanedQuery.dimensions = query.dimensions\n }\n \n if (query.timeDimensions && query.timeDimensions.length > 0) {\n cleanedQuery.timeDimensions = query.timeDimensions\n }\n \n if (query.filters && query.filters.length > 0) {\n cleanedQuery.filters = query.filters\n }\n \n if (query.order) {\n cleanedQuery.order = query.order\n }\n \n if (query.limit) {\n cleanedQuery.limit = query.limit\n }\n \n if (query.offset) {\n cleanedQuery.offset = query.offset\n }\n \n if (query.segments && query.segments.length > 0) {\n cleanedQuery.segments = query.segments\n }\n \n return cleanedQuery\n}\n\n/**\n * Clean a query and transform filters for server compatibility\n * This version transforms GroupFilter to legacy and/or format\n */\nexport function cleanQueryForServer(query: CubeQuery): CubeQuery {\n const cleanedQuery = cleanQuery(query)\n \n // Apply server transformation to filters\n if (cleanedQuery.filters && cleanedQuery.filters.length > 0) {\n cleanedQuery.filters = transformFiltersForServer(cleanedQuery.filters) as any\n }\n \n return cleanedQuery\n}\n\n/**\n * Create an empty query object\n */\nexport function createEmptyQuery(): CubeQuery {\n return {}\n}\n\n/**\n * Filter utility functions\n */\n\n/**\n * Check if a filter is a simple filter\n */\nexport function isSimpleFilter(filter: Filter): filter is SimpleFilter {\n return 'member' in filter && 'operator' in filter && 'values' in filter\n}\n\n/**\n * Check if a filter is a group filter\n */\nexport function isGroupFilter(filter: Filter): filter is GroupFilter {\n return 'type' in filter && 'filters' in filter\n}\n\n/**\n * Check if a filter is an AND filter\n */\nexport function isAndFilter(filter: Filter): filter is GroupFilter {\n return isGroupFilter(filter) && filter.type === 'and'\n}\n\n/**\n * Check if a filter is an OR filter\n */\nexport function isOrFilter(filter: Filter): filter is GroupFilter {\n return isGroupFilter(filter) && filter.type === 'or'\n}\n\n/**\n * Flatten all simple filters from a hierarchical filter structure\n */\nexport function flattenFilters(filters: Filter[]): SimpleFilter[] {\n const simple: SimpleFilter[] = []\n \n const flatten = (filter: Filter) => {\n if (isSimpleFilter(filter)) {\n simple.push(filter)\n } else if (isGroupFilter(filter)) {\n filter.filters.forEach(flatten)\n }\n }\n \n filters.forEach(flatten)\n return simple\n}\n\n/**\n * Get all filterable fields from schema (measures, dimensions, and time dimensions)\n * Returns ALL fields if no query provided, or only query fields if query provided\n */\nexport function getFilterableFields(schema: MetaResponse, query?: CubeQuery): MetaField[] {\n const allFields: MetaField[] = []\n \n schema.cubes.forEach(cube => {\n allFields.push(...cube.measures)\n allFields.push(...cube.dimensions)\n })\n \n // If no query provided, return all fields\n if (!query) {\n return allFields.sort((a, b) => a.name.localeCompare(b.name))\n }\n \n // Get currently selected fields from the query\n const selectedFields = new Set<string>()\n \n // Add measures\n if (query.measures) {\n query.measures.forEach(measure => selectedFields.add(measure))\n }\n \n // Add dimensions\n if (query.dimensions) {\n query.dimensions.forEach(dimension => selectedFields.add(dimension))\n }\n \n // Add time dimensions\n if (query.timeDimensions) {\n query.timeDimensions.forEach(td => selectedFields.add(td.dimension))\n }\n \n // Filter to only include selected fields\n const filterableFields = allFields.filter(field => selectedFields.has(field.name))\n \n return filterableFields.sort((a, b) => a.name.localeCompare(b.name))\n}\n\n/**\n * Get ALL filterable fields from schema, regardless of query selection\n */\nexport function getAllFilterableFields(schema: MetaResponse): MetaField[] {\n const allFields: MetaField[] = []\n \n schema.cubes.forEach(cube => {\n allFields.push(...cube.measures)\n allFields.push(...cube.dimensions)\n })\n \n return allFields.sort((a, b) => a.name.localeCompare(b.name))\n}\n\n/**\n * Get organized filter field options with query fields prioritized at top\n */\nexport function getOrganizedFilterFields(schema: MetaResponse, query?: CubeQuery): {\n queryFields: MetaField[]\n allFields: MetaField[]\n} {\n const allFields = getAllFilterableFields(schema)\n \n if (!query) {\n return {\n queryFields: [],\n allFields\n }\n }\n \n // Get currently selected fields from the query\n const selectedFields = new Set<string>()\n \n // Add measures\n if (query.measures) {\n query.measures.forEach(measure => selectedFields.add(measure))\n }\n \n // Add dimensions\n if (query.dimensions) {\n query.dimensions.forEach(dimension => selectedFields.add(dimension))\n }\n \n // Add time dimensions\n if (query.timeDimensions) {\n query.timeDimensions.forEach(td => selectedFields.add(td.dimension))\n }\n \n // Split fields into query fields and other fields\n const queryFields = allFields.filter(field => selectedFields.has(field.name))\n \n return {\n queryFields,\n allFields\n }\n}\n\n/**\n * Get available operators for a field type\n */\nexport function getAvailableOperators(fieldType: string): Array<{operator: string, label: string}> {\n const operators: Array<{operator: string, label: string}> = []\n \n for (const [operator, meta] of Object.entries(FILTER_OPERATORS)) {\n if (meta.fieldTypes.includes(fieldType)) {\n operators.push({\n operator,\n label: meta.label\n })\n }\n }\n \n return operators\n}\n\n/**\n * Get field type from schema\n */\nexport function getFieldType(fieldName: string, schema: MetaResponse): string {\n for (const cube of schema.cubes) {\n // Check measures\n const measure = cube.measures.find(m => m.name === fieldName)\n if (measure) return measure.type\n \n // Check dimensions\n const dimension = cube.dimensions.find(d => d.name === fieldName)\n if (dimension) return dimension.type\n }\n \n return 'string' // Default fallback\n}\n\n/**\n * Validate a filter\n */\nexport function validateFilter(filter: SimpleFilter, schema: MetaResponse): {\n isValid: boolean\n errors: string[]\n} {\n const errors: string[] = []\n \n // Check if field exists\n const fields = getFilterableFields(schema)\n const fieldExists = fields.some(f => f.name === filter.member)\n \n if (!fieldExists) {\n errors.push(`Field \"${filter.member}\" does not exist`)\n }\n \n // Check if operator is valid for field type\n if (fieldExists) {\n const fieldType = getFieldType(filter.member, schema)\n const operatorMeta = FILTER_OPERATORS[filter.operator]\n \n if (!operatorMeta) {\n errors.push(`Invalid operator \"${filter.operator}\"`)\n } else if (!operatorMeta.fieldTypes.includes(fieldType)) {\n errors.push(`Operator \"${filter.operator}\" is not valid for field type \"${fieldType}\"`)\n } else {\n // Check values\n if (operatorMeta.requiresValues && (!filter.values || filter.values.length === 0)) {\n errors.push(`Operator \"${filter.operator}\" requires values`)\n }\n \n if (!operatorMeta.supportsMultipleValues && filter.values && filter.values.length > 1) {\n errors.push(`Operator \"${filter.operator}\" does not support multiple values`)\n }\n }\n }\n \n return {\n isValid: errors.length === 0,\n errors\n }\n}\n\n/**\n * Count total filters in hierarchical structure\n */\nexport function countFilters(filters: Filter[]): number {\n let count = 0\n \n const countFilter = (filter: Filter) => {\n if (isSimpleFilter(filter)) {\n count++\n } else if (isGroupFilter(filter)) {\n filter.filters.forEach(countFilter)\n }\n }\n \n filters.forEach(countFilter)\n return count\n}\n\n/**\n * Create a new simple filter\n */\nexport function createSimpleFilter(member: string, operator: string = 'equals', values: any[] = []): SimpleFilter {\n return {\n member,\n operator: operator as any,\n values\n }\n}\n\n/**\n * Create a new AND filter group\n */\nexport function createAndFilter(filters: Filter[] = []): GroupFilter {\n return {\n type: 'and',\n filters\n }\n}\n\n/**\n * Create a new OR filter group\n */\nexport function createOrFilter(filters: Filter[] = []): GroupFilter {\n return {\n type: 'or',\n filters\n }\n}\n\n/**\n * Clean up filters by removing any that reference fields not in the current query\n * @deprecated This function is no longer used as we now support filtering on any schema field\n */\nexport function cleanupFilters(filters: Filter[], _query?: CubeQuery): Filter[] {\n // Return filters unchanged - we now support filtering on any field\n return filters || []\n}\n\n/**\n * Clean up filters by removing any that reference fields not in the current query (legacy)\n * Only used for backward compatibility - filters on non-query fields are now supported\n */\nexport function cleanupFiltersLegacy(filters: Filter[], query: CubeQuery): Filter[] {\n if (!filters || filters.length === 0) {\n return []\n }\n \n // Get currently selected fields from the query\n const selectedFields = new Set<string>()\n \n // Add measures\n if (query.measures) {\n query.measures.forEach(measure => selectedFields.add(measure))\n }\n \n // Add dimensions\n if (query.dimensions) {\n query.dimensions.forEach(dimension => selectedFields.add(dimension))\n }\n \n // Add time dimensions\n if (query.timeDimensions) {\n query.timeDimensions.forEach(td => selectedFields.add(td.dimension))\n }\n \n // Recursively clean filters\n const cleanFilter = (filter: Filter): Filter | null => {\n if (isSimpleFilter(filter)) {\n // Remove filter if its field is not selected\n return selectedFields.has(filter.member) ? filter : null\n } else if (isGroupFilter(filter)) {\n // Clean group recursively\n const cleanedFilters = filter.filters.map(cleanFilter).filter(f => f !== null) as Filter[]\n return cleanedFilters.length > 0 ? { type: filter.type, filters: cleanedFilters } : null\n }\n return null\n }\n \n // Clean all filters and remove nulls\n const cleanedFilters = filters.map(cleanFilter).filter(f => f !== null) as Filter[]\n \n return cleanedFilters\n}\n\n/**\n * Transform filters from new GroupFilter format to legacy server format\n * Server expects { and: [...] } and { or: [...] } instead of { type: 'and', filters: [...] }\n */\nexport function transformFiltersForServer(filters: Filter[]): any[] {\n const transformFilter = (filter: Filter): any => {\n if (isSimpleFilter(filter)) {\n return filter\n } else if (isGroupFilter(filter)) {\n const transformedSubFilters = filter.filters.map(transformFilter)\n \n if (filter.type === 'and') {\n return { and: transformedSubFilters }\n } else {\n return { or: transformedSubFilters }\n }\n }\n return filter\n }\n \n return filters.map(transformFilter)\n}\n\n/**\n * Date range utility functions\n */\n\n/**\n * Convert DateRangeType to Cube.js compatible date range format\n */\nexport function convertDateRangeTypeToValue(rangeType: string, number?: number): string {\n const typeMap: Record<string, string> = {\n 'today': 'today',\n 'yesterday': 'yesterday',\n 'this_week': 'this week',\n 'this_month': 'this month',\n 'this_quarter': 'this quarter',\n 'this_year': 'this year',\n 'last_7_days': 'last 7 days',\n 'last_30_days': 'last 30 days',\n 'last_week': 'last week',\n 'last_month': 'last month',\n 'last_quarter': 'last quarter',\n 'last_year': 'last year',\n 'last_12_months': 'last 12 months'\n }\n \n // Handle dynamic ranges with number input\n if (rangeType.startsWith('last_n_') && number !== undefined && number > 0) {\n const unit = rangeType.replace('last_n_', '')\n const unitSingular = unit.slice(0, -1) // Remove 's' for singular form\n return number === 1 ? `last ${unitSingular}` : `last ${number} ${unit}`\n }\n \n return typeMap[rangeType] || rangeType\n}\n\n/**\n * Check if a date range type requires a number input\n */\nexport function requiresNumberInput(rangeType: string): boolean {\n return rangeType.startsWith('last_n_')\n}\n\n/**\n * Format date for Cube.js (YYYY-MM-DD)\n */\nexport function formatDateForCube(date: Date): string {\n return date.toISOString().split('T')[0]\n}\n\n/**\n * Get the time dimensions that have date ranges applied\n */\nexport function getTimeDimensionsWithDateRanges(query: CubeQuery): Record<string, string | string[]> {\n const dateRanges: Record<string, string | string[]> = {}\n \n if (query.timeDimensions) {\n query.timeDimensions.forEach(td => {\n if (td.dateRange) {\n dateRanges[td.dimension] = td.dateRange\n }\n })\n }\n \n return dateRanges\n}\n\n/**\n * Check if a query has any time dimensions\n */\nexport function hasTimeDimensions(query: CubeQuery): boolean {\n return Boolean(query.timeDimensions && query.timeDimensions.length > 0)\n}\n\n/**\n * Transform a Cube.js query from external format to UI internal format\n * This handles format differences between server/API queries and QueryBuilder state\n */\nexport function transformQueryForUI(query: any): CubeQuery {\n if (!query || typeof query !== 'object') {\n return {}\n }\n \n const transformed: CubeQuery = {}\n \n // Copy simple fields if they exist\n if (query.measures) transformed.measures = Array.isArray(query.measures) ? query.measures : []\n if (query.dimensions) transformed.dimensions = Array.isArray(query.dimensions) ? query.dimensions : []\n if (query.timeDimensions) transformed.timeDimensions = Array.isArray(query.timeDimensions) ? query.timeDimensions : []\n if (query.order) transformed.order = query.order\n if (query.limit) transformed.limit = query.limit\n if (query.offset) transformed.offset = query.offset\n if (query.segments) transformed.segments = Array.isArray(query.segments) ? query.segments : []\n \n // Transform filters from server format to UI format\n if (query.filters && Array.isArray(query.filters)) {\n transformed.filters = transformFiltersFromServer(query.filters)\n }\n \n return cleanQuery(transformed)\n}\n\n/**\n * Transform filters from server/API format to UI format\n * Converts {and: [...]} and {or: [...]} to {type: 'and', filters: [...]} format\n */\nfunction transformFiltersFromServer(filters: any[]): Filter[] {\n return filters.map(filter => {\n if (!filter || typeof filter !== 'object') {\n return filter\n }\n \n // Handle legacy {and: [...]} format\n if ('and' in filter && Array.isArray(filter.and)) {\n return {\n type: 'and',\n filters: transformFiltersFromServer(filter.and)\n } as GroupFilter\n }\n \n // Handle legacy {or: [...]} format\n if ('or' in filter && Array.isArray(filter.or)) {\n return {\n type: 'or',\n filters: transformFiltersFromServer(filter.or)\n } as GroupFilter\n }\n \n // Handle new format {type: 'and', filters: [...]} - process recursively\n if ('type' in filter && 'filters' in filter && Array.isArray(filter.filters)) {\n return {\n type: filter.type,\n filters: transformFiltersFromServer(filter.filters)\n } as GroupFilter\n }\n \n // Simple filter - pass through\n return filter as SimpleFilter\n }).filter(Boolean) // Remove any null/undefined values\n}\n\n/**\n * Sorting utility functions\n */\n\n/**\n * Get field title from schema metadata, falling back to field name\n */\nexport function getFieldTitle(fieldName: string, schema: MetaResponse | null): string {\n if (!schema) return fieldName\n \n for (const cube of schema.cubes) {\n // Check measures\n const measure = cube.measures.find(m => m.name === fieldName)\n if (measure) return measure.title || measure.shortTitle || fieldName\n \n // Check dimensions\n const dimension = cube.dimensions.find(d => d.name === fieldName)\n if (dimension) return dimension.title || dimension.shortTitle || fieldName\n }\n \n return fieldName // Fallback to field name if not found\n}\n\n/**\n * Clean up order object by removing fields that are no longer in the query\n */\nexport function cleanupOrder(order: Record<string, 'asc' | 'desc'> | undefined, query: CubeQuery): Record<string, 'asc' | 'desc'> | undefined {\n if (!order) return undefined\n \n const allFields = [\n ...(query.measures || []),\n ...(query.dimensions || []),\n ...(query.timeDimensions || []).map(td => td.dimension)\n ]\n \n const cleanedOrder: Record<string, 'asc' | 'desc'> = {}\n for (const [field, direction] of Object.entries(order)) {\n if (allFields.includes(field)) {\n cleanedOrder[field] = direction\n }\n }\n \n return Object.keys(cleanedOrder).length > 0 ? cleanedOrder : undefined\n}\n\n/**\n * Get sort direction for a field from the order object\n */\nexport function getSortDirection(fieldName: string, order: Record<string, 'asc' | 'desc'> | undefined): 'asc' | 'desc' | null {\n return order?.[fieldName] || null\n}\n\n/**\n * Get tooltip text for sort button based on current direction\n */\nexport function getSortTooltip(direction: 'asc' | 'desc' | null): string {\n switch (direction) {\n case 'asc':\n return 'Sorted ascending (click for descending)'\n case 'desc':\n return 'Sorted descending (click to remove)'\n default:\n return 'Click to sort ascending'\n }\n}\n\n/**\n * Get next sort direction in the cycle: null -> asc -> desc -> null\n */\nexport function getNextSortDirection(current: 'asc' | 'desc' | null): 'asc' | 'desc' | null {\n switch (current) {\n case null:\n return 'asc'\n case 'asc':\n return 'desc'\n case 'desc':\n return null\n default:\n return 'asc'\n }\n}","import React from 'react'\nimport { getMeasureTypeIcon } from '../icons'\n\n/**\n * Get the appropriate icon component for a given measure type\n * All icons use amber coloring for consistency\n */\nexport function getMeasureIcon(\n measureType: string | undefined,\n className: string = 'w-4 h-4'\n): React.ReactElement {\n const IconComponent = getMeasureTypeIcon(measureType)\n return <IconComponent className={className} />\n}\n\n/**\n * Get all available measure type icons\n * Useful for documentation or UI that shows all measure types\n */\nexport function getAllMeasureIcons(): Record<string, React.ReactElement> {\n const types = ['count', 'countDistinct', 'countDistinctApprox', 'sum', 'avg', 'min', 'max', 'runningTotal', 'calculated', 'number']\n const icons: Record<string, React.ReactElement> = {}\n\n for (const type of types) {\n const IconComponent = getMeasureTypeIcon(type)\n icons[type] = <IconComponent className=\"w-4 h-4\" />\n }\n\n return icons\n}\n","/**\n * FilterItem Component\n * \n * Renders a single filter with field selection, operator selection, and value input.\n * Handles all the logic for individual filter management.\n */\n\nimport React, { useState, useEffect, useRef } from 'react'\nimport { getIcon } from '../../icons'\nimport FilterValueSelector from './FilterValueSelector'\nimport type { FilterItemProps, MetaField, DateRangeType } from '../QueryBuilder/types'\nimport { getAllFilterableFields, getOrganizedFilterFields, getFieldType, getAvailableOperators, convertDateRangeTypeToValue, formatDateForCube, requiresNumberInput } from './utils'\nimport { getMeasureIcon } from '../../utils/measureIcons'\nimport { DATE_RANGE_OPTIONS } from '../QueryBuilder/types'\n\nconst CloseIcon = getIcon('close')\nconst FilterIcon = getIcon('filter')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst SearchIcon = getIcon('search')\nconst DimensionIcon = getIcon('dimension')\nconst TimeDimensionIcon = getIcon('timeDimension')\n\nconst FilterItem: React.FC<FilterItemProps> = ({\n filter,\n index,\n onFilterChange,\n onFilterRemove,\n schema,\n query,\n hideFieldSelector = false,\n hideOperatorSelector = false,\n hideRemoveButton = false\n}) => {\n const [isFieldDropdownOpen, setIsFieldDropdownOpen] = useState(false)\n const [isOperatorDropdownOpen, setIsOperatorDropdownOpen] = useState(false)\n const [isDateRangeDropdownOpen, setIsDateRangeDropdownOpen] = useState(false)\n const [fieldSearchTerm, setFieldSearchTerm] = useState('')\n const containerRef = useRef<HTMLDivElement>(null)\n const searchInputRef = useRef<HTMLInputElement>(null)\n\n // Date range state - always initialized with defaults (must be before any early returns)\n const [rangeType, setRangeType] = useState<DateRangeType>('this_month')\n const [customDates, setCustomDates] = useState({\n startDate: formatDateForCube(new Date()),\n endDate: formatDateForCube(new Date())\n })\n const [numberValue, setNumberValue] = useState<number>(1)\n\n // Close dropdowns when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsFieldDropdownOpen(false)\n setIsOperatorDropdownOpen(false)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Close other dropdowns when opening one\n const handleFieldDropdownToggle = () => {\n setIsOperatorDropdownOpen(false)\n const newOpen = !isFieldDropdownOpen\n setIsFieldDropdownOpen(newOpen)\n setFieldSearchTerm('') // Reset search when toggling\n\n // Focus search input when opening\n if (newOpen) {\n setTimeout(() => searchInputRef.current?.focus(), 50)\n }\n }\n\n const handleOperatorDropdownToggle = () => {\n setIsFieldDropdownOpen(false)\n setIsOperatorDropdownOpen(!isOperatorDropdownOpen)\n }\n\n // Get field info (safe defaults if schema not loaded)\n const allFields = schema ? getAllFilterableFields(schema) : []\n const { queryFields } = schema ? getOrganizedFilterFields(schema, query) : { queryFields: [] }\n const selectedField = allFields.find(f => f.name === filter.member)\n const fieldType = selectedField ? selectedField.type : 'string'\n const availableOperators = getAvailableOperators(fieldType)\n\n // Determine if we should show date range selector (for time fields with inDateRange operator)\n const shouldShowDateRangeSelector = fieldType === 'time' && filter.operator === 'inDateRange'\n\n // Update date range state when filter.dateRange changes (must be before early return)\n useEffect(() => {\n if (!shouldShowDateRangeSelector || !filter.dateRange) return\n\n // Update rangeType\n if (Array.isArray(filter.dateRange)) {\n setRangeType('custom')\n setCustomDates({\n startDate: filter.dateRange[0] || '',\n endDate: filter.dateRange[1] || filter.dateRange[0] || ''\n })\n } else {\n // Check for flexible range patterns\n const flexibleRangeMatch = filter.dateRange.match(/^last (\\d+) (days|weeks|months|quarters|years)$/)\n if (flexibleRangeMatch) {\n const [, num, unit] = flexibleRangeMatch\n const unitPlural = unit === 'days' ? 'days' : unit === 'weeks' ? 'weeks' : unit === 'months' ? 'months' : unit === 'quarters' ? 'quarters' : 'years'\n setRangeType(`last_n_${unitPlural}` as DateRangeType)\n setNumberValue(parseInt(num) || 1)\n } else {\n // Check for predefined ranges\n let found = false\n for (const option of DATE_RANGE_OPTIONS) {\n if (option.value !== 'custom' && !requiresNumberInput(option.value) && convertDateRangeTypeToValue(option.value) === filter.dateRange) {\n setRangeType(option.value)\n found = true\n break\n }\n }\n if (!found) {\n setRangeType('custom')\n }\n }\n }\n }, [filter.dateRange, shouldShowDateRangeSelector])\n\n // Early return AFTER all hooks\n if (!schema) {\n return (\n <div className=\"text-sm text-dc-text-muted\">\n Schema not loaded\n </div>\n )\n }\n \n // Filter fields based on search term\n const filterFieldsBySearch = (fields: MetaField[]) => {\n if (!fieldSearchTerm) return fields\n const searchTerm = fieldSearchTerm.toLowerCase()\n return fields.filter(field => \n field.name.toLowerCase().includes(searchTerm) ||\n field.title.toLowerCase().includes(searchTerm) ||\n field.shortTitle.toLowerCase().includes(searchTerm)\n )\n }\n \n const filteredQueryFields = filterFieldsBySearch(queryFields)\n const filteredAllFields = filterFieldsBySearch(allFields)\n \n // Helper function to get field type icon\n const getFieldTypeIcon = (field: MetaField) => {\n if (field.type === 'time') {\n return <TimeDimensionIcon className=\"w-3 h-3 text-dc-accent\" />\n } else if (['count', 'sum', 'avg', 'min', 'max', 'countDistinct', 'countDistinctApprox', 'runningTotal', 'calculated', 'number'].includes(field.type)) {\n // Use dynamic icon based on measure type, with amber color\n const icon = getMeasureIcon(field.type, 'w-3 h-3 text-dc-warning')\n return icon\n } else {\n return <DimensionIcon className=\"w-3 h-3 text-dc-success\" />\n }\n }\n\n // Helper function to get field type badge\n const getFieldTypeBadge = (field: MetaField) => {\n if (field.type === 'time') {\n return <span className=\"text-xs bg-dc-time-dimension text-dc-time-dimension px-1.5 py-0.5 rounded-sm\">T</span>\n } else if (['count', 'sum', 'avg', 'min', 'max', 'countDistinct', 'number'].includes(field.type)) {\n return <span className=\"text-xs bg-dc-measure text-dc-measure px-1.5 py-0.5 rounded-sm\">M</span>\n } else {\n return <span className=\"text-xs bg-dc-dimension text-dc-dimension px-1.5 py-0.5 rounded-sm\">D</span>\n }\n }\n\n const handleFieldChange = (fieldName: string) => {\n // When field changes, reset operator and values\n const newFieldType = getFieldType(fieldName, schema)\n const newAvailableOperators = getAvailableOperators(newFieldType)\n const defaultOperator = newAvailableOperators[0]?.operator || 'equals'\n\n onFilterChange(index, {\n member: fieldName,\n operator: defaultOperator as any,\n values: [],\n dateRange: undefined // Reset dateRange when field changes\n })\n setIsFieldDropdownOpen(false)\n }\n \n const handleOperatorChange = (operator: string) => {\n onFilterChange(index, {\n ...filter,\n operator: operator as any,\n values: [], // Reset values when operator changes\n dateRange: undefined // Reset dateRange when operator changes\n })\n setIsOperatorDropdownOpen(false)\n }\n \n const handleValuesChange = (values: any[]) => {\n onFilterChange(index, {\n ...filter,\n values\n })\n }\n\n // Date range handlers for time dimension filters\n const handleDateRangeChange = (dateRange: string | string[]) => {\n onFilterChange(index, {\n ...filter,\n dateRange\n })\n }\n\n const handleRangeTypeChange = (newRangeType: DateRangeType) => {\n setIsDateRangeDropdownOpen(false)\n\n if (newRangeType === 'custom') {\n // For custom, use current custom dates or default to today\n if (customDates.startDate && customDates.endDate) {\n const dateRange = customDates.startDate === customDates.endDate\n ? customDates.startDate\n : [customDates.startDate, customDates.endDate]\n handleDateRangeChange(dateRange)\n }\n } else if (requiresNumberInput(newRangeType)) {\n // For number-based ranges, use the number value\n const cubeRangeValue = convertDateRangeTypeToValue(newRangeType, numberValue)\n handleDateRangeChange(cubeRangeValue)\n } else {\n // For predefined ranges, use the converted value\n const cubeRangeValue = convertDateRangeTypeToValue(newRangeType)\n handleDateRangeChange(cubeRangeValue)\n }\n\n setRangeType(newRangeType)\n }\n\n const handleCustomDateChange = (field: 'startDate' | 'endDate', value: string) => {\n const newCustomDates = { ...customDates, [field]: value }\n setCustomDates(newCustomDates)\n\n if (rangeType === 'custom' && newCustomDates.startDate) {\n const dateRange = !newCustomDates.endDate || newCustomDates.startDate === newCustomDates.endDate\n ? newCustomDates.startDate\n : [newCustomDates.startDate, newCustomDates.endDate]\n handleDateRangeChange(dateRange)\n }\n }\n\n const handleNumberChange = (value: number) => {\n setNumberValue(value)\n\n if (requiresNumberInput(rangeType)) {\n const cubeRangeValue = convertDateRangeTypeToValue(rangeType, value)\n handleDateRangeChange(cubeRangeValue)\n }\n }\n\n const selectedRangeLabel = DATE_RANGE_OPTIONS.find(opt => opt.value === rangeType)?.label || 'Custom'\n\n return (\n <div ref={containerRef} className=\"bg-dc-surface border border-dc-border rounded-lg p-3\">\n {/* Responsive layout - stacks on mobile, single row on desktop */}\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-3 min-w-0 max-w-full\">\n {/* Row 1 on mobile: Filter icon and field selection - conditionally hidden */}\n {!hideFieldSelector && (\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n <FilterIcon className=\"w-4 h-4 text-dc-text-muted shrink-0\" />\n\n {/* Field selection */}\n <div className=\"relative flex-1 min-w-0\">\n <button\n onClick={handleFieldDropdownToggle}\n className=\"w-full flex items-center justify-between text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent min-w-0\"\n >\n <span className=\"truncate\">\n {selectedField ? (\n <span className=\"font-medium\">{selectedField.name}</span>\n ) : (\n <span className=\"text-dc-text-muted\">Select field...</span>\n )}\n </span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-1 transition-transform ${\n isFieldDropdownOpen ? 'transform rotate-180' : ''\n }`} />\n </button>\n\n {isFieldDropdownOpen && (\n <div className=\"absolute z-20 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-80 overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-dc-border\">\n <div className=\"relative\">\n <SearchIcon className=\"w-4 h-4 absolute left-2 top-1/2 transform -translate-y-1/2 text-dc-text-muted\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n placeholder=\"Search fields...\"\n value={fieldSearchTerm}\n onChange={(e) => setFieldSearchTerm(e.target.value)}\n className=\"w-full pl-8 pr-3 py-1.5 text-sm border border-dc-border rounded-sm bg-dc-surface text-dc-text focus:ring-1 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n </div>\n\n {/* Fields list */}\n <div className=\"max-h-60 overflow-y-auto\">\n {/* Query fields section */}\n {filteredQueryFields.length > 0 && (\n <div>\n <div className=\"px-3 py-1.5 text-xs font-medium text-dc-text-muted bg-dc-surface-secondary border-b border-dc-border\">\n Fields in Query ({filteredQueryFields.length})\n </div>\n {filteredQueryFields.map((field) => (\n <button\n key={`query-${field.name}`}\n onClick={() => handleFieldChange(field.name)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-none focus:bg-dc-surface-hover ${\n field.name === filter.member ? 'bg-dc-accent-bg text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n <div className=\"flex items-center gap-2\">\n {getFieldTypeIcon(field)}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium truncate\">{field.name}</span>\n {getFieldTypeBadge(field)}\n </div>\n {field.title !== field.name && (\n <div className=\"text-xs text-dc-text-muted truncate\">{field.title}</div>\n )}\n </div>\n </div>\n </button>\n ))}\n </div>\n )}\n\n {/* All fields section */}\n <div>\n {filteredQueryFields.length > 0 && (\n <div className=\"px-3 py-1.5 text-xs font-medium text-dc-text-muted bg-dc-surface-secondary border-b border-dc-border\">\n All Available Fields ({filteredAllFields.length})\n </div>\n )}\n {filteredAllFields.map((field) => (\n <button\n key={`all-${field.name}`}\n onClick={() => handleFieldChange(field.name)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-none focus:bg-dc-surface-hover ${\n field.name === filter.member ? 'bg-dc-accent-bg text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n <div className=\"flex items-center gap-2\">\n {getFieldTypeIcon(field)}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium truncate\">{field.name}</span>\n {getFieldTypeBadge(field)}\n </div>\n {field.title !== field.name && (\n <div className=\"text-xs text-dc-text-muted truncate\">{field.title}</div>\n )}\n </div>\n </div>\n </button>\n ))}\n </div>\n\n {/* No results message */}\n {filteredAllFields.length === 0 && (\n <div className=\"px-3 py-4 text-sm text-dc-text-muted text-center\">\n No fields found matching \"{fieldSearchTerm}\"\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Row 2 on mobile: Operator and Value selection */}\n {selectedField && (\n <div className=\"flex items-center gap-2 flex-1 sm:flex-initial min-w-0\">\n {/* Operator selection - conditionally hidden */}\n {!hideOperatorSelector && (\n <div className=\"relative shrink-0\">\n <button\n onClick={handleOperatorDropdownToggle}\n className=\"w-full sm:w-32 flex items-center justify-between text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n >\n <span className=\"truncate\">\n {availableOperators.find(op => op.operator === filter.operator)?.label || filter.operator}\n </span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-1 transition-transform ${\n isOperatorDropdownOpen ? 'transform rotate-180' : ''\n }`} />\n </button>\n\n {isOperatorDropdownOpen && (\n <div className=\"absolute z-20 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-60 overflow-y-auto\">\n {availableOperators.map((operator) => (\n <button\n key={operator.operator}\n onClick={() => handleOperatorChange(operator.operator)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-none focus:bg-dc-surface-hover ${\n operator.operator === filter.operator ? 'bg-dc-accent-bg text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n {operator.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* Value input or Date Range Selector */}\n <div className=\"flex-1 min-w-0\">\n {shouldShowDateRangeSelector ? (\n /* Date Range Selector for time dimensions with inDateRange */\n <div className=\"flex items-center gap-2\">\n {/* Range type selector */}\n <div className=\"relative shrink-0\">\n <button\n onClick={() => {\n setIsOperatorDropdownOpen(false)\n setIsDateRangeDropdownOpen(!isDateRangeDropdownOpen)\n }}\n className=\"w-full sm:w-40 flex items-center justify-between text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n >\n <span className=\"truncate\">{selectedRangeLabel}</span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-1 transition-transform ${\n isDateRangeDropdownOpen ? 'transform rotate-180' : ''\n }`} />\n </button>\n\n {isDateRangeDropdownOpen && (\n <div className=\"absolute z-20 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-60 overflow-y-auto\">\n {DATE_RANGE_OPTIONS.map((option) => (\n <button\n key={option.value}\n onClick={() => handleRangeTypeChange(option.value)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-none focus:bg-dc-surface-hover ${\n option.value === rangeType ? 'bg-dc-accent-bg text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n {option.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Custom date inputs or number input */}\n {rangeType === 'custom' ? (\n <>\n <input\n type=\"date\"\n value={customDates.startDate}\n onChange={(e) => handleCustomDateChange('startDate', e.target.value)}\n placeholder=\"Start date\"\n className=\"flex-1 min-w-0 text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n <input\n type=\"date\"\n value={customDates.endDate}\n onChange={(e) => handleCustomDateChange('endDate', e.target.value)}\n placeholder=\"End date\"\n className=\"flex-1 min-w-0 text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </>\n ) : requiresNumberInput(rangeType) ? (\n <>\n <input\n type=\"number\"\n min=\"1\"\n max=\"1000\"\n value={numberValue}\n onChange={(e) => handleNumberChange(Math.max(1, parseInt(e.target.value) || 1))}\n placeholder=\"Number\"\n className=\"flex-1 min-w-0 text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n <div className=\"shrink-0 text-sm text-dc-text-secondary\">\n {rangeType.replace('last_n_', '').replace('_', ' ')}\n </div>\n </>\n ) : null}\n </div>\n ) : (\n /* Regular FilterValueSelector for non-dateRange filters */\n <FilterValueSelector\n fieldName={filter.member}\n operator={filter.operator}\n values={filter.values}\n onValuesChange={handleValuesChange}\n schema={schema}\n />\n )}\n </div>\n </div>\n )}\n \n {/* Row 3 on mobile: Remove button - conditionally hidden */}\n {!hideRemoveButton && (\n <div className=\"flex justify-end sm:justify-start\">\n <button\n onClick={() => onFilterRemove(index)}\n className=\"text-dc-text-muted hover:text-dc-error focus:outline-none shrink-0\"\n title=\"Remove filter\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default FilterItem","/**\n * FilterGroup Component\n * \n * Handles AND/OR logical groups with support for infinite nesting.\n * Renders child filters with proper indentation and group controls.\n */\n\nimport React, { useState } from 'react'\nimport { getIcon } from '../../icons'\nimport FilterItem from './FilterItem'\nimport type { FilterGroupProps } from '../QueryBuilder/types'\nimport type { SimpleFilter, GroupFilter } from '../../types'\nimport {\n isSimpleFilter,\n isGroupFilter,\n createSimpleFilter,\n createAndFilter,\n createOrFilter,\n getFilterableFields\n} from './utils'\n\nconst CloseIcon = getIcon('close')\nconst AddIcon = getIcon('add')\n\nconst FilterGroup: React.FC<FilterGroupProps> = ({\n group,\n index,\n onGroupChange,\n onGroupChangeWithUnwrap,\n onGroupRemove,\n schema,\n query,\n depth = 0\n}) => {\n const [showAddMenu, setShowAddMenu] = useState(false)\n \n const isAndGroup = group.type === 'and'\n const groupType = isAndGroup ? 'AND' : 'OR'\n const filters = group.filters\n \n // Style based on depth for visual nesting\n const indentClass = depth > 0 ? `ml-${Math.min(depth * 4, 16)}` : ''\n const borderColor = 'border-dc-border'\n const bgColor = 'bg-dc-bg-secondary'\n const textColor = 'text-dc-text-secondary'\n \n const handleGroupTypeToggle = () => {\n if (isAndGroup) {\n const newGroup = createOrFilter(filters)\n onGroupChange(index, newGroup)\n } else {\n const newGroup = createAndFilter(filters)\n onGroupChange(index, newGroup)\n }\n }\n \n const handleAddSimpleFilter = () => {\n if (!schema) return\n \n // Get the first available field as default\n const filterableFields = getFilterableFields(schema, query)\n const defaultField = filterableFields[0]?.name || ''\n const newFilter = createSimpleFilter(defaultField, 'equals', [])\n const newFilters = [...filters, newFilter]\n \n if (isAndGroup) {\n onGroupChange(index, createAndFilter(newFilters))\n } else {\n onGroupChange(index, createOrFilter(newFilters))\n }\n setShowAddMenu(false)\n }\n \n const handleAddAndGroup = () => {\n if (!schema) return\n \n // Get the first available field as default\n const filterableFields = getFilterableFields(schema, query)\n const defaultField = filterableFields[0]?.name || ''\n const newGroup = createAndFilter([createSimpleFilter(defaultField, 'equals', [])])\n const newFilters = [...filters, newGroup]\n \n if (isAndGroup) {\n onGroupChange(index, createAndFilter(newFilters))\n } else {\n onGroupChange(index, createOrFilter(newFilters))\n }\n setShowAddMenu(false)\n }\n \n const handleAddOrGroup = () => {\n if (!schema) return\n \n // Get the first available field as default\n const filterableFields = getFilterableFields(schema, query)\n const defaultField = filterableFields[0]?.name || ''\n const newGroup = createOrFilter([createSimpleFilter(defaultField, 'equals', [])])\n const newFilters = [...filters, newGroup]\n \n if (isAndGroup) {\n onGroupChange(index, createAndFilter(newFilters))\n } else {\n onGroupChange(index, createOrFilter(newFilters))\n }\n setShowAddMenu(false)\n }\n \n const handleFilterChange = (filterIndex: number, newFilter: SimpleFilter) => {\n const newFilters = [...filters]\n newFilters[filterIndex] = newFilter\n \n if (isAndGroup) {\n onGroupChange(index, createAndFilter(newFilters))\n } else {\n onGroupChange(index, createOrFilter(newFilters))\n }\n }\n \n const handleFilterRemove = (filterIndex: number) => {\n const newFilters = filters.filter((_, i) => i !== filterIndex)\n \n // If no filters left, remove the entire group\n if (newFilters.length === 0) {\n onGroupRemove(index)\n return\n }\n \n // If only one filter left, use unwrapping handler if available\n if (newFilters.length === 1) {\n const newGroup = group.type === 'and' ? createAndFilter(newFilters) : createOrFilter(newFilters)\n \n if (onGroupChangeWithUnwrap) {\n // Use the unwrapping handler for removal scenarios\n onGroupChangeWithUnwrap(index, newGroup)\n } else {\n // Fallback to regular handler (for nested groups)\n onGroupChange(index, newGroup)\n }\n return\n }\n \n // Otherwise, update the group with remaining filters (preserve the group type)\n const updatedGroup = group.type === 'and' ? createAndFilter(newFilters) : createOrFilter(newFilters)\n onGroupChange(index, updatedGroup)\n }\n \n const handleNestedGroupChange = (filterIndex: number, newGroup: GroupFilter) => {\n const newFilters = [...filters]\n newFilters[filterIndex] = newGroup\n \n if (isAndGroup) {\n onGroupChange(index, createAndFilter(newFilters))\n } else {\n onGroupChange(index, createOrFilter(newFilters))\n }\n }\n \n const handleNestedGroupRemove = (filterIndex: number) => {\n handleFilterRemove(filterIndex)\n }\n \n return (\n <div className={`${indentClass} ${borderColor} border-2 ${bgColor} rounded-lg py-3 pr-3 pl-2 space-y-3`}>\n {/* Group header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <button\n onClick={handleGroupTypeToggle}\n className={`px-3 py-1 rounded-sm text-sm font-semibold ${textColor} border border-current hover:bg-dc-surface hover:bg-opacity-20 focus:outline-hidden focus:ring-2 focus:ring-current focus:ring-opacity-50`}\n >\n {groupType}\n </button>\n <span className=\"text-sm text-dc-text-secondary\">\n {filters.length} condition{filters.length !== 1 ? 's' : ''}\n </span>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n {/* Add menu */}\n <div className=\"relative\">\n <button\n onClick={() => setShowAddMenu(!showAddMenu)}\n className=\"text-dc-text-muted hover:text-dc-text-secondary focus:outline-hidden\"\n title=\"Add condition\"\n >\n <AddIcon className=\"w-4 h-4\" />\n </button>\n\n {showAddMenu && (\n <div className=\"absolute right-0 mt-1 w-48 bg-dc-surface border border-dc-border rounded-md shadow-lg z-30\">\n <button\n onClick={handleAddSimpleFilter}\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover\"\n >\n Add Filter\n </button>\n <button\n onClick={handleAddAndGroup}\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover\"\n >\n Add AND Group\n </button>\n <button\n onClick={handleAddOrGroup}\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover\"\n >\n Add OR Group\n </button>\n </div>\n )}\n </div>\n\n {/* Remove group button */}\n <button\n onClick={() => onGroupRemove(index)}\n className=\"text-dc-text-muted hover:text-dc-error focus:outline-hidden\"\n title=\"Remove group\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n \n {/* Group content */}\n <div className=\"space-y-3\">\n {filters.map((filter, filterIndex) => {\n if (isSimpleFilter(filter)) {\n return (\n <FilterItem\n key={filterIndex}\n filter={filter}\n index={filterIndex}\n onFilterChange={handleFilterChange}\n onFilterRemove={handleFilterRemove}\n schema={schema}\n query={query}\n />\n )\n } else if (isGroupFilter(filter)) {\n return (\n <FilterGroup\n key={filterIndex}\n group={filter}\n index={filterIndex}\n onGroupChange={handleNestedGroupChange}\n onGroupRemove={handleNestedGroupRemove}\n schema={schema}\n query={query}\n depth={depth + 1}\n />\n )\n }\n return null\n })}\n \n {/* Empty state */}\n {filters.length === 0 && (\n <div className=\"text-center py-4 text-dc-text-muted text-sm\">\n No conditions in this group.\n <button\n onClick={handleAddSimpleFilter}\n className=\"ml-2 text-dc-accent hover:text-dc-accent focus:outline-hidden underline\"\n >\n Add a filter\n </button>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default FilterGroup","/**\n * FilterBuilder Component\n * \n * Main component for managing all filters in the query.\n * Handles the top-level filter state and provides controls for adding new filters and groups.\n */\n\nimport React from 'react'\nimport { getIcon } from '../../icons'\nimport FilterItem from './FilterItem'\nimport FilterGroup from './FilterGroup'\nimport type { FilterBuilderProps } from '../QueryBuilder/types'\nimport type { SimpleFilter, GroupFilter } from '../../types'\nimport {\n isSimpleFilter,\n isGroupFilter,\n isAndFilter,\n isOrFilter,\n createSimpleFilter,\n createAndFilter,\n createOrFilter,\n countFilters,\n getAllFilterableFields\n} from './utils'\n\nconst AddIcon = getIcon('add')\nconst FilterIcon = getIcon('filter')\n\nconst FilterBuilder: React.FC<FilterBuilderProps> = ({\n filters,\n schema,\n query,\n onFiltersChange,\n hideFieldSelector = false\n}) => {\n \n \n const totalFilterCount = countFilters(filters)\n \n // Get all filterable fields from schema\n const allFilterableFields = schema ? getAllFilterableFields(schema) : []\n const hasFilterableFields = allFilterableFields.length > 0\n \n const handleAddSimpleFilter = () => {\n if (!hasFilterableFields) return\n \n // Use the first available field as default\n const defaultField = allFilterableFields[0]?.name || ''\n const newFilter = createSimpleFilter(defaultField, 'equals', [])\n \n // Smart filter grouping logic:\n // - First filter: add as simple filter\n // - Second filter: create AND group with first filter + new filter\n // - Additional filters: add to existing group (AND or OR, respecting current type)\n \n if (filters.length === 0) {\n // First filter - add as simple filter\n onFiltersChange([newFilter])\n } else if (filters.length === 1 && isSimpleFilter(filters[0])) {\n // Second filter - create AND group with existing filter + new filter\n const andGroup = createAndFilter([filters[0], newFilter])\n onFiltersChange([andGroup])\n } else if (filters.length === 1 && isAndFilter(filters[0])) {\n // Additional filter - add to existing AND group\n const existingAndGroup = filters[0]\n const updatedAndGroup = createAndFilter([...existingAndGroup.filters, newFilter])\n onFiltersChange([updatedAndGroup])\n } else if (filters.length === 1 && isOrFilter(filters[0])) {\n // Additional filter - add to existing OR group\n const existingOrGroup = filters[0]\n const updatedOrGroup = createOrFilter([...existingOrGroup.filters, newFilter])\n onFiltersChange([updatedOrGroup])\n } else {\n // Fallback: just add to the end (shouldn't happen with new logic)\n onFiltersChange([...filters, newFilter])\n }\n }\n \n \n const handleFilterChange = (index: number, newFilter: SimpleFilter) => {\n const newFilters = [...filters]\n newFilters[index] = newFilter\n onFiltersChange(newFilters)\n }\n \n const handleFilterRemove = (index: number) => {\n // Simple case: just remove the filter\n // The handleGroupChange method will automatically handle unwrapping if needed\n const newFilters = filters.filter((_, i) => i !== index)\n onFiltersChange(newFilters)\n }\n \n const handleGroupChange = (index: number, newGroup: GroupFilter) => {\n const newFilters = [...filters]\n newFilters[index] = newGroup\n onFiltersChange(newFilters)\n }\n \n const handleGroupChangeWithUnwrap = (index: number, newGroup: GroupFilter) => {\n const newFilters = [...filters]\n \n // Check if the group has been reduced to a single filter and should be unwrapped\n // This is only used during filter removal operations\n if (newGroup.filters.length === 1 && isSimpleFilter(newGroup.filters[0])) {\n // Unwrap the single filter from the group\n newFilters[index] = newGroup.filters[0]\n } else {\n newFilters[index] = newGroup\n }\n \n onFiltersChange(newFilters)\n }\n \n const handleGroupRemove = () => {\n // When removing an AND group, we should remove all filters\n onFiltersChange([])\n }\n \n const handleClearAllFilters = () => {\n onFiltersChange([])\n }\n \n return (\n <div className=\"space-y-4 bg-dc-surface-secondary rounded-lg p-4\">\n {/* Header - hidden for universal time filters */}\n {!hideFieldSelector && (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center\">\n <FilterIcon className=\"w-4 h-4 text-dc-text-muted mr-2\" />\n <h4 className=\"text-sm font-semibold text-dc-text-secondary\">\n Filters ({totalFilterCount})\n </h4>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n {/* Clear all button */}\n {filters.length > 0 && (\n <button\n onClick={handleClearAllFilters}\n className=\"text-xs text-dc-text-muted hover:text-dc-error focus:outline-hidden underline\"\n >\n Clear all\n </button>\n )}\n\n {/* Add Filter button */}\n <button\n onClick={handleAddSimpleFilter}\n disabled={!hasFilterableFields}\n className={`flex items-center space-x-1 px-2 py-1 text-xs font-medium rounded focus:outline-hidden focus:ring-2 ${\n hasFilterableFields\n ? 'text-dc-accent bg-dc-accent-bg border border-dc-accent hover:bg-dc-accent-bg focus:ring-dc-accent'\n : 'text-dc-text-muted bg-dc-surface-secondary border border-dc-border cursor-not-allowed'\n }`}\n >\n <AddIcon className=\"w-3 h-3\" />\n <span>Add Filter</span>\n </button>\n </div>\n </div>\n )}\n \n {/* Filters list */}\n {filters.length > 0 && (\n <div className=\"space-y-3\">\n {filters.map((filter, index) => {\n \n if (isSimpleFilter(filter)) {\n return (\n <FilterItem\n key={index}\n filter={filter}\n index={index}\n onFilterChange={handleFilterChange}\n onFilterRemove={handleFilterRemove}\n schema={schema}\n query={query}\n hideFieldSelector={hideFieldSelector}\n hideRemoveButton={hideFieldSelector}\n />\n )\n } else if (isGroupFilter(filter)) {\n return (\n <FilterGroup\n key={index}\n group={filter}\n index={index}\n onGroupChange={handleGroupChange}\n onGroupChangeWithUnwrap={handleGroupChangeWithUnwrap}\n onGroupRemove={handleGroupRemove}\n schema={schema}\n query={query}\n depth={0}\n />\n )\n }\n return null\n })}\n </div>\n )}\n \n </div>\n )\n}\n\nexport default FilterBuilder","/**\n * DateRangeSelector Component\n * \n * Individual date range selector for a specific time dimension\n * Styled to match FilterItem component exactly\n */\n\nimport React, { useState, useEffect, useRef } from 'react'\nimport { getIcon } from '../../icons'\nimport { DATE_RANGE_OPTIONS, type DateRangeType } from '../QueryBuilder/types'\nimport { convertDateRangeTypeToValue, formatDateForCube, requiresNumberInput } from './utils'\n\nconst CloseIcon = getIcon('close')\nconst CalendarIcon = getIcon('timeDimension')\nconst ChevronDownIcon = getIcon('chevronDown')\n\ninterface DateRangeSelectorProps {\n timeDimension: string\n availableTimeDimensions: string[]\n currentDateRange?: string | string[]\n onDateRangeChange: (timeDimension: string, dateRange: string | string[]) => void\n onTimeDimensionChange: (oldTimeDimension: string, newTimeDimension: string) => void\n onRemove: (timeDimension: string) => void\n hideFieldSelector?: boolean // Hide the time dimension field selector (for read-only filters)\n hideRemoveButton?: boolean // Hide the remove button (for read-only filters)\n}\n\nconst DateRangeSelector: React.FC<DateRangeSelectorProps> = ({\n timeDimension,\n availableTimeDimensions,\n currentDateRange,\n onDateRangeChange,\n onTimeDimensionChange,\n onRemove,\n hideFieldSelector = false,\n hideRemoveButton = false\n}) => {\n // Parse current date range to determine the type and custom dates\n const getCurrentRangeType = (): DateRangeType => {\n if (!currentDateRange) return 'this_month'\n \n if (Array.isArray(currentDateRange)) {\n return 'custom'\n }\n \n // Check if it's a flexible range with number (e.g., \"last 9 weeks\")\n const flexibleRangeMatch = currentDateRange.match(/^last (\\d+) (days|weeks|months|quarters|years)$/)\n if (flexibleRangeMatch) {\n const [, , unit] = flexibleRangeMatch\n const unitPlural = unit === 'days' ? 'days' : unit === 'weeks' ? 'weeks' : unit === 'months' ? 'months' : unit === 'quarters' ? 'quarters' : 'years'\n return `last_n_${unitPlural}` as DateRangeType\n }\n \n // Find matching predefined range\n for (const option of DATE_RANGE_OPTIONS) {\n if (option.value !== 'custom' && !requiresNumberInput(option.value) && convertDateRangeTypeToValue(option.value) === currentDateRange) {\n return option.value\n }\n }\n \n return 'custom'\n }\n\n const getCurrentDates = (): { startDate: string; endDate: string } => {\n if (Array.isArray(currentDateRange) && currentDateRange.length >= 1) {\n return {\n startDate: currentDateRange[0] || '',\n endDate: currentDateRange[1] || currentDateRange[0] || ''\n }\n }\n \n // Default to today for custom ranges\n const today = formatDateForCube(new Date())\n return { startDate: today, endDate: today }\n }\n\n const getCurrentNumber = (): number => {\n if (!currentDateRange || Array.isArray(currentDateRange)) return 1\n \n // Check if it's a flexible range with number (e.g., \"last 9 weeks\")\n const flexibleRangeMatch = currentDateRange.match(/^last (\\d+) (days|weeks|months|quarters|years)$/)\n if (flexibleRangeMatch) {\n return parseInt(flexibleRangeMatch[1]) || 1\n }\n \n return 1\n }\n\n const [rangeType, setRangeType] = useState<DateRangeType>(getCurrentRangeType())\n const [customDates, setCustomDates] = useState(getCurrentDates())\n const [numberValue, setNumberValue] = useState<number>(getCurrentNumber())\n const [isRangeDropdownOpen, setIsRangeDropdownOpen] = useState(false)\n const [isTimeDimensionDropdownOpen, setIsTimeDimensionDropdownOpen] = useState(false)\n const containerRef = useRef<HTMLDivElement>(null)\n \n // Close dropdowns when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsRangeDropdownOpen(false)\n setIsTimeDimensionDropdownOpen(false)\n }\n }\n \n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Close other dropdowns when opening one\n const handleTimeDimensionDropdownToggle = () => {\n setIsRangeDropdownOpen(false)\n setIsTimeDimensionDropdownOpen(!isTimeDimensionDropdownOpen)\n }\n \n const handleRangeDropdownToggle = () => {\n setIsTimeDimensionDropdownOpen(false)\n setIsRangeDropdownOpen(!isRangeDropdownOpen)\n }\n\n const handleRangeTypeChange = (newRangeType: DateRangeType) => {\n setRangeType(newRangeType)\n setIsRangeDropdownOpen(false)\n \n if (newRangeType === 'custom') {\n // For custom, use current custom dates or default to today\n if (customDates.startDate && customDates.endDate) {\n const dateRange = customDates.startDate === customDates.endDate \n ? customDates.startDate\n : [customDates.startDate, customDates.endDate]\n onDateRangeChange(timeDimension, dateRange)\n }\n } else if (requiresNumberInput(newRangeType)) {\n // For number-based ranges, use the number value\n const cubeRangeValue = convertDateRangeTypeToValue(newRangeType, numberValue)\n onDateRangeChange(timeDimension, cubeRangeValue)\n } else {\n // For predefined ranges, use the converted value\n const cubeRangeValue = convertDateRangeTypeToValue(newRangeType)\n onDateRangeChange(timeDimension, cubeRangeValue)\n }\n }\n\n const handleCustomDateChange = (field: 'startDate' | 'endDate', value: string) => {\n const newCustomDates = { ...customDates, [field]: value }\n setCustomDates(newCustomDates)\n \n if (rangeType === 'custom' && newCustomDates.startDate) {\n const dateRange = !newCustomDates.endDate || newCustomDates.startDate === newCustomDates.endDate\n ? newCustomDates.startDate\n : [newCustomDates.startDate, newCustomDates.endDate]\n onDateRangeChange(timeDimension, dateRange)\n }\n }\n\n const handleNumberChange = (value: number) => {\n setNumberValue(value)\n \n if (requiresNumberInput(rangeType)) {\n const cubeRangeValue = convertDateRangeTypeToValue(rangeType, value)\n onDateRangeChange(timeDimension, cubeRangeValue)\n }\n }\n\n const handleTimeDimensionChange = (newTimeDimension: string) => {\n setIsTimeDimensionDropdownOpen(false)\n onTimeDimensionChange(timeDimension, newTimeDimension)\n }\n\n const selectedRangeLabel = DATE_RANGE_OPTIONS.find(opt => opt.value === rangeType)?.label || 'Custom'\n\n return (\n <div ref={containerRef} className=\"bg-dc-surface border border-dc-border rounded-lg p-3\">\n {/* Responsive layout - stacks on mobile, single row on desktop */}\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-3 min-w-0\">\n {/* Row 1: Filter icon and time dimension field - conditionally hidden */}\n {!hideFieldSelector && (\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n <CalendarIcon className=\"w-4 h-4 text-dc-text-muted shrink-0\" />\n\n {/* Time dimension field selector */}\n <div className=\"relative flex-1 min-w-0\">\n <button\n onClick={handleTimeDimensionDropdownToggle}\n className=\"w-full flex items-center justify-between text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent min-w-0\"\n >\n <span className=\"truncate\">{timeDimension}</span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 transition-transform ${\n isTimeDimensionDropdownOpen ? 'transform rotate-180' : ''\n }`} />\n </button>\n\n {isTimeDimensionDropdownOpen && (\n <div className=\"absolute z-20 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-60 overflow-y-auto\">\n {availableTimeDimensions.map((td) => (\n <button\n key={td}\n onClick={() => handleTimeDimensionChange(td)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover ${\n td === timeDimension ? 'bg-dc-accent-bg dark:bg-dc-accent-bg text-dc-accent dark:text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n {td}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Row 2: Date range selector */}\n <div className=\"flex items-center gap-2 flex-1 sm:flex-initial min-w-0\">\n {/* Range type selector with custom dropdown */}\n <div className=\"relative shrink-0\">\n <button\n onClick={handleRangeDropdownToggle}\n className=\"w-full sm:w-40 flex items-center justify-between text-left text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n >\n <span className=\"truncate\">{selectedRangeLabel}</span>\n <ChevronDownIcon className={`w-4 h-4 text-dc-text-muted shrink-0 ml-1 transition-transform ${\n isRangeDropdownOpen ? 'transform rotate-180' : ''\n }`} />\n </button>\n\n {isRangeDropdownOpen && (\n <div className=\"absolute z-20 left-0 right-0 mt-1 bg-dc-surface border border-dc-border rounded-md shadow-lg max-h-60 overflow-y-auto\">\n {DATE_RANGE_OPTIONS.map((option) => (\n <button\n key={option.value}\n onClick={() => handleRangeTypeChange(option.value)}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-dc-surface-hover focus:outline-hidden focus:bg-dc-surface-hover ${\n option.value === rangeType ? 'bg-dc-accent-bg dark:bg-dc-accent-bg text-dc-accent dark:text-dc-accent' : 'text-dc-text-secondary'\n }`}\n >\n {option.label}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Row 3: Custom date inputs, number input, or remove button */}\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n {rangeType === 'custom' ? (\n <>\n {/* Start date */}\n <div className=\"flex-1 min-w-0\">\n <input\n type=\"date\"\n value={customDates.startDate}\n onChange={(e) => handleCustomDateChange('startDate', e.target.value)}\n placeholder=\"dd/mm/yyyy\"\n className=\"w-full text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n\n {/* End date (optional) */}\n <div className=\"flex-1 min-w-0\">\n <input\n type=\"date\"\n value={customDates.endDate}\n onChange={(e) => handleCustomDateChange('endDate', e.target.value)}\n placeholder=\"dd/mm/yyyy\"\n className=\"w-full text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n </>\n ) : requiresNumberInput(rangeType) ? (\n <>\n {/* Number input for flexible ranges */}\n <div className=\"flex-1 min-w-0\">\n <input\n type=\"number\"\n min=\"1\"\n max=\"1000\"\n value={numberValue}\n onChange={(e) => handleNumberChange(Math.max(1, parseInt(e.target.value) || 1))}\n placeholder=\"Number\"\n className=\"w-full text-sm border border-dc-border rounded-sm px-2 py-1 bg-dc-surface text-dc-text hover:bg-dc-surface-hover focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n </div>\n\n {/* Unit display */}\n <div className=\"shrink-0 text-sm text-dc-text-secondary\">\n {rangeType.replace('last_n_', '').replace('_', ' ')}\n </div>\n </>\n ) : (\n // Empty placeholder to maintain layout consistency\n <div className=\"flex-1\"></div>\n )}\n\n {/* Remove button - conditionally hidden */}\n {!hideRemoveButton && (\n <button\n onClick={() => onRemove(timeDimension)}\n className=\"text-dc-text-muted hover:text-dc-error focus:outline-hidden shrink-0 p-1\"\n title=\"Remove date range\"\n >\n <CloseIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n </div>\n )\n}\n\nexport default DateRangeSelector","/**\n * CubeMetaExplorer Component\n * \n * Displays the cube schema in a collapsible tree view.\n * Users can click on dimensions, measures, and time dimensions to add them to their query.\n */\n\nimport React, { useState, Suspense, lazy, memo } from 'react'\nimport type { CubeMetaExplorerProps, MetaCube, MetaField } from '../QueryBuilder/types'\nimport { getMeasureIcon } from '../../utils/measureIcons'\nimport { useCubeContext } from '../../providers/CubeProvider'\nimport { getIcon } from '../../icons'\n\n// Lazy load the relationship diagram (imports reactflow which is large)\nconst CubeRelationshipDiagram = lazy(() =>\n import('../CubeRelationshipDiagram').then(mod => ({ default: mod.CubeRelationshipDiagram }))\n)\n\ntype SchemaViewType = 'tree' | 'diagram'\n\nconst CubeMetaExplorer: React.FC<CubeMetaExplorerProps> = ({\n schema,\n schemaStatus,\n schemaError,\n selectedFields,\n onFieldSelect,\n onFieldDeselect,\n onRetrySchema,\n onOpenSettings,\n onViewTypeChange,\n isExpanded = false\n}) => {\n // Get icons\n const ChevronDownIcon = getIcon('chevronDown')\n const ChevronRightIcon = getIcon('chevronRight')\n const WarningIcon = getIcon('warning')\n const RefreshIcon = getIcon('refresh')\n const SettingsIcon = getIcon('settings')\n const MeasureIcon = getIcon('measure')\n const DimensionIcon = getIcon('dimension')\n const TimeDimensionIcon = getIcon('timeDimension')\n const SegmentIcon = getIcon('segment')\n const MenuIcon = getIcon('menu')\n\n // Get features from context to check if schema diagram is enabled\n const { features } = useCubeContext()\n const showSchemaDiagram = features?.showSchemaDiagram === true\n\n const [expandedCubes, setExpandedCubes] = useState<Set<string>>(new Set())\n const [expandedSections, setExpandedSections] = useState<Set<string>>(new Set())\n const [searchTerm, setSearchTerm] = useState('')\n const [viewType, setViewType] = useState<SchemaViewType>('tree')\n\n // Track the original expansion state before search\n const [preSearchExpandedCubes, setPreSearchExpandedCubes] = useState<Set<string> | null>(null)\n const [preSearchExpandedSections, setPreSearchExpandedSections] = useState<Set<string> | null>(null)\n\n // Auto-switch to diagram view when expanded (only if schema diagram is enabled)\n React.useEffect(() => {\n if (isExpanded && showSchemaDiagram) {\n setViewType('diagram')\n }\n }, [isExpanded, showSchemaDiagram])\n\n\n // Auto-expand cubes and sections that contain search matches\n React.useEffect(() => {\n if (!schema) {\n return\n }\n\n const hasSearchTerm = searchTerm.trim().length > 0\n\n if (hasSearchTerm) {\n // Save current state before expanding for search (only if not already saved)\n if (preSearchExpandedCubes === null) {\n setPreSearchExpandedCubes(new Set(expandedCubes))\n setPreSearchExpandedSections(new Set(expandedSections))\n }\n\n const newExpandedCubes = new Set<string>()\n const newExpandedSections = new Set<string>()\n\n schema.cubes.forEach((cube: MetaCube) => {\n let cubeHasMatches = false\n\n // Check measures\n const matchingMeasures = cube.measures.filter(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n if (matchingMeasures.length > 0) {\n cubeHasMatches = true\n newExpandedSections.add(`${cube.name}-measures`)\n }\n\n // Check regular dimensions\n const regularDimensions = cube.dimensions.filter(d => d.type !== 'time')\n const matchingDimensions = regularDimensions.filter(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n if (matchingDimensions.length > 0) {\n cubeHasMatches = true\n newExpandedSections.add(`${cube.name}-dimensions`)\n }\n\n // Check time dimensions\n const timeDimensions = cube.dimensions.filter(d => d.type === 'time')\n const matchingTimeDimensions = timeDimensions.filter(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n if (matchingTimeDimensions.length > 0) {\n cubeHasMatches = true\n newExpandedSections.add(`${cube.name}-timeDimensions`)\n }\n\n // If cube has any matches, expand it\n if (cubeHasMatches) {\n newExpandedCubes.add(cube.name)\n }\n })\n\n // Combine pre-search state with search expansions\n const combinedCubes = new Set([...(preSearchExpandedCubes || []), ...newExpandedCubes])\n const combinedSections = new Set([...(preSearchExpandedSections || []), ...newExpandedSections])\n \n setExpandedCubes(combinedCubes)\n setExpandedSections(combinedSections)\n } else {\n // No search term - restore original state if we have it saved\n if (preSearchExpandedCubes !== null && preSearchExpandedSections !== null) {\n setExpandedCubes(preSearchExpandedCubes)\n setExpandedSections(preSearchExpandedSections)\n setPreSearchExpandedCubes(null)\n setPreSearchExpandedSections(null)\n }\n }\n }, [schema, searchTerm, preSearchExpandedCubes, preSearchExpandedSections])\n\n // Loading state\n if (schemaStatus === 'loading') {\n return (\n <div className=\"h-full flex items-center justify-center text-dc-text-muted\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 mx-auto mb-3\" style={{ borderBottomColor: 'var(--dc-primary)' }}></div>\n <div className=\"text-sm font-semibold mb-1\">Loading Schema...</div>\n <div className=\"text-xs\">Fetching cube metadata</div>\n </div>\n </div>\n )\n }\n\n // Error state\n if (schemaStatus === 'error') {\n const isCorsError = schemaError?.toLowerCase().includes('cors') || \n schemaError?.toLowerCase().includes('fetch')\n \n return (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center max-w-sm p-6\">\n <WarningIcon className=\"w-12 h-12 mx-auto text-dc-error mb-4\" />\n <div className=\"text-sm font-semibold text-dc-text mb-2\">\n Failed to Load Schema\n </div>\n <div className=\"text-xs text-dc-text-secondary mb-4\">\n {isCorsError ? (\n <>\n CORS error detected. The API endpoint may be incorrect or not accessible.\n </>\n ) : (\n <>\n {schemaError || 'Unable to connect to the Cube.js API'}\n </>\n )}\n </div>\n \n <div className=\"space-y-2\">\n {onRetrySchema && (\n <button\n onClick={onRetrySchema}\n className=\"w-full flex items-center justify-center space-x-2 px-3 py-2 text-sm font-medium text-dc-accent bg-dc-accent-bg border border-dc-accent rounded-md hover:bg-dc-accent-bg focus:outline-hidden focus:ring-2 focus:ring-dc-accent\"\n >\n <RefreshIcon className=\"w-4 h-4\" />\n <span>Retry</span>\n </button>\n )}\n\n {onOpenSettings && (\n <button\n onClick={onOpenSettings}\n className=\"w-full flex items-center justify-center space-x-2 px-3 py-2 text-sm font-medium text-dc-text-secondary bg-dc-surface border border-dc-border rounded-md hover:bg-dc-surface-hover focus:outline-hidden focus:ring-2 focus:ring-dc-accent\"\n >\n <SettingsIcon className=\"w-4 h-4\" />\n <span>Check API Settings</span>\n </button>\n )}\n </div>\n \n {isCorsError && (\n <div className=\"mt-4 p-3 bg-dc-warning-bg border border-dc-warning rounded-md\">\n <div className=\"text-xs text-dc-warning\">\n <div className=\"font-medium mb-1\">Common solutions:</div>\n <ul className=\"list-disc list-inside space-y-1\">\n <li>Verify the Base API URL is correct</li>\n <li>Ensure the server supports CORS</li>\n <li>Check if authentication is required</li>\n </ul>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // No schema loaded yet\n if (!schema) {\n return (\n <div className=\"h-full flex items-center justify-center text-dc-text-muted\">\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">No Schema</div>\n <div className=\"text-xs\">Schema not loaded</div>\n </div>\n </div>\n )\n }\n\n const toggleCubeExpansion = (cubeName: string) => {\n const newExpanded = new Set(expandedCubes)\n if (newExpanded.has(cubeName)) {\n newExpanded.delete(cubeName)\n } else {\n newExpanded.add(cubeName)\n }\n setExpandedCubes(newExpanded)\n \n // If we're in search mode, also update the pre-search state\n if (preSearchExpandedCubes !== null) {\n const newPreSearchExpanded = new Set(preSearchExpandedCubes)\n if (newPreSearchExpanded.has(cubeName)) {\n newPreSearchExpanded.delete(cubeName)\n } else {\n newPreSearchExpanded.add(cubeName)\n }\n setPreSearchExpandedCubes(newPreSearchExpanded)\n }\n }\n\n const toggleSectionExpansion = (sectionKey: string) => {\n const newExpanded = new Set(expandedSections)\n if (newExpanded.has(sectionKey)) {\n newExpanded.delete(sectionKey)\n } else {\n newExpanded.add(sectionKey)\n }\n setExpandedSections(newExpanded)\n \n // If we're in search mode, also update the pre-search state\n if (preSearchExpandedSections !== null) {\n const newPreSearchExpanded = new Set(preSearchExpandedSections)\n if (newPreSearchExpanded.has(sectionKey)) {\n newPreSearchExpanded.delete(sectionKey)\n } else {\n newPreSearchExpanded.add(sectionKey)\n }\n setPreSearchExpandedSections(newPreSearchExpanded)\n }\n }\n\n const handleFieldClick = (field: MetaField, fieldType: 'measures' | 'dimensions' | 'timeDimensions') => {\n const isSelected = (() => {\n switch (fieldType) {\n case 'measures':\n return selectedFields.measures.includes(field.name)\n case 'dimensions':\n return selectedFields.dimensions.includes(field.name)\n case 'timeDimensions':\n return selectedFields.timeDimensions.includes(field.name)\n default:\n return false\n }\n })()\n\n if (isSelected) {\n onFieldDeselect(field.name, fieldType)\n } else {\n onFieldSelect(field.name, fieldType)\n }\n }\n\n const filterFields = (fields: MetaField[]): MetaField[] => {\n if (!searchTerm) return fields\n return fields.filter(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n }\n\n const cubeHasMatches = (cube: MetaCube): boolean => {\n if (!searchTerm.trim()) return true\n \n const measureMatches = cube.measures.some(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n \n const dimensionMatches = cube.dimensions.some(field => \n field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n field.title.toLowerCase().includes(searchTerm.toLowerCase())\n )\n \n return measureMatches || dimensionMatches\n }\n\n const FieldItem: React.FC<{ \n field: MetaField\n fieldType: 'measures' | 'dimensions' | 'timeDimensions'\n icon: React.ReactNode\n }> = ({ field, fieldType, icon }) => {\n const isSelected = (() => {\n switch (fieldType) {\n case 'measures':\n return selectedFields.measures.includes(field.name)\n case 'dimensions':\n return selectedFields.dimensions.includes(field.name)\n case 'timeDimensions':\n return selectedFields.timeDimensions.includes(field.name)\n default:\n return false\n }\n })()\n\n const getSelectedStyles = () => {\n if (!isSelected) return 'hover:bg-dc-surface-hover text-dc-text-secondary'\n\n switch (fieldType) {\n case 'measures':\n return 'bg-dc-warning-bg text-dc-warning border border-dc-warning'\n case 'dimensions':\n return 'bg-dc-success-bg text-dc-success border border-dc-success'\n case 'timeDimensions':\n return 'bg-dc-accent-bg text-dc-accent border border-dc-accent'\n default:\n return 'bg-dc-accent-bg text-dc-accent border border-dc-accent'\n }\n }\n\n const getIconColor = () => {\n if (!isSelected) return 'text-dc-text-muted'\n \n switch (fieldType) {\n case 'measures':\n return 'text-dc-warning'\n case 'dimensions':\n return 'text-dc-success'\n case 'timeDimensions':\n return 'text-dc-accent'\n default:\n return 'text-dc-accent'\n }\n }\n\n const getCheckmarkColor = () => {\n switch (fieldType) {\n case 'measures':\n return 'text-dc-warning'\n case 'dimensions':\n return 'text-dc-success'\n case 'timeDimensions':\n return 'text-dc-accent'\n default:\n return 'text-dc-accent'\n }\n }\n\n return (\n <div\n className={`flex items-center px-2 py-1.5 text-xs cursor-pointer rounded-md transition-colors ${getSelectedStyles()}`}\n onClick={() => handleFieldClick(field, fieldType)}\n title={field.description || field.title}\n >\n <div className={`mr-1.5 ${getIconColor()}`}>\n {React.cloneElement(icon as React.ReactElement, { className: 'w-4 h-4' })}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium truncate text-xs\">{field.shortTitle}</div>\n <div className=\"text-xs text-dc-text-muted truncate\">{field.name}</div>\n </div>\n {isSelected && (\n <div className={`ml-1.5 ${getCheckmarkColor()}`}>\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n )}\n </div>\n )\n }\n\n const SectionHeader: React.FC<{\n title: string\n count: number\n sectionKey: string\n icon: React.ReactNode\n }> = ({ title, count, sectionKey, icon }) => {\n const isExpanded = expandedSections.has(sectionKey)\n \n // Get section type from sectionKey to apply consistent colors\n const getSectionType = (): 'dimensions' | 'timeDimensions' | 'measures' => {\n if (sectionKey.includes('-dimensions') && !sectionKey.includes('-timeDimensions')) {\n return 'dimensions'\n } else if (sectionKey.includes('-timeDimensions')) {\n return 'timeDimensions'\n } else {\n return 'measures'\n }\n }\n \n const getSectionColorClasses = () => {\n const sectionType = getSectionType()\n switch (sectionType) {\n case 'dimensions':\n return 'text-dc-success'\n case 'timeDimensions':\n return 'text-dc-accent'\n case 'measures':\n return 'text-dc-warning'\n default:\n return 'text-dc-text-secondary'\n }\n }\n \n return (\n <div\n className={`flex items-center px-2 py-1 text-sm font-semibold cursor-pointer hover:bg-dc-surface-hover rounded-md ${getSectionColorClasses()}`}\n onClick={() => toggleSectionExpansion(sectionKey)}\n >\n <div className=\"mr-1.5\">\n {isExpanded ? (\n <ChevronDownIcon className=\"w-3 h-3\" />\n ) : (\n <ChevronRightIcon className=\"w-3 h-3\" />\n )}\n </div>\n <div className=\"mr-1.5\">\n {icon}\n </div>\n <span className=\"flex-1\">{title}</span>\n <span className=\"text-xs text-dc-text-muted bg-dc-surface-secondary px-1.5 py-0.5 rounded-full\">\n {count}\n </span>\n </div>\n )\n }\n\n const NoMatchesMessage: React.FC = () => (\n <div className=\"flex items-center justify-center py-8 text-center\">\n <div className=\"max-w-sm\">\n <div className=\"text-dc-text-muted mb-2\">\n <svg className=\"w-12 h-12 mx-auto\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n </div>\n <div className=\"text-sm font-medium text-dc-text mb-1\">No matches found</div>\n <div className=\"text-xs text-dc-text-muted mb-3\">\n No fields match your search term \"{searchTerm}\"\n </div>\n <button\n onClick={() => setSearchTerm('')}\n className=\"inline-flex items-center px-3 py-1.5 text-xs font-medium text-dc-accent bg-dc-accent-bg border border-dc-accent rounded-md hover:bg-dc-accent-bg focus:outline-hidden focus:ring-2 focus:ring-dc-accent\"\n >\n Clear search\n </button>\n </div>\n </div>\n )\n\n return (\n <div className=\"flex-1 flex flex-col bg-dc-surface border border-dc-border rounded-lg min-h-0\">\n {/* Header */}\n <div className=\"border-b border-dc-border\">\n <div className=\"p-3 pb-0\">\n <div className=\"flex items-center justify-between mb-3\">\n <div>\n <h3 className=\"text-base font-semibold text-dc-text\">\n {viewType === 'diagram' ? 'Schema Diagram' : 'Schema Explorer'}\n </h3>\n </div>\n <div className=\"flex items-center space-x-2\">\n {onOpenSettings && (\n <button\n onClick={onOpenSettings}\n className=\"p-1 text-dc-text-muted hover:text-dc-text-secondary transition-colors\"\n title=\"Open settings\"\n >\n <SettingsIcon className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </div>\n\n {/* View Type Tabs and Search */}\n <div className=\"flex items-center gap-3 mb-3\">\n {showSchemaDiagram ? (\n <div className=\"flex space-x-1 bg-dc-surface-secondary p-1 rounded-md\">\n <button\n onClick={() => {\n setViewType('tree')\n onViewTypeChange?.('tree')\n }}\n className={`\n flex items-center px-3 py-1.5 rounded text-xs font-medium transition-colors\n ${viewType === 'tree'\n ? 'bg-dc-surface text-dc-text shadow-xs'\n : 'text-dc-text-secondary hover:text-dc-text'\n }\n `}\n >\n <MenuIcon className=\"w-3 h-3 mr-1.5\" />\n Fields\n </button>\n <button\n onClick={() => {\n setViewType('diagram')\n onViewTypeChange?.('diagram')\n }}\n className={`\n flex items-center px-3 py-1.5 rounded text-xs font-medium transition-colors\n ${viewType === 'diagram'\n ? 'bg-dc-surface text-dc-text shadow-xs'\n : 'text-dc-text-secondary hover:text-dc-text'\n }\n `}\n >\n <SegmentIcon className=\"w-3 h-3 mr-1.5\" />\n Schema\n </button>\n </div>\n ) : null}\n\n {/* Search input - visible for both views */}\n <div className=\"flex-1 relative min-w-0\">\n <input\n type=\"text\"\n placeholder=\"Search fields...\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n className=\"w-full px-2 py-1.5 border border-dc-border rounded-md text-sm bg-dc-surface text-dc-text focus:ring-2 focus:ring-dc-accent focus:border-dc-accent\"\n />\n <div className=\"absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none\">\n <svg className=\"h-4 w-4 text-dc-text-muted\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n </div>\n </div>\n </div>\n </div>\n\n </div>\n\n {/* Content */}\n <div className=\"flex-1 min-h-0 overflow-hidden\">\n {viewType === 'diagram' && showSchemaDiagram ? (\n /* Diagram View - schema relationship diagram (only when enabled) */\n <div className=\"h-full\">\n <Suspense fallback={\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"animate-pulse text-dc-text-muted\">Loading diagram...</div>\n </div>\n }>\n <CubeRelationshipDiagram\n className=\"h-full\"\n onCubeClick={(cubeName) => {\n if (!isExpanded) {\n // Auto-expand the clicked cube in tree view\n setExpandedCubes(prev => new Set([...prev, cubeName]))\n // Switch to tree view to show the expanded cube\n setViewType('tree')\n }\n }}\n onFieldClick={(cubeName, fieldName, fieldType) => {\n // Convert field type to QueryBuilder expected type and determine if time dimension\n let qbFieldType: 'measures' | 'dimensions' | 'timeDimensions'\n \n if (fieldType === 'measure') {\n qbFieldType = 'measures'\n } else {\n // For dimensions, check if it's a time dimension by looking at the schema\n const cube = schema?.cubes.find(c => c.name === cubeName)\n const dimension = cube?.dimensions.find(d => \n d.name === `${cubeName}.${fieldName}` || d.name === fieldName\n )\n \n qbFieldType = dimension?.type === 'time' ? 'timeDimensions' : 'dimensions'\n }\n \n const fullFieldName = `${cubeName}.${fieldName}`\n \n // Check if field is already selected\n const isSelected = selectedFields[qbFieldType].includes(fullFieldName)\n \n if (isSelected) {\n // Remove the field from the query\n onFieldDeselect(fullFieldName, qbFieldType)\n } else {\n // Add the field to the query\n onFieldSelect(fullFieldName, qbFieldType)\n }\n }}\n highlightedCubes={[\n ...selectedFields.measures.map(field => field.split('.')[0]),\n ...selectedFields.dimensions.map(field => field.split('.')[0]),\n ...selectedFields.timeDimensions.map(field => field.split('.')[0])\n ].filter((cube, index, arr) => arr.indexOf(cube) === index)} // Remove duplicates\n highlightedFields={[\n ...selectedFields.measures,\n ...selectedFields.dimensions,\n ...selectedFields.timeDimensions\n ]}\n searchTerm={searchTerm}\n />\n </Suspense>\n </div>\n ) : (\n /* Tree View - existing field list */\n <div className=\"h-full p-3 space-y-2 overflow-y-auto\">\n {(() => {\n // Filter cubes to only show those with matches (when searching)\n const filteredCubes = schema.cubes.filter(cubeHasMatches)\n \n // Show \"No matches\" message if searching but no cubes have matches\n if (searchTerm.trim() && filteredCubes.length === 0) {\n return <NoMatchesMessage />\n }\n \n return filteredCubes.map((cube: MetaCube) => {\n const isExpanded = expandedCubes.has(cube.name)\n const timeDimensions = cube.dimensions.filter(d => d.type === 'time')\n const regularDimensions = cube.dimensions.filter(d => d.type !== 'time')\n\n return (\n <div key={cube.name} className=\"border border-dc-border rounded-lg\">\n {/* Cube Header */}\n <div\n className=\"flex items-center px-3 py-2 cursor-pointer hover:bg-dc-surface-hover rounded-t-lg\"\n onClick={() => toggleCubeExpansion(cube.name)}\n >\n <div className=\"mr-2\">\n {isExpanded ? (\n <ChevronDownIcon className=\"w-4 h-4 text-dc-text-secondary\" />\n ) : (\n <ChevronRightIcon className=\"w-4 h-4 text-dc-text-secondary\" />\n )}\n </div>\n <div className=\"flex-1\">\n <div className=\"font-medium text-sm text-dc-text\">{cube.title}</div>\n <div className=\"text-xs text-dc-text-muted\">{cube.description}</div>\n </div>\n </div>\n\n {/* Cube Content */}\n {isExpanded && (\n <div className=\"border-t border-dc-border p-2 space-y-1\">\n {/* Dimensions - First (matching QueryPanel order) */}\n {regularDimensions.length > 0 && filterFields(regularDimensions).length > 0 && (\n <div>\n <SectionHeader\n title=\"Dimensions\"\n count={filterFields(regularDimensions).length}\n sectionKey={`${cube.name}-dimensions`}\n icon={<DimensionIcon className=\"w-4 h-4 text-dc-success\" />}\n />\n {expandedSections.has(`${cube.name}-dimensions`) && (\n <div className=\"ml-5 space-y-1 mt-1\">\n {filterFields(regularDimensions).map(dimension => (\n <FieldItem\n key={dimension.name}\n field={dimension}\n fieldType=\"dimensions\"\n icon={<DimensionIcon className=\"w-4 h-4\" />}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* Time Dimensions - Second (matching QueryPanel order) */}\n {timeDimensions.length > 0 && filterFields(timeDimensions).length > 0 && (\n <div>\n <SectionHeader\n title=\"Time Dimensions\"\n count={filterFields(timeDimensions).length}\n sectionKey={`${cube.name}-timeDimensions`}\n icon={<TimeDimensionIcon className=\"w-4 h-4 text-dc-accent\" />}\n />\n {expandedSections.has(`${cube.name}-timeDimensions`) && (\n <div className=\"ml-5 space-y-1 mt-1\">\n {filterFields(timeDimensions).map(timeDimension => (\n <FieldItem\n key={timeDimension.name}\n field={timeDimension}\n fieldType=\"timeDimensions\"\n icon={<TimeDimensionIcon className=\"w-4 h-4\" />}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* Measures - Third (matching QueryPanel order) */}\n {cube.measures.length > 0 && filterFields(cube.measures).length > 0 && (\n <div>\n <SectionHeader\n title=\"Measures\"\n count={filterFields(cube.measures).length}\n sectionKey={`${cube.name}-measures`}\n icon={<MeasureIcon className=\"w-4 h-4 text-dc-warning\" />}\n />\n {expandedSections.has(`${cube.name}-measures`) && (\n <div className=\"ml-5 space-y-1 mt-1\">\n {filterFields(cube.measures).map(measure => (\n <FieldItem\n key={measure.name}\n field={measure}\n fieldType=\"measures\"\n icon={getMeasureIcon(measure.type, 'w-4 h-4')}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n )\n })\n })()}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default memo(CubeMetaExplorer)\n","/**\n * FilterEditModal Component\n *\n * Modal for editing dashboard filter details including label, field, operator, and values\n *\n * Pattern: Self-contained modal with local state (matches PortletEditModal pattern)\n * - All editing state is local to the modal\n * - Changes only propagate on \"Done\" button click via onSave callback\n * - Cancel/close resets local state without saving\n */\n\nimport React, { useState, useCallback, useMemo, useEffect } from 'react'\nimport { getIcon } from '../../icons'\nimport FilterBuilder from '../shared/FilterBuilder'\n\nconst CloseIcon = getIcon('close')\nconst EyeIcon = getIcon('eye')\nconst EyeOffIcon = getIcon('eyeOff')\nimport DateRangeSelector from '../shared/DateRangeSelector'\nimport CubeMetaExplorer from '../shared/CubeMetaExplorer'\nimport { extractDashboardFields } from '../../utils/filterUtils'\nimport type { DashboardFilter, CubeMeta, Filter, DashboardConfig, SimpleFilter } from '../../types'\nimport type { MetaResponse } from '../../shared/types'\n\ninterface FilterEditModalProps {\n filter: DashboardFilter\n schema: CubeMeta | null\n dashboardConfig: DashboardConfig\n isOpen: boolean\n onSave: (filter: DashboardFilter) => void | Promise<void>\n onClose: () => void\n onDelete: () => void\n convertToMetaResponse: (cubeMeta: CubeMeta | null) => MetaResponse | null\n}\n\nconst FilterEditModal: React.FC<FilterEditModalProps> = ({\n filter,\n schema,\n dashboardConfig,\n isOpen,\n onSave,\n onClose,\n onDelete,\n convertToMetaResponse\n}) => {\n // Local state for editing - all changes stay local until \"Done\"\n const [localLabel, setLocalLabel] = useState(filter.label)\n const [localFilter, setLocalFilter] = useState(filter.filter)\n const [showAllFields, setShowAllFields] = useState(false)\n\n // Sync local state when filter prop changes or modal opens\n useEffect(() => {\n if (isOpen) {\n setLocalLabel(filter.label)\n setLocalFilter(filter.filter)\n }\n }, [filter, isOpen])\n\n // Extract fields used in dashboard\n const dashboardFields = useMemo(() => {\n return extractDashboardFields(dashboardConfig)\n }, [dashboardConfig])\n\n // Create filtered schema showing only dashboard fields\n const filteredSchema = useMemo<MetaResponse | null>(() => {\n if (!schema) return null\n\n if (showAllFields) {\n return convertToMetaResponse(schema)\n }\n\n const filteredCubes = schema.cubes\n .map(cube => {\n const cubeName = cube.name\n\n const filteredMeasures = cube.measures.filter(measure => {\n const fullName = measure.name.includes('.')\n ? measure.name\n : `${cubeName}.${measure.name}`\n return dashboardFields.measures.has(fullName)\n })\n\n const filteredDimensions = cube.dimensions.filter(dimension => {\n const fullName = dimension.name.includes('.')\n ? dimension.name\n : `${cubeName}.${dimension.name}`\n return dashboardFields.dimensions.has(fullName) ||\n dashboardFields.timeDimensions.has(fullName)\n })\n\n if (filteredMeasures.length > 0 || filteredDimensions.length > 0) {\n return {\n ...cube,\n measures: filteredMeasures,\n dimensions: filteredDimensions\n }\n }\n\n return null\n })\n .filter((cube): cube is NonNullable<typeof cube> => cube !== null)\n\n const filteredCubeMeta: CubeMeta = {\n ...schema,\n cubes: filteredCubes\n }\n\n return convertToMetaResponse(filteredCubeMeta)\n }, [schema, dashboardFields, showAllFields, convertToMetaResponse])\n\n // Extract the currently selected field to highlight it in the schema\n const selectedFieldInFilter = useMemo(() => {\n if ('member' in localFilter && localFilter.member) {\n return localFilter.member\n }\n return null\n }, [localFilter])\n\n // Handle label change - updates local state only\n const handleLabelChange = useCallback((newLabel: string) => {\n setLocalLabel(newLabel)\n }, [])\n\n // Handle filter changes from FilterBuilder - updates local state only\n const handleFilterBuilderChange = useCallback((filters: Filter[]) => {\n setLocalFilter(filters[0] || localFilter)\n }, [localFilter])\n\n // Handle field selection from schema explorer - updates local state only\n const handleFieldSelect = useCallback((fieldName: string) => {\n if ('member' in localFilter) {\n setLocalFilter({\n ...localFilter,\n member: fieldName,\n values: [] // Reset values when changing field\n })\n }\n }, [localFilter])\n\n // Handle date range change for universal time filters\n const handleDateRangeChange = useCallback((_timeDim: string, dateRange: string | string[]) => {\n if ('member' in localFilter) {\n setLocalFilter({\n ...localFilter,\n values: Array.isArray(dateRange) ? dateRange : [dateRange]\n } as SimpleFilter)\n }\n }, [localFilter])\n\n // Validate filter before saving\n const validateFilter = useCallback((): { isValid: boolean; message?: string } => {\n if (!localLabel.trim()) {\n return { isValid: false, message: 'Filter label is required' }\n }\n\n // Skip member validation for universal time filters (member is placeholder)\n if (!filter.isUniversalTime && 'member' in localFilter && !localFilter.member) {\n return { isValid: false, message: 'Please select a field for the filter' }\n }\n\n return { isValid: true }\n }, [localLabel, localFilter, filter.isUniversalTime])\n\n // Handle save - validate then call onSave with complete filter data\n const handleSave = useCallback(async () => {\n const validation = validateFilter()\n if (!validation.isValid) {\n alert(validation.message)\n return\n }\n\n const updatedFilter: DashboardFilter = {\n id: filter.id,\n label: localLabel,\n filter: localFilter,\n // Preserve isUniversalTime flag if present\n ...(filter.isUniversalTime && { isUniversalTime: true })\n }\n\n try {\n await onSave(updatedFilter)\n onClose()\n } catch (error) {\n console.error('Failed to save filter:', error)\n alert('Failed to save filter. Please try again.')\n }\n }, [filter.id, filter.isUniversalTime, localLabel, localFilter, validateFilter, onSave, onClose])\n\n // Handle cancel/close - reset local state\n const handleCancel = useCallback(() => {\n setLocalLabel(filter.label)\n setLocalFilter(filter.filter)\n onClose()\n }, [filter, onClose])\n\n return (\n <div\n className=\"fixed inset-0 z-50 backdrop-blur-md flex items-center justify-center p-2\"\n style={{ backgroundColor: 'var(--dc-overlay)' }}\n >\n <div\n className=\"rounded-lg max-w-7xl w-full h-[95vh] overflow-hidden flex flex-col bg-dc-surface border border-dc-border\"\n style={{ boxShadow: 'var(--dc-shadow-2xl)' }}\n >\n {/* Modal Header */}\n <div className=\"px-6 py-4 border-b border-dc-border flex items-center justify-between\">\n <div className=\"flex-1\">\n <label className=\"block text-sm font-medium mb-2 text-dc-text\">\n Filter Label\n </label>\n <input\n type=\"text\"\n value={localLabel}\n onChange={(e) => handleLabelChange(e.target.value)}\n className=\"w-full px-3 py-2 border border-dc-border rounded-md text-sm bg-dc-surface-secondary text-dc-text\"\n placeholder=\"Enter filter label\"\n />\n </div>\n <button\n onClick={handleCancel}\n className=\"ml-4 p-2 hover:bg-dc-surface-hover rounded-md transition-colors text-dc-text-secondary\"\n >\n <CloseIcon className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* Modal Body - Two Column Layout (or single column for universal time filters) */}\n <div className=\"flex-1 flex\">\n {/* Left Column - Schema Explorer (hidden for universal time filters) */}\n {!filter.isUniversalTime && (\n <div className=\"w-80 border-r border-dc-border bg-dc-surface overflow-auto\">\n <div className=\"p-4\">\n <div className=\"flex items-center justify-between mb-3\">\n <h3 className=\"text-sm font-semibold text-dc-text\">\n Available Fields\n </h3>\n <button\n onClick={() => setShowAllFields(!showAllFields)}\n className=\"flex items-center gap-1 text-xs px-2 py-1 rounded hover:bg-dc-surface-hover text-dc-text-muted\"\n title={showAllFields ? 'Show dashboard fields only' : 'Show all fields'}\n >\n {showAllFields ? (\n <>\n <EyeOffIcon className=\"w-3.5 h-3.5\" />\n <span>Dashboard</span>\n </>\n ) : (\n <>\n <EyeIcon className=\"w-3.5 h-3.5\" />\n <span>All</span>\n </>\n )}\n </button>\n </div>\n\n {!showAllFields && (\n <div className=\"text-xs text-dc-info mb-3 p-2 bg-dc-info-bg rounded border border-dc-info-border\">\n Showing only fields used in this dashboard\n </div>\n )}\n\n {filteredSchema && filteredSchema.cubes.length > 0 ? (\n <CubeMetaExplorer\n schema={filteredSchema}\n schemaStatus=\"success\"\n schemaError={null}\n selectedFields={{\n measures: selectedFieldInFilter ? [selectedFieldInFilter] : [],\n dimensions: selectedFieldInFilter ? [selectedFieldInFilter] : [],\n timeDimensions: selectedFieldInFilter ? [selectedFieldInFilter] : []\n }}\n onFieldSelect={(fieldName) => handleFieldSelect(fieldName)}\n onFieldDeselect={() => {}}\n />\n ) : (\n <div className=\"text-center py-8 text-dc-text-muted text-sm\">\n {showAllFields ? (\n <div>\n <p className=\"mb-2\">No schema available</p>\n <p className=\"text-xs\">Check your API connection</p>\n </div>\n ) : (\n <div>\n <p className=\"mb-2\">No fields used in dashboard</p>\n <p className=\"text-xs\">Add portlets to the dashboard first, or toggle to show all fields</p>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Right Column - Filter Builder or Date Range Selector */}\n <div className=\"flex-1 overflow-auto px-6 py-4 bg-dc-surface-secondary\">\n {filter.isUniversalTime ? (\n /* Universal time filter - show DateRangeSelector */\n <div>\n <div className=\"mb-4 p-3 rounded-md bg-dc-info-bg border border-dc-info-border\">\n <div className=\"text-sm font-medium text-dc-info mb-1\">\n Universal Time Filter\n </div>\n <div className=\"text-xs text-dc-text-secondary\">\n This filter applies to all time dimensions in portlets it&apos;s mapped to.\n Select a date range below to filter data across all time-based charts.\n </div>\n </div>\n <div className=\"mt-4\">\n <DateRangeSelector\n timeDimension=\"__universal_time__\"\n availableTimeDimensions={['__universal_time__']}\n currentDateRange={(() => {\n // Handle both dateRange property and values array\n const simpleFilter = localFilter as SimpleFilter\n if (simpleFilter.dateRange) return simpleFilter.dateRange\n if (simpleFilter.values) {\n // Single string value (preset like \"last 30 days\") - pass as string\n if (Array.isArray(simpleFilter.values) && simpleFilter.values.length === 1 && typeof simpleFilter.values[0] === 'string') {\n return simpleFilter.values[0]\n }\n return simpleFilter.values\n }\n return undefined\n })()}\n onDateRangeChange={handleDateRangeChange}\n onTimeDimensionChange={() => {}}\n onRemove={() => {}}\n hideFieldSelector={true}\n hideRemoveButton={true}\n />\n </div>\n </div>\n ) : (\n /* Regular filter - show FilterBuilder */\n <FilterBuilder\n filters={[localFilter]}\n schema={convertToMetaResponse(schema)}\n query={{}} // Empty query object - not needed for standalone filter editing\n onFiltersChange={handleFilterBuilderChange}\n />\n )}\n </div>\n </div>\n\n {/* Modal Footer */}\n <div className=\"px-6 py-4 border-t border-dc-border flex items-center justify-between bg-dc-surface\">\n <button\n onClick={onDelete}\n className=\"px-4 py-2 text-sm font-medium text-dc-danger hover:bg-dc-danger-bg rounded-md transition-colors\"\n >\n Delete Filter\n </button>\n <button\n onClick={handleSave}\n className=\"px-4 py-2 text-sm font-medium rounded-md transition-colors bg-dc-primary hover:bg-dc-primary-hover text-dc-primary-content\"\n >\n Done\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default FilterEditModal\n","/**\n * ReadOnlyFilterList Component\n *\n * Displays filters in read-only mode with interactive value selectors\n */\n\nimport React, { useCallback } from 'react'\nimport { getIcon } from '../../icons'\nimport FilterItem from '../shared/FilterItem'\n\nconst FilterIcon = getIcon('filter')\nconst ClockIcon = getIcon('timeDimension')\nimport DateRangeSelector from '../shared/DateRangeSelector'\nimport type { DashboardFilter, CubeMeta, SimpleFilter } from '../../types'\nimport type { MetaResponse } from '../../shared/types'\n\ninterface ReadOnlyFilterListProps {\n dashboardFilters: DashboardFilter[]\n schema: CubeMeta | null\n onFilterChange: (filterId: string, updatedFilter: DashboardFilter) => void\n onDateRangeChange: (filterId: string, dateRange: string | string[]) => void\n convertToMetaResponse: (cubeMeta: CubeMeta | null) => MetaResponse | null\n isTimeDimensionField: (fieldName: string) => boolean\n}\n\nconst ReadOnlyFilterList: React.FC<ReadOnlyFilterListProps> = ({\n dashboardFilters,\n schema,\n onFilterChange,\n onDateRangeChange,\n convertToMetaResponse,\n isTimeDimensionField\n}) => {\n // Render individual read-only filter\n const renderReadOnlyFilter = useCallback((dashboardFilter: DashboardFilter) => {\n const { id, label, filter, isUniversalTime } = dashboardFilter\n\n // Only render SimpleFilter in read-only mode (skip GroupFilters for now)\n if (!('member' in filter)) {\n return null\n }\n\n const simpleFilter = filter as SimpleFilter\n const isTimeDim = isTimeDimensionField(simpleFilter.member)\n\n // For universal time filters OR time dimensions with inDateRange, use DateRangeSelector\n if (isUniversalTime || (isTimeDim && simpleFilter.operator === 'inDateRange')) {\n // Get date range - handle both dateRange property and values array\n // If values is a single-element array with a preset string, use that string directly\n let dateRangeValue: string | string[] | undefined = simpleFilter.dateRange\n if (!dateRangeValue && simpleFilter.values) {\n if (Array.isArray(simpleFilter.values) && simpleFilter.values.length === 1 && typeof simpleFilter.values[0] === 'string') {\n // Single string value (preset like \"last 30 days\") - pass as string\n dateRangeValue = simpleFilter.values[0]\n } else {\n dateRangeValue = simpleFilter.values\n }\n }\n\n return (\n <div key={id} className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center gap-1.5 px-1\">\n {isUniversalTime && (\n <ClockIcon className=\"w-3.5 h-3.5 shrink-0\" style={{ color: 'var(--dc-primary)' }} />\n )}\n <label\n className=\"text-xs font-semibold uppercase tracking-wide truncate\"\n style={{ color: 'var(--dc-text-secondary)' }}\n title={isUniversalTime ? `${label} (applies to all time dimensions)` : label}\n >\n {label}\n </label>\n </div>\n <DateRangeSelector\n timeDimension={isUniversalTime ? '__universal_time__' : simpleFilter.member}\n availableTimeDimensions={isUniversalTime ? ['__universal_time__'] : [simpleFilter.member]}\n currentDateRange={dateRangeValue}\n onDateRangeChange={(_timeDim, dateRange) => onDateRangeChange(id, dateRange)}\n onTimeDimensionChange={() => {}} // Not editable in read-only mode\n onRemove={() => {}} // Not removable in read-only mode\n hideFieldSelector={true}\n hideRemoveButton={true}\n />\n </div>\n )\n }\n\n // For regular filters, use FilterItem\n return (\n <div key={id} className=\"flex flex-col gap-1.5\">\n <label\n className=\"text-xs font-semibold uppercase tracking-wide truncate px-1\"\n style={{ color: 'var(--dc-text-secondary)' }}\n title={label}\n >\n {label}\n </label>\n <FilterItem\n filter={simpleFilter}\n index={0} // Not used in read-only mode\n onFilterChange={(_index, updatedFilter) => {\n onFilterChange(id, {\n ...dashboardFilter,\n filter: updatedFilter\n })\n }}\n onFilterRemove={() => {}} // Not removable in read-only mode\n schema={convertToMetaResponse(schema)}\n query={{}} // Empty query object for read-only mode\n hideFieldSelector={true}\n hideOperatorSelector={true}\n hideRemoveButton={true}\n />\n </div>\n )\n }, [schema, convertToMetaResponse, isTimeDimensionField, onFilterChange, onDateRangeChange])\n\n if (dashboardFilters.length === 0) {\n return null\n }\n\n return (\n <div className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2 mb-3\">\n <FilterIcon className=\"w-4 h-4 shrink-0\" style={{ color: 'var(--dc-primary)' }} />\n <h3 className=\"text-sm font-semibold\" style={{ color: 'var(--dc-text)' }}>\n Filters\n </h3>\n {dashboardFilters.length > 0 && (\n <span\n className=\"px-1.5 py-0.5 rounded-full text-xs font-medium\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n {dashboardFilters.length}\n </span>\n )}\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {dashboardFilters.map(renderReadOnlyFilter)}\n </div>\n </div>\n )\n}\n\nexport default ReadOnlyFilterList\n","/**\n * EditModeFilterList Component\n *\n * Displays filters in edit mode with chips showing filter labels and edit/delete actions\n */\n\nimport React from 'react'\nimport { getIcon } from '../../icons'\nimport type { DashboardFilter } from '../../types'\n\nconst FilterIcon = getIcon('filter')\nconst AddIcon = getIcon('add')\nconst CloseIcon = getIcon('close')\nconst EditIcon = getIcon('edit')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst ClockIcon = getIcon('timeDimension')\n\ninterface EditModeFilterListProps {\n dashboardFilters: DashboardFilter[]\n onAddFilter: () => void\n onAddTimeFilter: () => void\n onEditFilter: (filterId: string) => void\n onRemoveFilter: (filterId: string) => void\n selectedFilterId?: string | null\n onFilterSelect?: (filterId: string) => void\n}\n\nconst EditModeFilterList: React.FC<EditModeFilterListProps> = ({\n dashboardFilters,\n onAddFilter,\n onAddTimeFilter,\n onEditFilter,\n onRemoveFilter,\n selectedFilterId,\n onFilterSelect\n}) => {\n const [isCollapsed, setIsCollapsed] = React.useState(false)\n\n // Render compact filter chip - just label + edit + delete\n const renderFilterChip = (dashboardFilter: DashboardFilter) => {\n const { id, label, isUniversalTime } = dashboardFilter\n const isSelected = selectedFilterId === id\n\n // Use calendar icon for universal time filters, funnel for regular filters\n const IconComponent = isUniversalTime ? ClockIcon : FilterIcon\n\n return (\n <div\n key={id}\n className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md border text-xs transition-all ${\n 'cursor-pointer hover:shadow-md'\n }`}\n style={{\n backgroundColor: isSelected ? 'var(--dc-primary)' : 'var(--dc-surface)',\n borderColor: isSelected ? 'var(--dc-primary)' : 'var(--dc-border)',\n borderWidth: isSelected ? '2px' : '1px',\n color: isSelected ? 'white' : 'var(--dc-text)',\n boxShadow: isSelected ? '0 0 0 3px rgba(var(--dc-primary-rgb), 0.1)' : 'none'\n }}\n onClick={() => {\n if (onFilterSelect) {\n onFilterSelect(id)\n }\n }}\n >\n <IconComponent\n className=\"w-3.5 h-3.5 shrink-0\"\n style={{ color: isSelected ? 'white' : 'var(--dc-primary)' }}\n />\n <span className=\"font-medium truncate\">{label}</span>\n\n {!isSelected && (\n <div className=\"flex items-center gap-0.5 ml-1\" onClick={(e) => e.stopPropagation()}>\n <button\n onClick={() => onEditFilter(id)}\n className=\"p-0.5 hover:bg-dc-hover rounded transition-colors\"\n title=\"Edit filter\"\n >\n <EditIcon className=\"w-3 h-3\" />\n </button>\n <button\n onClick={() => onRemoveFilter(id)}\n className=\"p-0.5 hover:bg-dc-danger-bg hover:text-dc-danger rounded transition-colors\"\n title=\"Remove filter\"\n >\n <CloseIcon className=\"w-3 h-3\" />\n </button>\n </div>\n )}\n </div>\n )\n }\n\n return (\n <>\n {/* Mobile: Header + collapsible content */}\n <div className=\"md:hidden\">\n {/* Header - clickable to toggle */}\n <div\n className=\"px-4 py-2 flex items-center justify-between cursor-pointer\"\n onClick={() => setIsCollapsed(!isCollapsed)}\n >\n <div className=\"flex items-center gap-2\">\n <FilterIcon className=\"w-4 h-4 shrink-0\" style={{ color: 'var(--dc-primary)' }} />\n <h3 className=\"text-sm font-semibold\" style={{ color: 'var(--dc-text)' }}>\n Filters\n </h3>\n {dashboardFilters.length > 0 && (\n <span\n className=\"px-1.5 py-0.5 rounded-full text-xs font-medium\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n {dashboardFilters.length}\n </span>\n )}\n <ChevronDownIcon\n className={`w-4 h-4 transition-transform ${isCollapsed ? '' : 'rotate-180'}`}\n style={{ color: 'var(--dc-text-secondary)' }}\n />\n </div>\n\n <div className=\"flex items-center gap-1\">\n {/* Only show Date Range button if no universal time filter exists */}\n {!dashboardFilters.some(f => f.isUniversalTime) && (\n <button\n onClick={(e) => {\n e.stopPropagation()\n onAddTimeFilter()\n }}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors hover:opacity-80\"\n style={{\n backgroundColor: 'var(--dc-surface)',\n color: 'var(--dc-primary)',\n border: '1px solid var(--dc-border)'\n }}\n title=\"Add date range filter (applies to all time dimensions)\"\n >\n <AddIcon className=\"w-3.5 h-3.5\" />\n <ClockIcon className=\"w-3.5 h-3.5\" />\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation()\n onAddFilter()\n }}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors hover:opacity-80\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n <AddIcon className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n </div>\n\n {/* Mobile Filter Chips - Collapsible */}\n {dashboardFilters.length > 0 && !isCollapsed && (\n <div className=\"px-4 pb-2 flex flex-col gap-2\">\n {dashboardFilters.map(renderFilterChip)}\n </div>\n )}\n\n {/* Mobile Empty State */}\n {dashboardFilters.length === 0 && !isCollapsed && (\n <div className=\"px-4 pb-2\">\n <div\n className=\"text-xs p-2 rounded-md text-center\"\n style={{\n backgroundColor: 'var(--dc-surface-secondary)',\n color: 'var(--dc-text-secondary)'\n }}\n >\n No filters configured. Click \"Add\" to create one.\n </div>\n </div>\n )}\n </div>\n\n {/* Desktop: Single row layout */}\n <div className=\"hidden md:flex md:items-center md:gap-3 px-4 py-2\">\n {/* Header Section */}\n <div className=\"flex items-center gap-2 shrink-0\">\n <FilterIcon className=\"w-4 h-4 shrink-0\" style={{ color: 'var(--dc-primary)' }} />\n <h3 className=\"text-sm font-semibold whitespace-nowrap\" style={{ color: 'var(--dc-text)' }}>\n Filters\n </h3>\n {dashboardFilters.length > 0 && (\n <span\n className=\"px-1.5 py-0.5 rounded-full text-xs font-medium\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n {dashboardFilters.length}\n </span>\n )}\n </div>\n\n {/* Filter Chips Section - grows to fill space */}\n {dashboardFilters.length > 0 ? (\n <div className=\"flex flex-wrap gap-2 flex-1 min-w-0\">\n {dashboardFilters.map(renderFilterChip)}\n </div>\n ) : (\n <div className=\"flex-1 min-w-0\">\n <div\n className=\"text-xs px-3 py-1 rounded-md inline-block\"\n style={{\n backgroundColor: 'var(--dc-surface-secondary)',\n color: 'var(--dc-text-secondary)'\n }}\n >\n No filters configured. Click \"Add\" to create one.\n </div>\n </div>\n )}\n\n {/* Add Button Section */}\n <div className=\"flex items-center gap-1 shrink-0\">\n {/* Only show Date Range button if no universal time filter exists */}\n {!dashboardFilters.some(f => f.isUniversalTime) && (\n <button\n onClick={onAddTimeFilter}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors hover:opacity-80\"\n style={{\n backgroundColor: 'var(--dc-surface)',\n color: 'var(--dc-primary)',\n border: '1px solid var(--dc-border)'\n }}\n title=\"Add date range filter (applies to all time dimensions)\"\n >\n <AddIcon className=\"w-3.5 h-3.5\" />\n <span>Date Range</span>\n </button>\n )}\n <button\n onClick={onAddFilter}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors hover:opacity-80\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n <AddIcon className=\"w-3.5 h-3.5\" />\n <span>Filter</span>\n </button>\n </div>\n </div>\n </>\n )\n}\n\nexport default EditModeFilterList\n","/**\n * DashboardFilterPanel Component\n *\n * Orchestrates dashboard-level filtering UI\n * - Edit mode: Shows filter chips with edit/delete actions\n * - View mode: Shows interactive read-only filters\n *\n * Pattern: Simplified coordination layer (matches portlet editing pattern)\n * - No local editing state (modal owns all edit state)\n * - Just tracks which filter is being edited and modal visibility\n * - Delegates to FilterEditModal for all editing logic\n */\n\nimport React, { useState, useCallback } from 'react'\nimport FilterEditModal from './DashboardFilters/FilterEditModal'\nimport ReadOnlyFilterList from './DashboardFilters/ReadOnlyFilterList'\nimport EditModeFilterList from './DashboardFilters/EditModeFilterList'\nimport type { DashboardFilter, CubeMeta, DashboardConfig } from '../types'\nimport type { MetaResponse } from '../shared/types'\n\ninterface DashboardFilterPanelProps {\n dashboardFilters: DashboardFilter[]\n editable: boolean\n schema: CubeMeta | null\n dashboardConfig: DashboardConfig\n onDashboardFiltersChange: (filters: DashboardFilter[]) => void\n onSaveFilters?: (filters: DashboardFilter[]) => void | Promise<void>\n selectedFilterId?: string | null\n onFilterSelect?: (filterId: string) => void\n isEditMode?: boolean\n}\n\nconst DashboardFilterPanel: React.FC<DashboardFilterPanelProps> = ({\n dashboardFilters,\n editable,\n schema,\n dashboardConfig,\n onDashboardFiltersChange,\n onSaveFilters,\n selectedFilterId,\n onFilterSelect,\n isEditMode = false\n}) => {\n // Track which filter is being edited and modal visibility (no local editing state)\n const [editingFilter, setEditingFilter] = useState<DashboardFilter | null>(null)\n const [showFilterBuilder, setShowFilterBuilder] = useState(false)\n\n // Convert CubeMeta to MetaResponse (QueryBuilder type)\n const convertToMetaResponse = useCallback((cubeMeta: CubeMeta | null): MetaResponse | null => {\n if (!cubeMeta) return null\n\n return {\n cubes: cubeMeta.cubes.map(cube => ({\n name: cube.name,\n title: cube.title || cube.name,\n description: cube.description || '',\n measures: cube.measures.map(m => ({\n name: m.name,\n title: m.title,\n type: m.type,\n description: '',\n shortTitle: m.shortTitle\n })),\n dimensions: cube.dimensions.map(d => ({\n name: d.name,\n title: d.title,\n type: d.type,\n description: '',\n shortTitle: d.shortTitle\n })),\n segments: cube.segments?.map(s => ({\n name: s.name,\n title: s.title,\n type: s.type,\n description: '',\n shortTitle: s.shortTitle\n })) || []\n }))\n }\n }, [])\n\n // Generate unique ID for new filters\n const generateFilterId = useCallback(() => {\n return `df_${Date.now()}_${Math.random().toString(36).substring(7)}`\n }, [])\n\n // Handle adding a new filter - create temporary filter for modal\n const handleAddFilter = useCallback(() => {\n const newFilter: DashboardFilter = {\n id: generateFilterId(),\n label: `Filter ${dashboardFilters.length + 1}`,\n filter: {\n member: '',\n operator: 'equals',\n values: []\n }\n }\n setEditingFilter(newFilter)\n setShowFilterBuilder(true)\n }, [dashboardFilters.length, generateFilterId])\n\n // Handle adding a universal time filter - applies to all time dimensions\n // Creates filter directly without opening modal (fixed name, user just sets date range in view mode)\n const handleAddTimeFilter = useCallback(() => {\n const newFilter: DashboardFilter = {\n id: generateFilterId(),\n label: 'Date Range Filter',\n isUniversalTime: true,\n filter: {\n member: '__universal_time__', // Placeholder, not used in merge logic\n operator: 'inDateRange',\n values: ['last 30 days']\n }\n }\n // Add directly to filters without opening modal\n const updatedFilters = [...dashboardFilters, newFilter]\n onDashboardFiltersChange(updatedFilters)\n }, [generateFilterId, dashboardFilters, onDashboardFiltersChange])\n\n // Handle editing an existing filter - just open modal with filter\n const handleEditFilter = useCallback((filterId: string) => {\n const filterToEdit = dashboardFilters.find(df => df.id === filterId)\n if (filterToEdit) {\n setEditingFilter(filterToEdit)\n setShowFilterBuilder(true)\n }\n }, [dashboardFilters])\n\n // Handle removing a filter - simple filter list update\n const handleRemoveFilter = useCallback((filterId: string) => {\n const updatedFilters = dashboardFilters.filter(df => df.id !== filterId)\n onDashboardFiltersChange(updatedFilters)\n\n // Close modal if we're deleting the filter being edited\n if (editingFilter?.id === filterId) {\n setEditingFilter(null)\n setShowFilterBuilder(false)\n }\n }, [dashboardFilters, editingFilter, onDashboardFiltersChange])\n\n // Handle save from modal - update or add filter and save\n const handleSaveFilter = useCallback(async (filterData: DashboardFilter) => {\n // Check if this is a new filter (not in current list) or an update\n const existingFilterIndex = dashboardFilters.findIndex(f => f.id === filterData.id)\n\n let updatedFilters: DashboardFilter[]\n if (existingFilterIndex >= 0) {\n // Update existing filter\n updatedFilters = dashboardFilters.map(f =>\n f.id === filterData.id ? filterData : f\n )\n } else {\n // Add new filter\n updatedFilters = [...dashboardFilters, filterData]\n }\n\n // Update dashboard state\n onDashboardFiltersChange(updatedFilters)\n\n // Trigger save if callback provided\n if (onSaveFilters) {\n try {\n await onSaveFilters(updatedFilters)\n } catch (error) {\n console.error('Failed to save filters:', error)\n throw error // Re-throw so modal can handle it\n }\n }\n }, [dashboardFilters, onDashboardFiltersChange, onSaveFilters])\n\n // Handle modal close - just clean up state\n const handleCloseFilterBuilder = useCallback(() => {\n setEditingFilter(null)\n setShowFilterBuilder(false)\n }, [])\n\n // Handle date range change in read-only mode\n const handleFilterDateRangeChange = useCallback((filterId: string, dateRange: string | string[]) => {\n const updatedFilters = dashboardFilters.map(df => {\n if (df.id === filterId) {\n const filter = df.filter\n if ('member' in filter) {\n return {\n ...df,\n filter: {\n ...filter,\n dateRange,\n values: Array.isArray(dateRange) ? dateRange : [dateRange]\n }\n }\n }\n }\n return df\n })\n onDashboardFiltersChange(updatedFilters)\n }, [dashboardFilters, onDashboardFiltersChange])\n\n // Handle filter change in read-only mode\n const handleReadOnlyFilterChange = useCallback((filterId: string, updatedFilter: DashboardFilter) => {\n const updatedFilters = dashboardFilters.map(df =>\n df.id === filterId ? updatedFilter : df\n )\n onDashboardFiltersChange(updatedFilters)\n }, [dashboardFilters, onDashboardFiltersChange])\n\n // Check if a field is a time dimension\n const isTimeDimensionField = useCallback((fieldName: string): boolean => {\n if (!schema) return false\n return schema.cubes.some(cube =>\n cube.dimensions.some(dim => dim.name === fieldName && dim.type === 'time')\n )\n }, [schema])\n\n // Hide filter panel completely when not editable (fully embedded mode without filter support)\n if (!editable) {\n return null\n }\n\n // Hide if no filters exist and not in edit mode (nothing to show)\n if (!isEditMode && dashboardFilters.length === 0) {\n return null\n }\n\n return (\n <div\n className=\"mb-4 border rounded-lg\"\n style={{\n borderColor: 'var(--dc-border)',\n backgroundColor: 'var(--dc-surface)',\n boxShadow: 'var(--dc-shadow-sm)'\n }}\n >\n {/* Edit Mode - Filter chips with edit/delete actions */}\n {isEditMode ? (\n <EditModeFilterList\n dashboardFilters={dashboardFilters}\n onAddFilter={handleAddFilter}\n onAddTimeFilter={handleAddTimeFilter}\n onEditFilter={handleEditFilter}\n onRemoveFilter={handleRemoveFilter}\n selectedFilterId={selectedFilterId}\n onFilterSelect={onFilterSelect}\n />\n ) : (\n /* View Mode - Read-only interactive filters */\n <ReadOnlyFilterList\n dashboardFilters={dashboardFilters}\n schema={schema}\n onFilterChange={handleReadOnlyFilterChange}\n onDateRangeChange={handleFilterDateRangeChange}\n convertToMetaResponse={convertToMetaResponse}\n isTimeDimensionField={isTimeDimensionField}\n />\n )}\n\n {/* Filter Edit Modal */}\n {editable && showFilterBuilder && editingFilter && (\n <FilterEditModal\n filter={editingFilter}\n schema={schema}\n dashboardConfig={dashboardConfig}\n isOpen={showFilterBuilder}\n onSave={handleSaveFilter}\n onClose={handleCloseFilterBuilder}\n onDelete={() => handleRemoveFilter(editingFilter.id)}\n convertToMetaResponse={convertToMetaResponse}\n />\n )}\n </div>\n )\n}\n\nexport default DashboardFilterPanel\n","/**\n * ScaledGridWrapper component\n * Applies CSS transform scaling to the dashboard grid for intermediate screen sizes\n * Maintains the exact desktop layout appearance, just proportionally smaller\n */\n\nimport React, { useState, useEffect, useRef } from 'react'\n\ninterface ScaledGridWrapperProps {\n scaleFactor: number\n designWidth: number\n children: React.ReactNode\n}\n\n/**\n * Wrapper component that scales the grid using CSS transform\n * Handles height compensation to prevent overflow/whitespace issues\n */\nexport default function ScaledGridWrapper({\n scaleFactor,\n designWidth,\n children\n}: ScaledGridWrapperProps) {\n const [actualHeight, setActualHeight] = useState(0)\n const innerRef = useRef<HTMLDivElement>(null)\n\n // Measure actual grid height to calculate visible height\n useEffect(() => {\n if (!innerRef.current) return\n\n const observer = new ResizeObserver((entries) => {\n setActualHeight(entries[0]?.contentRect.height ?? 0)\n })\n\n observer.observe(innerRef.current)\n\n // Set initial height\n setActualHeight(innerRef.current.offsetHeight || 0)\n\n return () => observer.disconnect()\n }, [])\n\n // The scaled visual height\n const visualHeight = actualHeight * scaleFactor\n\n return (\n <div\n className=\"scaled-grid-container\"\n style={{\n height: visualHeight > 0 ? visualHeight : 'auto',\n overflow: 'hidden',\n width: '100%'\n }}\n >\n <div\n ref={innerRef}\n className=\"scaled-grid-inner\"\n style={{\n transform: `scale(${scaleFactor})`,\n transformOrigin: 'top left',\n width: designWidth\n }}\n >\n {children}\n </div>\n </div>\n )\n}\n","/**\n * MobileStackedLayout component\n * Simple vertical stack layout for mobile screens (<768px)\n * Read-only view with portlets sorted by grid position\n */\n\nimport { useMemo, useRef, useState, useCallback } from 'react'\nimport { getIcon } from '../icons'\nimport AnalyticsPortlet from './AnalyticsPortlet'\n\nconst RefreshIcon = getIcon('refresh')\nimport { ScrollContainerProvider } from '../providers/ScrollContainerContext'\nimport type { DashboardFilter, DashboardConfig } from '../types'\nimport type { ColorPalette } from '../utils/colorPalettes'\n\n/**\n * Finds the nearest scrollable ancestor of an element.\n */\nfunction findScrollableAncestor(element: HTMLElement | null): HTMLElement | null {\n if (!element) return null\n\n let current = element.parentElement\n\n while (current) {\n const style = window.getComputedStyle(current)\n const overflowY = style.overflowY\n const overflowX = style.overflowX\n\n const hasScrollableOverflow =\n overflowY === 'auto' || overflowY === 'scroll' ||\n overflowX === 'auto' || overflowX === 'scroll'\n\n const hasScrollContent =\n current.scrollHeight > current.clientHeight ||\n current.scrollWidth > current.clientWidth\n\n if (hasScrollableOverflow && hasScrollContent) {\n return current\n }\n\n if (current === document.body) break\n current = current.parentElement\n }\n\n return null\n}\n\ninterface MobileStackedLayoutProps {\n config: DashboardConfig\n colorPalette?: ColorPalette\n dashboardFilters?: DashboardFilter[]\n onPortletRefresh?: (portletId: string) => void\n}\n\n/**\n * Mobile-optimized stacked layout for dashboard portlets\n * Renders portlets in a single column, sorted by grid position\n */\nexport default function MobileStackedLayout({\n config,\n colorPalette,\n dashboardFilters,\n onPortletRefresh\n}: MobileStackedLayoutProps) {\n const portletComponentRefs = useRef<{ [key: string]: { refresh: () => void } | null }>({})\n\n // Scroll container detection for lazy loading\n const [scrollContainer, setScrollContainer] = useState<HTMLElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n\n const setContainerRef = useCallback((node: HTMLDivElement | null) => {\n containerRef.current = node\n if (node) {\n setScrollContainer(findScrollableAncestor(node))\n }\n }, [])\n\n // Sort portlets by y position, then x position (top-to-bottom, left-to-right)\n const sortedPortlets = useMemo(() => {\n return [...config.portlets].sort((a, b) => {\n if (a.y !== b.y) return a.y - b.y\n return a.x - b.x\n })\n }, [config.portlets])\n\n const handlePortletRefresh = (portletId: string) => {\n // Refresh the specific portlet component\n portletComponentRefs.current[portletId]?.refresh()\n // Also call external handler if provided\n onPortletRefresh?.(portletId)\n }\n\n return (\n <ScrollContainerProvider value={scrollContainer}>\n <div ref={setContainerRef} className=\"mobile-stacked-layout space-y-4 px-2\">\n {sortedPortlets.map(portlet => {\n // Calculate height: use stored h * rowHeight (80px), with minimum\n const portletHeight = Math.max(300, portlet.h * 80)\n // Header is approximately 40px when shown\n const headerHeight = portlet.displayConfig?.hideHeader ? 0 : 40\n // Content height = total - header - padding (py-3 = 24px)\n const contentHeight = portletHeight - headerHeight - 24\n\n return (\n <div\n key={portlet.id}\n data-portlet-id={portlet.id}\n className=\"bg-dc-surface border border-dc-border rounded-lg flex flex-col\"\n style={{\n height: portletHeight,\n boxShadow: 'var(--dc-shadow-sm)'\n }}\n >\n {/* Portlet Header - Simplified for mobile (no edit controls) */}\n {!portlet.displayConfig?.hideHeader && (\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-dc-border shrink-0 bg-dc-surface-secondary rounded-t-lg\">\n <h3 className=\"font-semibold text-sm text-dc-text truncate flex-1\">\n {portlet.title}\n </h3>\n <div className=\"flex items-center gap-1 shrink-0 ml-2\">\n <button\n onClick={() => handlePortletRefresh(portlet.id)}\n className=\"p-1 bg-transparent border-none rounded-sm text-dc-text-secondary cursor-pointer hover:bg-dc-surface-hover transition-colors\"\n title=\"Refresh portlet data\"\n >\n <RefreshIcon style={{ width: '16px', height: '16px', color: 'currentColor' }} />\n </button>\n </div>\n </div>\n )}\n\n {/* Portlet Content - explicit height for charts to render */}\n <div\n className=\"px-2 py-3 overflow-visible flex flex-col\"\n style={{ height: contentHeight }}\n >\n <AnalyticsPortlet\n ref={el => { portletComponentRefs.current[portlet.id] = el }}\n query={portlet.query}\n chartType={portlet.chartType}\n chartConfig={portlet.chartConfig}\n displayConfig={portlet.displayConfig}\n dashboardFilters={dashboardFilters}\n dashboardFilterMapping={portlet.dashboardFilterMapping}\n eagerLoad={portlet.eagerLoad ?? config.eagerLoad ?? false}\n title={portlet.title}\n height={contentHeight}\n colorPalette={colorPalette}\n />\n </div>\n </div>\n )\n })}\n </div>\n </ScrollContainerProvider>\n )\n}\n","/**\n * Dashboard Grid Component\n * Uses react-grid-layout for responsive grid layout\n * Simplified version without app-specific dependencies\n */\n\nimport {\n useCallback,\n useRef,\n useState,\n useEffect,\n useMemo,\n type ReactNode,\n type HTMLAttributes,\n type DragEvent,\n type MouseEvent,\n type Ref\n} from 'react'\nimport ReactGridLayout, { verticalCompactor, type LayoutItem, type Layout } from 'react-grid-layout'\nimport { getIcon } from '../icons'\nimport { useScrollDetection } from '../hooks/useScrollDetection'\nimport { useElementVisibility } from '../hooks/useElementVisibility'\nimport DashboardPortletCard from './DashboardPortletCard'\nimport RowManagedLayout from './RowManagedLayout'\nimport FloatingEditToolbar from './FloatingEditToolbar'\n\nconst ChartBarIcon = getIcon('measure')\nconst RefreshIcon = getIcon('refresh')\nconst EditIcon = getIcon('edit')\nconst CheckIcon = getIcon('check')\nconst DeleteIcon = getIcon('delete')\nconst AddIcon = getIcon('add')\nconst CopyIcon = getIcon('copy')\nconst FilterIcon = getIcon('filter')\nconst DesktopIcon = getIcon('desktop')\nconst GridIcon = getIcon('segment')\nconst RowsIcon = getIcon('table')\nimport PortletEditModal from './PortletEditModal'\nimport PortletAnalysisModal from './PortletAnalysisModal'\nimport PortletFilterConfigModal from './PortletFilterConfigModal'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport ColorPaletteSelector from './ColorPaletteSelector'\nimport DashboardFilterPanel from './DashboardFilterPanel'\nimport ScaledGridWrapper from './ScaledGridWrapper'\nimport MobileStackedLayout from './MobileStackedLayout'\nimport { useResponsiveDashboard } from '../hooks/useResponsiveDashboard'\nimport { ScrollContainerProvider } from '../providers/ScrollContainerContext'\nimport type { ColorPalette } from '../utils/colorPalettes'\n\n/**\n * Finds the nearest scrollable ancestor of an element.\n * Used to detect scroll container for lazy loading IntersectionObserver.\n */\nfunction findScrollableAncestor(element: HTMLElement | null): HTMLElement | null {\n if (!element) return null\n\n let current = element.parentElement\n\n while (current) {\n const style = window.getComputedStyle(current)\n const overflowY = style.overflowY\n const overflowX = style.overflowX\n\n const hasScrollableOverflow =\n overflowY === 'auto' || overflowY === 'scroll' ||\n overflowX === 'auto' || overflowX === 'scroll'\n\n const hasScrollContent =\n current.scrollHeight > current.clientHeight ||\n current.scrollWidth > current.clientWidth\n\n if (hasScrollableOverflow && hasScrollContent) {\n return current\n }\n\n if (current === document.body) break\n current = current.parentElement\n }\n\n return null // Use viewport\n}\nimport type {\n DashboardConfig,\n PortletConfig,\n DashboardFilter,\n CubeMeta,\n DashboardLayoutMode,\n DashboardGridSettings,\n RowLayout,\n RowLayoutColumn\n} from '../types'\n\n// CSS for react-grid-layout should be imported by the consuming app\n// import 'react-grid-layout/css/styles.css'\n\ninterface DashboardGridProps {\n config: DashboardConfig\n editable?: boolean\n dashboardFilters?: DashboardFilter[] // Dashboard-level filters to apply to portlets\n loadingComponent?: ReactNode // Custom loading indicator for all portlets\n onConfigChange?: (config: DashboardConfig) => void\n onPortletRefresh?: (portletId: string) => void\n onSave?: (config: DashboardConfig) => Promise<void> | void\n colorPalette?: ColorPalette // Complete palette with both colors and gradient\n schema?: CubeMeta | null // Cube metadata for filter panel\n onDashboardFiltersChange?: (filters: DashboardFilter[]) => void // Handler for filter changes\n dashboardModes?: DashboardLayoutMode[]\n}\n\nconst DEFAULT_GRID_SETTINGS: DashboardGridSettings = {\n cols: 12,\n rowHeight: 80,\n minW: 2,\n minH: 2\n}\n\nconst createRowId = () => `row-${Date.now()}`\n\nconst getGridSettings = (config: DashboardConfig): DashboardGridSettings => ({\n cols: config.grid?.cols ?? DEFAULT_GRID_SETTINGS.cols,\n rowHeight: config.grid?.rowHeight ?? DEFAULT_GRID_SETTINGS.rowHeight,\n minW: config.grid?.minW ?? DEFAULT_GRID_SETTINGS.minW,\n minH: config.grid?.minH ?? DEFAULT_GRID_SETTINGS.minH\n})\n\nconst equalizeRowColumns = (\n portletIds: string[],\n gridSettings: DashboardGridSettings\n): RowLayoutColumn[] => {\n const count = portletIds.length\n if (count === 0) return []\n\n const { cols, minW } = gridSettings\n const minTotal = minW * count\n\n if (minTotal > cols) {\n const base = Math.floor(cols / count)\n const remainder = cols % count\n return portletIds.map((id, index) => ({\n portletId: id,\n w: base + (index < remainder ? 1 : 0)\n }))\n }\n\n const remaining = cols - minTotal\n const extra = Math.floor(remaining / count)\n const remainder = remaining % count\n\n return portletIds.map((id, index) => ({\n portletId: id,\n w: minW + extra + (index < remainder ? 1 : 0)\n }))\n}\n\nconst adjustRowWidths = (\n columns: RowLayoutColumn[],\n gridSettings: DashboardGridSettings\n): RowLayoutColumn[] => {\n if (columns.length === 0) return []\n\n const { cols, minW } = gridSettings\n const adjusted = columns.map(column => ({\n ...column,\n w: Math.max(minW, column.w)\n }))\n\n let total = adjusted.reduce((sum, column) => sum + column.w, 0)\n if (total === cols) return adjusted\n\n if (total < cols) {\n let remaining = cols - total\n let index = 0\n while (remaining > 0) {\n adjusted[index % adjusted.length].w += 1\n remaining -= 1\n index += 1\n }\n return adjusted\n }\n\n let overflow = total - cols\n for (let index = adjusted.length - 1; index >= 0 && overflow > 0; index -= 1) {\n const column = adjusted[index]\n const reducible = Math.max(0, column.w - minW)\n if (reducible === 0) continue\n const delta = Math.min(reducible, overflow)\n column.w -= delta\n overflow -= delta\n }\n\n return adjusted\n}\n\nconst convertPortletsToRows = (\n portlets: PortletConfig[],\n gridSettings: DashboardGridSettings\n): RowLayout[] => {\n if (portlets.length === 0) return []\n\n const sorted = [...portlets].sort((a, b) => {\n if (a.y !== b.y) return a.y - b.y\n return a.x - b.x\n })\n\n const rowsByY = new Map<number, PortletConfig[]>()\n sorted.forEach(portlet => {\n const row = rowsByY.get(portlet.y) ?? []\n row.push(portlet)\n rowsByY.set(portlet.y, row)\n })\n\n return Array.from(rowsByY.entries())\n .sort(([a], [b]) => a - b)\n .map(([rowY, rowPortlets]) => {\n const rowHeight = Math.max(\n gridSettings.minH,\n ...rowPortlets.map(portlet => portlet.h)\n )\n const portletIds = rowPortlets.map(portlet => portlet.id)\n return {\n id: `row-${rowY}`,\n h: rowHeight,\n columns: equalizeRowColumns(portletIds, gridSettings)\n }\n })\n}\n\nconst normalizeRows = (\n rows: RowLayout[],\n portlets: PortletConfig[],\n gridSettings: DashboardGridSettings\n): RowLayout[] => {\n const portletIds = new Set(portlets.map(portlet => portlet.id))\n return rows\n .map(row => ({\n ...row,\n h: Math.max(gridSettings.minH, row.h),\n columns: adjustRowWidths(\n row.columns.filter(column => portletIds.has(column.portletId)),\n gridSettings\n )\n }))\n .filter(row => row.columns.length > 0)\n}\n\nconst convertRowsToPortlets = (\n rows: RowLayout[],\n portlets: PortletConfig[]\n): PortletConfig[] => {\n const portletMap = new Map(portlets.map(portlet => [portlet.id, portlet]))\n let currentY = 0\n\n const updated: PortletConfig[] = []\n rows.forEach(row => {\n let currentX = 0\n row.columns.forEach(column => {\n const portlet = portletMap.get(column.portletId)\n if (!portlet) return\n updated.push({\n ...portlet,\n x: currentX,\n y: currentY,\n w: column.w,\n h: row.h\n })\n currentX += column.w\n })\n currentY += row.h\n })\n\n const updatedIds = new Set(updated.map(portlet => portlet.id))\n portlets.forEach(portlet => {\n if (!updatedIds.has(portlet.id)) {\n updated.push(portlet)\n }\n })\n\n return updated\n}\n\nexport default function DashboardGrid({\n config,\n editable = false,\n dashboardFilters,\n loadingComponent,\n onConfigChange,\n onPortletRefresh,\n onSave,\n colorPalette,\n schema,\n onDashboardFiltersChange,\n dashboardModes\n}: DashboardGridProps) {\n // Get features from context for conditional modal rendering\n const { features } = useCubeContext()\n\n // Responsive dashboard hook for three-tier layout strategy\n const {\n containerRef,\n containerWidth,\n displayMode,\n scaleFactor,\n isEditable: isResponsiveEditable,\n designWidth\n } = useResponsiveDashboard()\n\n const allowedModes: DashboardLayoutMode[] = dashboardModes && dashboardModes.length > 0\n ? dashboardModes\n : ['rows', 'grid']\n const fallbackMode: DashboardLayoutMode = allowedModes.includes('rows') ? 'rows' : allowedModes[0] ?? 'grid'\n const configMode = config.layoutMode ?? 'grid'\n const layoutMode: DashboardLayoutMode = allowedModes.includes(configMode)\n ? configMode\n : fallbackMode\n const gridSettings = useMemo(() => getGridSettings(config), [config])\n\n // Scroll container detection for lazy loading\n // Null = viewport, element = scrolling container\n // Detection happens once in the ref callback to avoid double state updates\n const [scrollContainer, setScrollContainer] = useState<HTMLElement | null>(null)\n const containerElementRef = useRef<HTMLDivElement | null>(null)\n const scrollContainerRef = useRef<HTMLElement | null>(null)\n const editBarRef = useRef<HTMLDivElement | null>(null)\n\n // Combined ref for container\n const combinedContainerRef = useCallback((node: HTMLDivElement | null) => {\n containerElementRef.current = node\n containerRef(node)\n if (node) {\n const foundScrollContainer = findScrollableAncestor(node)\n setScrollContainer(foundScrollContainer)\n scrollContainerRef.current = foundScrollContainer\n }\n }, [containerRef])\n\n // Calculate grid width based on display mode\n // Desktop: use actual container width (allows wider than 1200px)\n // Scaled: use design width (1200px) and apply CSS scaling\n const gridWidth = displayMode === 'desktop' ? containerWidth : designWidth\n const [draftRows, setDraftRows] = useState<RowLayout[] | null>(null)\n const draftRowsRef = useRef<RowLayout[] | null>(null)\n const dragStateRef = useRef<{ rowIndex: number; colIndex: number; portletId: string } | null>(null)\n const [isDraggingPortlet, setIsDraggingPortlet] = useState(false)\n\n // Refs to store portlet refs for refresh functionality\n const portletRefs = useRef<{ [key: string]: HTMLDivElement | null }>({})\n const portletComponentRefs = useRef<{ [key: string]: { refresh: () => void } | null }>({})\n\n // Track if component has been initialized to prevent saves during initial load\n const [isInitialized, setIsInitialized] = useState(false)\n const [lastKnownLayout, setLastKnownLayout] = useState<any[]>([])\n\n // Edit mode state - dashboard is readonly by default\n const [isEditMode, setIsEditMode] = useState(false)\n\n // Filter selection mode state\n const [selectedFilterId, setSelectedFilterId] = useState<string | null>(null)\n\n // Determine if editing is allowed (only in desktop mode)\n const canEdit = editable && isEditMode && isResponsiveEditable && !selectedFilterId\n const canChangeLayoutMode = editable && isEditMode && isResponsiveEditable && !selectedFilterId && allowedModes.length > 1\n\n // Exit filter selection mode when leaving edit mode or when switching to non-desktop mode\n useEffect(() => {\n if ((!isEditMode || !isResponsiveEditable) && selectedFilterId) {\n setSelectedFilterId(null)\n }\n }, [isEditMode, isResponsiveEditable, selectedFilterId])\n\n // Exit edit mode when switching to non-desktop view\n useEffect(() => {\n if (!isResponsiveEditable && isEditMode) {\n setIsEditMode(false)\n }\n }, [isResponsiveEditable, isEditMode])\n\n // Track scroll state for sticky header using debounced scroll detection\n // Uses the actual scroll container (found via findScrollableAncestor) instead of window\n const isScrolled = useScrollDetection(scrollContainerRef, {\n threshold: 20,\n debounceMs: 150,\n container: scrollContainer // State dependency to trigger re-init when container found\n })\n\n // Track edit bar visibility for floating toolbar\n // When edit bar scrolls out of view, show floating toolbar\n const isEditBarVisible = useElementVisibility(editBarRef, {\n threshold: 80,\n debounceMs: 100,\n containerRef: scrollContainerRef,\n container: scrollContainer // State dependency to trigger re-init when container found\n })\n\n // Modal states\n const [isPortletModalOpen, setIsPortletModalOpen] = useState(false)\n const [editingPortlet, setEditingPortlet] = useState<PortletConfig | null>(null)\n const [isFilterConfigModalOpen, setIsFilterConfigModalOpen] = useState(false)\n const [filterConfigPortlet, setFilterConfigPortlet] = useState<PortletConfig | null>(null)\n\n // Debug data state - keyed by portlet ID\n const [debugData, setDebugData] = useState<{ [portletId: string]: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n } }>({})\n\n useEffect(() => {\n draftRowsRef.current = draftRows\n }, [draftRows])\n\n const resolvedRows = useMemo(() => {\n if (layoutMode !== 'rows') return []\n const baseRows = draftRows ?? config.rows ?? convertPortletsToRows(config.portlets, gridSettings)\n return normalizeRows(baseRows, config.portlets, gridSettings)\n }, [layoutMode, draftRows, config.rows, config.portlets, gridSettings])\n\n const updateRowLayout = useCallback(async (\n rows: RowLayout[],\n save = true,\n portletsOverride?: PortletConfig[]\n ) => {\n if (!onConfigChange) return\n const portlets = portletsOverride ?? config.portlets\n const normalizedRows = normalizeRows(rows, portlets, gridSettings)\n const updatedPortlets = convertRowsToPortlets(normalizedRows, portlets)\n const updatedConfig = {\n ...config,\n layoutMode: 'rows' as const,\n rows: normalizedRows,\n portlets: updatedPortlets\n }\n\n setDraftRows(null)\n onConfigChange(updatedConfig)\n\n if (save && onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed after row layout change:', error)\n }\n }\n }, [config, gridSettings, onConfigChange, onSave])\n\n // Set up initialization tracking\n useEffect(() => {\n // Mark as initialized after first render to prevent saves during load/resize\n const timer = setTimeout(() => {\n setIsInitialized(true)\n // Store initial layout for comparison\n const initialLayout = config.portlets.map(portlet => ({\n i: portlet.id,\n x: portlet.x,\n y: portlet.y,\n w: portlet.w,\n h: portlet.h\n }))\n setLastKnownLayout(initialLayout)\n }, 200) // Slightly longer delay to ensure responsive grid is fully settled\n\n return () => clearTimeout(timer)\n }, [config.portlets])\n\n // Scroll detection now handled by useScrollDetection hook above (lines 373-378)\n // This eliminates the old window.addEventListener('scroll') listener that was\n // listening to the wrong element and causing performance issues\n\n // Set up ESC key listener for filter selection mode\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && selectedFilterId) {\n setSelectedFilterId(null)\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown)\n }\n }, [selectedFilterId])\n\n // Helper function to check if layout actually changed (not just reordered due to responsive changes)\n const hasLayoutActuallyChanged = useCallback((newLayout: any[]) => {\n if (!isInitialized || lastKnownLayout.length === 0) return false\n \n // Compare each item's position and size\n for (const newItem of newLayout) {\n const oldItem = lastKnownLayout.find(item => item.i === newItem.i)\n if (!oldItem) continue // New item, this is a change\n \n if (oldItem.x !== newItem.x || oldItem.y !== newItem.y || \n oldItem.w !== newItem.w || oldItem.h !== newItem.h) {\n return true\n }\n }\n return false\n }, [isInitialized, lastKnownLayout])\n\n const handleLayoutChange = useCallback((_layout: Layout) => {\n // This function is called for ALL layout changes\n // We should NOT save here - only update internal state if needed\n // Actual saving only happens in handleDragStop and handleResizeStop for explicit user actions\n\n // Note: We don't call onConfigChange here to prevent saving intermediate layout changes\n // The layout changes are handled by react-grid-layout internally\n }, []) // No dependencies since we're not doing anything\n\n // Handle drag stop - save when user finishes dragging (only if layout actually changed)\n const handleDragStop = useCallback(async (layout: Layout, _oldItem: LayoutItem | null, _newItem: LayoutItem | null, _placeholder: LayoutItem | null, _e: Event, _element: HTMLElement | undefined) => {\n if (!editable || !isEditMode || !onSave || !isInitialized) return\n\n // Only save if the layout actually changed from user interaction\n // Convert readonly Layout to mutable array for comparison\n const mutableLayout = [...layout]\n if (!hasLayoutActuallyChanged(mutableLayout)) {\n return // No actual change, don't save\n }\n\n // Get the current updated config (only called in desktop mode)\n const updatedPortlets = config.portlets.map(portlet => {\n const layoutItem = mutableLayout.find(item => item.i === portlet.id)\n if (layoutItem) {\n return {\n ...portlet,\n x: layoutItem.x,\n y: layoutItem.y,\n w: layoutItem.w,\n h: layoutItem.h\n }\n }\n return portlet\n })\n\n // Preserve existing responsive layouts, only update with new lg layout\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets,\n layouts: {\n ...config.layouts,\n lg: mutableLayout // Only save the large layout, let RGL handle responsive adjustments\n }\n }\n\n // Update our tracking of the last known layout\n setLastKnownLayout(mutableLayout)\n\n // Update config state first\n onConfigChange?.(updatedConfig)\n\n // Auto-save after drag operation\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed after drag:', error)\n }\n }, [config.portlets, config.layouts, editable, isEditMode, onConfigChange, onSave, isInitialized, hasLayoutActuallyChanged])\n\n // Handle resize stop - update config and save (resize is user interaction)\n const handleResizeStop = useCallback(async (layout: Layout, _oldItem: LayoutItem | null, _newItem: LayoutItem | null, _placeholder: LayoutItem | null, _e: Event, _element: HTMLElement | undefined) => {\n if (!editable || !isEditMode || !onConfigChange || !isInitialized) return\n\n // Only proceed if the layout actually changed from user interaction\n // Convert readonly Layout to mutable array for comparison\n const mutableLayout = [...layout]\n if (!hasLayoutActuallyChanged(mutableLayout)) {\n return // No actual change, don't save\n }\n\n // Get the current updated config (only called in desktop mode)\n const updatedPortlets = config.portlets.map(portlet => {\n const layoutItem = mutableLayout.find(item => item.i === portlet.id)\n if (layoutItem) {\n return {\n ...portlet,\n x: layoutItem.x,\n y: layoutItem.y,\n w: layoutItem.w,\n h: layoutItem.h\n }\n }\n return portlet\n })\n\n // Preserve existing responsive layouts, only update with new lg layout\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets,\n layouts: {\n ...config.layouts,\n lg: mutableLayout // Only save the large layout, let RGL handle responsive adjustments\n }\n }\n\n // Update our tracking of the last known layout\n setLastKnownLayout(mutableLayout)\n\n // Update config state\n onConfigChange(updatedConfig)\n\n // Auto-save after resize operation (user deliberately resized)\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed after resize:', error)\n }\n }\n }, [config.portlets, config.layouts, editable, isEditMode, onConfigChange, onSave, isInitialized, hasLayoutActuallyChanged])\n\n const handleLayoutModeChange = useCallback(async (mode: DashboardLayoutMode) => {\n if (!onConfigChange || mode === layoutMode || !canChangeLayoutMode || !allowedModes.includes(mode)) return\n\n const baseRows = normalizeRows(\n config.rows && config.rows.length > 0\n ? config.rows\n : convertPortletsToRows(config.portlets, gridSettings),\n config.portlets,\n gridSettings\n )\n\n const updatedPortlets = convertRowsToPortlets(baseRows, config.portlets)\n const updatedConfig = {\n ...config,\n layoutMode: mode,\n rows: baseRows,\n portlets: updatedPortlets\n }\n\n setDraftRows(null)\n onConfigChange(updatedConfig)\n\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed after layout mode switch:', error)\n }\n }\n }, [allowedModes, canChangeLayoutMode, config, gridSettings, layoutMode, onConfigChange, onSave])\n\n const startRowResize = useCallback((rowIndex: number, event: MouseEvent<HTMLDivElement>) => {\n if (!canEdit) return\n event.preventDefault()\n\n const startY = event.clientY\n const startRows = resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n\n const handleMouseMove = (moveEvent: globalThis.MouseEvent) => {\n const delta = moveEvent.clientY - startY\n const deltaUnits = Math.round(delta / gridSettings.rowHeight)\n const nextRows = startRows.map((row, index) => {\n if (index !== rowIndex) return row\n return {\n ...row,\n h: Math.max(gridSettings.minH, row.h + deltaUnits)\n }\n })\n setDraftRows(nextRows)\n }\n\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n const finalRows = draftRowsRef.current ?? startRows\n updateRowLayout(finalRows)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }, [canEdit, gridSettings, resolvedRows, updateRowLayout])\n\n const startColumnResize = useCallback((rowIndex: number, columnIndex: number, event: MouseEvent<HTMLDivElement>) => {\n if (!canEdit) return\n event.preventDefault()\n\n const startX = event.clientX\n const startRows = resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n\n const row = startRows[rowIndex]\n const leftColumn = row?.columns[columnIndex]\n const rightColumn = row?.columns[columnIndex + 1]\n if (!row || !leftColumn || !rightColumn) return\n\n const columnGap = 16\n const rowContentWidth = gridWidth - (row.columns.length - 1) * columnGap\n const unitWidth = rowContentWidth / gridSettings.cols\n\n const handleMouseMove = (moveEvent: globalThis.MouseEvent) => {\n const delta = moveEvent.clientX - startX\n const deltaUnits = Math.round(delta / unitWidth)\n if (deltaUnits === 0) {\n setDraftRows(startRows)\n return\n }\n\n let nextLeft = leftColumn.w + deltaUnits\n let nextRight = rightColumn.w - deltaUnits\n\n if (nextLeft < gridSettings.minW) {\n const diff = gridSettings.minW - nextLeft\n nextLeft = gridSettings.minW\n nextRight -= diff\n }\n\n if (nextRight < gridSettings.minW) {\n const diff = gridSettings.minW - nextRight\n nextRight = gridSettings.minW\n nextLeft -= diff\n }\n\n if (nextLeft < gridSettings.minW || nextRight < gridSettings.minW) return\n\n const nextRows = startRows.map((rowItem, index) => {\n if (index !== rowIndex) return rowItem\n const nextColumns = rowItem.columns.map((column, colIndex) => {\n if (colIndex === columnIndex) {\n return { ...column, w: nextLeft }\n }\n if (colIndex === columnIndex + 1) {\n return { ...column, w: nextRight }\n }\n return column\n })\n return {\n ...rowItem,\n columns: adjustRowWidths(nextColumns, gridSettings)\n }\n })\n setDraftRows(nextRows)\n }\n\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n const finalRows = draftRowsRef.current ?? startRows\n updateRowLayout(finalRows)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }, [canEdit, gridSettings, gridWidth, resolvedRows, updateRowLayout])\n\n const handlePortletDragStart = useCallback((rowIndex: number, colIndex: number, portletId: string, event: DragEvent<HTMLDivElement>) => {\n if (!canEdit) return\n dragStateRef.current = { rowIndex, colIndex, portletId }\n setIsDraggingPortlet(true)\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', portletId)\n }, [canEdit])\n\n const handlePortletDragEnd = useCallback(() => {\n dragStateRef.current = null\n setIsDraggingPortlet(false)\n }, [])\n\n const handleRowDrop = useCallback((rowIndex: number, insertIndex: number | null) => {\n const dragState = dragStateRef.current\n if (!dragState) return\n\n const nextRows = resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n\n const sourceRowIndex = dragState.rowIndex\n const sourceRow = nextRows[sourceRowIndex]\n if (!sourceRow) return\n\n const [movedColumn] = sourceRow.columns.splice(dragState.colIndex, 1)\n let sourceRowRemoved = false\n if (sourceRow.columns.length === 0) {\n nextRows.splice(sourceRowIndex, 1)\n sourceRowRemoved = true\n }\n\n let targetRowIndex = rowIndex\n if (sourceRowRemoved && sourceRowIndex < rowIndex) {\n targetRowIndex -= 1\n }\n\n const targetRow = nextRows[targetRowIndex]\n if (!targetRow) return\n\n let targetIndex = insertIndex ?? targetRow.columns.length\n if (!sourceRowRemoved && sourceRowIndex === targetRowIndex && insertIndex !== null) {\n if (insertIndex > dragState.colIndex) {\n targetIndex -= 1\n }\n }\n targetRow.columns.splice(targetIndex, 0, movedColumn)\n\n const movedBetweenRows = sourceRowIndex !== targetRowIndex || sourceRowRemoved\n if (movedBetweenRows) {\n if (!sourceRowRemoved) {\n nextRows[sourceRowIndex] = {\n ...nextRows[sourceRowIndex],\n columns: equalizeRowColumns(\n nextRows[sourceRowIndex].columns.map(column => column.portletId),\n gridSettings\n )\n }\n }\n nextRows[targetRowIndex] = {\n ...nextRows[targetRowIndex],\n columns: equalizeRowColumns(\n nextRows[targetRowIndex].columns.map(column => column.portletId),\n gridSettings\n )\n }\n }\n\n updateRowLayout(nextRows)\n }, [gridSettings, resolvedRows, updateRowLayout])\n\n const handleNewRowDrop = useCallback((insertIndex: number) => {\n const dragState = dragStateRef.current\n if (!dragState) return\n\n const nextRows = resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n\n const sourceRow = nextRows[dragState.rowIndex]\n if (!sourceRow) return\n\n const [movedColumn] = sourceRow.columns.splice(dragState.colIndex, 1)\n if (sourceRow.columns.length === 0) {\n nextRows.splice(dragState.rowIndex, 1)\n } else {\n sourceRow.columns = equalizeRowColumns(\n sourceRow.columns.map(column => column.portletId),\n gridSettings\n )\n }\n\n const newRow: RowLayout = {\n id: createRowId(),\n h: Math.max(gridSettings.minH, 5),\n columns: equalizeRowColumns([movedColumn.portletId], gridSettings)\n }\n nextRows.splice(insertIndex, 0, newRow)\n\n updateRowLayout(nextRows)\n }, [gridSettings, resolvedRows, updateRowLayout])\n\n // Handle portlet refresh\n const handlePortletRefresh = useCallback((portletId: string) => {\n const portletComponent = portletComponentRefs.current[portletId]\n if (portletComponent && portletComponent.refresh) {\n portletComponent.refresh()\n }\n if (onPortletRefresh) {\n onPortletRefresh(portletId)\n }\n }, [onPortletRefresh])\n\n // Handle adding new portlet\n const handleAddPortlet = useCallback(() => {\n setEditingPortlet(null)\n setIsPortletModalOpen(true)\n }, [])\n\n // Handle editing existing portlet\n const handleEditPortlet = useCallback((portlet: PortletConfig) => {\n setEditingPortlet(portlet)\n setIsPortletModalOpen(true)\n }, [])\n\n // Handle portlet save\n const handlePortletSave = useCallback(async (portletData: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'>) => {\n if (!onConfigChange) return\n\n let updatedPortlets = [...config.portlets]\n let isNewPortlet = false\n let newPortletId: string | null = null\n\n if (editingPortlet) {\n // Editing existing portlet\n const index = updatedPortlets.findIndex(p => p.id === editingPortlet.id)\n if (index !== -1) {\n updatedPortlets[index] = portletData as PortletConfig\n }\n } else {\n // Adding new portlet\n isNewPortlet = true\n const newPortlet: PortletConfig = {\n ...portletData,\n id: `portlet-${Date.now()}`,\n x: 0,\n y: 0\n } as PortletConfig\n\n newPortletId = newPortlet.id\n\n // Find the best position for the new portlet\n const gridLayout = updatedPortlets.map(p => ({ i: p.id, x: p.x, y: p.y, w: p.w, h: p.h }))\n let maxY = 0\n gridLayout.forEach(item => {\n if (item.y + item.h > maxY) {\n maxY = item.y + item.h\n }\n })\n newPortlet.y = maxY\n\n updatedPortlets.push(newPortlet)\n }\n\n if (layoutMode === 'rows') {\n const baseRows = resolvedRows.length > 0\n ? resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n : normalizeRows(\n config.rows ?? convertPortletsToRows(config.portlets, gridSettings),\n updatedPortlets,\n gridSettings\n )\n\n const nextRows = isNewPortlet && newPortletId\n ? [\n ...baseRows,\n {\n id: createRowId(),\n h: Math.max(gridSettings.minH, 5),\n columns: equalizeRowColumns([newPortletId], gridSettings)\n }\n ]\n : baseRows\n\n await updateRowLayout(nextRows, true, updatedPortlets)\n } else {\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n\n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }\n\n setIsPortletModalOpen(false)\n setEditingPortlet(null)\n\n // Scroll to the new portlet after DOM update\n if (isNewPortlet && newPortletId) {\n setTimeout(() => {\n const scrollToPortlet = () => {\n // Try both the ref and DOM query selector\n let portletElement: HTMLElement | null = portletRefs.current[newPortletId!]\n if (!portletElement) {\n portletElement = document.querySelector(`[data-portlet-id=\"${newPortletId}\"]`)\n }\n \n if (portletElement) {\n portletElement.scrollIntoView({ \n behavior: 'smooth', \n block: 'center',\n inline: 'nearest'\n })\n return true\n }\n return false\n }\n \n // Try multiple times with increasing delays\n if (!scrollToPortlet()) {\n setTimeout(() => {\n if (!scrollToPortlet()) {\n setTimeout(() => {\n scrollToPortlet()\n }, 300)\n }\n }, 200)\n }\n }, 200)\n }\n }, [config, editingPortlet, gridSettings, layoutMode, onConfigChange, onSave, resolvedRows, updateRowLayout])\n\n // Handle deleting portlet\n const handleDeletePortlet = useCallback(async (portletId: string) => {\n if (!onConfigChange) return\n \n if (window.confirm('Are you sure you want to delete this portlet?')) {\n const updatedPortlets = config.portlets.filter(p => p.id !== portletId)\n\n if (layoutMode === 'rows') {\n const nextRows = resolvedRows\n .map(row => ({\n ...row,\n columns: row.columns.filter(column => column.portletId !== portletId)\n }))\n .filter(row => row.columns.length > 0)\n .map(row => ({\n ...row,\n columns: equalizeRowColumns(\n row.columns.map(column => column.portletId),\n gridSettings\n )\n }))\n\n await updateRowLayout(nextRows, true, updatedPortlets)\n } else {\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n \n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }\n }\n }, [config, gridSettings, layoutMode, onConfigChange, onSave, resolvedRows, updateRowLayout])\n\n // Handle duplicating portlet\n const handleDuplicatePortlet = useCallback(async (portletId: string) => {\n if (!onConfigChange) return\n \n const originalPortlet = config.portlets.find(p => p.id === portletId)\n if (!originalPortlet) return\n\n // Create duplicated portlet with new ID and updated title\n const duplicatedPortlet: PortletConfig = {\n ...originalPortlet,\n id: `portlet-${Date.now()}`,\n title: `${originalPortlet.title} Duplicated`,\n x: 0,\n y: 0\n }\n\n // Find the best position for the duplicated portlet\n const gridLayout = config.portlets.map(p => ({ i: p.id, x: p.x, y: p.y, w: p.w, h: p.h }))\n let maxY = 0\n gridLayout.forEach(item => {\n if (item.y + item.h > maxY) {\n maxY = item.y + item.h\n }\n })\n duplicatedPortlet.y = maxY\n\n const updatedPortlets = [...config.portlets, duplicatedPortlet]\n if (layoutMode === 'rows') {\n const baseRows = resolvedRows.map(row => ({\n ...row,\n columns: row.columns.map(column => ({ ...column }))\n }))\n const nextRows = [\n ...baseRows,\n {\n id: createRowId(),\n h: Math.max(gridSettings.minH, 5),\n columns: equalizeRowColumns([duplicatedPortlet.id], gridSettings)\n }\n ]\n await updateRowLayout(nextRows, true, updatedPortlets)\n } else {\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n \n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }\n\n // Scroll to the duplicated portlet after DOM update\n setTimeout(() => {\n const scrollToPortlet = () => {\n // Try both the ref and DOM query selector\n let portletElement: HTMLElement | null = portletRefs.current[duplicatedPortlet.id]\n if (!portletElement) {\n portletElement = document.querySelector(`[data-portlet-id=\"${duplicatedPortlet.id}\"]`)\n }\n \n if (portletElement) {\n portletElement.scrollIntoView({ \n behavior: 'smooth', \n block: 'center',\n inline: 'nearest'\n })\n return true\n }\n return false\n }\n \n // Try multiple times with increasing delays\n if (!scrollToPortlet()) {\n setTimeout(() => {\n if (!scrollToPortlet()) {\n setTimeout(() => {\n scrollToPortlet()\n }, 300)\n }\n }, 200)\n }\n }, 200)\n }, [config, gridSettings, layoutMode, onConfigChange, onSave, resolvedRows, updateRowLayout])\n\n // Handle color palette changes\n const handlePaletteChange = useCallback(async (paletteName: string) => {\n if (!onConfigChange) return\n\n const updatedConfig = {\n ...config,\n colorPalette: paletteName\n }\n\n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }, [config, onConfigChange, onSave])\n\n // Handle opening filter config modal\n const handleOpenFilterConfig = useCallback((portlet: PortletConfig) => {\n setFilterConfigPortlet(portlet)\n setIsFilterConfigModalOpen(true)\n }, [])\n\n // Handle saving filter configuration\n const handleSaveFilterConfig = useCallback(async (mapping: string[]) => {\n if (!onConfigChange || !filterConfigPortlet) return\n\n const updatedPortlets = config.portlets.map(p => {\n if (p.id === filterConfigPortlet.id) {\n return {\n ...p,\n dashboardFilterMapping: mapping\n }\n }\n return p\n })\n\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n\n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }, [config, filterConfigPortlet, onConfigChange, onSave])\n\n // Memoized callbacks for DashboardPortletCard to prevent re-renders\n const handleDebugDataReady = useCallback((portletId: string, data: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n }) => {\n setDebugData(prev => ({\n ...prev,\n [portletId]: data\n }))\n }, [])\n\n const handleSetPortletRef = useCallback((portletId: string, element: HTMLDivElement | null) => {\n portletRefs.current[portletId] = element\n }, [])\n\n const handleSetPortletComponentRef = useCallback((portletId: string, element: { refresh: () => void } | null) => {\n portletComponentRefs.current[portletId] = element\n }, [])\n\n // Memoized icons object to prevent re-renders\n const portletIcons = useMemo(() => ({\n RefreshIcon, EditIcon, DeleteIcon, CopyIcon, FilterIcon\n }), [])\n\n // Handle toggling filter for a portlet (used in filter selection mode)\n const handleToggleFilterForPortlet = useCallback(async (portletId: string, filterId: string) => {\n if (!onConfigChange) return\n\n const updatedPortlets = config.portlets.map(p => {\n if (p.id === portletId) {\n const currentMapping = p.dashboardFilterMapping || []\n const hasFilter = currentMapping.includes(filterId)\n\n return {\n ...p,\n dashboardFilterMapping: hasFilter\n ? currentMapping.filter(id => id !== filterId)\n : [...currentMapping, filterId]\n }\n }\n return p\n })\n\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n\n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }, [config, onConfigChange, onSave])\n\n // Handle filter selection (click on filter chip)\n const handleFilterSelect = useCallback((filterId: string) => {\n // Toggle selection: if already selected, deselect\n setSelectedFilterId(prev => prev === filterId ? null : filterId)\n }, [])\n\n // Handle select all - apply current filter to all portlets\n const handleSelectAllForFilter = useCallback(async (filterId: string) => {\n if (!onConfigChange) return\n\n const updatedPortlets = config.portlets.map(p => {\n const currentMapping = p.dashboardFilterMapping || []\n // Add the filter if it's not already in the mapping\n if (!currentMapping.includes(filterId)) {\n return {\n ...p,\n dashboardFilterMapping: [...currentMapping, filterId]\n }\n }\n return p\n })\n\n const updatedConfig = {\n ...config,\n portlets: updatedPortlets\n }\n\n onConfigChange(updatedConfig)\n\n // Auto-save if handler is provided\n if (onSave) {\n try {\n await onSave(updatedConfig)\n } catch (error) {\n console.error('Auto-save failed:', error)\n }\n }\n }, [config, onConfigChange, onSave])\n\n // Get the selected filter object\n const selectedFilter = selectedFilterId\n ? dashboardFilters?.find(f => f.id === selectedFilterId)\n : null\n\n // Memoize renderPortletCard to prevent unnecessary re-renders of DashboardPortletCard\n // IMPORTANT: Must be defined before any early returns to follow Rules of Hooks\n // All callback props are already memoized with useCallback above\n const renderPortletCard = useCallback((\n portlet: PortletConfig,\n containerProps?: HTMLAttributes<HTMLDivElement>,\n headerProps?: HTMLAttributes<HTMLDivElement>\n ) => (\n <DashboardPortletCard\n portlet={portlet}\n editable={editable}\n isEditMode={isEditMode}\n selectedFilterId={selectedFilterId}\n debugData={debugData[portlet.id]}\n dashboardFilters={dashboardFilters}\n configEagerLoad={config.eagerLoad}\n loadingComponent={loadingComponent}\n colorPalette={colorPalette}\n containerProps={containerProps}\n headerProps={headerProps}\n onToggleFilter={handleToggleFilterForPortlet}\n onRefresh={handlePortletRefresh}\n onDuplicate={handleDuplicatePortlet}\n onEdit={handleEditPortlet}\n onDelete={handleDeletePortlet}\n onOpenFilterConfig={handleOpenFilterConfig}\n onDebugDataReady={handleDebugDataReady}\n setPortletRef={handleSetPortletRef}\n setPortletComponentRef={handleSetPortletComponentRef}\n icons={portletIcons}\n />\n ), [\n editable,\n isEditMode,\n selectedFilterId,\n debugData,\n dashboardFilters,\n config.eagerLoad,\n loadingComponent,\n colorPalette,\n handleToggleFilterForPortlet,\n handlePortletRefresh,\n handleDuplicatePortlet,\n handleEditPortlet,\n handleDeletePortlet,\n handleOpenFilterConfig,\n handleDebugDataReady,\n handleSetPortletRef,\n handleSetPortletComponentRef,\n portletIcons\n ])\n\n if (!config.portlets || config.portlets.length === 0) {\n return (\n <>\n <div className=\"flex justify-center items-center min-h-[50vh]\">\n <div className=\"text-center\">\n <ChartBarIcon style={{ width: '64px', height: '64px', color: 'var(--dc-text-muted)', margin: '0 auto 16px auto' }} />\n <h3 className=\"text-lg font-semibold mb-2 text-dc-text\">No Portlets</h3>\n <p className=\"text-sm text-dc-text-secondary mb-4\">Add your first portlet to start visualizing your data</p>\n {editable && (\n <button\n onClick={handleAddPortlet}\n className=\"inline-flex items-center px-4 py-2 border border-dc-border bg-dc-surface rounded-md focus:outline-hidden focus:ring-2\"\n style={{\n color: 'var(--dc-primary)',\n borderColor: 'var(--dc-primary)'\n }}\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-surface-hover)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-surface)'}\n >\n <AddIcon className=\"w-5 h-5 mr-2\" />\n Add Portlet\n </button>\n )}\n </div>\n </div>\n \n {/* Portlet Modal - conditionally render new or old modal based on feature flag */}\n {features.useAnalysisBuilder ? (\n <PortletAnalysisModal\n isOpen={isPortletModalOpen}\n onClose={() => {\n setIsPortletModalOpen(false)\n setEditingPortlet(null)\n }}\n onSave={handlePortletSave}\n portlet={editingPortlet}\n title={editingPortlet ? 'Edit Portlet' : 'Add New Portlet'}\n submitText={editingPortlet ? 'Update Portlet' : 'Add Portlet'}\n colorPalette={colorPalette}\n />\n ) : (\n <PortletEditModal\n isOpen={isPortletModalOpen}\n onClose={() => {\n setIsPortletModalOpen(false)\n setEditingPortlet(null)\n }}\n onSave={handlePortletSave}\n portlet={editingPortlet}\n title={editingPortlet ? 'Edit Portlet' : 'Add New Portlet'}\n submitText={editingPortlet ? 'Update Portlet' : 'Add Portlet'}\n colorPalette={colorPalette}\n />\n )}\n </>\n )\n }\n\n // Generate grid layout from portlets - only use for lg (desktop) breakpoint\n // Let react-grid-layout handle responsive adjustments automatically\n const baseLayout: LayoutItem[] = config.portlets.map(portlet => ({\n i: portlet.id,\n x: portlet.x,\n y: portlet.y,\n w: portlet.w,\n h: portlet.h,\n minW: gridSettings.minW,\n minH: gridSettings.minH, // 2 rows at 80px = 160px minimum\n // Only enable drag/resize in edit mode\n isDraggable: canEdit,\n isResizable: canEdit,\n ...(canEdit ? { resizeHandles: ['s', 'w', 'e', 'n', 'se', 'sw', 'ne', 'nw'] as const } : {})\n }))\n\n // Render the portlet grid content (shared between desktop and scaled modes)\n const renderGridContent = () => (\n <ReactGridLayout\n className=\"layout\"\n layout={baseLayout}\n onLayoutChange={handleLayoutChange}\n onDragStop={handleDragStop}\n onResizeStop={handleResizeStop}\n width={gridWidth}\n gridConfig={{\n cols: gridSettings.cols,\n rowHeight: gridSettings.rowHeight,\n margin: [16, 16],\n containerPadding: [0, 0]\n }}\n dragConfig={{\n enabled: canEdit,\n handle: '.portlet-drag-handle'\n }}\n resizeConfig={{\n enabled: canEdit,\n handles: ['s', 'w', 'e', 'n', 'se', 'sw', 'ne', 'nw'],\n // Invisible but functional resize handles\n handleComponent: (axis, ref) => (\n <div\n ref={ref as Ref<HTMLDivElement>}\n className={`react-resizable-handle react-resizable-handle-${axis}`}\n style={{ opacity: 0 }}\n />\n )\n }}\n compactor={verticalCompactor}\n >\n {config.portlets\n .filter(portlet => portlet && portlet.id) // Guard against malformed portlets\n .map(portlet => (\n <div key={portlet.id}>\n {renderPortletCard(portlet)}\n </div>\n ))}\n </ReactGridLayout>\n )\n\n const renderRowContent = () => (\n <RowManagedLayout\n rows={resolvedRows}\n portlets={config.portlets}\n gridSettings={gridSettings}\n gridWidth={gridWidth}\n canEdit={canEdit}\n isDragging={isDraggingPortlet}\n onRowResize={startRowResize}\n onColumnResize={startColumnResize}\n onPortletDragStart={handlePortletDragStart}\n onPortletDragEnd={handlePortletDragEnd}\n onRowDrop={handleRowDrop}\n onNewRowDrop={handleNewRowDrop}\n renderPortlet={renderPortletCard}\n />\n )\n\n const renderActiveLayout = layoutMode === 'rows' ? renderRowContent() : renderGridContent()\n const editModeHint = 'Drag • Resize • Auto-save'\n\n return (\n <ScrollContainerProvider value={scrollContainer}>\n <div ref={combinedContainerRef} className=\"dashboard-grid-container w-full\" style={{ maxWidth: '100%', overflow: 'hidden' }}>\n {editable && features.editToolbar !== 'floating' && (\n <div\n ref={editBarRef}\n className={`mb-4 flex justify-between items-center sticky top-0 z-10 px-4 py-4 bg-dc-surface-tertiary border border-dc-border rounded-lg transition-all duration-200 ${\n isScrolled ? 'border-b' : ''\n }`}\n style={{\n boxShadow: isScrolled ? 'var(--dc-shadow-md)' : 'var(--dc-shadow-sm)'\n }}\n >\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => isResponsiveEditable && setIsEditMode(!isEditMode)}\n disabled={!isResponsiveEditable}\n className={`inline-flex items-center px-4 py-2 text-sm font-medium rounded-md transition-colors focus:outline-hidden focus:ring-2 focus:ring-offset-2 ${\n !isResponsiveEditable\n ? 'opacity-50 cursor-not-allowed bg-dc-surface-secondary border border-dc-border'\n : isEditMode\n ? 'bg-dc-surface-secondary border border-dc-border hover:bg-dc-surface-hover'\n : 'bg-dc-surface border border-dc-border hover:bg-dc-surface-hover'\n }`}\n style={{\n color: !isResponsiveEditable ? 'var(--dc-text-muted)' : 'var(--dc-primary)',\n borderColor: !isResponsiveEditable ? 'var(--dc-border)' : isEditMode ? 'var(--dc-border)' : 'var(--dc-primary)'\n }}\n >\n {isEditMode ? <CheckIcon className=\"w-4 h-4 mr-1.5\" /> : <EditIcon className=\"w-4 h-4 mr-1.5\" />}\n {isEditMode ? 'Finish Editing' : 'Edit'}\n </button>\n {isEditMode && allowedModes.length > 1 && (\n <div className=\"inline-flex rounded-md border border-dc-border overflow-hidden whitespace-nowrap\">\n <button\n onClick={() => handleLayoutModeChange('grid')}\n disabled={!canChangeLayoutMode}\n className={`inline-flex items-center gap-2 whitespace-nowrap px-3 py-1.5 text-sm font-medium transition-colors ${\n layoutMode === 'grid'\n ? 'bg-dc-surface-secondary text-dc-text shadow-inner'\n : 'bg-dc-surface text-dc-text-secondary hover:bg-dc-surface-hover'\n } ${!canChangeLayoutMode ? 'cursor-not-allowed opacity-50' : ''}`}\n >\n <GridIcon className=\"w-4 h-4 shrink-0\" />\n Grid\n </button>\n <button\n onClick={() => handleLayoutModeChange('rows')}\n disabled={!canChangeLayoutMode}\n className={`inline-flex items-center gap-2 whitespace-nowrap px-3 py-1.5 text-sm font-medium transition-colors ${\n layoutMode === 'rows'\n ? 'bg-dc-surface-secondary text-dc-text shadow-inner'\n : 'bg-dc-surface text-dc-text-secondary hover:bg-dc-surface-hover'\n } ${!canChangeLayoutMode ? 'cursor-not-allowed opacity-50' : ''}`}\n >\n <RowsIcon className=\"w-4 h-4 shrink-0\" />\n Rows\n </button>\n </div>\n )}\n {!isResponsiveEditable && (\n <div className=\"flex items-center gap-2 text-sm text-dc-text-secondary\">\n <DesktopIcon className=\"w-4 h-4\" />\n <span>Desktop view required for editing</span>\n </div>\n )}\n {isEditMode && isResponsiveEditable && (\n <p className=\"hidden md:block text-sm text-dc-text-secondary\">\n {editModeHint}\n </p>\n )}\n </div>\n\n {/* Color Palette Selector and Add Portlet - Only show in edit mode */}\n {isEditMode && (\n <div className=\"flex items-center gap-3\">\n <ColorPaletteSelector\n currentPalette={config.colorPalette}\n onPaletteChange={handlePaletteChange}\n className=\"shrink-0\"\n />\n\n <button\n onClick={handleAddPortlet}\n className=\"inline-flex items-center px-4 py-2 text-sm font-medium border rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 border-dc-border bg-dc-surface hover:bg-dc-surface-hover\"\n style={{\n color: 'var(--dc-primary)',\n borderColor: 'var(--dc-primary)'\n }}\n >\n <AddIcon className=\"w-5 h-5 mr-2\" />\n Add Portlet\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Floating Edit Toolbar - appears when top edit bar scrolls out of view (or always if editToolbar='floating') */}\n {editable && features.editToolbar !== 'top' && displayMode === 'desktop' && (\n <FloatingEditToolbar\n isEditBarVisible={features.editToolbar === 'floating' ? false : isEditBarVisible}\n position={features.floatingToolbarPosition || 'right'}\n isEditMode={isEditMode}\n onEditModeToggle={() => isResponsiveEditable && setIsEditMode(!isEditMode)}\n layoutMode={layoutMode}\n onLayoutModeChange={handleLayoutModeChange}\n allowedModes={allowedModes}\n canChangeLayoutMode={canChangeLayoutMode}\n currentPalette={config.colorPalette || 'default'}\n onPaletteChange={handlePaletteChange}\n onAddPortlet={handleAddPortlet}\n />\n )}\n\n {/* Dashboard Filter Panel - Always visible below toolbar */}\n <DashboardFilterPanel\n dashboardFilters={dashboardFilters || []}\n editable={editable}\n schema={schema || null}\n dashboardConfig={config}\n onDashboardFiltersChange={onDashboardFiltersChange || (() => {})}\n onSaveFilters={onSave ? async (filters: DashboardFilter[]) => {\n const updatedConfig = {\n ...config,\n filters\n }\n await onSave(updatedConfig)\n } : undefined}\n selectedFilterId={selectedFilterId}\n onFilterSelect={handleFilterSelect}\n isEditMode={isEditMode}\n />\n\n {/* Filter Selection Mode Banner */}\n {selectedFilterId && selectedFilter && (\n <div\n className=\"mb-4 px-4 py-3 rounded-md border-2 transition-all\"\n style={{\n backgroundColor: 'var(--dc-primary)',\n borderColor: 'var(--dc-primary)',\n color: 'white'\n }}\n >\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <FilterIcon className=\"w-5 h-5 shrink-0\" />\n <span className=\"font-medium\">\n Filter Selection Mode - Click portlets to toggle '{selectedFilter.label}'\n </span>\n <span className=\"text-sm opacity-90 hidden sm:inline\">• Press ESC to exit</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => handleSelectAllForFilter(selectedFilterId)}\n className=\"px-3 py-1 rounded-md transition-colors text-sm font-medium\"\n style={{\n backgroundColor: 'rgba(255, 255, 255, 0.2)',\n color: 'white'\n }}\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.3)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.2)'}\n >\n Select All\n </button>\n <button\n onClick={() => setSelectedFilterId(null)}\n className=\"px-3 py-1 rounded-md transition-colors text-sm font-medium\"\n style={{\n backgroundColor: 'rgba(255, 255, 255, 0.2)',\n color: 'white'\n }}\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.3)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.2)'}\n >\n Exit\n </button>\n </div>\n </div>\n </div>\n )}\n \n {/* Render layout based on display mode */}\n {displayMode === 'mobile' ? (\n <MobileStackedLayout\n config={config}\n colorPalette={colorPalette}\n dashboardFilters={dashboardFilters}\n onPortletRefresh={handlePortletRefresh}\n />\n ) : displayMode === 'scaled' ? (\n <ScaledGridWrapper scaleFactor={scaleFactor} designWidth={designWidth}>\n {renderActiveLayout}\n </ScaledGridWrapper>\n ) : (\n renderActiveLayout\n )}\n \n {/* Portlet Modal - conditionally render new or old modal based on feature flag */}\n {features.useAnalysisBuilder ? (\n <PortletAnalysisModal\n isOpen={isPortletModalOpen}\n onClose={() => {\n setIsPortletModalOpen(false)\n setEditingPortlet(null)\n }}\n onSave={handlePortletSave}\n portlet={editingPortlet}\n title={editingPortlet ? 'Edit Portlet' : 'Add New Portlet'}\n submitText={editingPortlet ? 'Update Portlet' : 'Add Portlet'}\n colorPalette={colorPalette}\n />\n ) : (\n <PortletEditModal\n isOpen={isPortletModalOpen}\n onClose={() => {\n setIsPortletModalOpen(false)\n setEditingPortlet(null)\n }}\n onSave={handlePortletSave}\n portlet={editingPortlet}\n title={editingPortlet ? 'Edit Portlet' : 'Add New Portlet'}\n submitText={editingPortlet ? 'Update Portlet' : 'Add Portlet'}\n colorPalette={colorPalette}\n />\n )}\n\n {/* Filter Configuration Modal */}\n <PortletFilterConfigModal\n isOpen={isFilterConfigModalOpen}\n onClose={() => {\n setIsFilterConfigModalOpen(false)\n setFilterConfigPortlet(null)\n }}\n dashboardFilters={dashboardFilters || []}\n currentMapping={filterConfigPortlet?.dashboardFilterMapping || []}\n onSave={handleSaveFilterConfig}\n portletTitle={filterConfigPortlet?.title || ''}\n />\n </div>\n </ScrollContainerProvider>\n )\n}\n","/**\n * Analytics Dashboard Component\n * Main dashboard container that uses CubeProvider context\n * Minimal dependencies, designed to be embedded in existing apps\n */\n\nimport { useCallback, useRef, useMemo } from 'react'\nimport DashboardGrid from './DashboardGrid'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport { getColorPalette } from '../utils/colorPalettes'\nimport type { AnalyticsDashboardProps, DashboardConfig, DashboardFilter } from '../types'\n\nexport default function AnalyticsDashboard({\n config,\n editable = false,\n dashboardFilters: propDashboardFilters,\n loadingComponent,\n onConfigChange,\n onSave,\n onDirtyStateChange\n}: AnalyticsDashboardProps) {\n // Get cube metadata for filter building\n const { meta, dashboardModes } = useCubeContext()\n\n // Track initial config to prevent saves during initial load\n const initialConfigRef = useRef(config)\n const hasConfigChangedFromInitial = useRef(false)\n\n // Merge programmatic filters (props) with config filters by ID\n // Config provides structure/metadata, props provide value overrides\n const mergedDashboardFilters = useMemo<DashboardFilter[]>(() => {\n const configFilters = config.filters || []\n const propFilters = propDashboardFilters || []\n\n // If no prop filters, use config filters as-is\n if (propFilters.length === 0) {\n return configFilters\n }\n\n // If no config filters, use prop filters as-is\n if (configFilters.length === 0) {\n return propFilters\n }\n\n // Merge by ID: config filters provide structure, prop filters provide values\n const mergedFilters: DashboardFilter[] = configFilters.map(configFilter => {\n // Find matching prop filter by ID\n const propFilter = propFilters.find(pf => pf.id === configFilter.id)\n\n if (propFilter) {\n // Merge: preserve config metadata, use prop filter values\n return {\n ...configFilter, // Preserve id, label, isUniversalTime from config\n filter: propFilter.filter // Use filter values from prop override\n }\n }\n\n // No override for this filter, use config as-is\n return configFilter\n })\n\n // Add any prop filters that don't exist in config (new filters)\n const configIds = new Set(configFilters.map(cf => cf.id))\n const newFilters = propFilters.filter(pf => !configIds.has(pf.id))\n\n return [...mergedFilters, ...newFilters]\n }, [config.filters, propDashboardFilters])\n\n // Enhanced save handler that tracks dirty state and prevents saves during initial load\n const handleSaveWithDirtyTracking = useCallback(async (config: DashboardConfig) => {\n // Don't save if this config hasn't actually changed from the initial load\n if (!hasConfigChangedFromInitial.current) {\n return // Prevent saves during initial load/responsive changes\n }\n \n if (onDirtyStateChange) {\n onDirtyStateChange(true) // Mark as dirty when save starts\n }\n \n try {\n if (onSave) {\n await onSave(config)\n }\n \n // Update our reference point after successful save\n initialConfigRef.current = config\n \n // Mark as clean after successful save\n if (onDirtyStateChange) {\n onDirtyStateChange(false)\n }\n } catch (error) {\n // Keep dirty state if save failed\n console.error('Save failed:', error)\n throw error\n }\n }, [onSave, onDirtyStateChange])\n\n // Enhanced config change handler that marks as dirty (only after initial load)\n const handleConfigChangeWithDirtyTracking = useCallback((config: DashboardConfig) => {\n if (onConfigChange) {\n onConfigChange(config)\n }\n \n // Check if this is a meaningful change from the initial config\n const configString = JSON.stringify(config)\n const initialConfigString = JSON.stringify(initialConfigRef.current)\n \n if (configString !== initialConfigString) {\n hasConfigChangedFromInitial.current = true\n \n if (onDirtyStateChange) {\n onDirtyStateChange(true)\n }\n }\n }, [onConfigChange, onDirtyStateChange])\n\n // Handle dashboard filter changes\n const handleDashboardFiltersChange = useCallback((filters: DashboardFilter[]) => {\n // Only update config if we're not using programmatic filters\n if (!propDashboardFilters || propDashboardFilters.length === 0) {\n const updatedConfig = {\n ...config,\n filters\n }\n handleConfigChangeWithDirtyTracking(updatedConfig)\n } else {\n console.warn('Dashboard filters are controlled via props - config changes ignored')\n }\n }, [config, propDashboardFilters, handleConfigChangeWithDirtyTracking])\n\n // Resolve complete palette object based on config\n const colorPalette = useMemo(() => {\n const paletteName = config.colorPalette\n return getColorPalette(paletteName)\n }, [config.colorPalette])\n\n return (\n <div className=\"w-full\">\n {/* Dashboard Grid (now includes filter panel) */}\n <DashboardGrid\n config={config}\n editable={editable}\n dashboardFilters={mergedDashboardFilters}\n loadingComponent={loadingComponent}\n onConfigChange={handleConfigChangeWithDirtyTracking}\n onSave={handleSaveWithDirtyTracking}\n colorPalette={colorPalette}\n schema={meta}\n dashboardModes={dashboardModes}\n onDashboardFiltersChange={handleDashboardFiltersChange}\n />\n </div>\n )\n}\n","/**\n * Portlet Container Component\n * Simple wrapper for individual portlets\n */\n\nimport { useState, useCallback } from 'react'\nimport AnalyticsPortlet from './AnalyticsPortlet'\nimport DebugModal from './DebugModal'\nimport type { PortletConfig } from '../types'\n\ninterface PortletContainerProps {\n portlet: PortletConfig\n editable?: boolean\n onEdit?: (portlet: PortletConfig) => void\n onDelete?: (portletId: string) => void\n onRefresh?: (portletId: string) => void\n}\n\nexport default function PortletContainer({ \n portlet, \n editable = false,\n onEdit,\n onDelete,\n onRefresh\n}: PortletContainerProps) {\n const [debugData, setDebugData] = useState<{\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n } | null>(null)\n\n // Memoize debug data callback to prevent AnalyticsPortlet re-renders\n const handleDebugDataReady = useCallback((data: {\n chartConfig: any\n displayConfig: any\n queryObject: any\n data: any[]\n chartType: string\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number }\n }) => {\n setDebugData(data)\n }, [])\n\n return (\n <div className=\"bg-dc-surface border border-dc-border rounded-lg flex flex-col h-full\" style={{ boxShadow: 'var(--dc-shadow-sm)' }}>\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-dc-border shrink-0 bg-dc-surface-secondary rounded-t-lg px-3 py-2 md:px-6 md:py-3\">\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n <h3 className=\"font-semibold text-sm truncate text-dc-text\">{portlet.title}</h3>\n {/* Debug button - right next to title */}\n {debugData && (\n <DebugModal\n chartConfig={debugData.chartConfig}\n displayConfig={debugData.displayConfig}\n queryObject={debugData.queryObject}\n data={debugData.data}\n chartType={debugData.chartType}\n cacheInfo={debugData.cacheInfo}\n />\n )}\n </div>\n\n <div className=\"flex items-center gap-2 ml-4\">\n\n {editable && (\n <>\n <button\n onClick={() => onRefresh?.(portlet.id)}\n className=\"p-1.5 hover:bg-dc-surface-hover rounded-sm text-dc-text-secondary\"\n title=\"Refresh\"\n >\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </button>\n <button\n onClick={() => onEdit?.(portlet)}\n className=\"p-1.5 hover:bg-dc-surface-hover rounded-sm text-dc-text-secondary\"\n title=\"Edit\"\n >\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n </button>\n <button\n onClick={() => onDelete?.(portlet.id)}\n className=\"p-1.5 rounded-sm text-dc-danger\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--dc-danger-bg)'}\n onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}\n title=\"Delete\"\n >\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n </>\n )}\n </div>\n </div>\n\n {/* Content */}\n <div className=\"px-2 py-3 md:px-4 md:pt-6 md:pb-4 flex-1 min-h-0\">\n <AnalyticsPortlet\n query={portlet.query}\n chartType={portlet.chartType}\n chartConfig={portlet.chartConfig}\n displayConfig={portlet.displayConfig}\n title={portlet.title}\n height=\"100%\"\n onDebugDataReady={handleDebugDataReady}\n />\n </div>\n </div>\n )\n}","import React, { useState, useEffect } from 'react'\nimport Modal from './Modal'\n\ninterface DashboardEditModalProps {\n isOpen: boolean\n onClose: () => void\n onSave: (data: { name: string; description?: string }) => Promise<void> | void\n title: string\n submitText: string\n initialName?: string\n initialDescription?: string\n}\n\nexport default function DashboardEditModal({\n isOpen,\n onClose,\n onSave,\n title,\n submitText,\n initialName = '',\n initialDescription = ''\n}: DashboardEditModalProps) {\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [isSaving, setIsSaving] = useState(false)\n\n // Initialize form values when modal opens\n useEffect(() => {\n if (isOpen) {\n setName(initialName)\n setDescription(initialDescription)\n }\n }, [isOpen, initialName, initialDescription])\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n \n if (!name.trim()) {\n return\n }\n\n setIsSaving(true)\n \n try {\n await onSave({\n name: name.trim(),\n description: description.trim() || undefined\n })\n handleClose()\n } catch {\n // Failed to save dashboard\n // Don't close modal on error so user can retry\n } finally {\n setIsSaving(false)\n }\n }\n\n const handleClose = () => {\n setName('')\n setDescription('')\n setIsSaving(false)\n onClose()\n }\n\n const footer = (\n <>\n <button\n type=\"button\"\n onClick={handleClose}\n disabled={isSaving}\n className=\"px-4 py-2 text-sm font-medium text-dc-text-secondary bg-dc-surface border border-dc-border rounded-md hover:bg-dc-surface-hover disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n form=\"dashboard-form\"\n disabled={isSaving || !name.trim()}\n className=\"px-4 py-2 text-sm font-medium text-white bg-dc-primary border border-transparent rounded-md hover:bg-dc-primary-hover disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isSaving ? 'Saving...' : submitText}\n </button>\n </>\n )\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={handleClose}\n title={title}\n size=\"fullscreen-mobile\"\n footer={footer}\n >\n <form id=\"dashboard-form\" onSubmit={handleSubmit} className=\"space-y-4 w-full\">\n <div>\n <label htmlFor=\"dashboard-name\" className=\"block text-sm font-medium text-dc-text-secondary mb-1\">\n Dashboard Name\n </label>\n <input\n type=\"text\"\n id=\"dashboard-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"w-full px-3 py-2 border border-dc-border rounded-md bg-dc-surface text-dc-text focus:outline-none focus:ring-2 focus:ring-dc-primary focus:border-dc-primary\"\n placeholder=\"Enter dashboard name...\"\n required\n autoFocus\n />\n </div>\n\n <div>\n <label htmlFor=\"dashboard-description\" className=\"block text-sm font-medium text-dc-text-secondary mb-1\">\n Description (optional)\n </label>\n <textarea\n id=\"dashboard-description\"\n rows={3}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n className=\"w-full px-3 py-2 border border-dc-border rounded-md bg-dc-surface text-dc-text focus:outline-none focus:ring-2 focus:ring-dc-primary focus:border-dc-primary\"\n placeholder=\"Enter description...\"\n />\n </div>\n </form>\n </Modal>\n )\n}"],"names":["observerMap","RootIds","rootId","unsupportedValue","getRootId","root","optionsToId","options","key","createObserver","id","instance","elements","thresholds","observer","entries","entry","_a2","inView","threshold","callback","observe","element","fallbackInView","bounds","callbacks","useInView","delay","trackVisibility","rootMargin","triggerOnce","skip","initialInView","onChange","ref","setRef","React2","lastInViewRef","state","setState","unobserve","previousInView","entryTarget","previousEntryTarget","result","isMultiQueryData","data","getQueryLabels","labels","row","label","getQueryIndices","indices","index","a","b","mergeResultsConcat","resultSets","_queries","merged","resultSet","queryIndex","mergeResultsByKey","queries","mergeKeys","_labels","mergedMap","measures","keyValue","k","baseRow","mergedRow","measure","field","aKey","bKey","mergeQueryResults","strategy","getCombinedFields","dimensions","timeDimensions","query","m","d","td","generateQueryLabel","firstMeasure","parts","validateMergeKey","mergeKey","missingInQueries","useMultiCubeQuery","config","cubeApi","batchCoordinator","enableBatching","useCubeContext","useState","lastConfigRef","useRef","useEffect","configString","queryId","prevState","errors","rs","firstError","e","successfulResults","_","i","successfulQueries","err","error","RefreshIcon","getIcon","ChartErrorBoundary","Component","props","errorInfo","jsxs","jsx","isMultiQueryConfig","obj","EMPTY_FILTERS","FilterCache","keyStr","value","firstKey","applicableFiltersCache","mergedFiltersCache","timeDimensionsCache","shouldIncludeFilter","filter","simpleFilter","f","getApplicableDashboardFilters","dashboardFilters","filterMapping","cacheKey","cached","df","frozenResult","convertToServerFormat","groupFilter","convertedFilters","mergeDashboardAndPortletFilters","portletFilters","extractDashboardFields","dashboardConfig","portlet","dimension","extractFieldsFromFilters","filters","fields","getDateRangeFromFilter","applyUniversalTimeFilters","portletTimeDimensions","universalTimeFilters","dateRange","AnalyticsPortlet","React","forwardRef","chartType","chartConfig","displayConfig","dashboardFilterMapping","eagerLoad","_isVisible","height","_title","colorPalette","loadingComponent","onDebugDataReady","refreshCounter","setRefreshCounter","onDebugDataReadyRef","scrollContainer","useScrollContainer","inViewRef","isVisible","chartTypeConfig","useChartConfig","shouldSkipQuery","regularFilters","useMemo","queryObject","multiQueryConfig","parsed","applicableFilters","q","mergedFilters","mergedTimeDimensions","isMultiQuery","shouldSkipSingle","shouldSkipMulti","singleQueryResult","useCubeQuery","multiQueryResult","isLoading","multiQueryData","useImperativeHandle","prev","getData","hasMandatoryFields","zone","LoadingIndicator","chartHeight","isValidChartType","LazyChart","useScrollDetection","containerRef","debounceMs","container","isScrolled","setIsScrolled","timeoutRef","handleScroll","shouldBeScrolled","useElementVisibility","elementRef","setIsVisible","hasBeenVisibleRef","checkVisibility","elementRect","containerRect","visible","scrollTarget","rafId","highlightJs","loadingPromise","loadSyntaxHighlighter","hljs","javascript","sql","sql$1","json","json$1","highlightCodeBlocks","block","DebugModal","cacheInfo","isOpen","setIsOpen","handleKeyDown","event","timer","ICON_STYLE","arePropsEqual","prevProps","nextProps","containerPropsEqual","shallowEqualObjects","headerPropsEqual","keysA","keysB","DashboardPortletCard","editable","isEditMode","selectedFilterId","debugData","configEagerLoad","containerProps","headerProps","onToggleFilter","onRefresh","onDuplicate","onEdit","onDelete","onOpenFilterConfig","setPortletRef","setPortletComponentRef","icons","hasSelectedFilter","isInSelectionMode","mergedContainerClassName","mergedHeaderClassName","containerOnClick","_containerClassName","containerStyle","restContainerProps","headerOnClick","_headerClassName","headerStyle","restHeaderProps","handleDebugDataReady","useCallback","el","Fragment","COLUMN_GAP","RowManagedLayout","rows","portlets","gridSettings","gridWidth","canEdit","isDragging","onRowResize","onColumnResize","onPortletDragStart","onPortletDragEnd","onRowDrop","onNewRowDrop","renderPortlet","portletMap","activeDropKey","setActiveDropKey","setDropActive","isDragActive","handlePortletDragStart","rowIndex","columnIndex","portletId","handlePortletDragEnd","topDropActive","bottomDropActive","rowHeight","safeGridWidth","paddingLeft","paddingRight","unitWidth","column","width","COLOR_PALETTES","getColorPalette","paletteName","p","EditIcon","CheckIcon","GridIcon","RowsIcon","AddIcon","SwatchIcon","FloatingEditToolbar","isEditBarVisible","position","onEditModeToggle","layoutMode","onLayoutModeChange","allowedModes","canChangeLayoutMode","currentPalette","onPaletteChange","onAddPortlet","isPaletteOpen","setIsPaletteOpen","paletteRef","handleClickOutside","positionClasses","isHidden","toolbarContent","ToolbarButton","CompactPaletteDropdown","palette","createPortal","Icon","tooltip","isActive","disabled","onClick","color","Modal","onClose","title","size","closeOnBackdropClick","closeOnEscape","showCloseButton","children","footer","noPadding","handleEscapeKey","parseRelativeDateRange","now","lowerRange","utcYear","utcMonth","utcDate","utcDay","start","end","mondayOffset","quarter","lastDaysMatch","days","lastWeeksMatch","lastMondayOffset","currentQuarter","lastQuarter","year","lastMonthsMatch","months","lastYearsMatch","years","parseDateRange","formatDateForCube","date","calculatePriorPeriod","currentStart","currentEnd","periodLengthMs","periodLengthDays","priorEnd","priorStart","findFieldInSchema","fieldName","schema","cube","getFieldTitle","found","schemaToFieldOptions","mode","isTime","filterFieldOptions","searchTerm","selectedCube","filtered","opt","term","groupFieldsByCube","grouped","option","existing","RECENT_FIELDS_KEY","MAX_RECENT_FIELDS","getRecentFields","stored","addRecentField","recent","getRecentFieldOptions","recentFieldNames","allOptions","recentOptions","getCubeNames","getCubeTitle","cubeName","c","FieldSearchItem","isSelected","isFocused","onMouseEnter","getFieldIcon","getMeasureTypeIcon","getFieldTypeIcon","getBadgeStyle","getTypeLabel","FieldSearchItem$1","memo","FieldDetailPanel","getIconBgStyle","getTypeDisplay","FieldDetailPanel$1","SearchIcon","CloseIcon","FieldSearchModal","onSelect","selectedFields","externalRecentFields","setSearchTerm","setSelectedCube","focusedField","setFocusedField","focusedIndex","setFocusedIndex","lastSelectedIndex","setLastSelectedIndex","searchInputRef","resultsContainerRef","fieldOptionsMode","allFieldOptions","cubeNames","filteredFields","groupedFields","flatFieldsList","list","selectSingleField","keepOpen","metaField","handleSelectField","fieldIndex","shiftKey","startIndex","endIndex","rangeField","next","focusedElement","searchPlaceholder","modalTitle","focusedFieldId","idx","sum","FILTER_OPERATORS","DATE_RANGE_OPTIONS","isSimpleFilter","isGroupFilter","transformFiltersForServer","transformFilter","transformedSubFilters","cleanQuery","cleanedQuery","cleanQueryForServer","getAvailableOperators","fieldType","operators","operator","meta","convertDateRangeTypeToValue","rangeType","number","typeMap","unit","unitSingular","requiresNumberInput","formatReason","reason","getReasonBadgeClasses","QueryAnalysisPanel","analysis","InfoIcon","ArrowRightIcon","WarningIcon","TableIcon","LinkIcon","SuccessIcon","ErrorIcon","jp","step","stepIdx","jc","pa","jk","w","deepFreeze","name","prop","type","Response","escapeHTML","inherit$1","original","objects","SPAN_CLOSE","emitsWrappingTags","node","scopeToCSSClass","prefix","pieces","x","HTMLRenderer","parseTree","text","className","newNode","opts","TokenTree","scope","builder","child","TokenTreeEmitter","emitter","source","re","lookahead","concat","anyNumberOfTimes","optional","args","stripOptionsFromArgs","either","countMatchGroups","startsWith","lexeme","match","BACKREF_RE","_rewriteBackreferences","regexps","joinWith","numCaptures","regex","offset","out","MATCH_NOTHING_RE","IDENT_RE","UNDERSCORE_IDENT_RE","NUMBER_RE","C_NUMBER_RE","BINARY_NUMBER_RE","RE_STARTERS_RE","SHEBANG","beginShebang","resp","BACKSLASH_ESCAPE","APOS_STRING_MODE","QUOTE_STRING_MODE","PHRASAL_WORDS_MODE","COMMENT","begin","modeOptions","ENGLISH_WORD","C_LINE_COMMENT_MODE","C_BLOCK_COMMENT_MODE","HASH_COMMENT_MODE","NUMBER_MODE","C_NUMBER_MODE","BINARY_NUMBER_MODE","REGEXP_MODE","TITLE_MODE","UNDERSCORE_TITLE_MODE","METHOD_GUARD","MODES","skipIfHasPrecedingDot","response","scopeClassName","_parent","beginKeywords","parent","compileIllegal","compileMatch","compileRelevance","beforeMatchExt","originalMode","COMMON_KEYWORDS","DEFAULT_KEYWORD_SCOPE","compileKeywords","rawKeywords","caseInsensitive","scopeName","compiledKeywords","compileList","keywordList","keyword","pair","scoreForKeyword","providedScore","commonKeyword","seenDeprecations","message","warn","deprecated","version","MultiClassError","remapScopeNames","regexes","scopeNames","emit","positions","beginMultiClass","endMultiClass","scopeSugar","MultiClass","compileLanguage","language","langRe","global","MultiRegex","terminators","s","matchData","ResumableMultiRegex","matcher","m2","buildModeRegex","mm","compileMode","cmode","ext","keywordPattern","expandOrCloneMode","dependencyOnParent","variant","HTMLInjectionError","html","escape","inherit","NO_MATCH","MAX_KEYWORD_HITS","HLJS","languages","aliases","plugins","SAFE_MODE","LANGUAGE_NOT_FOUND","PLAINTEXT_LANGUAGE","shouldNotHighlight","languageName","blockLanguage","classes","getLanguage","_class","highlight","codeOrLanguageName","optionsOrCode","ignoreIllegals","code","context","fire","_highlight","codeToHighlight","continuation","keywordHits","keywordData","matchText","processKeywords","top","modeBuffer","lastIndex","buf","word","kind","keywordRelevance","relevance","cssClass","emitKeyword","processSubLanguage","continuations","highlightAuto","processBuffer","emitMultiClass","max","klass","startNewMode","endOfMode","matchPlusRemainder","matched","doIgnore","resumeScanAtSamePosition","doBeginMatch","newMode","beforeCallbacks","cb","doEndMatch","endMode","origin","processContinuations","current","item","lastMatch","processLexeme","textBeforeMatch","processed","iterations","md","beforeMatch","processedCount","justTextHighlightResult","languageSubset","plaintext","results","autoDetection","sorted","best","secondBest","updateClassName","currentLang","resultLang","highlightElement","configure","userOptions","initHighlighting","highlightAll","initHighlightingOnLoad","wantsHighlight","boot","registerLanguage","languageDefinition","lang","error$1","registerAliases","unregisterLanguage","alias","listLanguages","aliasList","upgradePluginAPI","plugin","addPlugin","removePlugin","deprecateHighlightBlock","core","ATTRIBUTE","PUNCTUATION","LITERALS","LITERALS_MODE","COMMENT_MODE","STRING","QUOTED_IDENTIFIER","MULTI_WORD_TYPES","TYPES","NON_RESERVED_WORDS","RESERVED_WORDS","RESERVED_FUNCTIONS","POSSIBLE_WITHOUT_PARENS","COMBOS","FUNCTIONS","KEYWORDS","VARIABLE","OPERATOR","FUNCTION_CALL","kws_to_regex","kw","MULTI_WORD_KEYWORDS","reduceRelevancy","exceptions","when","qualifyFn","CodeBlock","maxHeight","copied","setCopied","codeRef","CopyIcon","handleCopy","textArea","isTimeDimension","breakdown","getFirstTimeDimension","breakdowns","getFirstDimension","getDimensions","getTimeDimensions","getChartAvailability","metrics","measureCount","dimensionCount","timeDimensionCount","totalBreakdowns","getAllChartAvailability","chartTypes","availability","selectBestChartType","currentChartType","hasTimeDimension","hasDimension","hasMeasure","getSmartChartDefaults","buildChartConfig","timeDimension","allBreakdowns","shouldAutoSwitchChartType","userManuallySelected","recommendedType","ChevronDownIcon","ColorPaletteSelector","dropdownRef","currentPaletteObj","handlePaletteSelect","AnalysisResultsPanel","executionStatus","executionResults","executionError","totalRowCount","resultsStale","currentPaletteName","onColorPaletteChange","allQueries","activeView","onActiveViewChange","displayLimit","onDisplayLimitChange","hasMetrics","debugDataPerQuery","onShareClick","canShare","shareButtonState","onClearClick","canClear","enableAI","isAIOpen","onAIToggle","queryCount","perQueryResults","activeTableIndex","onActiveTableChange","showDebug","setShowDebug","activeDebugIndex","setActiveDebugIndex","currentDebugData","debugSql","debugAnalysis","debugLoading","debugError","debugQuery","combinedQueryForChart","allMeasures","ChartIcon","CodeIcon","ShareIcon","TrashIcon","SparklesIcon","renderLoading","renderError","renderHeader","hasQueryContent","renderWaiting","renderEmpty","renderNoData","renderChart","renderDebug","renderTable","tableIndex","tableData","tableQuery","limitedData","renderOverlaySpinner","hasResults","renderSuccess","shouldShowResults","MetricItemCard","metric","fieldMeta","onRemove","sortDirection","sortPriority","onToggleSort","onDragStart","onDragEnd","ChevronUpIcon","ChevronUpDownIcon","measureType","MeasureIcon","displayTitle","getSortIcon","getSortTooltip","isDraggable","findFieldMeta","getNextSortDirection","MetricsSection","onAdd","order","onOrderChange","onReorder","draggedIndex","setDraggedIndex","dropTargetIndex","setDropTargetIndex","draggedIndexRef","dropTargetIndexRef","orderKeys","metricsWithMeta","dragCloneRef","handleDragStart","target","clone","rect","offsetX","offsetY","handleDragEnd","handleItemDragOver","itemIndex","currentDraggedIndex","targetIndex","handleItemDrop","currentDropTargetIndex","adjustedTarget","handleSectionDragLeave","relatedTarget","getItemTransform","gapSize","shouldShowGapIndicator","SectionHeading","transform","showGapBefore","nextDirection","TIME_GRANULARITIES","BreakdownItemCard","onGranularityChange","onComparisonToggle","comparisonDisabled","DimensionIcon","TimeIcon","g","BreakdownSection","activeComparisonId","breakdownsWithMeta","granularity","TimeDimensionIcon","FilterConfigModal","initialFilter","onSave","onCancel","anchorElement","setFilter","isOperatorDropdownOpen","setIsOperatorDropdownOpen","isValueDropdownOpen","setIsValueDropdownOpen","isDateRangeDropdownOpen","setIsDateRangeDropdownOpen","setRangeType","numberValue","setNumberValue","searchText","setSearchText","modalPosition","setModalPosition","debouncedSearchText","useDebounce","fieldInfo","isTimeField","isMeasureField","isDimensionField","fieldTitle","operatorMeta","availableOperators","shouldShowDateRange","shouldShowComboBox","distinctValues","valuesLoading","valuesError","searchValues","useFilterValues","modalHeight","spaceAbove","spaceBelow","modalWidth","shouldAppearAbove","left","flexMatch","singularMatch","num","handleOperatorChange","handleValueSelect","values","handleValueRemove","valueToRemove","v","handleDirectInput","numValue","handleBetweenStartInput","currentValues","newValues","handleBetweenEndInput","handleDateInput","handleRangeTypeChange","newRangeType","today","handleNumberValueChange","handleCustomStartDate","handleCustomEndDate","operatorLabel","op","dateRangeLabel","FieldIcon","renderValueInput","AnalysisFilterItem","onUpdate","isModalOpen","setIsModalOpen","buttonRef","valueDisplay","formatValueDisplay","updatedFilter","AnalysisFilterGroup","group","onAddFilter","depth","hideRemoveButton","isAddMenuOpen","setIsAddMenuOpen","addMenuRef","handleToggleType","newType","handleUpdateFilter","newFilter","newFilters","handleRemoveFilter","handleAddNestedGroup","newGroup","handleAddFilterClick","createNestedAddFilterHandler","nestedIndex","relativePath","getBorderColor","getGroupBgColor","conditionCount","conditionLabel","countFilters","count","getSelectedFields","addFilterAtPath","path","firstIndex","restPath","targetFilter","AnalysisFilterSection","onFiltersChange","onFieldDropped","showFieldModal","setShowFieldModal","isDragOver","setIsDragOver","pendingAddPath","totalFilterCount","handleDragOver","handleDragLeave","handleDrop","handleFieldSelected","_fieldType","_cubeName","defaultOperator","updatedFilters","handleUpdateTopLevelFilter","handleRemoveTopLevelFilter","handleClearAll","createAddFilterHandler","basePath","renderFilter","parentPath","currentPath","AnalysisAxisDropZone","onDrop","onDragOver","draggedItem","getFieldMeta","yAxisAssignment","onYAxisAssignmentChange","description","mandatory","maxItems","emptyText","isDraggedOver","setIsDraggedOver","isReorderDraggedOver","setIsReorderDraggedOver","draggingFieldRef","fieldsRef","getCanAcceptMore","effectiveCount","getIsFull","canAcceptMore","isFull","handleGlobalDragEnd","isTopHalf","fromIndex","handleFieldDragEnd","getDefaultFieldMeta","renderFieldIcon","IconComponent","isLeavingContainer","isRelatedTargetOutside","isBeingDragged","currentAxis","chartConfigRegistry","barChartConfig","lineChartConfig","areaChartConfig","pieChartConfig","scatterChartConfig","bubbleChartConfig","radarChartConfig","radialBarChartConfig","treemapChartConfig","dataTableConfig","activityGridChartConfig","kpiNumberConfig","kpiDeltaConfig","kpiTextConfig","markdownConfig","chartTypeLabels","ChartTypeSelector","selectedType","onTypeChange","compact","labelA","labelB","SelectedIcon","selectedLabel","useCase","chartAvailability","isAvailable","unavailableReason","tooltipText","AnalysisChartConfigPanel","onChartTypeChange","onChartConfigChange","setDraggedItem","availableFields","getChartConfig","getFieldsForDropZone","allAvailableFields","hasChanges","newConfig","dropZone","currentFields","validFields","getFieldType","schemaMeta","breakdownItem","fromAxis","toAxis","fromValue","filteredValue","toValue","dropZoneConfig","dz","handleRemoveFromAxis","_removed","rest","handleReorder","toIndex","axisKey","newArray","movedItem","handleYAxisAssignmentChange","axis","unassignedFields","assignedFields","hasUnassignedFields","AnalysisDisplayConfigPanel","onDisplayConfigChange","AxisFormatControls","AnalysisQueryPanel","activeTab","onActiveTabChange","onAddMetric","onRemoveMetric","onReorderMetrics","onAddBreakdown","onRemoveBreakdown","onBreakdownGranularityChange","onBreakdownComparisonToggle","onReorderBreakdowns","onDropFieldToFilter","_validationStatus","_validationError","activeQueryIndex","mergeStrategy","onActiveQueryChange","onAddQuery","onRemoveQuery","onMergeStrategyChange","breakdownsLocked","combinedMetrics","combinedBreakdowns","multiQueryValidation","comparisonEnabledBreakdown","handleQueryTabClick","handleRemoveQuery","getQueryTabLabel","warning","LZString","keyStrBase64","keyStrUriSafe","baseReverseDic","getBaseValue","alphabet","character","input","res","compressed","uncompressed","TotalLen","current_value","bitsPerChar","getCharFromInt","context_dictionary","context_dictionaryToCreate","context_c","context_wc","context_w","context_enlargeIn","context_dictSize","context_numBits","context_data","context_data_val","context_data_position","ii","length","resetValue","getNextValue","dictionary","enlargeIn","dictSize","numBits","bits","resb","maxpower","power","module","MAX_HASH_LENGTH","SHARE_PREFIX","compressAndEncode","compressToEncodedURIComponent","decodeAndDecompress","encoded","decompressFromEncodedURIComponent","compressWithFallback","fullEncoded","queryOnlyState","queryOnlyEncoded","parseShareHash","hash","clearShareHash","url","sendGeminiMessage","apiKey","userPrompt","endpoint","requestBody","headers","errorMessage","errorData","errorText","extractTextFromResponse","extractTimeDimensions","validateTimeDimensionAlignment","q1TimeDims","qTimeDims","refTimeDim","matchingDim","validateMergeKeys","allFields","detectMeasureCollisions","warnings","measureCounts","collisions","collisionIndices","detectAsymmetricDateRanges","dateRanges","r","validateMultiQueryConfig","isMultiQueryValid","getValidationSummary","AnalysisAIPanel","onPromptChange","isGenerating","hasGeneratedQuery","onGenerate","onAccept","STORAGE_KEY","AUTO_EXECUTE_DELAY","generateId","generateMetricLabel","findDateFilterForField","nested","simple","buildCompareDateRangeFromFilter","timeDimensionField","dateFilter","currentPeriod","priorPeriod","removeComparisonDateFilter","acc","cleanedSubFilters","buildCubeQuery","comparisonFields","filteredFilters","compareDateRange","createInitialState","loadInitialStateFromStorage","disableLocalStorage","saved","AnalysisBuilder","initialQuery","initialChartConfig","initialData","externalColorPalette","disableLocalStorageProp","_hideSettings","onQueryChange","cachedStorage","queryToState","queryStates","setQueryStates","setActiveQueryIndex","setMergeStrategy","multiConfig","q1Breakdowns","updater","prevStates","newStates","needsSync","qs","setChartType","setChartConfig","setDisplayConfig","localPaletteName","setLocalPaletteName","effectiveColorPalette","setActiveTab","setActiveView","setDisplayLimit","userManuallySelectedChart","setUserManuallySelectedChart","setDebugDataPerQuery","fieldModalMode","setFieldModalMode","setShareButtonState","features","aiState","setAIState","sharedState","queryConfig","currentQuery","isMultiQueryMode","allMetrics","validQueries","currentQueryString","debouncedQuery","setDebouncedQuery","debounceTimerRef","lastQueryStringRef","hasInitialDataRef","initialQueryStringRef","prevMetricsBreakdownsRef","chartConfigRef","isValidQuery","hasValidMultiQuery","serverQuery","debouncedMultiConfig","setActiveTableIndex","isChartConfigEmpty","val","currentKey","newChartType","newChartConfig","smartDefaults","timeoutId","activeState","storageState","queriesToFetch","isCancelled","handleAddMetric","handleRemoveMetric","fieldToRemove","newMetrics","newOrder","existingIndex","newMetric","newBreakdown","handleAddBreakdown","handleRemoveBreakdown","newBreakdowns","handleBreakdownGranularityChange","handleBreakdownComparisonToggle","breakdownId","targetBreakdown","isEnabling","currentFilters","updateBreakdowns","handleReorderMetrics","handleReorderBreakdowns","handleFiltersChange","handleDropFieldToFilter","existingFilters","handleOrderChange","direction","handleAddQuery","currentState","newState","handleActiveQueryChange","handleMergeStrategyChange","seen","combined","qIndex","handleClearQuery","handleOpenAI","handleCloseAI","handleAIPromptChange","prompt","handleGenerateAI","responseText","aiChartType","aiChartConfig","handleAcceptAI","handleCancelAI","handleChartTypeChange","handleChartConfigChange","handleDisplayConfigChange","handleShare","shareableState","queryOnly","QueryBuilderShim","analysisBuilderRef","AxisDropZone","getFieldStyling","dragOverIndex","setDragOverIndex","handleReorderDragOver","handleReorderDragLeave","handleReorderDrop","baseClasses","hoverClasses","ChartConfigPanel","dim","SAMPLE_QUERIES","PortletEditModal","submitText","formTitle","setFormTitle","setQuery","setDashboardFilterMapping","isValidating","setIsValidating","validationResult","setValidationResult","lastValidatedQuery","setLastValidatedQuery","dryRunData","setDryRunData","showQueryBuilder","setShowQueryBuilder","queryBuilderInitialQuery","setQueryBuilderInitialQuery","queryBuilderRef","autoPopulateChartConfig","_result","defaultWidth","defaultHeight","formattedQuery","runDryRunValidation","handleSubmit","hasQueryChanged","queryToSave","handleSampleQuery","sampleQuery","handleQueryChange","queryToValidate","silent","isEditModeLoad","parsedQuery","details","errorMsg","handleValidateQuery","handleOpenQueryBuilder","handleApplyQueryBuilderQuery","validationState","handleBackToForm","handleClose","isQueryValidAndCurrent","QueryBuilder","sample","PortletAnalysisModal","builderRef","handleSave","firstQuery","portletData","handleCancel","PortletFilterConfigModal","currentMapping","portletTitle","selectedFilters","setSelectedFilters","handleToggleFilter","filterId","formatFilterPreview","valuesText","filterCount","FilterValueSelector","onValuesChange","hasLoadedInitial","setHasLoadedInitial","lastSearchedTerm","isDimension","shouldFetchValues","handleDropdownToggle","newIsOpen","handleSearchChange","newSearchText","handleDateRangeEndInput","isAndFilter","isOrFilter","getFilterableFields","getAllFilterableFields","getOrganizedFilterFields","countFilter","createSimpleFilter","member","createAndFilter","createOrFilter","getMeasureIcon","FilterIcon","FilterItem","onFilterChange","onFilterRemove","hideFieldSelector","hideOperatorSelector","isFieldDropdownOpen","setIsFieldDropdownOpen","fieldSearchTerm","setFieldSearchTerm","customDates","setCustomDates","handleFieldDropdownToggle","newOpen","handleOperatorDropdownToggle","queryFields","selectedField","shouldShowDateRangeSelector","flexibleRangeMatch","filterFieldsBySearch","filteredQueryFields","filteredAllFields","getFieldTypeBadge","handleFieldChange","newFieldType","handleValuesChange","handleDateRangeChange","cubeRangeValue","handleCustomDateChange","newCustomDates","handleNumberChange","selectedRangeLabel","FilterGroup","onGroupChange","onGroupChangeWithUnwrap","onGroupRemove","showAddMenu","setShowAddMenu","isAndGroup","groupType","indentClass","borderColor","bgColor","textColor","handleGroupTypeToggle","handleAddSimpleFilter","defaultField","handleAddAndGroup","handleAddOrGroup","handleFilterChange","filterIndex","handleFilterRemove","updatedGroup","handleNestedGroupChange","handleNestedGroupRemove","FilterBuilder","allFilterableFields","hasFilterableFields","andGroup","existingAndGroup","updatedAndGroup","existingOrGroup","updatedOrGroup","handleGroupChange","handleGroupChangeWithUnwrap","handleGroupRemove","handleClearAllFilters","CalendarIcon","DateRangeSelector","availableTimeDimensions","currentDateRange","onDateRangeChange","onTimeDimensionChange","getCurrentRangeType","getCurrentDates","getCurrentNumber","isRangeDropdownOpen","setIsRangeDropdownOpen","isTimeDimensionDropdownOpen","setIsTimeDimensionDropdownOpen","handleTimeDimensionDropdownToggle","handleRangeDropdownToggle","handleTimeDimensionChange","newTimeDimension","CubeRelationshipDiagram","lazy","mod","CubeMetaExplorer","schemaStatus","schemaError","onFieldSelect","onFieldDeselect","onRetrySchema","onOpenSettings","onViewTypeChange","isExpanded","ChevronRightIcon","SettingsIcon","SegmentIcon","MenuIcon","showSchemaDiagram","expandedCubes","setExpandedCubes","expandedSections","setExpandedSections","viewType","setViewType","preSearchExpandedCubes","setPreSearchExpandedCubes","preSearchExpandedSections","setPreSearchExpandedSections","newExpandedCubes","newExpandedSections","cubeHasMatches","combinedCubes","combinedSections","isCorsError","toggleCubeExpansion","newExpanded","newPreSearchExpanded","toggleSectionExpansion","sectionKey","handleFieldClick","filterFields","measureMatches","dimensionMatches","FieldItem","icon","getSelectedStyles","getIconColor","getCheckmarkColor","SectionHeader","getSectionType","NoMatchesMessage","Suspense","qbFieldType","fullFieldName","arr","filteredCubes","regularDimensions","CubeMetaExplorer$1","EyeIcon","EyeOffIcon","FilterEditModal","convertToMetaResponse","localLabel","setLocalLabel","localFilter","setLocalFilter","showAllFields","setShowAllFields","dashboardFields","filteredSchema","filteredMeasures","fullName","filteredDimensions","filteredCubeMeta","selectedFieldInFilter","handleLabelChange","newLabel","handleFilterBuilderChange","handleFieldSelect","_timeDim","validateFilter","validation","ClockIcon","ReadOnlyFilterList","isTimeDimensionField","renderReadOnlyFilter","dashboardFilter","isUniversalTime","isTimeDim","dateRangeValue","_index","EditModeFilterList","onAddTimeFilter","onEditFilter","onRemoveFilter","onFilterSelect","isCollapsed","setIsCollapsed","renderFilterChip","DashboardFilterPanel","onDashboardFiltersChange","onSaveFilters","editingFilter","setEditingFilter","showFilterBuilder","setShowFilterBuilder","cubeMeta","generateFilterId","handleAddFilter","handleAddTimeFilter","handleEditFilter","filterToEdit","handleSaveFilter","filterData","existingFilterIndex","handleCloseFilterBuilder","handleFilterDateRangeChange","handleReadOnlyFilterChange","ScaledGridWrapper","scaleFactor","designWidth","actualHeight","setActualHeight","innerRef","visualHeight","findScrollableAncestor","style","overflowY","overflowX","hasScrollableOverflow","hasScrollContent","MobileStackedLayout","onPortletRefresh","portletComponentRefs","setScrollContainer","setContainerRef","sortedPortlets","handlePortletRefresh","ScrollContainerProvider","portletHeight","headerHeight","contentHeight","ChartBarIcon","DeleteIcon","DesktopIcon","DEFAULT_GRID_SETTINGS","createRowId","getGridSettings","equalizeRowColumns","portletIds","cols","minW","minTotal","base","remainder","remaining","extra","adjustRowWidths","columns","adjusted","total","overflow","reducible","delta","convertPortletsToRows","rowsByY","rowY","rowPortlets","normalizeRows","convertRowsToPortlets","currentY","updated","currentX","updatedIds","DashboardGrid","onConfigChange","dashboardModes","containerWidth","displayMode","isResponsiveEditable","useResponsiveDashboard","fallbackMode","configMode","containerElementRef","scrollContainerRef","editBarRef","combinedContainerRef","foundScrollContainer","draftRows","setDraftRows","draftRowsRef","dragStateRef","isDraggingPortlet","setIsDraggingPortlet","portletRefs","isInitialized","setIsInitialized","lastKnownLayout","setLastKnownLayout","setIsEditMode","setSelectedFilterId","isPortletModalOpen","setIsPortletModalOpen","editingPortlet","setEditingPortlet","isFilterConfigModalOpen","setIsFilterConfigModalOpen","filterConfigPortlet","setFilterConfigPortlet","setDebugData","resolvedRows","baseRows","updateRowLayout","save","portletsOverride","normalizedRows","updatedPortlets","updatedConfig","initialLayout","hasLayoutActuallyChanged","newLayout","newItem","oldItem","handleLayoutChange","_layout","handleDragStop","layout","_oldItem","_newItem","_placeholder","_e","_element","mutableLayout","layoutItem","handleResizeStop","handleLayoutModeChange","startRowResize","startY","startRows","handleMouseMove","moveEvent","deltaUnits","nextRows","handleMouseUp","finalRows","startColumnResize","startX","leftColumn","rightColumn","nextLeft","nextRight","diff","rowItem","nextColumns","colIndex","handleRowDrop","insertIndex","dragState","sourceRowIndex","sourceRow","movedColumn","sourceRowRemoved","targetRowIndex","targetRow","handleNewRowDrop","newRow","portletComponent","handleAddPortlet","handleEditPortlet","handlePortletSave","isNewPortlet","newPortletId","newPortlet","gridLayout","maxY","scrollToPortlet","portletElement","handleDeletePortlet","handleDuplicatePortlet","originalPortlet","duplicatedPortlet","handlePaletteChange","handleOpenFilterConfig","handleSaveFilterConfig","mapping","handleSetPortletRef","handleSetPortletComponentRef","portletIcons","handleToggleFilterForPortlet","hasFilter","handleFilterSelect","handleSelectAllForFilter","selectedFilter","renderPortletCard","baseLayout","renderActiveLayout","ReactGridLayout","verticalCompactor","AnalyticsDashboard","propDashboardFilters","onDirtyStateChange","initialConfigRef","hasConfigChangedFromInitial","mergedDashboardFilters","configFilters","propFilters","configFilter","propFilter","pf","configIds","cf","handleSaveWithDirtyTracking","handleConfigChangeWithDirtyTracking","initialConfigString","handleDashboardFiltersChange","PortletContainer","DashboardEditModal","initialName","initialDescription","setName","setDescription","isSaving","setIsSaving"],"mappings":"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ACJ,GAEQC,IAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IACA;AAAA,EACJ,GAEQC,IAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,GAGQC,IAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,GAKQC,IAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;A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","x_google_ignoreList":[0,24,25,26,46]}