drizzle-cube 0.4.21 → 0.4.23

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 (102) hide show
  1. package/dist/adapters/express/index.cjs +1 -1
  2. package/dist/adapters/express/index.js +2 -2
  3. package/dist/adapters/fastify/index.cjs +1 -1
  4. package/dist/adapters/fastify/index.js +2 -2
  5. package/dist/adapters/{handler-B-tEntiU.cjs → handler-C3hT7g2W.cjs} +1 -1
  6. package/dist/adapters/{handler-9Rdn7zM2.js → handler-t7Qd1IYi.js} +1 -1
  7. package/dist/adapters/hono/index.cjs +6 -6
  8. package/dist/adapters/hono/index.d.ts +13 -6
  9. package/dist/adapters/hono/index.js +65 -65
  10. package/dist/adapters/{mcp-transport-m1X1GtwG.js → mcp-transport-B6ZudTSk.js} +7 -0
  11. package/dist/adapters/{mcp-transport-8u9G5oNa.cjs → mcp-transport-DCiSGtp1.cjs} +1 -1
  12. package/dist/adapters/nextjs/index.cjs +2 -2
  13. package/dist/adapters/nextjs/index.js +2 -2
  14. package/dist/client/charts.js +12 -12
  15. package/dist/client/chunks/{RetentionCombinedChart-CLq89aOJ.js → RetentionCombinedChart-BK3NPsHP.js} +2 -2
  16. package/dist/client/chunks/{RetentionCombinedChart-CLq89aOJ.js.map → RetentionCombinedChart-BK3NPsHP.js.map} +1 -1
  17. package/dist/client/chunks/{analysis-builder-3z9fHE2F.js → analysis-builder-DVrv9Q4n.js} +9 -9
  18. package/dist/client/chunks/{analysis-builder-3z9fHE2F.js.map → analysis-builder-DVrv9Q4n.js.map} +1 -1
  19. package/dist/client/chunks/{analysis-builder-shared-Da-vlQa_.js → analysis-builder-shared-CrENEvEk.js} +6 -6
  20. package/dist/client/chunks/{analysis-builder-shared-Da-vlQa_.js.map → analysis-builder-shared-CrENEvEk.js.map} +1 -1
  21. package/dist/client/chunks/{chart-activity-grid-CPGcTSuh.js → chart-activity-grid-OG6he4YS.js} +2 -2
  22. package/dist/client/chunks/{chart-activity-grid-CPGcTSuh.js.map → chart-activity-grid-OG6he4YS.js.map} +1 -1
  23. package/dist/client/chunks/{chart-area-ByJQ7NZd.js → chart-area-TawAd2k9.js} +3 -3
  24. package/dist/client/chunks/{chart-area-ByJQ7NZd.js.map → chart-area-TawAd2k9.js.map} +1 -1
  25. package/dist/client/chunks/{chart-bar-dj14frMt.js → chart-bar-D3vtCNQG.js} +2 -2
  26. package/dist/client/chunks/{chart-bar-dj14frMt.js.map → chart-bar-D3vtCNQG.js.map} +1 -1
  27. package/dist/client/chunks/{chart-box-plot-ZatBpatq.js → chart-box-plot-BXwN2rO5.js} +2 -2
  28. package/dist/client/chunks/{chart-box-plot-ZatBpatq.js.map → chart-box-plot-BXwN2rO5.js.map} +1 -1
  29. package/dist/client/chunks/{chart-bubble-CemotLx-.js → chart-bubble-ZfNe8t5k.js} +2 -2
  30. package/dist/client/chunks/{chart-bubble-CemotLx-.js.map → chart-bubble-ZfNe8t5k.js.map} +1 -1
  31. package/dist/client/chunks/{chart-candlestick-BIR4uGGt.js → chart-candlestick-DmF3haFu.js} +2 -2
  32. package/dist/client/chunks/{chart-candlestick-BIR4uGGt.js.map → chart-candlestick-DmF3haFu.js.map} +1 -1
  33. package/dist/client/chunks/{chart-data-table-BsAjHe7o.js → chart-data-table-DJZPkArt.js} +4 -4
  34. package/dist/client/chunks/{chart-data-table-BsAjHe7o.js.map → chart-data-table-DJZPkArt.js.map} +1 -1
  35. package/dist/client/chunks/{chart-funnel-dofnhD24.js → chart-funnel-CE9x0Io9.js} +2 -2
  36. package/dist/client/chunks/{chart-funnel-dofnhD24.js.map → chart-funnel-CE9x0Io9.js.map} +1 -1
  37. package/dist/client/chunks/{chart-gauge-CKJJ8m3b.js → chart-gauge-Djs5FWxB.js} +2 -2
  38. package/dist/client/chunks/{chart-gauge-CKJJ8m3b.js.map → chart-gauge-Djs5FWxB.js.map} +1 -1
  39. package/dist/client/chunks/{chart-heat-map-BVuPUKHT.js → chart-heat-map-CqtMkdxd.js} +2 -2
  40. package/dist/client/chunks/{chart-heat-map-BVuPUKHT.js.map → chart-heat-map-CqtMkdxd.js.map} +1 -1
  41. package/dist/client/chunks/{chart-kpi-delta-DUD3f8vL.js → chart-kpi-delta-DEzA74cL.js} +4 -4
  42. package/dist/client/chunks/{chart-kpi-delta-DUD3f8vL.js.map → chart-kpi-delta-DEzA74cL.js.map} +1 -1
  43. package/dist/client/chunks/{chart-kpi-number-iJh-PzsM.js → chart-kpi-number-Bab-BZtX.js} +3 -3
  44. package/dist/client/chunks/{chart-kpi-number-iJh-PzsM.js.map → chart-kpi-number-Bab-BZtX.js.map} +1 -1
  45. package/dist/client/chunks/{chart-kpi-text-x6pV9v9Q.js → chart-kpi-text-BkTgckDJ.js} +3 -3
  46. package/dist/client/chunks/{chart-kpi-text-x6pV9v9Q.js.map → chart-kpi-text-BkTgckDJ.js.map} +1 -1
  47. package/dist/client/chunks/{chart-line-DzyZkugh.js → chart-line-DhM-Hvu0.js} +3 -3
  48. package/dist/client/chunks/{chart-line-DzyZkugh.js.map → chart-line-DhM-Hvu0.js.map} +1 -1
  49. package/dist/client/chunks/{chart-measure-profile-C2IkBG3V.js → chart-measure-profile-4vQxFm69.js} +3 -3
  50. package/dist/client/chunks/{chart-measure-profile-C2IkBG3V.js.map → chart-measure-profile-4vQxFm69.js.map} +1 -1
  51. package/dist/client/chunks/{chart-pie-akbfRfb9.js → chart-pie-B86KRcHI.js} +2 -2
  52. package/dist/client/chunks/{chart-pie-akbfRfb9.js.map → chart-pie-B86KRcHI.js.map} +1 -1
  53. package/dist/client/chunks/{chart-radar-BaN-Kjww.js → chart-radar-BhDBmJRh.js} +2 -2
  54. package/dist/client/chunks/{chart-radar-BaN-Kjww.js.map → chart-radar-BhDBmJRh.js.map} +1 -1
  55. package/dist/client/chunks/{chart-radial-bar-DpptEL3s.js → chart-radial-bar-Brugya8X.js} +2 -2
  56. package/dist/client/chunks/{chart-radial-bar-DpptEL3s.js.map → chart-radial-bar-Brugya8X.js.map} +1 -1
  57. package/dist/client/chunks/{chart-sankey-CG-3hHmX.js → chart-sankey-D2L8ympI.js} +2 -2
  58. package/dist/client/chunks/{chart-sankey-CG-3hHmX.js.map → chart-sankey-D2L8ympI.js.map} +1 -1
  59. package/dist/client/chunks/{chart-scatter-l_yTVxF3.js → chart-scatter-CAkbBDkK.js} +2 -2
  60. package/dist/client/chunks/{chart-scatter-l_yTVxF3.js.map → chart-scatter-CAkbBDkK.js.map} +1 -1
  61. package/dist/client/chunks/{chart-sunburst-KhDcKhmZ.js → chart-sunburst-DaxJ-cob.js} +2 -2
  62. package/dist/client/chunks/{chart-sunburst-KhDcKhmZ.js.map → chart-sunburst-DaxJ-cob.js.map} +1 -1
  63. package/dist/client/chunks/{chart-tree-map-CBbiaBXV.js → chart-tree-map-CrDJAvZU.js} +2 -2
  64. package/dist/client/chunks/{chart-tree-map-CBbiaBXV.js.map → chart-tree-map-CrDJAvZU.js.map} +1 -1
  65. package/dist/client/chunks/{chart-waterfall-CX3vx_lI.js → chart-waterfall-BBwSfEKT.js} +3 -3
  66. package/dist/client/chunks/{chart-waterfall-CX3vx_lI.js.map → chart-waterfall-BBwSfEKT.js.map} +1 -1
  67. package/dist/client/chunks/{charts-core-CU9u_HtL.js → charts-core-B4Rbfdcn.js} +2 -2
  68. package/dist/client/chunks/{charts-core-CU9u_HtL.js.map → charts-core-B4Rbfdcn.js.map} +1 -1
  69. package/dist/client/chunks/{charts-loader-B3tt5oKG.js → charts-loader-DbrwgvCK.js} +25 -25
  70. package/dist/client/chunks/{charts-loader-B3tt5oKG.js.map → charts-loader-DbrwgvCK.js.map} +1 -1
  71. package/dist/client/chunks/{components-CMGGxqOB.js → components-GzooQM5J.js} +9 -9
  72. package/dist/client/chunks/{components-CMGGxqOB.js.map → components-GzooQM5J.js.map} +1 -1
  73. package/dist/client/chunks/{core-D_8mkGpQ.js → core-Y9e-sNfb.js} +2 -2
  74. package/dist/client/chunks/{core-D_8mkGpQ.js.map → core-Y9e-sNfb.js.map} +1 -1
  75. package/dist/client/chunks/{icons-M7shurcH.js → icons-DFJw-2HU.js} +6 -6
  76. package/dist/client/chunks/{icons-M7shurcH.js.map → icons-DFJw-2HU.js.map} +1 -1
  77. package/dist/client/chunks/{providers-CgxXm6Ll.js → providers-CCw8Kjlc.js} +2 -2
  78. package/dist/client/chunks/{providers-CgxXm6Ll.js.map → providers-CCw8Kjlc.js.map} +1 -1
  79. package/dist/client/chunks/{syntaxHighlighting-BQfjio-i.js → syntaxHighlighting-DAMSW_A6.js} +2 -2
  80. package/dist/client/chunks/{syntaxHighlighting-BQfjio-i.js.map → syntaxHighlighting-DAMSW_A6.js.map} +1 -1
  81. package/dist/client/chunks/{useDirtyStateTracking-Cu1HSjmo.js → useDirtyStateTracking-CjhwBXRw.js} +20 -20
  82. package/dist/client/chunks/{useDirtyStateTracking-Cu1HSjmo.js.map → useDirtyStateTracking-CjhwBXRw.js.map} +1 -1
  83. package/dist/client/chunks/useExplainAI-IiW55BaQ.js +182 -0
  84. package/dist/client/chunks/useExplainAI-IiW55BaQ.js.map +1 -0
  85. package/dist/client/chunks/{vendor-AVsJ2ni0.js → vendor-B2EH3V58.js} +7 -7
  86. package/dist/client/chunks/{vendor-AVsJ2ni0.js.map → vendor-B2EH3V58.js.map} +1 -1
  87. package/dist/client/components.js +1 -1
  88. package/dist/client/hooks/useNotebookLayout.d.ts +8 -0
  89. package/dist/client/hooks.d.ts +2 -0
  90. package/dist/client/hooks.js +51 -190
  91. package/dist/client/hooks.js.map +1 -1
  92. package/dist/client/icons.js +1 -1
  93. package/dist/client/index.js +871 -742
  94. package/dist/client/index.js.map +1 -1
  95. package/dist/client/providers.js +1 -1
  96. package/dist/client/styles.css +1 -1
  97. package/dist/client/utils.js +7 -7
  98. package/dist/client-bundle-stats.html +1 -1
  99. package/dist/server/index.cjs +1 -1
  100. package/dist/server/index.d.ts +5 -0
  101. package/dist/server/index.js +7 -0
  102. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-builder-shared-Da-vlQa_.js","sources":["../../../src/shared/date-utils.ts","../../../src/client/components/AnalysisBuilder/utils/filterUtils.ts","../../../src/client/components/AnalysisBuilder/utils/queryUtils.ts","../../../src/client/components/AnalysisBuilder/utils/storageUtils.ts","../../../src/client/shared/chartDefaults.ts","../../../src/client/components/AnalysisBuilder/ExplainAIPanel.tsx","../../../src/client/components/AnalysisBuilder/ExecutionPlanPanel.tsx","../../../src/client/adapters/queryModeAdapter.ts","../../../src/client/adapters/adapterRegistry.ts","../../../src/client/stores/slices/coreSlice.ts","../../../src/client/stores/slices/querySlice.ts","../../../src/client/stores/slices/funnelSlice.ts","../../../src/client/stores/slices/flowSlice.ts","../../../src/client/stores/slices/retentionSlice.ts","../../../src/client/stores/slices/uiSlice.ts","../../../src/client/stores/analysisBuilderStore.tsx","../../../src/client/utils/multiQueryValidation.ts","../../../src/client/hooks/useAnalysisQueryBuilder.ts","../../../src/client/hooks/useAnalysisCombinedFields.ts","../../../src/client/hooks/useAnalysisQueryExecution.ts","../../../src/client/hooks/useAnalysisChartDefaults.ts","../../../src/client/hooks/useAnalysisUIState.ts","../../../src/client/utils/shareUtils.ts","../../../src/client/hooks/useAnalysisInitialization.ts","../../../src/client/hooks/useAnalysisBuilderHook.ts","../../../src/client/utils/funnelValidation.ts"],"sourcesContent":["/**\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 * Filter Manipulation Utilities for AnalysisBuilder\n *\n * Functions for searching, modifying, and removing filters from filter arrays.\n * These handle both simple filters and nested group filters (AND/OR).\n */\n\nimport type { Filter } from '../../../types'\nimport { parseDateRange, calculatePriorPeriod, formatDateForCube } from '../../../../shared/date-utils'\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 */\nexport function 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 */\nexport function 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 */\nexport function 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 * Query Building Utilities for AnalysisBuilder\n *\n * Functions for constructing CubeQuery objects from builder state.\n */\n\nimport type { CubeQuery, Filter } from '../../../types'\nimport type { MetricItem, BreakdownItem } from '../types'\nimport { removeComparisonDateFilter, buildCompareDateRangeFromFilter } from './filterUtils'\nimport { shouldIncludeFilter } from '../../../utils/filterUtils'\n\n/**\n * Convert metrics and breakdowns to CubeQuery format\n * Handles comparison mode by building compareDateRange for time dimensions\n */\nexport function buildCubeQuery(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n filters: Filter[],\n order?: Record<string, 'asc' | 'desc'>,\n preserveComparisonFilters: boolean = false\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 if (!preserveComparisonFilters) {\n for (const field of comparisonFields) {\n filteredFilters = removeComparisonDateFilter(filteredFilters, field)\n }\n }\n\n // Strip filters with empty values (e.g., {member: \"X.id\", values: [], operator: \"equals\"})\n // These generate AND FALSE conditions on the server\n filteredFilters = filteredFilters.filter(f => shouldIncludeFilter(f))\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 * 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 * State Persistence Utilities for AnalysisBuilder\n *\n * Functions for saving and loading builder state from localStorage.\n */\n\nimport type { Filter } from '../../../types'\nimport type { MetricItem, BreakdownItem, AnalysisBuilderState, AnalysisBuilderStorageState } from '../types'\n\n// Storage key for localStorage persistence\n// v3: Uses slice composition and AnalysisConfig format (clean break from v2)\nexport const STORAGE_KEY = 'drizzle-cube-analysis-builder-v3'\n\n/** @deprecated Use STORAGE_KEY instead */\nexport const STORAGE_KEY_V2 = 'drizzle-cube-analysis-builder-v2'\n\n/**\n * Create initial empty state for AnalysisBuilder\n *\n * Note: Only client-side configuration state is stored.\n * Server state (execution results, loading, errors) is managed by TanStack Query.\n */\nexport function createInitialState(): AnalysisBuilderState {\n return {\n metrics: [],\n breakdowns: [],\n filters: [],\n order: undefined,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Load all state from localStorage once (to avoid repeated parsing)\n */\nexport function 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\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 (legacy format for backward compatibility)\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 * 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 * ExplainAIPanel - Display AI analysis of EXPLAIN plans in a modal\n *\n * Shows:\n * - Assessment badge (good/warning/critical)\n * - Query understanding\n * - Issues identified\n * - Actionable recommendations with code snippets\n *\n * Displayed in a near full-screen modal with scrolling support\n */\n\nimport React from 'react'\nimport type { AIExplainAnalysis, ExplainRecommendation, ExplainIssue } from '../../types'\nimport CodeBlock from '../../shared/components/CodeBlock'\n\ninterface ExplainAIPanelProps {\n /** AI analysis result */\n analysis: AIExplainAnalysis\n /** Callback to close the modal */\n onClose?: () => void\n /** Legacy: Callback to clear/close (backward compatible with old API) */\n onClear?: () => void\n}\n\n/**\n * Helper to safely render text that might be an object from AI\n * AI responses sometimes return objects instead of strings for text fields\n */\nfunction safeText(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'object' && value !== null) return JSON.stringify(value)\n return String(value ?? '')\n}\n\n/**\n * Color classes for assessment badges\n */\nconst assessmentColors = {\n good: 'bg-dc-success-bg text-dc-success border-dc-success',\n warning: 'bg-dc-warning-bg text-dc-warning border-dc-warning',\n critical: 'bg-dc-danger-bg text-dc-error border-dc-error',\n}\n\n/**\n * Color classes for severity badges\n */\nconst severityColors = {\n critical: 'bg-dc-danger-bg text-dc-error',\n warning: 'bg-dc-warning-bg text-dc-warning',\n suggestion: 'bg-dc-accent-bg text-dc-accent',\n}\n\n/**\n * Color classes for issue severity\n */\nconst issueSeverityColors = {\n high: 'text-dc-error',\n medium: 'text-dc-warning',\n low: 'text-dc-text-muted',\n}\n\n/**\n * Assessment badge component\n */\nfunction AssessmentBadge({ assessment, reason }: { assessment: 'good' | 'warning' | 'critical'; reason: unknown }) {\n const labels = {\n good: 'Good',\n warning: 'Warning',\n critical: 'Critical',\n }\n\n return (\n <div className={`dc:p-4 dc:rounded-lg dc:border ${assessmentColors[assessment]}`}>\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:mb-1\">\n <span className=\"dc:font-semibold dc:uppercase dc:text-base\">\n {assessment === 'good' && '✓ '}\n {assessment === 'warning' && '⚠ '}\n {assessment === 'critical' && '✕ '}\n {labels[assessment]}\n </span>\n </div>\n <p className=\"dc:text-sm\">{safeText(reason)}</p>\n </div>\n )\n}\n\n/**\n * Issue item component\n */\nfunction IssueItem({ issue }: { issue: ExplainIssue }) {\n return (\n <div className=\"dc:flex dc:items-start dc:gap-2 dc:py-2\">\n <span className={`dc:text-sm ${issueSeverityColors[issue.severity]}`}>\n {issue.severity === 'high' && '●'}\n {issue.severity === 'medium' && '○'}\n {issue.severity === 'low' && '○'}\n </span>\n <span className=\"dc:text-sm text-dc-text-secondary\">{safeText(issue.description)}</span>\n </div>\n )\n}\n\n/**\n * Copy button component\n */\nfunction CopyButton({ text }: { text: string }) {\n const [copied, setCopied] = React.useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <button\n onClick={handleCopy}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:rounded bg-dc-surface hover:bg-dc-surface-hover text-dc-text-muted\"\n title=\"Copy to clipboard\"\n >\n {copied ? 'Copied!' : 'Copy'}\n </button>\n )\n}\n\n/**\n * Recommendation card component\n */\nfunction RecommendationCard({ rec }: { rec: ExplainRecommendation }) {\n const typeLabels = {\n index: 'INDEX',\n table: 'TABLE',\n cube: 'CUBE',\n general: 'TIP',\n }\n\n return (\n <div className=\"dc:p-4 dc:border border-dc-border dc:rounded-lg bg-dc-surface\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:mb-2\">\n <span\n className={`dc:px-2 dc:py-0.5 dc:text-xs dc:font-medium dc:rounded ${severityColors[rec.severity]}`}\n >\n {typeLabels[rec.type]}\n </span>\n <h5 className=\"dc:font-medium text-dc-text\">{safeText(rec.title)}</h5>\n </div>\n\n {/* Description */}\n <p className=\"dc:text-sm text-dc-text-secondary dc:mb-3\">{safeText(rec.description)}</p>\n\n {/* SQL code for index/table recommendations */}\n {rec.sql && (\n <div className=\"dc:mt-2\">\n <CodeBlock\n code={rec.sql}\n language=\"sql\"\n headerRight={<CopyButton text={rec.sql} />}\n />\n </div>\n )}\n\n {/* TypeScript code for cube recommendations - display as text since CodeBlock doesn't support TS */}\n {rec.cubeCode && (\n <div className=\"dc:mt-2\">\n {rec.cubeName && (\n <p className=\"dc:text-xs text-dc-text-muted dc:mb-1\">\n Add to <code className=\"bg-dc-surface-secondary dc:px-1 dc:rounded\">{rec.cubeName}</code> cube:\n </p>\n )}\n <div className=\"dc:relative\">\n <pre className=\"dc:p-3 dc:text-xs bg-dc-surface-secondary dc:rounded dc:overflow-x-auto dc:font-mono text-dc-text\">\n {rec.cubeCode}\n </pre>\n <div className=\"dc:absolute dc:top-1 dc:right-1\">\n <CopyButton text={rec.cubeCode} />\n </div>\n </div>\n </div>\n )}\n\n {/* Expected impact */}\n {rec.estimatedImpact && (\n <p className=\"dc:text-xs text-dc-text-muted dc:mt-2\">\n <strong>Expected impact:</strong> {safeText(rec.estimatedImpact)}\n </p>\n )}\n </div>\n )\n}\n\n/**\n * ExplainAIPanel - Modal component for displaying AI analysis results\n * Shows in a near full-screen modal with scrolling\n */\nexport function ExplainAIPanel({ analysis, onClose, onClear }: ExplainAIPanelProps) {\n // Support both onClose (new) and onClear (legacy) for backward compatibility\n const handleClose = onClose || onClear\n\n // Close on Escape key\n React.useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && handleClose) {\n handleClose()\n }\n }\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [handleClose])\n\n // Prevent body scroll when modal is open\n React.useEffect(() => {\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = ''\n }\n }, [])\n\n return (\n <div className=\"dc:fixed dc:inset-0 dc:z-50 dc:flex dc:items-center dc:justify-center dc:p-4 bg-black/50\">\n {/* Modal backdrop */}\n <div\n className=\"dc:absolute dc:inset-0\"\n onClick={handleClose}\n aria-hidden=\"true\"\n />\n\n {/* Modal content */}\n <div className=\"dc:relative dc:w-full dc:max-w-4xl dc:max-h-[90vh] bg-dc-surface dc:rounded-lg dc:shadow-xl dc:flex dc:flex-col\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-6 dc:py-4 dc:border-b border-dc-border dc:flex-shrink-0\">\n <div className=\"dc:flex dc:items-center dc:gap-3\">\n <span className=\"dc:text-lg\">✨</span>\n <h3 className=\"dc:text-lg dc:font-semibold text-dc-text\">AI Performance Analysis</h3>\n </div>\n <button\n onClick={handleClose}\n className=\"dc:p-2 dc:rounded-lg hover:bg-dc-surface-hover text-dc-text-secondary hover:text-dc-text dc:transition-colors\"\n aria-label=\"Close\"\n >\n <svg className=\"dc:w-5 dc:h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Scrollable content */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:px-6 dc:py-4 dc:space-y-6\">\n {/* Assessment */}\n <AssessmentBadge\n assessment={analysis.assessment}\n reason={analysis.assessmentReason}\n />\n\n {/* Summary */}\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">Summary</h4>\n <p className=\"text-dc-text\">{safeText(analysis.summary)}</p>\n </div>\n\n {/* Query Understanding */}\n {analysis.queryUnderstanding && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">Query Analysis</h4>\n <p className=\"text-dc-text-secondary\">{safeText(analysis.queryUnderstanding)}</p>\n </div>\n )}\n\n {/* Issues */}\n {analysis.issues && analysis.issues.length > 0 && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">\n Issues Found ({analysis.issues.length})\n </h4>\n <div className=\"dc:space-y-1 bg-dc-surface-secondary dc:rounded-lg dc:p-3\">\n {analysis.issues.map((issue, i) => (\n <IssueItem key={i} issue={issue} />\n ))}\n </div>\n </div>\n )}\n\n {/* Recommendations */}\n {analysis.recommendations && analysis.recommendations.length > 0 && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-3\">\n Recommendations ({analysis.recommendations.length})\n </h4>\n <div className=\"dc:space-y-4\">\n {analysis.recommendations.map((rec, i) => (\n <RecommendationCard key={i} rec={rec} />\n ))}\n </div>\n </div>\n )}\n\n {/* No recommendations case */}\n {(!analysis.recommendations || analysis.recommendations.length === 0) && (\n <div className=\"text-dc-text-muted dc:italic dc:p-4 bg-dc-surface-secondary dc:rounded-lg\">\n No specific recommendations. The query appears to be well-optimized.\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-6 dc:py-3 dc:border-t border-dc-border dc:flex-shrink-0 bg-dc-surface-secondary\">\n {/* Meta info */}\n {analysis._meta && (\n <div className=\"dc:text-xs text-dc-text-muted\">\n Model: {analysis._meta.model}\n {analysis._meta.usingUserKey && ' (using your API key)'}\n </div>\n )}\n <button\n onClick={handleClose}\n className=\"dc:px-4 dc:py-2 dc:text-sm dc:font-medium dc:rounded-lg bg-dc-primary text-white hover:bg-dc-primary-hover dc:transition-colors\"\n >\n Close\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ExplainAIPanel\n","/**\n * ExecutionPlanPanel - Shared component for SQL display, EXPLAIN plans, and AI analysis\n *\n * Used across all analysis modes (query, funnel, flow) to show:\n * - Generated SQL with copy functionality\n * - Explain Plan button with \"Include timing\" toggle\n * - EXPLAIN results with summary badges\n * - AI Analysis button (in Explain Plan header) and modal\n *\n * This is a composable component - the parent handles the layout,\n * this component handles the SQL -> Explain -> AI workflow.\n */\n\nimport { useState, memo } from 'react'\nimport { CodeBlock } from '../../shared'\nimport { ExplainAIPanel } from './ExplainAIPanel'\nimport type { ExplainResult, AIExplainAnalysis } from '../../types'\n\ninterface ExecutionPlanPanelProps {\n /** The generated SQL to display */\n sql: { sql: string; params?: unknown[] } | null | undefined\n /** Whether SQL is loading */\n sqlLoading?: boolean\n /** Error loading SQL */\n sqlError?: Error | null\n /** Placeholder text when no SQL */\n sqlPlaceholder?: string\n\n /** EXPLAIN plan result */\n explainResult: ExplainResult | null\n /** Whether EXPLAIN is running */\n explainLoading?: boolean\n /** Whether EXPLAIN has been run at least once */\n explainHasRun?: boolean\n /** Error running EXPLAIN */\n explainError?: Error | null\n /** Run EXPLAIN with options */\n runExplain: (options: { analyze: boolean }) => void\n\n /** AI analysis result */\n aiAnalysis?: AIExplainAnalysis | null\n /** Whether AI analysis is in progress */\n aiAnalysisLoading?: boolean\n /** Error from AI analysis */\n aiAnalysisError?: Error | null\n /** Run AI analysis */\n runAIAnalysis?: (explainResult: ExplainResult, query: unknown) => void\n /** Clear AI analysis (unused but kept for interface compatibility) */\n clearAIAnalysis?: () => void\n /** Whether AI is enabled */\n enableAI?: boolean\n\n /** The query object for AI context */\n query?: unknown\n\n /** Title for the SQL block */\n title?: string\n /** Height for the SQL block */\n height?: string\n}\n\n/**\n * ExecutionPlanPanel - Displays SQL, EXPLAIN results, and AI analysis\n */\nexport const ExecutionPlanPanel = memo(function ExecutionPlanPanel({\n sql,\n sqlLoading = false,\n sqlError,\n sqlPlaceholder = 'Add metrics to generate SQL',\n\n explainResult,\n explainLoading = false,\n explainHasRun = false,\n explainError,\n runExplain,\n\n aiAnalysis,\n aiAnalysisLoading = false,\n aiAnalysisError,\n runAIAnalysis,\n clearAIAnalysis: _clearAIAnalysis,\n enableAI = false,\n\n query,\n\n title = 'Generated SQL',\n height = '16rem',\n}: ExecutionPlanPanelProps) {\n const [useAnalyze, setUseAnalyze] = useState(false)\n const [showAIModal, setShowAIModal] = useState(false)\n\n // Format SQL with parameters\n const formattedSql = sql\n ? sql.sql +\n (sql.params && sql.params.length > 0\n ? '\\n\\n-- Parameters:\\n' + JSON.stringify(sql.params, null, 2)\n : '')\n : ''\n\n // Handle AI analysis - always re-run to get fresh results after schema/index changes\n const handleAIClick = () => {\n if (runAIAnalysis && explainResult && query) {\n // Always run fresh analysis - indexes may have been added since last run\n runAIAnalysis(explainResult, query)\n setShowAIModal(true)\n }\n }\n\n // Close modal\n const handleCloseModal = () => {\n setShowAIModal(false)\n }\n\n // Build the AI button for use in Explain Plan header\n const aiButton = enableAI && explainResult ? (\n <button\n onClick={handleAIClick}\n disabled={aiAnalysisLoading}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium dc:rounded bg-dc-accent text-white hover:bg-dc-accent-hover dc:disabled:opacity-50 dc:disabled:cursor-not-allowed dc:flex dc:items-center dc:gap-1\"\n >\n {aiAnalysisLoading ? (\n <>\n <span className=\"dc:animate-spin\">⟳</span>\n Analyzing...\n </>\n ) : (\n <>✨ AI Analysis</>\n )}\n </button>\n ) : null\n\n return (\n <div className=\"dc:space-y-3\">\n {/* SQL Block */}\n {sqlLoading ? (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm dc:animate-pulse\" style={{ height }}>\n Loading SQL...\n </div>\n </>\n ) : sqlError ? (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\" style={{ height }}>\n {sqlError.message}\n </div>\n </>\n ) : sql ? (\n <CodeBlock\n code={formattedSql}\n language=\"sql\"\n title={title}\n height={height}\n headerRight={\n <>\n {/* Include timing checkbox */}\n <label className=\"dc:flex dc:items-center dc:gap-1 dc:text-xs text-dc-text-secondary dc:cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={useAnalyze}\n onChange={(e) => setUseAnalyze(e.target.checked)}\n className=\"dc:w-3 dc:h-3 dc:rounded border-dc-border text-dc-accent focus:ring-dc-accent\"\n />\n Include timing\n </label>\n\n {/* Explain Plan button */}\n <button\n onClick={() => runExplain({ analyze: useAnalyze })}\n disabled={explainLoading}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium dc:rounded dc:border border-dc-border bg-dc-surface hover:bg-dc-surface-hover text-dc-text-secondary hover:text-dc-text dc:transition-colors dc:disabled:opacity-50 dc:disabled:cursor-not-allowed\"\n >\n {explainLoading ? 'Running...' : 'Explain Plan'}\n </button>\n </>\n }\n />\n ) : (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm\" style={{ height }}>\n {sqlPlaceholder}\n </div>\n </>\n )}\n\n {/* EXPLAIN Results */}\n {explainHasRun && (\n <div>\n {explainLoading ? (\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm dc:animate-pulse\">\n Running EXPLAIN{useAnalyze ? ' ANALYZE' : ''}...\n </div>\n ) : explainError ? (\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\">\n <strong>Explain Error:</strong> {explainError.message}\n </div>\n ) : explainResult ? (\n <div className=\"dc:space-y-3\">\n {/* Summary badges */}\n <div className=\"dc:flex dc:flex-wrap dc:items-center dc:gap-2\">\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-accent text-white dc:rounded\">\n {explainResult.summary.database.toUpperCase()}\n </span>\n {explainResult.summary.hasSequentialScans && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-warning-bg text-dc-warning dc:border border-dc-warning dc:rounded\">\n Sequential Scans Detected\n </span>\n )}\n {explainResult.summary.usedIndexes.length > 0 && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-success-bg text-dc-success dc:border border-dc-success dc:rounded\">\n {explainResult.summary.usedIndexes.length} Index{explainResult.summary.usedIndexes.length !== 1 ? 'es' : ''} Used\n </span>\n )}\n {explainResult.summary.executionTime !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Execution: {explainResult.summary.executionTime.toFixed(2)}ms\n </span>\n )}\n {explainResult.summary.planningTime !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Planning: {explainResult.summary.planningTime.toFixed(2)}ms\n </span>\n )}\n {explainResult.summary.totalCost !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Cost: {explainResult.summary.totalCost.toFixed(2)}\n </span>\n )}\n </div>\n\n {/* Index usage details */}\n {explainResult.summary.usedIndexes.length > 0 && (\n <div className=\"dc:text-xs text-dc-text-muted\">\n <strong>Indexes:</strong> {explainResult.summary.usedIndexes.join(', ')}\n </div>\n )}\n\n {/* Raw EXPLAIN output with AI button in header */}\n <CodeBlock\n code={explainResult.raw}\n language=\"sql\"\n title={`Execution Plan (${explainResult.summary.database})`}\n height=\"16rem\"\n headerRight={aiButton}\n />\n </div>\n ) : null}\n </div>\n )}\n\n {/* AI Analysis Error (shown inline) */}\n {aiAnalysisError && (\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\">\n <strong>AI Analysis Error:</strong> {aiAnalysisError.message}\n </div>\n )}\n\n {/* AI Analysis Modal */}\n {showAIModal && aiAnalysis && (\n <ExplainAIPanel\n analysis={aiAnalysis}\n onClose={handleCloseModal}\n />\n )}\n </div>\n )\n})\n\nexport default ExecutionPlanPanel\n","/**\n * Query Mode Adapter\n *\n * Handles conversion between UI state and AnalysisConfig for query mode.\n * Supports both single queries and multi-query configurations.\n */\n\nimport type { ModeAdapter, ValidationResult } from './modeAdapter'\nimport type {\n AnalysisConfig,\n QueryAnalysisConfig,\n AnalysisType,\n ChartConfig,\n} from '../types/analysisConfig'\nimport { generateId, generateMetricLabel } from '../components/AnalysisBuilder/utils'\nimport { buildCompareDateRangeFromFilter } from '../components/AnalysisBuilder/utils/filterUtils'\nimport type {\n CubeQuery,\n MultiQueryConfig,\n QueryMergeStrategy,\n Filter,\n} from '../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n} from '../components/AnalysisBuilder/types'\n\n// ============================================================================\n// Query Slice State Type\n// ============================================================================\n\n/**\n * The shape of query mode state in the store.\n * This is what the adapter's load() returns and save() receives.\n */\nexport interface QuerySliceState {\n /** Array of query states (one per query tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the active query tab */\n activeQueryIndex: number\n /** Strategy for combining multiple queries */\n mergeStrategy: QueryMergeStrategy\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create an empty query state\n */\nfunction createEmptyQueryState(): AnalysisBuilderState {\n return {\n metrics: [],\n breakdowns: [],\n filters: [],\n order: undefined,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Convert metrics to CubeQuery measures\n */\nfunction metricsToMeasures(metrics: MetricItem[]): string[] {\n return metrics.map((m) => m.field)\n}\n\n/**\n * Convert breakdowns to CubeQuery dimensions and timeDimensions\n * Includes compareDateRange for time dimensions with comparison enabled\n */\nfunction breakdownsToQuery(\n breakdowns: BreakdownItem[],\n filters: Filter[]\n): {\n dimensions: string[]\n timeDimensions: NonNullable<CubeQuery['timeDimensions']>\n} {\n const dimensions: string[] = []\n const timeDimensions: NonNullable<CubeQuery['timeDimensions']> = []\n\n for (const b of breakdowns) {\n if (b.isTimeDimension) {\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, calculate and include compareDateRange\n if (b.enableComparison) {\n const compareDateRange = buildCompareDateRangeFromFilter(b.field, filters)\n if (compareDateRange) {\n td.compareDateRange = compareDateRange\n }\n }\n\n timeDimensions.push(td)\n } else {\n dimensions.push(b.field)\n }\n }\n\n return { dimensions, timeDimensions }\n}\n\n/**\n * Build a CubeQuery from an AnalysisBuilderState\n */\nfunction stateToCubeQuery(state: AnalysisBuilderState): CubeQuery {\n const { dimensions, timeDimensions } = breakdownsToQuery(\n state.breakdowns,\n state.filters\n )\n\n const query: CubeQuery = {\n measures: metricsToMeasures(state.metrics),\n dimensions,\n }\n\n if (timeDimensions.length > 0) {\n query.timeDimensions = timeDimensions\n }\n\n if (state.filters.length > 0) {\n query.filters = state.filters\n }\n\n if (state.order && Object.keys(state.order).length > 0) {\n query.order = state.order\n }\n\n return query\n}\n\n/**\n * Convert CubeQuery measures to MetricItems\n */\nfunction measuresToMetrics(measures: string[]): MetricItem[] {\n return measures.map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index),\n }))\n}\n\n/**\n * Convert CubeQuery dimensions and timeDimensions to BreakdownItems\n * Restores enableComparison from compareDateRange presence\n */\nfunction queryToBreakdowns(query: CubeQuery): BreakdownItem[] {\n const breakdowns: BreakdownItem[] = []\n\n // Regular dimensions\n if (query.dimensions) {\n for (const dim of query.dimensions) {\n breakdowns.push({\n id: generateId(),\n field: dim,\n isTimeDimension: false,\n })\n }\n }\n\n // Time dimensions\n if (query.timeDimensions) {\n for (const td of query.timeDimensions) {\n // Restore enableComparison if compareDateRange exists\n const hasComparison = Boolean(\n td.compareDateRange && td.compareDateRange.length > 0\n )\n\n breakdowns.push({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true,\n enableComparison: hasComparison,\n })\n }\n }\n\n return breakdowns\n}\n\n/**\n * Convert CubeQuery to AnalysisBuilderState\n */\nfunction cubeQueryToState(query: CubeQuery): AnalysisBuilderState {\n return {\n metrics: measuresToMetrics(query.measures || []),\n breakdowns: queryToBreakdowns(query),\n filters: (query.filters as Filter[]) || [],\n order: query.order,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Check if a query object is a MultiQueryConfig\n */\nfunction isMultiQueryConfig(query: unknown): query is MultiQueryConfig {\n return (\n typeof query === 'object' &&\n query !== null &&\n 'queries' in query &&\n Array.isArray((query as MultiQueryConfig).queries)\n )\n}\n\n// ============================================================================\n// Query Mode Adapter\n// ============================================================================\n\nexport const queryModeAdapter: ModeAdapter<QuerySliceState> = {\n type: 'query',\n\n createInitial(): QuerySliceState {\n return {\n queryStates: [createEmptyQueryState()],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n }\n },\n\n extractState(storeState: Record<string, unknown>): QuerySliceState {\n return {\n queryStates: storeState.queryStates as AnalysisBuilderState[],\n activeQueryIndex: storeState.activeQueryIndex as number,\n mergeStrategy: storeState.mergeStrategy as QueryMergeStrategy,\n }\n },\n\n canLoad(config: unknown): config is AnalysisConfig {\n if (!config || typeof config !== 'object') return false\n\n const c = config as Record<string, unknown>\n\n // Check version and analysis type\n if (c.version !== 1) return false\n if (c.analysisType !== 'query') return false\n\n // Check query exists\n if (!c.query || typeof c.query !== 'object') return false\n\n return true\n },\n\n load(config: AnalysisConfig): QuerySliceState {\n // Type guard - ensure it's a query config\n if (config.analysisType !== 'query') {\n throw new Error(\n `Cannot load ${config.analysisType} config with query adapter`\n )\n }\n\n const queryConfig = config as QueryAnalysisConfig\n\n // Handle multi-query config\n if (isMultiQueryConfig(queryConfig.query)) {\n const multiConfig = queryConfig.query\n const queryStates = multiConfig.queries.map(cubeQueryToState)\n\n // Ensure at least one query state\n if (queryStates.length === 0) {\n queryStates.push(createEmptyQueryState())\n }\n\n return {\n queryStates,\n activeQueryIndex: 0,\n mergeStrategy: multiConfig.mergeStrategy || 'concat',\n }\n }\n\n // Handle single query\n return {\n queryStates: [cubeQueryToState(queryConfig.query)],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n }\n },\n\n save(\n state: QuerySliceState,\n charts: Partial<Record<AnalysisType, ChartConfig>>,\n activeView: 'table' | 'chart'\n ): QueryAnalysisConfig {\n // Build queries from state\n const queries = state.queryStates.map(stateToCubeQuery)\n\n // Determine if single or multi-query\n const isSingle = queries.length === 1 && state.mergeStrategy === 'concat'\n\n // Build the query field\n const query: CubeQuery | MultiQueryConfig = isSingle\n ? queries[0]\n : {\n queries,\n mergeStrategy: state.mergeStrategy,\n }\n\n return {\n version: 1,\n analysisType: 'query',\n activeView,\n charts: {\n query: charts.query || this.getDefaultChartConfig(),\n },\n query,\n }\n },\n\n validate(state: QuerySliceState): ValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Check if any query has metrics\n const hasAnyMetrics = state.queryStates.some((q) => q.metrics.length > 0)\n if (!hasAnyMetrics) {\n errors.push('At least one metric is required')\n }\n\n // Check each query state\n state.queryStates.forEach((qs, index) => {\n const prefix = state.queryStates.length > 1 ? `Query ${index + 1}: ` : ''\n\n if (qs.metrics.length === 0 && qs.breakdowns.length === 0) {\n warnings.push(`${prefix}Query is empty`)\n }\n })\n\n // Multi-query specific validation\n if (state.queryStates.length > 1) {\n if (state.mergeStrategy === 'merge') {\n // Check if all queries have compatible dimensions for merging\n const firstBreakdowns = state.queryStates[0].breakdowns.map(\n (b) => b.field\n )\n const allHaveSameBreakdowns = state.queryStates.every((qs) => {\n const breakdowns = qs.breakdowns.map((b) => b.field)\n return (\n breakdowns.length === firstBreakdowns.length &&\n breakdowns.every((b) => firstBreakdowns.includes(b))\n )\n })\n if (!allHaveSameBreakdowns) {\n warnings.push(\n 'Queries have different breakdowns - merge results may be unexpected'\n )\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n },\n\n clear(_state: QuerySliceState): QuerySliceState {\n // Reset to single empty query (ignoring previous state)\n return this.createInitial()\n },\n\n getDefaultChartConfig(): ChartConfig {\n return {\n chartType: 'bar',\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n },\n}\n","/**\n * Adapter Registry\n *\n * A central registry for mode adapters. This allows the store to look up\n * the appropriate adapter based on analysis type without hardcoding\n * conditionals throughout the codebase.\n *\n * The registry uses lazy initialization to ensure adapters are always\n * available, regardless of import order or tree-shaking. Built-in adapters\n * (query, funnel) are registered automatically on first access.\n *\n * Usage:\n * // Lookup (in store) - adapters are auto-initialized\n * const adapter = adapterRegistry.get(state.analysisType)\n * const modeState = adapter.extractState(storeState)\n *\n * // Manual registration (for custom adapters)\n * adapterRegistry.register(customAdapter)\n */\n\nimport type { ModeAdapter } from './modeAdapter'\nimport type { AnalysisType } from '../types/analysisConfig'\nimport { queryModeAdapter } from './queryModeAdapter'\nimport { funnelModeAdapter } from './funnelModeAdapter'\nimport { flowModeAdapter } from './flowModeAdapter'\nimport { retentionModeAdapter } from './retentionModeAdapter'\n\n// Internal storage for registered adapters\nconst adapters = new Map<AnalysisType, ModeAdapter<unknown>>()\n\n// Track if built-in adapters have been initialized\nlet builtInAdaptersInitialized = false\n\n/**\n * Initialize built-in adapters (query, funnel).\n * Called automatically on first registry access.\n * Safe to call multiple times.\n */\nfunction ensureBuiltInAdaptersInitialized(): void {\n if (builtInAdaptersInitialized) return\n\n if (!adapters.has('query')) {\n adapters.set('query', queryModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('funnel')) {\n adapters.set('funnel', funnelModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('flow')) {\n adapters.set('flow', flowModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('retention')) {\n adapters.set('retention', retentionModeAdapter as ModeAdapter<unknown>)\n }\n\n builtInAdaptersInitialized = true\n}\n\n/**\n * Adapter registry - manages mode adapters\n */\nexport const adapterRegistry = {\n /**\n * Register an adapter for a specific analysis type.\n * Should be called once at app initialization.\n *\n * @param adapter - The adapter to register\n */\n register<T>(adapter: ModeAdapter<T>): void {\n if (adapters.has(adapter.type)) {\n console.warn(\n `[adapterRegistry] Overwriting existing adapter for type: ${adapter.type}`\n )\n }\n adapters.set(adapter.type, adapter as ModeAdapter<unknown>)\n },\n\n /**\n * Get the adapter for a specific analysis type.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @param type - The analysis type to get adapter for\n * @returns The registered adapter\n * @throws Error if no adapter is registered for the type\n */\n get<T>(type: AnalysisType): ModeAdapter<T> {\n ensureBuiltInAdaptersInitialized()\n const adapter = adapters.get(type)\n if (!adapter) {\n throw new Error(\n `[adapterRegistry] No adapter registered for type: ${type}. ` +\n `Available types: ${Array.from(adapters.keys()).join(', ') || 'none'}`\n )\n }\n return adapter as ModeAdapter<T>\n },\n\n /**\n * Check if an adapter is registered for a specific type.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @param type - The analysis type to check\n * @returns True if an adapter is registered\n */\n has(type: AnalysisType): boolean {\n ensureBuiltInAdaptersInitialized()\n return adapters.has(type)\n },\n\n /**\n * Get all registered analysis types.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @returns Array of registered types\n */\n getRegisteredTypes(): AnalysisType[] {\n ensureBuiltInAdaptersInitialized()\n return Array.from(adapters.keys())\n },\n\n /**\n * Clear all registered adapters.\n * Primarily useful for testing.\n * Note: Built-in adapters will be re-initialized on next access.\n */\n clear(): void {\n adapters.clear()\n builtInAdaptersInitialized = false\n },\n}\n","/**\n * Core Slice\n *\n * Handles:\n * - analysisType (mode selection)\n * - charts map (per-mode chart configurations)\n * - save/load delegation to adapters\n *\n * This slice is mode-agnostic - it delegates to the adapter registry\n * for mode-specific logic.\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\n// Import from barrel export to ensure adapters are auto-registered via initializeAdapters()\nimport {\n adapterRegistry,\n queryModeAdapter,\n funnelModeAdapter,\n flowModeAdapter,\n retentionModeAdapter,\n} from '../../adapters'\nimport type {\n AnalysisConfig,\n AnalysisType,\n ChartConfig,\n AnalysisWorkspace,\n QueryAnalysisConfig,\n FunnelAnalysisConfig,\n FlowAnalysisConfig,\n RetentionAnalysisConfig,\n} from '../../types/analysisConfig'\nimport type { ChartType, ChartAxisConfig, ChartDisplayConfig } from '../../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Core slice state\n */\nexport interface CoreSliceState {\n /** Current analysis mode */\n analysisType: AnalysisType\n\n /**\n * Per-mode chart configuration map.\n * Each mode owns its own chart settings.\n * Phase 4: This is now the source of truth for all chart configuration.\n */\n charts: {\n [K in AnalysisType]?: ChartConfig\n }\n\n /**\n * Per-mode active view (table or chart) map.\n * Each mode owns its own view preference.\n * This preserves view preference when switching between modes.\n */\n activeViews: {\n [K in AnalysisType]?: 'table' | 'chart'\n }\n\n /** Whether user manually selected a chart type */\n userManuallySelectedChart: boolean\n /** Color palette name */\n localPaletteName: string\n}\n\n/**\n * Core slice actions\n */\nexport interface CoreSliceActions {\n /** Set the analysis type (switches between Query/Funnel modes) */\n setAnalysisType: (type: AnalysisType) => void\n\n /** Set chart type for current mode */\n setChartType: (type: ChartType) => void\n\n /** Set chart type with manual selection flag */\n setChartTypeManual: (type: ChartType) => void\n\n /** Set chart config for current mode */\n setChartConfig: (config: ChartAxisConfig) => void\n\n /** Set display config for current mode */\n setDisplayConfig: (config: ChartDisplayConfig) => void\n\n /** Set color palette name */\n setLocalPaletteName: (name: string) => void\n\n /** Set user manually selected chart flag */\n setUserManuallySelectedChart: (value: boolean) => void\n\n /**\n * @deprecated Use setChartType() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelChartType: (type: ChartType) => void\n\n /**\n * @deprecated Use setChartConfig() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelChartConfig: (config: ChartAxisConfig) => void\n\n /**\n * @deprecated Use setDisplayConfig() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n\n /**\n * Save current state to AnalysisConfig format.\n * Delegates to the appropriate adapter based on analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n save: () => AnalysisConfig\n\n /**\n * Load state from AnalysisConfig.\n * Delegates to the appropriate adapter based on config.analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n load: (config: AnalysisConfig) => void\n\n /**\n * Save ALL modes to AnalysisWorkspace format.\n * Used for localStorage persistence to preserve state across mode switches.\n */\n saveWorkspace: () => AnalysisWorkspace\n\n /**\n * Load ALL modes from AnalysisWorkspace.\n * Used for localStorage persistence to restore state for all modes.\n */\n loadWorkspace: (workspace: AnalysisWorkspace) => void\n}\n\nexport type CoreSlice = CoreSliceState & CoreSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialCoreState = (): CoreSliceState => ({\n analysisType: 'query',\n\n // Use adapter defaults as single source of truth for chart configuration\n charts: {\n query: queryModeAdapter.getDefaultChartConfig(),\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n flow: flowModeAdapter.getDefaultChartConfig(),\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n\n // Per-mode active view preference\n activeViews: {\n query: 'chart',\n funnel: 'chart',\n flow: 'chart',\n retention: 'chart',\n },\n\n userManuallySelectedChart: false,\n localPaletteName: 'default',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the core slice.\n * Uses StateCreator pattern for composability with other slices.\n */\nexport const createCoreSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n CoreSlice\n> = (set, get) => ({\n ...createInitialCoreState(),\n\n setAnalysisType: (type) => {\n set((state) => {\n // Ensure the target mode has chart config (apply defaults if missing)\n const charts = { ...state.charts }\n if (!charts[type]) {\n const adapter = adapterRegistry.get(type)\n charts[type] = adapter.getDefaultChartConfig()\n }\n const activeViews = { ...state.activeViews }\n if (!activeViews[type]) {\n activeViews[type] = 'chart'\n }\n return {\n analysisType: type,\n charts,\n activeViews,\n activeView: activeViews[type] ?? 'chart',\n }\n })\n },\n\n setChartType: (type) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartType: type },\n },\n }\n })\n },\n\n setChartTypeManual: (type) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartType: type },\n },\n userManuallySelectedChart: true,\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setChartConfig: (config) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: 'bar',\n chartConfig: config,\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartConfig: config },\n },\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setDisplayConfig: (config) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: 'bar',\n chartConfig: {},\n displayConfig: config,\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, displayConfig: config },\n },\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setLocalPaletteName: (name) => set({ localPaletteName: name }),\n\n setUserManuallySelectedChart: (value) => set({ userManuallySelectedChart: value }),\n\n // @deprecated - Use setChartType() instead\n // Kept for backward compatibility\n setFunnelChartType: (type) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, chartType: type },\n },\n }\n })\n },\n\n // @deprecated - Use setChartConfig() instead\n // Kept for backward compatibility\n setFunnelChartConfig: (config) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: 'funnel',\n chartConfig: config,\n displayConfig: {},\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, chartConfig: config },\n },\n }\n })\n },\n\n // @deprecated - Use setDisplayConfig() instead\n // Kept for backward compatibility\n setFunnelDisplayConfig: (config) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: 'funnel',\n chartConfig: {},\n displayConfig: config,\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, displayConfig: config },\n },\n }\n })\n },\n\n save: () => {\n const state = get()\n const adapter = adapterRegistry.get(state.analysisType)\n\n // Use adapter's extractState method for mode-specific state\n const modeState = adapter.extractState(state as unknown as Record<string, unknown>)\n\n // Use per-mode activeView, falling back to legacy activeView\n const activeView = state.activeViews[state.analysisType] ?? state.activeView ?? 'chart'\n\n return adapter.save(modeState, state.charts, activeView)\n },\n\n load: (config) => {\n const adapter = adapterRegistry.get(config.analysisType)\n\n // Validate config can be loaded\n if (!adapter.canLoad(config)) {\n console.warn('[coreSlice] Invalid config, cannot load')\n return\n }\n\n const modeState = adapter.load(config)\n\n // Merge charts to preserve other modes' settings\n const currentState = get()\n const mergedCharts = {\n ...currentState.charts,\n ...config.charts,\n }\n\n // Apply defaults if current mode's chart config is missing\n if (!mergedCharts[config.analysisType]) {\n mergedCharts[config.analysisType] = adapter.getDefaultChartConfig()\n }\n\n // Merge activeViews to preserve other modes' view preferences\n const mergedActiveViews = {\n ...currentState.activeViews,\n [config.analysisType]: config.activeView,\n }\n\n // Update state (mode-agnostic)\n set({\n analysisType: config.analysisType,\n charts: mergedCharts,\n activeView: config.activeView,\n activeViews: mergedActiveViews,\n // Mode-specific state from adapter\n ...(modeState as any),\n })\n },\n\n saveWorkspace: (): AnalysisWorkspace => {\n const state = get()\n const stateAsRecord = state as unknown as Record<string, unknown>\n\n // Save query mode state using adapter's extractState\n const queryAdapter = adapterRegistry.get('query')\n const queryModeState = queryAdapter.extractState(stateAsRecord)\n const queryActiveView = state.activeViews.query ?? state.activeView ?? 'chart'\n const queryConfig = queryAdapter.save(\n queryModeState,\n state.charts,\n queryActiveView\n ) as QueryAnalysisConfig\n\n // Save funnel mode state using adapter's extractState\n const funnelAdapter = adapterRegistry.get('funnel')\n const funnelModeState = funnelAdapter.extractState(stateAsRecord)\n const funnelActiveView = state.activeViews.funnel ?? state.activeView ?? 'chart'\n const funnelConfig = funnelAdapter.save(\n funnelModeState,\n state.charts,\n funnelActiveView\n ) as FunnelAnalysisConfig\n\n // Save flow mode state using adapter's extractState\n const flowAdapter = adapterRegistry.get('flow')\n const flowModeState = flowAdapter.extractState(stateAsRecord)\n const flowActiveView = state.activeViews.flow ?? state.activeView ?? 'chart'\n const flowConfig = flowAdapter.save(\n flowModeState,\n state.charts,\n flowActiveView\n ) as FlowAnalysisConfig\n\n // Save retention mode state using adapter's extractState\n const retentionAdapter = adapterRegistry.get('retention')\n const retentionModeState = retentionAdapter.extractState(stateAsRecord)\n const retentionActiveView = state.activeViews.retention ?? state.activeView ?? 'chart'\n const retentionConfig = retentionAdapter.save(\n retentionModeState,\n state.charts,\n retentionActiveView\n ) as RetentionAnalysisConfig\n\n return {\n version: 1,\n activeType: state.analysisType,\n modes: {\n query: queryConfig,\n funnel: funnelConfig,\n flow: flowConfig,\n retention: retentionConfig,\n },\n }\n },\n\n loadWorkspace: (workspace: AnalysisWorkspace): void => {\n const queryAdapter = adapterRegistry.get('query')\n const funnelAdapter = adapterRegistry.get('funnel')\n const flowAdapter = adapterRegistry.get('flow')\n const retentionAdapter = adapterRegistry.get('retention')\n\n let queryModeState: Record<string, unknown> = {}\n let funnelModeState: Record<string, unknown> = {}\n let flowModeState: Record<string, unknown> = {}\n let retentionModeState: Record<string, unknown> = {}\n let mergedCharts = { ...get().charts }\n let mergedActiveViews = { ...get().activeViews }\n\n // Load query mode if present\n if (workspace.modes.query && queryAdapter.canLoad(workspace.modes.query)) {\n queryModeState = queryAdapter.load(workspace.modes.query) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.query.charts }\n mergedActiveViews.query = workspace.modes.query.activeView ?? 'chart'\n }\n\n // Load funnel mode if present\n if (workspace.modes.funnel && funnelAdapter.canLoad(workspace.modes.funnel)) {\n funnelModeState = funnelAdapter.load(workspace.modes.funnel) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.funnel.charts }\n mergedActiveViews.funnel = workspace.modes.funnel.activeView ?? 'chart'\n }\n\n // Load flow mode if present\n if (workspace.modes.flow && flowAdapter.canLoad(workspace.modes.flow)) {\n flowModeState = flowAdapter.load(workspace.modes.flow) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.flow.charts }\n mergedActiveViews.flow = workspace.modes.flow.activeView ?? 'chart'\n }\n\n // Load retention mode if present\n if (workspace.modes.retention && retentionAdapter.canLoad(workspace.modes.retention)) {\n retentionModeState = retentionAdapter.load(workspace.modes.retention) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.retention.charts }\n mergedActiveViews.retention = workspace.modes.retention.activeView ?? 'chart'\n }\n\n // Determine activeView from the active mode's config\n const activeConfig = workspace.modes[workspace.activeType]\n const activeView = activeConfig?.activeView ?? 'chart'\n\n set({\n analysisType: workspace.activeType,\n charts: mergedCharts,\n activeViews: mergedActiveViews,\n activeView,\n ...queryModeState,\n ...funnelModeState,\n ...flowModeState,\n ...retentionModeState,\n })\n },\n})\n","/**\n * Query Slice\n *\n * Handles query mode state and actions:\n * - queryStates (array of query configurations)\n * - activeQueryIndex (current query tab)\n * - mergeStrategy (how to combine multiple queries)\n * - All metrics, breakdowns, filters actions\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type {\n Filter,\n SimpleFilter,\n QueryMergeStrategy,\n CubeQuery,\n MultiQueryConfig,\n} from '../../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n} from '../../components/AnalysisBuilder/types'\nimport {\n generateId,\n generateMetricLabel,\n createInitialState,\n buildCubeQuery,\n} from '../../components/AnalysisBuilder/utils'\nimport { convertDateRangeTypeToValue } from '../../shared/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Query slice state\n */\nexport interface QuerySliceState {\n /** Array of query states (one per tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the currently active query tab */\n activeQueryIndex: number\n /** Strategy for merging multi-query results */\n mergeStrategy: QueryMergeStrategy\n}\n\n/**\n * Query slice actions\n */\nexport interface QuerySliceActions {\n // Query state management\n setQueryStates: (states: AnalysisBuilderState[]) => void\n updateQueryState: (\n index: number,\n updater: (state: AnalysisBuilderState) => AnalysisBuilderState\n ) => void\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n\n // Multi-query actions\n addQuery: () => void\n removeQuery: (index: number) => void\n\n // Metrics actions\n addMetric: (field: string, label?: string) => void\n removeMetric: (id: string) => void\n toggleMetric: (fieldName: string) => void\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n\n // Breakdowns actions\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n removeBreakdown: (id: string) => void\n toggleBreakdown: (fieldName: string, isTimeDimension: boolean, granularity?: string) => void\n setBreakdownGranularity: (id: string, granularity: string) => void\n toggleBreakdownComparison: (id: string) => void\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n\n // Filters actions\n setFilters: (filters: Filter[]) => void\n dropFieldToFilter: (field: string) => void\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n\n // Utility actions\n getCurrentState: () => AnalysisBuilderState\n getMergeKeys: () => string[] | undefined\n isMultiQueryMode: () => boolean\n buildCurrentQuery: () => CubeQuery\n buildAllQueries: () => CubeQuery[]\n buildMultiQueryConfig: () => MultiQueryConfig | null\n}\n\nexport type QuerySlice = QuerySliceState & QuerySliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialQueryState = (): QuerySliceState => ({\n queryStates: [createInitialState()],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the query slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createQuerySlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n QuerySlice\n> = (set, get) => ({\n ...createInitialQueryState(),\n\n // ==========================================================================\n // Query State Management\n // ==========================================================================\n\n setQueryStates: (states) => set({ queryStates: states }),\n\n updateQueryState: (index, updater) =>\n set((state) => {\n const newStates = [...state.queryStates]\n newStates[index] = updater(newStates[index] || createInitialState())\n return { queryStates: newStates }\n }),\n\n setActiveQueryIndex: (index) => set({ activeQueryIndex: index }),\n\n setMergeStrategy: (strategy) => set({ mergeStrategy: strategy }),\n\n // ==========================================================================\n // Multi-Query Actions\n // ==========================================================================\n\n addQuery: () =>\n set((state) => {\n const currentState = state.queryStates[state.activeQueryIndex] || createInitialState()\n const newState: AnalysisBuilderState = {\n ...createInitialState(),\n metrics: [...currentState.metrics],\n breakdowns: [...currentState.breakdowns],\n filters: [...currentState.filters],\n }\n return {\n queryStates: [...state.queryStates, newState],\n activeQueryIndex: state.queryStates.length,\n }\n }),\n\n removeQuery: (index) =>\n set((state) => {\n if (state.queryStates.length <= 1) return state\n const newStates = state.queryStates.filter((_, i) => i !== index)\n let newActiveIndex = state.activeQueryIndex\n if (index === state.activeQueryIndex) {\n newActiveIndex = Math.max(0, state.activeQueryIndex - 1)\n } else if (index < state.activeQueryIndex) {\n newActiveIndex = state.activeQueryIndex - 1\n }\n return { queryStates: newStates, activeQueryIndex: newActiveIndex }\n }),\n\n // ==========================================================================\n // Metrics Actions\n // ==========================================================================\n\n addMetric: (field, label) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newMetric: MetricItem = {\n id: generateId(),\n field,\n label: label || generateMetricLabel(currentState.metrics.length),\n }\n newStates[index] = {\n ...currentState,\n metrics: [...currentState.metrics, newMetric],\n }\n return { queryStates: newStates }\n }),\n\n removeMetric: (id) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const fieldToRemove = currentState.metrics.find((m) => m.id === id)?.field\n const newMetrics = currentState.metrics.filter((m) => m.id !== id)\n\n // Clean up sort order for removed field\n let newOrder = currentState.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 newStates[index] = {\n ...currentState,\n metrics: newMetrics,\n order: newOrder,\n }\n return { queryStates: newStates }\n }),\n\n toggleMetric: (fieldName) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingIndex = currentState.metrics.findIndex((m) => m.field === fieldName)\n\n if (existingIndex >= 0) {\n newStates[index] = {\n ...currentState,\n metrics: currentState.metrics.filter((_, i) => i !== existingIndex),\n }\n } else {\n const newMetric: MetricItem = {\n id: generateId(),\n field: fieldName,\n label: generateMetricLabel(currentState.metrics.length),\n }\n newStates[index] = {\n ...currentState,\n metrics: [...currentState.metrics, newMetric],\n }\n }\n return { queryStates: newStates }\n }),\n\n reorderMetrics: (fromIndex, toIndex) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newMetrics = [...currentState.metrics]\n const [movedItem] = newMetrics.splice(fromIndex, 1)\n newMetrics.splice(toIndex, 0, movedItem)\n newStates[index] = {\n ...currentState,\n metrics: newMetrics,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Breakdowns Actions\n // ==========================================================================\n\n addBreakdown: (field, isTimeDimension, granularity) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n\n // Only allow one time dimension\n if (isTimeDimension) {\n const hasExisting = currentState.breakdowns.some((b) => b.isTimeDimension)\n if (hasExisting) return state\n }\n\n const newBreakdown: BreakdownItem = {\n id: generateId(),\n field,\n isTimeDimension,\n granularity: isTimeDimension ? granularity || 'month' : undefined,\n }\n newStates[index] = {\n ...currentState,\n breakdowns: [...currentState.breakdowns, newBreakdown],\n }\n return { queryStates: newStates }\n }),\n\n removeBreakdown: (id) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const fieldToRemove = currentState.breakdowns.find((b) => b.id === id)?.field\n const newBreakdowns = currentState.breakdowns.filter((b) => b.id !== id)\n\n // Clean up sort order for removed field\n let newOrder = currentState.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 newStates[index] = {\n ...currentState,\n breakdowns: newBreakdowns,\n order: newOrder,\n }\n return { queryStates: newStates }\n }),\n\n toggleBreakdown: (fieldName, isTimeDimension, granularity) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingIndex = currentState.breakdowns.findIndex((b) => b.field === fieldName)\n\n if (existingIndex >= 0) {\n newStates[index] = {\n ...currentState,\n breakdowns: currentState.breakdowns.filter((_, i) => i !== existingIndex),\n }\n } else {\n // Check if we already have a time dimension\n if (isTimeDimension) {\n const hasExisting = currentState.breakdowns.some((b) => b.isTimeDimension)\n if (hasExisting) return state\n }\n\n const newBreakdown: BreakdownItem = {\n id: generateId(),\n field: fieldName,\n isTimeDimension,\n granularity: isTimeDimension ? granularity || 'month' : undefined,\n }\n newStates[index] = {\n ...currentState,\n breakdowns: [...currentState.breakdowns, newBreakdown],\n }\n }\n return { queryStates: newStates }\n }),\n\n setBreakdownGranularity: (id, granularity) =>\n set((state) => {\n const { mergeStrategy, activeQueryIndex, queryStates } = state\n const newStates = [...queryStates]\n\n // In merge mode, granularity changes update Q1 (source of truth)\n const targetIndex = mergeStrategy === 'merge' && activeQueryIndex > 0 ? 0 : activeQueryIndex\n\n newStates[targetIndex] = {\n ...newStates[targetIndex],\n breakdowns: newStates[targetIndex].breakdowns.map((b) =>\n b.id === id ? { ...b, granularity } : b\n ),\n }\n return { queryStates: newStates }\n }),\n\n toggleBreakdownComparison: (id) =>\n set((state) => {\n const { mergeStrategy, activeQueryIndex, queryStates, charts, analysisType } = state\n const newStates = [...queryStates]\n\n // Get source breakdowns based on mode\n const sourceIndex = mergeStrategy === 'merge' && activeQueryIndex > 0 ? 0 : activeQueryIndex\n\n // Find the breakdown being toggled\n const targetBreakdown = newStates[sourceIndex].breakdowns.find((b) => b.id === id)\n const isEnablingComparison = targetBreakdown && !targetBreakdown.enableComparison\n\n // Update breakdowns with comparison toggle\n const updatedBreakdowns = newStates[sourceIndex].breakdowns.map((b) => {\n if (b.id === id) {\n return { ...b, enableComparison: !b.enableComparison }\n }\n // Clear comparison from other time dimensions\n if (b.isTimeDimension && b.enableComparison) {\n return { ...b, enableComparison: false }\n }\n return b\n })\n\n newStates[sourceIndex] = {\n ...newStates[sourceIndex],\n breakdowns: updatedBreakdowns,\n }\n\n // Build result object\n const result: Partial<AnalysisBuilderStore> = { queryStates: newStates }\n\n // If enabling comparison, auto-add date filter if not present\n if (isEnablingComparison && targetBreakdown?.isTimeDimension && targetBreakdown.field) {\n const currentFilters = newStates[sourceIndex].filters || []\n\n // Check if a date filter already exists for this field\n const hasDateFilter = currentFilters.some((f) => {\n if ('member' in f) {\n const simple = f as SimpleFilter\n return simple.member === targetBreakdown.field && simple.operator === 'inDateRange'\n }\n return false\n })\n\n // If no date filter exists, add one with 'this month' as default\n if (!hasDateFilter) {\n const newDateFilter: SimpleFilter = {\n member: targetBreakdown.field,\n operator: 'inDateRange',\n values: [],\n dateRange: convertDateRangeTypeToValue('last_n_months', 3),\n } as SimpleFilter\n\n newStates[sourceIndex] = {\n ...newStates[sourceIndex],\n filters: [...currentFilters, newDateFilter],\n }\n result.queryStates = newStates\n }\n\n // Auto-switch to line chart if not already (line chart is best for comparison)\n const currentChartConfig = charts[analysisType]\n if (currentChartConfig && currentChartConfig.chartType !== 'line') {\n result.charts = {\n ...charts,\n [analysisType]: {\n ...currentChartConfig,\n chartType: 'line',\n },\n }\n result.userManuallySelectedChart = false\n result.activeView = 'chart'\n result.activeViews = {\n ...state.activeViews,\n [analysisType]: 'chart',\n }\n }\n }\n\n return result\n }),\n\n reorderBreakdowns: (fromIndex, toIndex) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newBreakdowns = [...currentState.breakdowns]\n const [movedItem] = newBreakdowns.splice(fromIndex, 1)\n newBreakdowns.splice(toIndex, 0, movedItem)\n newStates[index] = {\n ...currentState,\n breakdowns: newBreakdowns,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Filters Actions\n // ==========================================================================\n\n setFilters: (filters) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n newStates[index] = {\n ...newStates[index],\n filters,\n }\n return { queryStates: newStates }\n }),\n\n dropFieldToFilter: (field) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingFilters = currentState.filters || []\n\n // Check if we already have a filter for this field\n const hasFilter = existingFilters.some((f) => 'member' in f && f.member === field)\n if (hasFilter) return state\n\n const newFilter: Filter = {\n member: field,\n operator: 'set',\n values: [],\n }\n\n let updatedFilters: Filter[]\n if (existingFilters.length === 0) {\n updatedFilters = [newFilter]\n } else if (existingFilters.length === 1 && 'type' in existingFilters[0]) {\n const group = existingFilters[0] as { type: 'and' | 'or'; filters: Filter[] }\n updatedFilters = [{ ...group, filters: [...group.filters, newFilter] }]\n } else {\n updatedFilters = [{ type: 'and' as const, filters: [...existingFilters, newFilter] }]\n }\n\n newStates[index] = {\n ...currentState,\n filters: updatedFilters,\n }\n return { queryStates: newStates }\n }),\n\n setOrder: (fieldName, direction) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newOrder = { ...(currentState.order || {}) }\n\n if (direction === null) {\n delete newOrder[fieldName]\n } else {\n newOrder[fieldName] = direction\n }\n\n newStates[index] = {\n ...currentState,\n order: Object.keys(newOrder).length > 0 ? newOrder : undefined,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Utility Actions\n // ==========================================================================\n\n getCurrentState: () => {\n const state = get()\n return state.queryStates[state.activeQueryIndex] || createInitialState()\n },\n\n getMergeKeys: () => {\n const state = get()\n if (state.mergeStrategy !== 'merge' || state.queryStates.length === 0) {\n return undefined\n }\n const q1Breakdowns = state.queryStates[0].breakdowns\n if (q1Breakdowns.length === 0) return undefined\n return q1Breakdowns.map((b) => b.field)\n },\n\n isMultiQueryMode: () => {\n const state = get()\n if (state.queryStates.length <= 1) return false\n const queriesWithContent = state.queryStates.filter(\n (qs) => qs.metrics.length > 0 || qs.breakdowns.length > 0\n )\n return queriesWithContent.length > 1\n },\n\n buildCurrentQuery: () => {\n const state = get()\n const current = state.queryStates[state.activeQueryIndex] || createInitialState()\n return buildCubeQuery(current.metrics, current.breakdowns, current.filters, current.order)\n },\n\n buildAllQueries: () => {\n const state = get()\n const q1Breakdowns = state.queryStates[0]?.breakdowns || []\n\n return state.queryStates.map((qs, index) => {\n // In merge mode, Q2+ inherit Q1's breakdowns\n const breakdowns =\n state.mergeStrategy === 'merge' && index > 0 ? q1Breakdowns : qs.breakdowns\n\n return buildCubeQuery(qs.metrics, breakdowns, qs.filters, qs.order)\n })\n },\n\n buildMultiQueryConfig: () => {\n const state = get()\n if (!get().isMultiQueryMode()) return null\n\n const allQueries = get().buildAllQueries()\n // Filter to queries that have at least one measure, dimension, or time dimension\n const validQueries = allQueries.filter((q) => {\n return (\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n })\n\n if (validQueries.length < 2) return null\n\n return {\n queries: validQueries,\n mergeStrategy: state.mergeStrategy,\n mergeKeys: get().getMergeKeys(),\n queryLabels: validQueries.map((_, i) => `Q${i + 1}`),\n }\n },\n})\n","/**\n * Funnel Slice\n *\n * Handles funnel mode state and actions:\n * - funnelCube (selected cube for all steps)\n * - funnelSteps (step definitions)\n * - funnelTimeDimension (temporal ordering)\n * - funnelBindingKey (entity linking)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { FunnelStepState, FunnelBindingKey, FunnelConfig } from '../../types'\nimport type { ServerFunnelQuery } from '../../types/funnel'\nimport { generateId } from '../../components/AnalysisBuilder/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Funnel slice state\n */\nexport interface FunnelSliceState {\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (separate from queryStates) */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Binding key dimension that links funnel steps together */\n funnelBindingKey: FunnelBindingKey | null\n /** @deprecated Use funnelSteps[].timeToConvert instead - kept for backward compat */\n stepTimeToConvert: (string | null)[]\n}\n\n/**\n * Funnel slice actions\n */\nexport interface FunnelSliceActions {\n /** Add a new funnel step */\n addFunnelStep: () => void\n /** Remove a funnel step by index */\n removeFunnelStep: (index: number) => void\n /** Update a funnel step by index */\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n /** Set the active funnel step index */\n setActiveFunnelStepIndex: (index: number) => void\n /** Reorder funnel steps */\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n /** Set the time dimension for funnel */\n setFunnelTimeDimension: (dimension: string | null) => void\n /** Set the funnel binding key */\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n /** Set the funnel cube (clears binding key/time dimension, updates all steps) */\n setFunnelCube: (cube: string | null) => void\n /** @deprecated No-op - use updateFunnelStep with timeToConvert instead */\n setStepTimeToConvert: (stepIndex: number, duration: string | null) => void\n /** @deprecated Always returns null - use buildFunnelQueryFromSteps instead */\n buildFunnelConfig: () => FunnelConfig | null\n /** Build ServerFunnelQuery from dedicated funnelSteps */\n buildFunnelQueryFromSteps: () => ServerFunnelQuery | null\n /** Check if in funnel mode (analysisType === 'funnel') */\n isFunnelMode: () => boolean\n /** Check if funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: () => boolean\n}\n\nexport type FunnelSlice = FunnelSliceState & FunnelSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialFunnelState = (): FunnelSliceState => ({\n funnelCube: null,\n funnelSteps: [],\n activeFunnelStepIndex: 0,\n funnelTimeDimension: null,\n funnelBindingKey: null,\n stepTimeToConvert: [], // Deprecated - kept for backward compat\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the funnel slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createFunnelSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n FunnelSlice\n> = (set, get) => ({\n ...createInitialFunnelState(),\n\n addFunnelStep: () =>\n set((state) => {\n // Copy filters and timeToConvert from last step if exists\n const lastStep = state.funnelSteps[state.funnelSteps.length - 1]\n const newStep: FunnelStepState = {\n id: generateId(),\n name: `Step ${state.funnelSteps.length + 1}`,\n cube: state.funnelCube || '',\n // Deep copy filters from previous step, or empty array if first step\n filters: lastStep?.filters ? JSON.parse(JSON.stringify(lastStep.filters)) : [],\n // Copy timeToConvert from previous step\n timeToConvert: lastStep?.timeToConvert,\n }\n return {\n funnelSteps: [...state.funnelSteps, newStep],\n activeFunnelStepIndex: state.funnelSteps.length,\n }\n }),\n\n removeFunnelStep: (index) =>\n set((state) => {\n if (state.funnelSteps.length <= 1) return state\n const newSteps = state.funnelSteps.filter((_, i) => i !== index)\n const newActiveIndex = Math.min(state.activeFunnelStepIndex, newSteps.length - 1)\n return {\n funnelSteps: newSteps,\n activeFunnelStepIndex: newActiveIndex,\n }\n }),\n\n updateFunnelStep: (index, updates) =>\n set((state) => {\n const newSteps = [...state.funnelSteps]\n if (newSteps[index]) {\n newSteps[index] = { ...newSteps[index], ...updates }\n }\n return { funnelSteps: newSteps }\n }),\n\n setActiveFunnelStepIndex: (index) => set({ activeFunnelStepIndex: index }),\n\n reorderFunnelSteps: (fromIndex, toIndex) =>\n set((state) => {\n const newSteps = [...state.funnelSteps]\n const [removed] = newSteps.splice(fromIndex, 1)\n newSteps.splice(toIndex, 0, removed)\n return { funnelSteps: newSteps }\n }),\n\n setFunnelTimeDimension: (dimension) => set({ funnelTimeDimension: dimension }),\n\n setFunnelBindingKey: (bindingKey) => set({ funnelBindingKey: bindingKey }),\n\n setFunnelCube: (cube) =>\n set((state) => {\n // Update all existing steps to use the new cube\n const updatedSteps = state.funnelSteps.map((step) => ({\n ...step,\n cube: cube || '',\n }))\n return {\n funnelCube: cube,\n // Clear binding key and time dimension since they may not exist in new cube\n funnelBindingKey: null,\n funnelTimeDimension: null,\n funnelSteps: updatedSteps,\n }\n }),\n\n // Deprecated: no-op - legacy queryStates-based funnels are no longer supported\n // Use updateFunnelStep with timeToConvert instead\n setStepTimeToConvert: () => {},\n\n // Deprecated: always returns null - legacy queryStates-based funnels are no longer supported\n // Use buildFunnelQueryFromSteps instead\n buildFunnelConfig: () => null,\n\n // New: Build ServerFunnelQuery from dedicated funnelSteps\n buildFunnelQueryFromSteps: () => {\n const state = get()\n if (state.analysisType !== 'funnel') return null\n if (!state.funnelBindingKey) return null\n if (!state.funnelTimeDimension) return null\n if (state.funnelSteps.length < 2) return null\n\n // Validate all steps have a cube and name\n const validSteps = state.funnelSteps.filter((s) => s.cube && s.name)\n if (validSteps.length < 2) return null\n\n return {\n funnel: {\n bindingKey: state.funnelBindingKey.dimension,\n timeDimension: state.funnelTimeDimension,\n steps: validSteps.map((step) => ({\n name: step.name,\n cube: step.cube,\n filter: step.filters.length > 0 ? step.filters : undefined,\n timeToConvert: step.timeToConvert,\n })),\n includeTimeMetrics: true,\n },\n }\n },\n\n isFunnelMode: () => get().analysisType === 'funnel',\n\n isFunnelModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'funnel') return false\n if (!state.funnelBindingKey) return false\n if (!state.funnelTimeDimension) return false\n if (state.funnelSteps.length < 2) return false\n\n // All steps need at least cube and name\n const validSteps = state.funnelSteps.filter((s) => s.cube && s.name)\n return validSteps.length >= 2\n },\n})\n","/**\n * Flow Slice\n *\n * Handles flow mode state and actions:\n * - flowCube (selected cube for flow analysis)\n * - flowBindingKey (entity linking)\n * - flowTimeDimension (temporal ordering)\n * - startingStep (anchor event definition)\n * - stepsBefore/stepsAfter (exploration depth)\n * - eventDimension (event categorization)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { Filter, FunnelBindingKey } from '../../types'\nimport type { ServerFlowQuery, FlowStartingStep } from '../../types/flow'\nimport { FLOW_MIN_DEPTH, FLOW_MAX_DEPTH } from '../../types/flow'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Flow slice state\n */\nexport interface FlowSliceState {\n /** Selected cube for flow mode (must be an eventStream cube) */\n flowCube: string | null\n /** Binding key that links events to entities */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for event ordering */\n flowTimeDimension: string | null\n /** Starting step configuration (anchor point for exploration) */\n startingStep: FlowStartingStep\n /** Number of steps to explore before starting step (0-5) */\n stepsBefore: number\n /** Number of steps to explore after starting step (0-5) */\n stepsAfter: number\n /** Event dimension that categorizes events (node labels) */\n eventDimension: string | null\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n}\n\n/**\n * Flow slice actions\n */\nexport interface FlowSliceActions {\n /** Set the flow cube (clears binding key/time dimension) */\n setFlowCube: (cube: string | null) => void\n /** Set the flow binding key */\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the flow time dimension */\n setFlowTimeDimension: (dim: string | null) => void\n /** Set the event dimension */\n setEventDimension: (dim: string | null) => void\n /** Set the starting step name */\n setStartingStepName: (name: string) => void\n /** Set all starting step filters at once */\n setStartingStepFilters: (filters: Filter[]) => void\n /** Add a filter to the starting step */\n addStartingStepFilter: (filter: Filter) => void\n /** Remove a filter from the starting step by index */\n removeStartingStepFilter: (index: number) => void\n /** Update a filter in the starting step by index */\n updateStartingStepFilter: (index: number, filter: Filter) => void\n /** Set the number of steps to explore before starting step */\n setStepsBefore: (count: number) => void\n /** Set the number of steps to explore after starting step */\n setStepsAfter: (count: number) => void\n /** Set the join strategy */\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n /** Check if in flow mode (analysisType === 'flow') */\n isFlowMode: () => boolean\n /** Check if flow mode is properly configured and ready for execution */\n isFlowModeEnabled: () => boolean\n /** Build ServerFlowQuery from flow state */\n buildFlowQuery: () => ServerFlowQuery | null\n}\n\nexport type FlowSlice = FlowSliceState & FlowSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialFlowState = (): FlowSliceState => ({\n flowCube: null,\n flowBindingKey: null,\n flowTimeDimension: null,\n startingStep: {\n name: '',\n filters: [],\n },\n stepsBefore: 3,\n stepsAfter: 3,\n eventDimension: null,\n joinStrategy: 'auto',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the flow slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createFlowSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n FlowSlice\n> = (set, get) => ({\n ...createInitialFlowState(),\n\n setFlowCube: (cube) =>\n set(() => ({\n flowCube: cube,\n // Clear binding key and time dimension since they may not exist in new cube\n flowBindingKey: null,\n flowTimeDimension: null,\n eventDimension: null,\n // Reset starting step filters when cube changes\n startingStep: {\n name: '',\n filters: [],\n },\n })),\n\n setFlowBindingKey: (key) => set({ flowBindingKey: key }),\n\n setFlowTimeDimension: (dim) => set({ flowTimeDimension: dim }),\n\n setEventDimension: (dim) => set({ eventDimension: dim }),\n\n setStartingStepName: (name) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n name,\n },\n })),\n\n setStartingStepFilters: (filters) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters,\n },\n })),\n\n addStartingStepFilter: (filter) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters: [...state.startingStep.filters, filter],\n },\n })),\n\n removeStartingStepFilter: (index) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters: state.startingStep.filters.filter((_, i) => i !== index),\n },\n })),\n\n updateStartingStepFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.startingStep.filters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return {\n startingStep: {\n ...state.startingStep,\n filters: newFilters,\n },\n }\n }),\n\n setStepsBefore: (count) =>\n set({\n stepsBefore: Math.max(FLOW_MIN_DEPTH, Math.min(FLOW_MAX_DEPTH, count)),\n }),\n\n setStepsAfter: (count) =>\n set({\n stepsAfter: Math.max(FLOW_MIN_DEPTH, Math.min(FLOW_MAX_DEPTH, count)),\n }),\n\n setJoinStrategy: (strategy) =>\n set(() => ({\n joinStrategy: strategy,\n })),\n\n isFlowMode: () => get().analysisType === 'flow',\n\n isFlowModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'flow') return false\n if (!state.flowCube) return false\n if (!state.flowBindingKey?.dimension) return false\n if (!state.flowTimeDimension) return false\n if (!state.eventDimension) return false\n if (state.startingStep.filters.length === 0) return false\n\n return true\n },\n\n buildFlowQuery: () => {\n const state = get()\n\n if (state.analysisType !== 'flow') return null\n if (!state.flowBindingKey?.dimension) return null\n if (!state.flowTimeDimension) return null\n if (!state.eventDimension) return null\n if (state.startingStep.filters.length === 0) return null\n\n // Convert binding key to server format\n let bindingKey: ServerFlowQuery['flow']['bindingKey']\n if (typeof state.flowBindingKey.dimension === 'string') {\n bindingKey = state.flowBindingKey.dimension\n } else if (Array.isArray(state.flowBindingKey.dimension)) {\n bindingKey = state.flowBindingKey.dimension.map((mapping) => ({\n cube: mapping.cube,\n dimension: mapping.dimension,\n }))\n } else {\n return null\n }\n\n // Convert starting step filter to server format\n // Server accepts Filter | Filter[] for multiple filters\n const startingStepFilter: Filter | Filter[] =\n state.startingStep.filters.length === 1\n ? state.startingStep.filters[0]\n : state.startingStep.filters\n\n // Determine output mode based on chart type\n // Sunburst requires path-qualified nodes, sankey allows path convergence\n const flowChartType = state.charts?.flow?.chartType\n const outputMode: 'sankey' | 'sunburst' =\n flowChartType === 'sunburst' ? 'sunburst' : 'sankey'\n const effectiveStepsBefore = outputMode === 'sunburst' ? 0 : state.stepsBefore\n\n return {\n flow: {\n bindingKey,\n timeDimension: state.flowTimeDimension,\n startingStep: {\n name: state.startingStep.name || 'Starting Step',\n filter: startingStepFilter,\n },\n stepsBefore: effectiveStepsBefore,\n stepsAfter: state.stepsAfter,\n eventDimension: state.eventDimension,\n outputMode,\n joinStrategy: state.joinStrategy,\n },\n }\n },\n})\n","/**\n * Retention Slice\n *\n * Simplified Mixpanel-style retention state management:\n * - Single cube for all analysis\n * - Single timestamp dimension\n * - Single cohort with breakdown support\n * - Granularity = viewing periods\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { Filter, FunnelBindingKey } from '../../types'\nimport type {\n ServerRetentionQuery,\n RetentionSliceState,\n RetentionGranularity,\n RetentionType,\n DateRange,\n RetentionBreakdownItem,\n} from '../../types/retention'\nimport {\n defaultRetentionSliceState,\n RETENTION_MIN_PERIODS,\n RETENTION_MAX_PERIODS,\n} from '../../types/retention'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Retention slice actions\n */\nexport interface RetentionSliceActions {\n /** Set the single cube for retention analysis (clears related fields) */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\nexport type RetentionSlice = RetentionSliceState & RetentionSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialRetentionState = (): RetentionSliceState => ({\n ...defaultRetentionSliceState,\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the retention slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createRetentionSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n RetentionSlice\n> = (set, get) => ({\n ...createInitialRetentionState(),\n\n setRetentionCube: (cube) =>\n set(() => ({\n retentionCube: cube,\n // Clear related fields when cube changes\n retentionTimeDimension: null,\n retentionBindingKey: null,\n retentionCohortFilters: [],\n retentionActivityFilters: [],\n retentionBreakdowns: [],\n })),\n\n setRetentionBindingKey: (key) => set({ retentionBindingKey: key }),\n\n setRetentionTimeDimension: (dim) =>\n set({ retentionTimeDimension: dim }),\n\n setRetentionDateRange: (range) =>\n set({ retentionDateRange: range }),\n\n setRetentionCohortFilters: (filters) =>\n set({ retentionCohortFilters: filters }),\n\n addRetentionCohortFilter: (filter) =>\n set((state) => ({\n retentionCohortFilters: [...state.retentionCohortFilters, filter],\n })),\n\n removeRetentionCohortFilter: (index) =>\n set((state) => ({\n retentionCohortFilters: state.retentionCohortFilters.filter(\n (_, i) => i !== index\n ),\n })),\n\n updateRetentionCohortFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.retentionCohortFilters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return { retentionCohortFilters: newFilters }\n }),\n\n setRetentionActivityFilters: (filters) =>\n set({ retentionActivityFilters: filters }),\n\n addRetentionActivityFilter: (filter) =>\n set((state) => ({\n retentionActivityFilters: [...state.retentionActivityFilters, filter],\n })),\n\n removeRetentionActivityFilter: (index) =>\n set((state) => ({\n retentionActivityFilters: state.retentionActivityFilters.filter(\n (_, i) => i !== index\n ),\n })),\n\n updateRetentionActivityFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.retentionActivityFilters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return { retentionActivityFilters: newFilters }\n }),\n\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) =>\n set({ retentionBreakdowns: breakdowns }),\n\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) =>\n set((state) => ({\n retentionBreakdowns: [...state.retentionBreakdowns, breakdown],\n })),\n\n removeRetentionBreakdown: (field: string) =>\n set((state) => ({\n retentionBreakdowns: state.retentionBreakdowns.filter((b) => b.field !== field),\n })),\n\n setRetentionViewGranularity: (granularity) =>\n set({ retentionViewGranularity: granularity }),\n\n setRetentionPeriods: (periods) =>\n set({\n retentionPeriods: Math.max(\n RETENTION_MIN_PERIODS,\n Math.min(RETENTION_MAX_PERIODS, periods)\n ),\n }),\n\n setRetentionType: (type) => set({ retentionType: type }),\n\n isRetentionMode: () => get().analysisType === 'retention',\n\n isRetentionModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'retention') return false\n if (!state.retentionBindingKey?.dimension) return false\n if (!state.retentionTimeDimension) return false\n\n return true\n },\n\n buildRetentionQuery: () => {\n const state = get()\n\n if (state.analysisType !== 'retention') return null\n if (!state.retentionBindingKey?.dimension) return null\n if (!state.retentionTimeDimension) return null\n\n // Convert binding key to server format\n let bindingKey: ServerRetentionQuery['retention']['bindingKey']\n if (typeof state.retentionBindingKey.dimension === 'string') {\n bindingKey = state.retentionBindingKey.dimension\n } else if (Array.isArray(state.retentionBindingKey.dimension)) {\n bindingKey = state.retentionBindingKey.dimension.map((mapping) => ({\n cube: mapping.cube,\n dimension: mapping.dimension,\n }))\n } else {\n return null\n }\n\n // Build base query\n const query: ServerRetentionQuery = {\n retention: {\n timeDimension: state.retentionTimeDimension,\n bindingKey,\n dateRange: state.retentionDateRange,\n granularity: state.retentionViewGranularity,\n periods: state.retentionPeriods,\n retentionType: state.retentionType,\n },\n }\n\n // Add cohort filters if present\n if (state.retentionCohortFilters.length > 0) {\n query.retention.cohortFilters =\n state.retentionCohortFilters.length === 1\n ? state.retentionCohortFilters[0]\n : state.retentionCohortFilters\n }\n\n // Add activity filters if present\n if (state.retentionActivityFilters.length > 0) {\n query.retention.activityFilters =\n state.retentionActivityFilters.length === 1\n ? state.retentionActivityFilters[0]\n : state.retentionActivityFilters\n }\n\n // Add breakdown dimensions if present\n if (state.retentionBreakdowns.length > 0) {\n query.retention.breakdownDimensions = state.retentionBreakdowns.map((b) => b.field)\n }\n\n return query\n },\n\n getRetentionValidation: () => {\n const state = get()\n const errors: string[] = []\n const warnings: string[] = []\n\n if (state.analysisType !== 'retention') {\n return { isValid: true, errors: [], warnings: [] }\n }\n\n // Check cube\n if (!state.retentionCube) {\n errors.push('Select a cube for retention analysis')\n }\n\n // Check binding key\n if (!state.retentionBindingKey?.dimension) {\n errors.push('Select a user identifier (binding key) to track retention')\n }\n\n // Check timestamp dimension\n if (!state.retentionTimeDimension) {\n errors.push('Select a timestamp dimension for the analysis')\n }\n\n // Check date range (REQUIRED)\n if (!state.retentionDateRange?.start || !state.retentionDateRange?.end) {\n errors.push('Date range is required for retention analysis')\n } else {\n // Validate date format\n const startDate = new Date(state.retentionDateRange.start)\n const endDate = new Date(state.retentionDateRange.end)\n if (isNaN(startDate.getTime())) {\n errors.push('Invalid start date format')\n }\n if (isNaN(endDate.getTime())) {\n errors.push('Invalid end date format')\n }\n if (startDate > endDate) {\n errors.push('Start date must be before or equal to end date')\n }\n }\n\n // Check periods\n if (state.retentionPeriods < 1) {\n errors.push('At least 1 retention period is required')\n }\n if (state.retentionPeriods > 52) {\n warnings.push('More than 52 periods may impact performance')\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n },\n})\n","/**\n * UI Slice\n *\n * Handles UI-related state and actions:\n * - activeTab (query panel tab)\n * - activeView (table or chart)\n * - displayLimit (table row limit)\n * - Modal state (field search modal)\n * - AI state (AI panel)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type {\n QueryPanelTab,\n AIState,\n} from '../../components/AnalysisBuilder/types'\nimport { createInitialState } from '../../components/AnalysisBuilder/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Field modal mode for field search\n */\nexport type FieldModalMode = 'metrics' | 'breakdown'\n\n/**\n * UI slice state\n */\nexport interface UISliceState {\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field search modal is open */\n showFieldModal: boolean\n /** Current mode for field search modal */\n fieldModalMode: FieldModalMode\n /** AI panel state */\n aiState: AIState\n}\n\n/**\n * UI slice actions\n */\nexport interface UISliceActions {\n // Tab/View actions\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n\n // Field modal actions\n openMetricsModal: () => void\n openBreakdownsModal: () => void\n closeFieldModal: () => void\n\n // AI actions\n openAI: () => void\n closeAI: () => void\n setAIPrompt: (prompt: string) => void\n setAIGenerating: (generating: boolean) => void\n setAIError: (error: string | null) => void\n setAIHasGeneratedQuery: (hasQuery: boolean) => void\n saveAIPreviousState: () => void\n restoreAIPreviousState: () => void\n}\n\nexport type UISlice = UISliceState & UISliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialAIState: AIState = {\n isOpen: false,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: null,\n}\n\nexport const createInitialUIState = (): UISliceState => ({\n activeTab: 'query',\n activeView: 'chart',\n displayLimit: 100,\n showFieldModal: false,\n fieldModalMode: 'metrics',\n aiState: initialAIState,\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the UI slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createUISlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n UISlice\n> = (set, _get) => ({\n ...createInitialUIState(),\n\n // ==========================================================================\n // Tab/View Actions\n // ==========================================================================\n\n setActiveTab: (tab) => set({ activeTab: tab }),\n\n setActiveView: (view) =>\n set((state) => ({\n activeView: view,\n activeViews: {\n ...state.activeViews,\n [state.analysisType]: view,\n },\n })),\n\n setDisplayLimit: (limit) => set({ displayLimit: limit }),\n\n // ==========================================================================\n // Field Modal Actions\n // ==========================================================================\n\n openMetricsModal: () => set({ showFieldModal: true, fieldModalMode: 'metrics' }),\n\n openBreakdownsModal: () => set({ showFieldModal: true, fieldModalMode: 'breakdown' }),\n\n closeFieldModal: () => set({ showFieldModal: false }),\n\n // ==========================================================================\n // AI Actions\n // ==========================================================================\n\n openAI: () =>\n set((state) => ({\n aiState: { ...state.aiState, isOpen: true },\n })),\n\n closeAI: () =>\n set((state) => ({\n aiState: { ...state.aiState, isOpen: false },\n })),\n\n setAIPrompt: (prompt) =>\n set((state) => ({\n aiState: { ...state.aiState, userPrompt: prompt },\n })),\n\n setAIGenerating: (generating) =>\n set((state) => ({\n aiState: { ...state.aiState, isGenerating: generating },\n })),\n\n setAIError: (error) =>\n set((state) => ({\n aiState: { ...state.aiState, error },\n })),\n\n setAIHasGeneratedQuery: (hasQuery) =>\n set((state) => ({\n aiState: { ...state.aiState, hasGeneratedQuery: hasQuery },\n })),\n\n saveAIPreviousState: () =>\n set((state) => {\n const currentState = state.queryStates[state.activeQueryIndex]\n // Get chart config from charts map (Phase 4 - use charts map as source of truth)\n const chartConfig = state.charts[state.analysisType] || {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n return {\n aiState: {\n ...state.aiState,\n previousState: currentState\n ? {\n metrics: [...currentState.metrics],\n breakdowns: [...currentState.breakdowns],\n filters: [...currentState.filters],\n chartType: chartConfig.chartType,\n chartConfig: { ...chartConfig.chartConfig },\n displayConfig: { ...chartConfig.displayConfig },\n }\n : null,\n },\n }\n }),\n\n restoreAIPreviousState: () =>\n set((state) => {\n const prev = state.aiState.previousState\n if (!prev) return state\n\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n newStates[index] = {\n ...(newStates[index] || createInitialState()),\n metrics: prev.metrics,\n breakdowns: prev.breakdowns,\n filters: prev.filters,\n }\n\n // Phase 4: Write to charts map instead of legacy fields\n return {\n queryStates: newStates,\n charts: {\n ...state.charts,\n [state.analysisType]: {\n chartType: prev.chartType,\n chartConfig: prev.chartConfig,\n displayConfig: prev.displayConfig,\n },\n },\n aiState: { ...initialAIState },\n } as any\n }),\n})\n","/**\n * AnalysisBuilder Zustand Store (Instance-based)\n *\n * Centralized state management for AnalysisBuilder, consolidating:\n * - Query state (multi-query support with per-query metrics, breakdowns, filters)\n * - Chart configuration (type, axis config, display config)\n * - UI state (tabs, views, modals)\n * - AI state\n *\n * KEY ARCHITECTURE: Instance-based stores\n * - Each AnalysisBuilder component gets its own store instance\n * - Standalone mode: Uses localStorage persistence\n * - Modal/portlet editing mode: No persistence, initializes from props\n *\n * Uses Zustand's createStore (factory) instead of create (singleton).\n * Store is provided via React Context.\n */\n\nimport { createContext, useContext, useRef, type ReactNode } from 'react'\nimport { createStore, useStore, type StoreApi } from 'zustand'\nimport { devtools, persist, subscribeWithSelector } from 'zustand/middleware'\nimport type {\n Filter,\n SimpleFilter,\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n CubeQuery,\n QueryMergeStrategy,\n MultiQueryConfig,\n FunnelBindingKey,\n FunnelConfig,\n AnalysisType,\n FunnelStepState,\n} from '../types'\nimport type { ServerFunnelQuery } from '../types/funnel'\nimport type { ServerFlowQuery, FlowStartingStep } from '../types/flow'\nimport type {\n ServerRetentionQuery,\n RetentionGranularity,\n RetentionType,\n DateRange,\n RetentionBreakdownItem,\n} from '../types/retention'\nimport { getDateRangeFromPreset, DEFAULT_DATE_RANGE_PRESET } from '../types/retention'\nimport type {\n AnalysisBuilderState,\n QueryPanelTab,\n AIState,\n} from '../components/AnalysisBuilder/types'\nimport {\n generateId,\n generateMetricLabel,\n createInitialState,\n STORAGE_KEY,\n} from '../components/AnalysisBuilder/utils'\nimport { adapterRegistry } from '../adapters/adapterRegistry'\nimport { queryModeAdapter } from '../adapters/queryModeAdapter'\nimport { funnelModeAdapter } from '../adapters/funnelModeAdapter'\nimport { flowModeAdapter } from '../adapters/flowModeAdapter'\nimport { retentionModeAdapter } from '../adapters/retentionModeAdapter'\nimport type { AnalysisConfig, ChartConfig, AnalysisWorkspace } from '../types/analysisConfig'\nimport { isValidAnalysisConfig, isValidAnalysisWorkspace } from '../types/analysisConfig'\nimport {\n createCoreSlice,\n createQuerySlice,\n createFunnelSlice,\n createFlowSlice,\n createRetentionSlice,\n createUISlice,\n createInitialCoreState,\n createInitialQueryState,\n createInitialFunnelState,\n createInitialFlowState,\n createInitialRetentionState,\n} from './slices'\n\n// Note: Adapters are registered in coreSlice.ts (single registration point)\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Field modal mode for field search\n */\nexport type FieldModalMode = 'metrics' | 'breakdown'\n\n/**\n * Complete store state interface\n */\nexport interface AnalysisBuilderStoreState {\n // =========================================================================\n // Analysis Type (Explicit mode selection)\n // =========================================================================\n /** Explicit analysis type - determines which mode is active */\n analysisType: AnalysisType\n\n // =========================================================================\n // Per-Mode Chart Configuration (NEW - Phase 2)\n // =========================================================================\n /**\n * Per-mode chart configuration map.\n * Each mode owns its own chart settings, enabling mode switching\n * without losing chart configurations.\n */\n charts: {\n [K in AnalysisType]?: ChartConfig\n }\n\n /**\n * Per-mode active view (table or chart) map.\n * Each mode owns its own view preference, enabling mode switching\n * without losing view preferences.\n */\n activeViews: {\n [K in AnalysisType]?: 'table' | 'chart'\n }\n\n // =========================================================================\n // Query State (Query/Multi modes)\n // =========================================================================\n /** Array of query states (one per tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the currently active query tab */\n activeQueryIndex: number\n /** Strategy for merging multi-query results (used when queryStates.length > 1) */\n mergeStrategy: QueryMergeStrategy\n\n // =========================================================================\n // Chart Configuration (unified in charts map - Phase 4 cleanup)\n // =========================================================================\n /** Whether user manually selected chart type (disables auto-switch) */\n userManuallySelectedChart: boolean\n /** Current color palette name */\n localPaletteName: string\n\n // =========================================================================\n // UI State\n // =========================================================================\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field search modal is open */\n showFieldModal: boolean\n /** Current mode for field search modal */\n fieldModalMode: FieldModalMode\n\n // =========================================================================\n // AI State\n // =========================================================================\n /** AI panel state */\n aiState: AIState\n\n // =========================================================================\n // Funnel State (when analysisType === 'funnel')\n // =========================================================================\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (separate from queryStates) */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Binding key dimension that links funnel steps together */\n funnelBindingKey: FunnelBindingKey | null\n /** @deprecated Use funnelSteps[].timeToConvert instead - kept for backward compat */\n stepTimeToConvert: (string | null)[]\n\n // =========================================================================\n // Flow State (when analysisType === 'flow')\n // =========================================================================\n /** Selected cube for flow mode (must be an eventStream cube) */\n flowCube: string | null\n /** Binding key that links events to entities */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for event ordering */\n flowTimeDimension: string | null\n /** Starting step configuration (anchor point for exploration) */\n startingStep: FlowStartingStep\n /** Number of steps to explore before starting step (1-5) */\n stepsBefore: number\n /** Number of steps to explore after starting step (1-5) */\n stepsAfter: number\n /** Event dimension that categorizes events (node labels) */\n eventDimension: string | null\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n\n // =========================================================================\n // Retention State (when analysisType === 'retention')\n // Simplified Mixpanel-style with single global configuration\n // =========================================================================\n /** Single cube for retention analysis */\n retentionCube: string | null\n /** Binding key that identifies entities */\n retentionBindingKey: FunnelBindingKey | null\n /** Single timestamp dimension for cohort entry and activity */\n retentionTimeDimension: string | null\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: DateRange\n /** Filters that define who enters the cohort */\n retentionCohortFilters: Filter[]\n /** Filters that define what counts as a return */\n retentionActivityFilters: Filter[]\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: RetentionBreakdownItem[]\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: RetentionGranularity\n /** Number of periods to analyze (1-52) */\n retentionPeriods: number\n /** Type of retention calculation */\n retentionType: RetentionType\n}\n\n/**\n * Store actions interface\n */\nexport interface AnalysisBuilderStoreActions {\n // =========================================================================\n // Analysis Type Actions\n // =========================================================================\n /** Set the analysis type (switches between Query/Multi/Funnel modes) */\n setAnalysisType: (type: AnalysisType) => void\n\n // =========================================================================\n // Query State Actions (Query/Multi modes)\n // =========================================================================\n /** Set all query states */\n setQueryStates: (states: AnalysisBuilderState[]) => void\n /** Update a specific query state by index */\n updateQueryState: (\n index: number,\n updater: (state: AnalysisBuilderState) => AnalysisBuilderState\n ) => void\n /** Set active query index */\n setActiveQueryIndex: (index: number) => void\n /** Set merge strategy */\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n\n // =========================================================================\n // Metrics Actions\n // =========================================================================\n /** Open field modal in metrics mode */\n openMetricsModal: () => void\n /** Add a metric to current query */\n addMetric: (field: string, label?: string) => void\n /** Remove a metric from current query */\n removeMetric: (id: string) => void\n /** Toggle a metric (add if not present, remove if present) */\n toggleMetric: (fieldName: string) => void\n /** Reorder metrics */\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n\n // =========================================================================\n // Breakdowns Actions\n // =========================================================================\n /** Open field modal in breakdown mode */\n openBreakdownsModal: () => void\n /** Add a breakdown to current query */\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n /** Remove a breakdown from current query */\n removeBreakdown: (id: string) => void\n /** Toggle a breakdown (add if not present, remove if present) */\n toggleBreakdown: (\n fieldName: string,\n isTimeDimension: boolean,\n granularity?: string\n ) => void\n /** Change granularity for a time dimension breakdown */\n setBreakdownGranularity: (id: string, granularity: string) => void\n /** Toggle comparison mode for a time dimension breakdown */\n toggleBreakdownComparison: (id: string) => void\n /** Reorder breakdowns */\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n\n // =========================================================================\n // Filters Actions\n // =========================================================================\n /** Set filters for current query */\n setFilters: (filters: Filter[]) => void\n /** Drop a field to create a filter */\n dropFieldToFilter: (field: string) => void\n /** Set sort order for a field */\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n\n // =========================================================================\n // Multi-Query Actions\n // =========================================================================\n /** Add a new query tab */\n addQuery: () => void\n /** Remove a query tab */\n removeQuery: (index: number) => void\n\n // =========================================================================\n // Chart Actions\n // =========================================================================\n /** Set chart type */\n setChartType: (type: ChartType) => void\n /** Set chart type with manual selection flag */\n setChartTypeManual: (type: ChartType) => void\n /** Set chart config */\n setChartConfig: (config: ChartAxisConfig) => void\n /** Set display config */\n setDisplayConfig: (config: ChartDisplayConfig) => void\n /** Set color palette name */\n setLocalPaletteName: (name: string) => void\n /** Set user manually selected chart flag */\n setUserManuallySelectedChart: (value: boolean) => void\n\n // =========================================================================\n // UI Actions\n // =========================================================================\n /** Set active tab */\n setActiveTab: (tab: QueryPanelTab) => void\n /** Set active view */\n setActiveView: (view: 'table' | 'chart') => void\n /** Set display limit */\n setDisplayLimit: (limit: number) => void\n /** Close field modal */\n closeFieldModal: () => void\n\n // =========================================================================\n // AI Actions\n // =========================================================================\n /** Open AI panel */\n openAI: () => void\n /** Close AI panel */\n closeAI: () => void\n /** Set AI prompt */\n setAIPrompt: (prompt: string) => void\n /** Set AI generating state */\n setAIGenerating: (generating: boolean) => void\n /** Set AI error */\n setAIError: (error: string | null) => void\n /** Set AI has generated query */\n setAIHasGeneratedQuery: (hasQuery: boolean) => void\n /** Save previous state for AI undo */\n saveAIPreviousState: () => void\n /** Restore previous state (AI cancel/undo) */\n restoreAIPreviousState: () => void\n\n // =========================================================================\n // Funnel Actions (when analysisType === 'funnel')\n // =========================================================================\n /** Add a new funnel step */\n addFunnelStep: () => void\n /** Remove a funnel step by index */\n removeFunnelStep: (index: number) => void\n /** Update a funnel step by index */\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n /** Set the active funnel step index */\n setActiveFunnelStepIndex: (index: number) => void\n /** Reorder funnel steps */\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n /** Set the time dimension for funnel */\n setFunnelTimeDimension: (dimension: string | null) => void\n /** Set the funnel binding key */\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n /** Set the funnel cube (clears binding key/time dimension, updates all steps) */\n setFunnelCube: (cube: string | null) => void\n /** @deprecated Set time window for a specific step - use updateFunnelStep instead */\n setStepTimeToConvert: (stepIndex: number, duration: string | null) => void\n /** @deprecated Build FunnelConfig from queryStates - use buildFunnelQueryFromSteps instead */\n buildFunnelConfig: () => FunnelConfig | null\n /** Build ServerFunnelQuery from dedicated funnelSteps */\n buildFunnelQueryFromSteps: () => ServerFunnelQuery | null\n /** Check if in funnel mode (analysisType === 'funnel') */\n isFunnelMode: () => boolean\n /** Check if funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: () => boolean\n /** Set funnel chart type */\n setFunnelChartType: (type: ChartType) => void\n /** Set funnel chart config */\n setFunnelChartConfig: (config: ChartAxisConfig) => void\n /** Set funnel display config */\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n\n // =========================================================================\n // Flow Actions (when analysisType === 'flow')\n // =========================================================================\n /** Set the flow cube (clears binding key/time dimension) */\n setFlowCube: (cube: string | null) => void\n /** Set the flow binding key */\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the flow time dimension */\n setFlowTimeDimension: (dim: string | null) => void\n /** Set the event dimension */\n setEventDimension: (dim: string | null) => void\n /** Set the starting step name */\n setStartingStepName: (name: string) => void\n /** Set all starting step filters at once */\n setStartingStepFilters: (filters: Filter[]) => void\n /** Add a filter to the starting step */\n addStartingStepFilter: (filter: Filter) => void\n /** Remove a filter from the starting step by index */\n removeStartingStepFilter: (index: number) => void\n /** Update a filter in the starting step by index */\n updateStartingStepFilter: (index: number, filter: Filter) => void\n /** Set the number of steps to explore before starting step */\n setStepsBefore: (count: number) => void\n /** Set the number of steps to explore after starting step */\n setStepsAfter: (count: number) => void\n /** Set the join strategy for flow execution */\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n /** Check if in flow mode (analysisType === 'flow') */\n isFlowMode: () => boolean\n /** Check if flow mode is properly configured and ready for execution */\n isFlowModeEnabled: () => boolean\n /** Build ServerFlowQuery from flow state */\n buildFlowQuery: () => ServerFlowQuery | null\n\n // =========================================================================\n // Retention Actions (when analysisType === 'retention')\n // Simplified Mixpanel-style with single global configuration\n // =========================================================================\n /** Set the single cube for retention analysis (clears related fields) */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n\n // =========================================================================\n // Utility Actions\n // =========================================================================\n /** Clear only the current mode's state (preserves other modes) */\n clearCurrentMode: () => void\n /** @deprecated Clear the current query - use clearCurrentMode instead */\n clearQuery: () => void\n /** Get current state (helper accessor) */\n getCurrentState: () => AnalysisBuilderState\n /** Get merge keys (computed from Q1 breakdowns) */\n getMergeKeys: () => string[] | undefined\n /** Check if in multi-query mode */\n isMultiQueryMode: () => boolean\n /** Build current CubeQuery */\n buildCurrentQuery: () => CubeQuery\n /** Build all queries */\n buildAllQueries: () => CubeQuery[]\n /** Build MultiQueryConfig */\n buildMultiQueryConfig: () => MultiQueryConfig | null\n /** Reset store to initial state */\n reset: () => void\n\n // =========================================================================\n // Save/Load Actions (NEW - Phase 2)\n // =========================================================================\n /**\n * Save current state to AnalysisConfig format.\n * Delegates to the appropriate adapter based on analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n save: () => AnalysisConfig\n\n /**\n * Load state from AnalysisConfig.\n * Delegates to the appropriate adapter based on config.analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n load: (config: AnalysisConfig) => void\n\n /**\n * Save ALL modes to AnalysisWorkspace format.\n * Used for localStorage persistence to preserve state across mode switches.\n */\n saveWorkspace: () => AnalysisWorkspace\n\n /**\n * Load ALL modes from AnalysisWorkspace.\n * Used for localStorage persistence to restore state for all modes.\n */\n loadWorkspace: (workspace: AnalysisWorkspace) => void\n\n // =========================================================================\n // Validation Actions (NEW - Phase 5)\n // =========================================================================\n /**\n * Validate current state using the adapter for the current analysis type.\n * Returns validation errors and warnings that can be displayed to the user.\n */\n getValidation: () => import('../adapters/modeAdapter').ValidationResult\n}\n\n/**\n * Combined store type\n */\nexport type AnalysisBuilderStore = AnalysisBuilderStoreState &\n AnalysisBuilderStoreActions\n\n/**\n * Initial funnel state for creating a store instance.\n * Chart configuration is handled via CreateStoreOptions.initialChartConfig instead.\n */\nexport interface InitialFunnelState {\n funnelCube?: string | null\n funnelSteps?: FunnelStepState[]\n funnelTimeDimension?: string | null\n funnelBindingKey?: FunnelBindingKey | null\n}\n\nexport interface InitialFlowState {\n flowCube?: string | null\n flowBindingKey?: FunnelBindingKey | null\n flowTimeDimension?: string | null\n startingStep?: FlowStartingStep\n stepsBefore?: number\n stepsAfter?: number\n eventDimension?: string | null\n joinStrategy?: 'auto' | 'lateral' | 'window'\n}\n\nexport interface InitialRetentionState {\n retentionCube?: string | null\n retentionBindingKey?: FunnelBindingKey | null\n retentionTimeDimension?: string | null\n retentionDateRange?: DateRange\n retentionCohortFilters?: Filter[]\n retentionActivityFilters?: Filter[]\n retentionBreakdowns?: RetentionBreakdownItem[]\n retentionViewGranularity?: RetentionGranularity\n retentionPeriods?: number\n retentionType?: RetentionType\n}\n\n/**\n * Options for creating a store instance\n */\nexport interface CreateStoreOptions {\n /** Initial query configuration */\n initialQuery?: CubeQuery | MultiQueryConfig\n /** Initial chart configuration */\n initialChartConfig?: {\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n }\n /** Disable localStorage persistence */\n disableLocalStorage?: boolean\n /** Initial analysis type (query or funnel) */\n initialAnalysisType?: AnalysisType\n /** Initial funnel state (when analysisType === 'funnel') */\n initialFunnelState?: InitialFunnelState\n /** Initial flow state (when analysisType === 'flow') */\n initialFlowState?: InitialFlowState\n /** Initial retention state (when analysisType === 'retention') */\n initialRetentionState?: InitialRetentionState\n /** Initial active view (table or chart) - used to prevent flash when loading from share */\n initialActiveView?: 'table' | 'chart'\n}\n\n// Note: Initial state is now handled by slice initializers\n// (createInitialCoreState, createInitialQueryState, createInitialFunnelState, createInitialUIState)\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Convert CubeQuery to AnalysisBuilderState\n */\nfunction queryToState(query: CubeQuery): AnalysisBuilderState {\n const baseFilters = query.filters ? [...query.filters] : []\n\n const timeDimensions = query.timeDimensions || []\n const breakdowns = [\n ...(query.dimensions || []).map((field) => ({\n id: generateId(),\n field,\n isTimeDimension: false,\n })),\n ...timeDimensions.map((td) => ({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true,\n enableComparison: Boolean(td.compareDateRange && td.compareDateRange.length > 0),\n })),\n ]\n\n let filters = baseFilters\n\n // Restore date filters for comparison-enabled time dimensions when missing.\n for (const td of timeDimensions) {\n if (!td.compareDateRange || td.compareDateRange.length === 0) continue\n\n const hasDateFilter = filters.some(\n (filter) =>\n 'member' in filter &&\n (filter as SimpleFilter).member === td.dimension &&\n (filter as SimpleFilter).operator === 'inDateRange'\n )\n\n const firstRange = td.compareDateRange[0]\n const dateRange =\n Array.isArray(firstRange) || typeof firstRange === 'string'\n ? firstRange\n : undefined\n\n if (!dateRange) continue\n\n if (!hasDateFilter) {\n filters = [\n ...filters,\n {\n member: td.dimension,\n operator: 'inDateRange',\n values: [],\n dateRange,\n } as SimpleFilter,\n ]\n continue\n }\n\n filters = filters.map((filter) => {\n if (\n 'member' in filter &&\n (filter as SimpleFilter).member === td.dimension &&\n (filter as SimpleFilter).operator === 'inDateRange' &&\n !(filter as SimpleFilter).dateRange\n ) {\n return { ...(filter as SimpleFilter), dateRange }\n }\n return filter\n })\n }\n\n return {\n ...createInitialState(),\n metrics: (query.measures || []).map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index),\n })),\n breakdowns,\n filters,\n order: query.order,\n }\n}\n\n/**\n * Check if config is MultiQueryConfig\n */\nfunction isMultiQueryConfig(config: CubeQuery | MultiQueryConfig): config is MultiQueryConfig {\n return 'queries' in config && Array.isArray(config.queries)\n}\n\n/**\n * Convert store creation options to AnalysisConfig.\n * Returns null if no meaningful options are provided (use defaults).\n */\nfunction optionsToAnalysisConfig(options: CreateStoreOptions): AnalysisConfig | null {\n // Handle funnel mode with funnel state\n if (options.initialAnalysisType === 'funnel' && options.initialFunnelState) {\n const defaultFunnelChart = funnelModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings (legacy funnel chart fields removed)\n const funnelChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultFunnelChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultFunnelChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultFunnelChart.displayConfig,\n }\n\n // Build funnel config via adapter's save method structure\n const funnelState = {\n funnelCube: options.initialFunnelState.funnelCube ?? null,\n funnelSteps: options.initialFunnelState.funnelSteps || [],\n activeFunnelStepIndex: 0,\n funnelTimeDimension: options.initialFunnelState.funnelTimeDimension ?? null,\n funnelBindingKey: options.initialFunnelState.funnelBindingKey ?? null,\n }\n\n return funnelModeAdapter.save(\n funnelState,\n { funnel: funnelChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle flow mode with flow state\n if (options.initialAnalysisType === 'flow' && options.initialFlowState) {\n const defaultFlowChart = flowModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings\n const flowChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultFlowChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultFlowChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultFlowChart.displayConfig,\n }\n\n // Build flow config via adapter's save method structure\n const flowState = {\n flowCube: options.initialFlowState.flowCube ?? null,\n flowBindingKey: options.initialFlowState.flowBindingKey ?? null,\n flowTimeDimension: options.initialFlowState.flowTimeDimension ?? null,\n startingStep: options.initialFlowState.startingStep || { name: '', filters: [] },\n stepsBefore: options.initialFlowState.stepsBefore ?? 3,\n stepsAfter: options.initialFlowState.stepsAfter ?? 3,\n eventDimension: options.initialFlowState.eventDimension ?? null,\n joinStrategy: options.initialFlowState.joinStrategy ?? 'auto',\n }\n\n return flowModeAdapter.save(\n flowState,\n { flow: flowChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle retention mode with retention state\n if (options.initialAnalysisType === 'retention' && options.initialRetentionState) {\n const defaultRetentionChart = retentionModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings\n const retentionChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultRetentionChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultRetentionChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultRetentionChart.displayConfig,\n }\n\n // Build retention state - use default date range for fallback\n const defaultDateRange = getDateRangeFromPreset(DEFAULT_DATE_RANGE_PRESET)\n\n const retentionState = {\n retentionCube: options.initialRetentionState.retentionCube ?? null,\n retentionBindingKey: options.initialRetentionState.retentionBindingKey ?? null,\n retentionTimeDimension: options.initialRetentionState.retentionTimeDimension ?? null,\n retentionDateRange: options.initialRetentionState.retentionDateRange ?? defaultDateRange,\n retentionCohortFilters: options.initialRetentionState.retentionCohortFilters || [],\n retentionActivityFilters: options.initialRetentionState.retentionActivityFilters || [],\n retentionBreakdowns: options.initialRetentionState.retentionBreakdowns || [],\n retentionViewGranularity: options.initialRetentionState.retentionViewGranularity ?? 'week',\n retentionPeriods: options.initialRetentionState.retentionPeriods ?? 12,\n retentionType: options.initialRetentionState.retentionType ?? 'classic',\n }\n\n return retentionModeAdapter.save(\n retentionState,\n { retention: retentionChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle query mode with initial query\n if (options.initialQuery) {\n const query = options.initialQuery\n let queryStates: AnalysisBuilderState[]\n let mergeStrategy: QueryMergeStrategy = 'concat'\n\n if (isMultiQueryConfig(query)) {\n queryStates = query.queries.map(queryToState)\n if (query.mergeStrategy) {\n mergeStrategy = query.mergeStrategy\n }\n } else {\n queryStates = [queryToState(query)]\n }\n\n const defaultQueryChart = queryModeAdapter.getDefaultChartConfig()\n const queryChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultQueryChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultQueryChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultQueryChart.displayConfig,\n }\n\n return queryModeAdapter.save(\n { queryStates, activeQueryIndex: 0, mergeStrategy },\n { query: queryChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle just chart config (no query)\n if (options.initialChartConfig) {\n const defaultQueryChart = queryModeAdapter.getDefaultChartConfig()\n const queryChartConfig: ChartConfig = {\n chartType: options.initialChartConfig.chartType || defaultQueryChart.chartType,\n chartConfig: options.initialChartConfig.chartConfig || defaultQueryChart.chartConfig,\n displayConfig: options.initialChartConfig.displayConfig || defaultQueryChart.displayConfig,\n }\n\n return queryModeAdapter.save(\n { queryStates: [createInitialState()], activeQueryIndex: 0, mergeStrategy: 'concat' },\n { query: queryChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle just active view\n if (options.initialActiveView) {\n // Return a minimal config with just activeView set\n return queryModeAdapter.save(\n { queryStates: [createInitialState()], activeQueryIndex: 0, mergeStrategy: 'concat' },\n { query: queryModeAdapter.getDefaultChartConfig() },\n options.initialActiveView\n )\n }\n\n // No meaningful options - use store defaults\n return null\n}\n\n// NOTE: createStoreActions has been replaced by slice composition.\n// See createAnalysisBuilderStore below which composes:\n// - createCoreSlice\n// - createQuerySlice\n// - createFunnelSlice\n// - createUISlice\n// - createCrossSliceActions\n\n\n// ============================================================================\n// Cross-Slice Actions\n// ============================================================================\n\n/**\n * Cross-slice actions that coordinate state across multiple slices.\n * These can't be in individual slices because they need to update state\n * from multiple slices atomically.\n */\ninterface CrossSliceActions {\n reset: () => void\n clearCurrentMode: () => void\n clearQuery: () => void\n getValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\nfunction createCrossSliceActions(\n set: (\n partial:\n | Partial<AnalysisBuilderStore>\n | ((state: AnalysisBuilderStore) => Partial<AnalysisBuilderStore>)\n ) => void,\n get: () => AnalysisBuilderStore\n): CrossSliceActions {\n return {\n reset: () => {\n // Reset to default state using slice initializers\n set({\n ...createInitialCoreState(),\n ...createInitialQueryState(),\n ...createInitialFunnelState(),\n ...createInitialFlowState(),\n ...createInitialRetentionState(),\n // Apply adapter defaults for charts (may differ from slice defaults)\n charts: {\n query: queryModeAdapter.getDefaultChartConfig(),\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n flow: flowModeAdapter.getDefaultChartConfig(),\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n activeViews: {\n query: 'chart',\n funnel: 'chart',\n flow: 'chart',\n retention: 'chart',\n },\n } as Partial<AnalysisBuilderStore>)\n },\n\n clearCurrentMode: () =>\n set((state) => {\n switch (state.analysisType) {\n case 'funnel':\n // Use slice initializer for funnel state\n return {\n ...createInitialFunnelState(),\n charts: {\n ...state.charts,\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'flow':\n // Use slice initializer for flow state\n return {\n ...createInitialFlowState(),\n charts: {\n ...state.charts,\n flow: flowModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'retention':\n // Use slice initializer for retention state\n return {\n ...createInitialRetentionState(),\n charts: {\n ...state.charts,\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'query':\n default:\n // Use slice initializer for query state\n return {\n ...createInitialQueryState(),\n userManuallySelectedChart: false,\n charts: {\n ...state.charts,\n query: queryModeAdapter.getDefaultChartConfig(),\n },\n }\n }\n }),\n\n clearQuery: () =>\n set((state) => {\n const newStates = [...state.queryStates]\n newStates[state.activeQueryIndex] = createInitialState()\n return {\n queryStates: newStates,\n userManuallySelectedChart: false,\n charts: {\n ...state.charts,\n query: queryModeAdapter.getDefaultChartConfig(),\n },\n }\n }),\n\n getValidation: () => {\n const state = get()\n const adapter = adapterRegistry.get(state.analysisType)\n\n // Use adapter's extractState method for mode-specific state\n const modeState = adapter.extractState(state as unknown as Record<string, unknown>)\n\n return adapter.validate(modeState)\n },\n }\n}\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\n/**\n * Create a new store instance with optional persistence.\n * Composes slices: coreSlice, querySlice, funnelSlice, uiSlice.\n */\nexport function createAnalysisBuilderStore(options: CreateStoreOptions = {}) {\n // Convert options to AnalysisConfig for loading\n const initialConfig = optionsToAnalysisConfig(options)\n\n // Store creator function that composes all slices\n const storeCreator = (\n set: (\n partial:\n | Partial<AnalysisBuilderStore>\n | ((state: AnalysisBuilderStore) => Partial<AnalysisBuilderStore>)\n ) => void,\n get: () => AnalysisBuilderStore,\n store: StoreApi<AnalysisBuilderStore>\n ) => ({\n // Compose slices - they provide default state and actions\n ...createCoreSlice(set, get, store),\n ...createQuerySlice(set, get, store),\n ...createFunnelSlice(set, get, store),\n ...createFlowSlice(set, get, store),\n ...createRetentionSlice(set, get, store),\n ...createUISlice(set, get, store),\n\n // Cross-slice actions\n ...createCrossSliceActions(set, get),\n })\n\n // Create store with or without persistence\n if (options.disableLocalStorage) {\n // No persistence - for modal/portlet editing\n const store = createStore<AnalysisBuilderStore>()(\n devtools(subscribeWithSelector(storeCreator), {\n name: 'AnalysisBuilderStore (no-persist)',\n })\n )\n\n // Apply initial config if provided\n if (initialConfig) {\n store.getState().load(initialConfig)\n }\n\n return store\n }\n\n // With persistence - for standalone mode\n return createStore<AnalysisBuilderStore>()(\n devtools(\n subscribeWithSelector(\n persist(storeCreator, {\n name: STORAGE_KEY,\n // Use workspace format to preserve ALL modes' state\n partialize: (state) => state.saveWorkspace(),\n merge: (persisted, current) => {\n // Try workspace format first (new format)\n if (persisted && isValidAnalysisWorkspace(persisted)) {\n return {\n ...current,\n _persistedWorkspace: persisted,\n } as typeof current\n }\n // Backward compat: single AnalysisConfig (migrate to workspace on next save)\n if (persisted && isValidAnalysisConfig(persisted)) {\n return {\n ...current,\n _persistedConfig: persisted,\n } as typeof current\n }\n // Invalid/legacy format - use current (fresh start)\n // Also preserve initialConfig to apply if provided\n if (initialConfig) {\n return {\n ...current,\n _initialConfig: initialConfig,\n } as typeof current\n }\n return current\n },\n onRehydrateStorage: () => (state) => {\n // After rehydration, call loadWorkspace/load with persisted or initial config\n if (state) {\n if ((state as any)._persistedWorkspace) {\n // New workspace format - load all modes\n const workspace = (state as any)._persistedWorkspace as AnalysisWorkspace\n delete (state as any)._persistedWorkspace\n delete (state as any)._persistedConfig\n delete (state as any)._initialConfig\n state.loadWorkspace(workspace)\n } else if ((state as any)._persistedConfig) {\n // Legacy single-mode format - load only that mode\n // Will be migrated to workspace on next save\n const config = (state as any)._persistedConfig\n delete (state as any)._persistedConfig\n delete (state as any)._initialConfig\n state.load(config)\n } else if ((state as any)._initialConfig) {\n const config = (state as any)._initialConfig\n delete (state as any)._initialConfig\n state.load(config)\n }\n }\n },\n })\n ),\n { name: 'AnalysisBuilderStore' }\n )\n )\n}\n\n// ============================================================================\n// React Context & Provider\n// ============================================================================\n\n/**\n * Context for the store instance\n */\nconst AnalysisBuilderStoreContext = createContext<StoreApi<AnalysisBuilderStore> | null>(null)\n\n/**\n * Provider props\n */\nexport interface AnalysisBuilderStoreProviderProps {\n children: ReactNode\n /** Initial query configuration */\n initialQuery?: CubeQuery | MultiQueryConfig\n /** Initial chart configuration */\n initialChartConfig?: {\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n }\n /** Disable localStorage persistence */\n disableLocalStorage?: boolean\n /** Initial analysis type (query or funnel) */\n initialAnalysisType?: AnalysisType\n /** Initial funnel state (when analysisType === 'funnel') */\n initialFunnelState?: InitialFunnelState\n /** Initial flow state (when analysisType === 'flow') */\n initialFlowState?: InitialFlowState\n /** Initial retention state (when analysisType === 'retention') */\n initialRetentionState?: InitialRetentionState\n /** Initial active view (table or chart) - used to prevent flash when loading from share */\n initialActiveView?: 'table' | 'chart'\n}\n\n/**\n * Provider component that creates a store instance per AnalysisBuilder\n */\nexport function AnalysisBuilderStoreProvider({\n children,\n initialQuery,\n initialChartConfig,\n disableLocalStorage,\n initialAnalysisType,\n initialFunnelState,\n initialFlowState,\n initialRetentionState,\n initialActiveView,\n}: AnalysisBuilderStoreProviderProps) {\n // Create store instance once per provider mount\n const storeRef = useRef<StoreApi<AnalysisBuilderStore> | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createAnalysisBuilderStore({\n initialQuery,\n initialChartConfig,\n disableLocalStorage,\n initialAnalysisType,\n initialFunnelState,\n initialFlowState,\n initialRetentionState,\n initialActiveView,\n })\n }\n\n return (\n <AnalysisBuilderStoreContext.Provider value={storeRef.current}>\n {children}\n </AnalysisBuilderStoreContext.Provider>\n )\n}\n\n/**\n * Hook to access the store from context\n * @throws Error if used outside of provider\n */\nexport function useAnalysisBuilderStore<T>(selector: (state: AnalysisBuilderStore) => T): T {\n const store = useContext(AnalysisBuilderStoreContext)\n if (!store) {\n throw new Error('useAnalysisBuilderStore must be used within AnalysisBuilderStoreProvider')\n }\n return useStore(store, selector)\n}\n\n/**\n * Hook to get the raw store API (for actions that need direct access)\n */\nexport function useAnalysisBuilderStoreApi(): StoreApi<AnalysisBuilderStore> {\n const store = useContext(AnalysisBuilderStoreContext)\n if (!store) {\n throw new Error('useAnalysisBuilderStoreApi must be used within AnalysisBuilderStoreProvider')\n }\n return store\n}\n\n// ============================================================================\n// Selectors (for optimized re-renders)\n// ============================================================================\n\n/**\n * Select current query state\n */\nexport const selectCurrentState = (state: AnalysisBuilderStore) =>\n state.queryStates[state.activeQueryIndex] || createInitialState()\n\n/**\n * Select current metrics\n */\nexport const selectMetrics = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).metrics\n\n/**\n * Select current breakdowns\n */\nexport const selectBreakdowns = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).breakdowns\n\n/**\n * Select current filters\n */\nexport const selectFilters = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).filters\n\n/**\n * Select current chart config from the charts map (NEW - Phase 2)\n * This is the preferred way to access chart configuration.\n * Falls back to default chart config if mode's config is missing.\n */\nexport const selectCurrentChartConfig = (state: AnalysisBuilderStore): ChartConfig => {\n const config = state.charts[state.analysisType]\n if (config) return config\n\n // Fallback to adapter default (shouldn't happen in normal usage)\n return adapterRegistry.get(state.analysisType).getDefaultChartConfig()\n}\n\n/**\n * Select chart type from current mode's chart config\n */\nexport const selectChartType = (state: AnalysisBuilderStore): ChartType =>\n selectCurrentChartConfig(state).chartType\n\n/**\n * Select chart axis config from current mode's chart config\n */\nexport const selectChartAxisConfig = (state: AnalysisBuilderStore): ChartAxisConfig =>\n selectCurrentChartConfig(state).chartConfig\n\n/**\n * Select display config from current mode's chart config\n */\nexport const selectChartDisplayConfig = (state: AnalysisBuilderStore): ChartDisplayConfig =>\n selectCurrentChartConfig(state).displayConfig\n\n/**\n * Select chart configuration (returns mode-appropriate config)\n * @deprecated Use selectCurrentChartConfig instead (reads from charts map)\n */\nexport const selectChartConfig = (state: AnalysisBuilderStore) => {\n // Use charts map (Phase 2 approach)\n const config = state.charts[state.analysisType]\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n\n // No fallback - charts map is the source of truth (Phase 4 cleanup)\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select query mode chart configuration (always returns query mode config)\n */\nexport const selectQueryModeChartConfig = (state: AnalysisBuilderStore) => {\n // charts map is the source of truth (Phase 4 cleanup)\n const config = state.charts.query\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select funnel mode chart configuration (always returns funnel mode config)\n */\nexport const selectFunnelModeChartConfig = (state: AnalysisBuilderStore) => {\n // charts map is the source of truth (Phase 4 cleanup)\n const config = state.charts.funnel\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'funnel' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select UI state\n */\nexport const selectUIState = (state: AnalysisBuilderStore) => ({\n activeTab: state.activeTab,\n activeView: state.activeView,\n displayLimit: state.displayLimit,\n showFieldModal: state.showFieldModal,\n fieldModalMode: state.fieldModalMode,\n})\n\n/**\n * Select analysis type\n */\nexport const selectAnalysisType = (state: AnalysisBuilderStore) => state.analysisType\n\n/**\n * Select multi-query state\n */\nexport const selectMultiQueryState = (state: AnalysisBuilderStore) => ({\n queryStates: state.queryStates,\n activeQueryIndex: state.activeQueryIndex,\n mergeStrategy: state.mergeStrategy,\n // Multi-query mode is when we have more than one query in 'query' analysis type\n isMultiQueryMode: state.analysisType === 'query' && state.queryStates.length > 1,\n})\n\n/**\n * Select funnel cube\n */\nexport const selectFunnelCube = (state: AnalysisBuilderStore) => state.funnelCube\n\n/**\n * Select funnel state (new dedicated state)\n */\nexport const selectFunnelState = (state: AnalysisBuilderStore) => ({\n funnelCube: state.funnelCube,\n funnelSteps: state.funnelSteps,\n activeFunnelStepIndex: state.activeFunnelStepIndex,\n funnelTimeDimension: state.funnelTimeDimension,\n funnelBindingKey: state.funnelBindingKey,\n isFunnelMode: state.analysisType === 'funnel',\n // Deprecated field kept for backward compat\n stepTimeToConvert: state.stepTimeToConvert,\n})\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, QueryMergeStrategy } 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' and 'funnel' strategies: only warnings\n */\nexport function validateMultiQueryConfig(\n queries: CubeQuery[],\n mergeStrategy: QueryMergeStrategy,\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 * useAnalysisQueryBuilder\n *\n * Builds and validates queries from Zustand store state.\n * Handles single-query and multi-query modes.\n */\n\nimport { useMemo } from 'react'\nimport { useAnalysisBuilderStore } from '../stores/analysisBuilderStore'\nimport { validateMultiQueryConfig, type MultiQueryValidationResult } from '../utils/multiQueryValidation'\nimport { buildCubeQuery } from '../components/AnalysisBuilder/utils'\nimport type { CubeQuery, MultiQueryConfig, QueryMergeStrategy } from '../types'\nimport type { AnalysisBuilderState } from '../components/AnalysisBuilder/types'\n\nexport interface UseAnalysisQueryBuilderResult {\n /** Current query state (active query) */\n queryState: AnalysisBuilderState\n /** All query states (for multi-query mode) */\n queryStates: AnalysisBuilderState[]\n /** Active query index */\n activeQueryIndex: number\n /** Merge strategy for multi-query */\n mergeStrategy: QueryMergeStrategy\n /** Whether in multi-query mode */\n isMultiQueryMode: boolean\n /** Merge keys (computed from Q1 breakdowns) */\n mergeKeys: string[] | undefined\n /** Current query as CubeQuery */\n currentQuery: CubeQuery\n /** All queries as CubeQuery[] */\n allQueries: CubeQuery[]\n /** MultiQueryConfig (if in multi-query mode) */\n multiQueryConfig: MultiQueryConfig | null\n /** Multi-query validation result */\n multiQueryValidation: MultiQueryValidationResult | null\n /** Whether current query is valid */\n isValidQuery: boolean | undefined\n\n // Actions\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n addQuery: () => void\n removeQuery: (index: number) => void\n}\n\nexport function useAnalysisQueryBuilder(): UseAnalysisQueryBuilderResult {\n // Store state\n const queryStates = useAnalysisBuilderStore((state) => state.queryStates)\n const activeQueryIndex = useAnalysisBuilderStore((state) => state.activeQueryIndex)\n const mergeStrategy = useAnalysisBuilderStore((state) => state.mergeStrategy)\n\n // Store actions\n const setActiveQueryIndex = useAnalysisBuilderStore((state) => state.setActiveQueryIndex)\n const setMergeStrategy = useAnalysisBuilderStore((state) => state.setMergeStrategy)\n const addQuery = useAnalysisBuilderStore((state) => state.addQuery)\n const removeQuery = useAnalysisBuilderStore((state) => state.removeQuery)\n\n // Store getters\n const getCurrentState = useAnalysisBuilderStore((state) => state.getCurrentState)\n const getMergeKeys = useAnalysisBuilderStore((state) => state.getMergeKeys)\n const isMultiQueryModeGetter = useAnalysisBuilderStore((state) => state.isMultiQueryMode)\n // Derived state\n const queryState = getCurrentState()\n const isMultiQueryMode = isMultiQueryModeGetter()\n const mergeKeys = getMergeKeys()\n\n // Build current query from active state\n const currentQuery = useMemo(() => {\n const current = queryStates[activeQueryIndex] || queryState\n return buildCubeQuery(current.metrics, current.breakdowns, current.filters, current.order)\n }, [queryStates, activeQueryIndex, queryState])\n\n // Build all queries (respect merge mode for shared breakdowns)\n const allQueries = useMemo(() => {\n const q1Breakdowns = queryStates[0]?.breakdowns || []\n return queryStates.map((qs, index) => {\n const breakdowns = mergeStrategy === 'merge' && index > 0 ? q1Breakdowns : qs.breakdowns\n return buildCubeQuery(qs.metrics, breakdowns, qs.filters, qs.order)\n })\n }, [queryStates, mergeStrategy])\n\n // Build multi-query config from queries\n const multiQueryConfig = useMemo(() => {\n if (queryStates.length <= 1) return null\n\n // Filter to queries that have at least one measure, dimension, or time dimension\n // Note: Legacy mergeStrategy === 'funnel' is no longer supported\n const validQueries = allQueries.filter((q) => {\n return (\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n })\n\n if (validQueries.length < 2) return null\n\n return {\n queries: validQueries,\n mergeStrategy,\n mergeKeys,\n queryLabels: validQueries.map((_, i) => `Q${i + 1}`),\n }\n }, [allQueries, queryStates.length, mergeStrategy, mergeKeys])\n\n // Validate multi-query configuration\n const multiQueryValidation = useMemo((): MultiQueryValidationResult | null => {\n if (!isMultiQueryMode) return null\n return validateMultiQueryConfig(allQueries, mergeStrategy, mergeKeys || [])\n }, [isMultiQueryMode, allQueries, mergeStrategy, mergeKeys])\n\n // Check if query is valid\n const isValidQuery = useMemo(() => {\n return (\n (currentQuery.measures && currentQuery.measures.length > 0) ||\n (currentQuery.dimensions && currentQuery.dimensions.length > 0) ||\n (currentQuery.timeDimensions && currentQuery.timeDimensions.length > 0)\n )\n }, [currentQuery])\n\n return {\n queryState,\n queryStates,\n activeQueryIndex,\n mergeStrategy,\n isMultiQueryMode,\n mergeKeys,\n currentQuery,\n allQueries,\n multiQueryConfig,\n multiQueryValidation,\n isValidQuery,\n\n // Actions\n setActiveQueryIndex,\n setMergeStrategy,\n addQuery,\n removeQuery,\n }\n}\n","/**\n * useAnalysisCombinedFields\n *\n * Computes combined metrics and breakdowns from all queries in multi-query mode.\n * In single-query mode, returns the current query's metrics and breakdowns.\n */\n\nimport { useMemo } from 'react'\nimport type { AnalysisBuilderState, MetricItem, BreakdownItem } from '../components/AnalysisBuilder/types'\nimport type { QueryMergeStrategy } from '../types'\n\nexport interface UseAnalysisCombinedFieldsOptions {\n queryState: AnalysisBuilderState\n queryStates: AnalysisBuilderState[]\n isMultiQueryMode: boolean\n mergeStrategy: QueryMergeStrategy\n activeQueryIndex: number\n}\n\nexport interface UseAnalysisCombinedFieldsResult {\n /** Combined metrics from all queries (for chart config) */\n combinedMetrics: MetricItem[]\n /** Combined breakdowns from all queries (for chart config) */\n combinedBreakdowns: BreakdownItem[]\n /** Effective breakdowns for display (Q1's in merge mode, otherwise current query's) */\n effectiveBreakdowns: BreakdownItem[]\n}\n\nexport function useAnalysisCombinedFields(\n options: UseAnalysisCombinedFieldsOptions\n): UseAnalysisCombinedFieldsResult {\n const { queryState, queryStates, isMultiQueryMode, mergeStrategy, activeQueryIndex } = options\n\n // Combined metrics from all queries\n const combinedMetrics = useMemo(() => {\n if (!isMultiQueryMode) return queryState.metrics\n const seen = new Set<string>()\n const combined: MetricItem[] = []\n for (let qIndex = 0; qIndex < queryStates.length; qIndex++) {\n const qs = queryStates[qIndex]\n for (const metric of qs.metrics) {\n const key = `Q${qIndex + 1}:${metric.field}`\n if (!seen.has(key)) {\n seen.add(key)\n combined.push({\n ...metric,\n label: `${metric.label} (Q${qIndex + 1})`,\n })\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, queryState.metrics])\n\n // Combined breakdowns from all queries\n const combinedBreakdowns = useMemo(() => {\n if (!isMultiQueryMode) return queryState.breakdowns\n const seen = new Set<string>()\n const combined: BreakdownItem[] = []\n for (const qs of queryStates) {\n for (const breakdown of qs.breakdowns) {\n if (!seen.has(breakdown.field)) {\n seen.add(breakdown.field)\n combined.push(breakdown)\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, queryState.breakdowns])\n\n // Effective breakdowns for the current view\n // In merge mode, Q2+ should visually show Q1's breakdowns since they're shared\n const effectiveBreakdowns = useMemo(() => {\n if (mergeStrategy === 'merge' && activeQueryIndex > 0) {\n // Show Q1's breakdowns for Q2+ in merge mode\n return queryStates[0]?.breakdowns || []\n }\n return queryState.breakdowns\n }, [mergeStrategy, activeQueryIndex, queryStates, queryState.breakdowns])\n\n return {\n combinedMetrics,\n combinedBreakdowns,\n effectiveBreakdowns,\n }\n}\n","/**\n * useAnalysisQueryExecution\n *\n * Coordinates TanStack Query execution for single, multi-query, and funnel modes.\n * Provides unified loading states, results, and refetch functionality.\n */\n\nimport { useMemo, useCallback } from 'react'\nimport {\n useCubeLoadQuery,\n useMultiCubeLoadQuery,\n useFunnelQuery,\n useFlowQuery,\n useRetentionQuery,\n useDryRunQuery,\n useDryRunQueries,\n type DebugDataEntry,\n} from './queries'\nimport { useCubeMeta } from '../providers/CubeProvider'\nimport type { CubeQuery, MultiQueryConfig, FunnelBindingKey, QueryMergeStrategy, AnalysisType } from '../types'\nimport type { ExecutionStatus } from '../components/AnalysisBuilder/types'\nimport type { ServerFunnelQuery } from '../types/funnel'\nimport type { ServerFlowQuery, FlowChartData } from '../types/flow'\nimport type { ServerRetentionQuery, RetentionChartData } from '../types/retention'\nimport { buildFunnelConfigFromQueries } from '../utils/funnelExecution'\n\nexport interface UseAnalysisQueryExecutionOptions {\n /** Current query (for single-query mode) */\n currentQuery: CubeQuery\n /** All queries (for dry-run and multi-query) */\n allQueries: CubeQuery[]\n /** Multi-query config (null if single-query mode) */\n multiQueryConfig: MultiQueryConfig | null\n /** Whether in multi-query mode */\n isMultiQueryMode: boolean\n /** Whether current query is valid */\n isValidQuery: boolean\n /** Initial data (skip first fetch) */\n initialData?: unknown[]\n /** Merge strategy (for detecting funnel mode - legacy) */\n mergeStrategy?: QueryMergeStrategy\n /** Funnel binding key (required for funnel mode) */\n funnelBindingKey?: FunnelBindingKey | null\n /**\n * Whether funnel mode is properly configured (from store).\n * This includes filter-only step validation that isMultiQueryMode doesn't provide.\n * @deprecated Use analysisType === 'funnel' instead\n */\n isFunnelModeEnabled?: boolean\n /**\n * Analysis type for explicit mode routing.\n * When provided, takes precedence over legacy mode detection.\n */\n analysisType?: AnalysisType\n /**\n * Pre-built server funnel query from store's buildFunnelQueryFromSteps().\n * Used when analysisType === 'funnel' with the new dedicated funnel state.\n */\n serverFunnelQuery?: ServerFunnelQuery | null\n /**\n * Pre-built server flow query from store's buildFlowQuery().\n * Used when analysisType === 'flow' with the new dedicated flow state.\n */\n serverFlowQuery?: ServerFlowQuery | null\n /**\n * Pre-built server retention query from store's buildRetentionQuery().\n * Used when analysisType === 'retention' with the new dedicated retention state.\n */\n serverRetentionQuery?: ServerRetentionQuery | null\n /**\n * Validation result for retention mode from store's getRetentionValidation().\n * Used to display specific errors in the debug panel.\n */\n retentionValidation?: { isValid: boolean; errors: string[]; warnings: string[] } | null\n}\n\nexport interface UseAnalysisQueryExecutionResult {\n /** Query execution status */\n executionStatus: ExecutionStatus\n /** Query results (merged for multi-query) */\n executionResults: unknown[] | null\n /** Per-query results (for table view in multi-query mode) */\n perQueryResults: (unknown[] | null)[] | null\n /** Whether query is loading */\n isLoading: boolean\n /** Whether query is fetching (includes refetch) */\n isFetching: boolean\n /** Query error */\n error: Error | null\n /** Debug data per query (for non-funnel modes) */\n debugDataPerQuery: DebugDataEntry[]\n /** Whether query has been debounced (for smart defaults trigger) */\n hasDebounced: boolean\n /** Refetch function. Pass { bustCache: true } to bypass client and server caches. */\n refetch: (options?: { bustCache?: boolean }) => void\n /**\n * In funnel mode, these are the actually executed queries with:\n * - Binding key dimension auto-added\n * - IN filter applied for steps 2+\n * Use these for debug display instead of the original queries.\n * @deprecated Server-side funnel uses a unified query. Use funnelServerQuery instead.\n */\n funnelExecutedQueries: CubeQuery[] | null\n /**\n * The actual server funnel query { funnel: {...} }\n * This is the unified query sent to the server (not per-step queries).\n */\n funnelServerQuery: ServerFunnelQuery | null\n /**\n * Debug data specifically for funnel mode\n * Contains unified dry-run SQL and mode metadata.\n */\n funnelDebugData: DebugDataEntry | null\n /**\n * The server flow query being executed (when analysisType === 'flow')\n */\n flowServerQuery: ServerFlowQuery | null\n /**\n * Flow chart data (nodes and links for Sankey visualization)\n */\n flowChartData: FlowChartData | null\n /**\n * Debug data specifically for flow mode\n * Contains unified dry-run SQL and mode metadata.\n */\n flowDebugData: DebugDataEntry | null\n /**\n * The server retention query being executed (when analysisType === 'retention')\n */\n retentionServerQuery: ServerRetentionQuery | null\n /**\n * Retention chart data (cohort × period matrix)\n */\n retentionChartData: RetentionChartData | null\n /**\n * Debug data specifically for retention mode\n * Contains unified dry-run SQL and mode metadata.\n */\n retentionDebugData: DebugDataEntry | null\n /**\n * Retention validation result (errors explaining why query cannot be built)\n */\n retentionValidation: { isValid: boolean; errors: string[]; warnings: string[] } | null\n /**\n * Whether the current query config differs from the last executed query.\n * Used for manual refresh mode to show \"needs refresh\" indicator.\n */\n needsRefresh: boolean\n /**\n * Query warnings from the server (e.g., fan-out without dimensions).\n * Displayed as a banner above results.\n */\n warnings: import('../shared/types').QueryWarning[] | undefined\n}\n\nexport function useAnalysisQueryExecution(\n options: UseAnalysisQueryExecutionOptions\n): UseAnalysisQueryExecutionResult {\n const {\n currentQuery,\n allQueries,\n multiQueryConfig,\n isMultiQueryMode,\n isValidQuery,\n initialData,\n mergeStrategy: _mergeStrategy, // Unused - legacy mergeStrategy === 'funnel' is no longer supported\n funnelBindingKey,\n isFunnelModeEnabled,\n analysisType,\n serverFunnelQuery,\n serverFlowQuery,\n serverRetentionQuery,\n retentionValidation,\n } = options\n\n // Get field label resolver from cube context (for human-readable labels)\n const { getFieldLabel } = useCubeMeta()\n\n // Determine execution mode based on analysisType\n // Note: Legacy mergeStrategy === 'funnel' is no longer supported\n // Funnel mode is now exclusively determined by analysisType === 'funnel'\n const isFunnelMode = analysisType === 'funnel' || isFunnelModeEnabled\n\n // Flow mode is exclusively determined by analysisType === 'flow'\n const isFlowMode = analysisType === 'flow'\n\n // Retention mode is exclusively determined by analysisType === 'retention'\n const isRetentionMode = analysisType === 'retention'\n\n // Multi mode is 'query' analysis type with multiple queries\n const isMultiMode = analysisType === 'query' && isMultiQueryMode\n\n // Single mode is 'query' analysis type without multiple queries\n const isSingleMode = analysisType === 'query' && !isMultiQueryMode\n\n // Check if we're using the new dedicated funnel mode (with serverFunnelQuery)\n const isNewFunnelMode = analysisType === 'funnel' && !!serverFunnelQuery\n\n // Build funnel config when in funnel mode (legacy - from queryStates)\n // Skip when using new dedicated funnel mode with serverFunnelQuery\n const funnelConfig = useMemo(() => {\n // If using new funnel mode with prebuilt query, skip legacy config building\n if (isNewFunnelMode) return null\n if (!isFunnelMode || !funnelBindingKey || allQueries.length < 2) return null\n return buildFunnelConfigFromQueries(allQueries, funnelBindingKey)\n }, [isNewFunnelMode, isFunnelMode, funnelBindingKey, allQueries])\n\n // Single query execution (only when analysisType is 'query' or legacy single mode)\n const singleQueryResult = useCubeLoadQuery(currentQuery, {\n skip: !isValidQuery || !isSingleMode,\n debounceMs: 300,\n })\n\n // Multi-query execution (only when analysisType is 'multi' or legacy multi mode)\n const multiQueryResult = useMultiCubeLoadQuery(multiQueryConfig, {\n skip: !multiQueryConfig || !isMultiMode,\n debounceMs: 300,\n })\n\n // Funnel query execution\n // Use prebuiltServerQuery when in new funnel mode, otherwise use funnelConfig\n const funnelQueryResult = useFunnelQuery(funnelConfig, {\n skip: !isFunnelMode || (!funnelConfig && !serverFunnelQuery),\n debounceMs: 300,\n prebuiltServerQuery: isNewFunnelMode ? serverFunnelQuery : undefined,\n })\n\n // Flow query execution\n const flowQueryResult = useFlowQuery(serverFlowQuery ?? null, {\n skip: !isFlowMode || !serverFlowQuery,\n debounceMs: 300,\n })\n\n // Retention query execution\n const retentionQueryResult = useRetentionQuery(serverRetentionQuery ?? null, {\n skip: !isRetentionMode || !serverRetentionQuery,\n debounceMs: 300,\n getFieldLabel, // Pass label resolver for human-readable binding key display\n })\n\n // Dry-run queries for debug data (skip in funnel, flow, and retention mode)\n const dryRunResult = useDryRunQueries({\n queries: isMultiQueryMode ? allQueries : [currentQuery],\n isMultiQueryMode,\n skip: !isValidQuery || isFunnelMode || isFlowMode || isRetentionMode,\n })\n\n // Funnel dry-run query (only in funnel mode)\n // Use the serverQuery from useFunnelQuery to get the unified funnel SQL\n const funnelDryRunResult = useDryRunQuery(\n funnelQueryResult.serverQuery as CubeQuery | null,\n { skip: !isFunnelMode || !funnelQueryResult.serverQuery }\n )\n\n // Flow dry-run query (only in flow mode)\n // Use the serverQuery from useFlowQuery to get the unified flow SQL\n const flowDryRunResult = useDryRunQuery(\n flowQueryResult.serverQuery as CubeQuery | null,\n { skip: !isFlowMode || !flowQueryResult.serverQuery }\n )\n\n // Retention dry-run query (only in retention mode)\n // Use the serverRetentionQuery input to get the unified retention SQL\n const retentionDryRunResult = useDryRunQuery(\n serverRetentionQuery as CubeQuery | null,\n { skip: !isRetentionMode || !serverRetentionQuery }\n )\n\n // Unify results based on mode\n const isLoading = isRetentionMode\n ? retentionQueryResult.isLoading || retentionQueryResult.isDebouncing\n : isFlowMode\n ? flowQueryResult.isLoading || flowQueryResult.isDebouncing\n : isFunnelMode\n ? funnelQueryResult.isExecuting || funnelQueryResult.isDebouncing\n : isMultiMode\n ? multiQueryResult.isLoading\n : singleQueryResult.isLoading\n const isFetching = isRetentionMode\n ? retentionQueryResult.isFetching\n : isFlowMode\n ? flowQueryResult.isFetching\n : isFunnelMode\n ? funnelQueryResult.isExecuting\n : isMultiMode\n ? multiQueryResult.isFetching\n : singleQueryResult.isFetching\n const error = isRetentionMode\n ? retentionQueryResult.error\n : isFlowMode\n ? flowQueryResult.error\n : isFunnelMode\n ? funnelQueryResult.error\n : isMultiMode\n ? multiQueryResult.error\n : singleQueryResult.error\n\n // Has debounced (for smart defaults trigger)\n const hasDebounced = Boolean(\n singleQueryResult.debouncedQuery ||\n multiQueryResult.debouncedConfig ||\n !funnelQueryResult.isDebouncing || // Funnel has debounced when not debouncing\n !flowQueryResult.isDebouncing || // Flow has debounced when not debouncing\n !retentionQueryResult.isDebouncing // Retention has debounced when not debouncing\n )\n\n // Unified refetch function\n // Pass options (including bustCache) through to underlying hooks\n const refetch = useCallback((options?: { bustCache?: boolean }) => {\n if (isRetentionMode) {\n // Retention uses execute for bustCache support\n retentionQueryResult.execute(options)\n } else if (isFlowMode) {\n flowQueryResult.refetch(options)\n } else if (isFunnelMode) {\n funnelQueryResult.execute(options)\n } else if (isMultiMode) {\n multiQueryResult.refetch(options)\n } else {\n singleQueryResult.refetch(options)\n }\n }, [isRetentionMode, isFlowMode, isFunnelMode, isMultiMode, retentionQueryResult, flowQueryResult, funnelQueryResult, multiQueryResult, singleQueryResult])\n\n // Execution status\n const executionStatus: ExecutionStatus = useMemo(() => {\n const hasResults = isRetentionMode\n ? retentionQueryResult.chartData\n : isFlowMode\n ? flowQueryResult.data\n : isFunnelMode\n ? funnelQueryResult.chartData\n : isMultiMode\n ? multiQueryResult.data\n : singleQueryResult.rawData\n if (initialData && initialData.length > 0 && !hasResults) return 'success'\n if (!isValidQuery) return 'idle'\n if (isLoading && !hasResults) return 'loading'\n if (isFetching && hasResults) return 'refreshing'\n if (error) return 'error'\n if (hasResults) return 'success'\n return 'idle'\n }, [isValidQuery, isLoading, isFetching, error, singleQueryResult.rawData, multiQueryResult.data, funnelQueryResult.chartData, flowQueryResult.data, retentionQueryResult.chartData, initialData, isMultiMode, isFunnelMode, isFlowMode, isRetentionMode])\n\n // Execution results\n const executionResults = useMemo(() => {\n // Retention mode returns transformed flat data for chart compatibility\n if (isRetentionMode && retentionQueryResult.chartData) {\n // Transform RetentionChartData to flat rows\n // Format: [{ \"Retention.period\": \"P0\", \"Retention.rate\": 0.45, \"Retention.segment\": \"US\", ... }]\n return retentionQueryResult.chartData.rows.map(row => ({\n 'Retention.period': `P${row.period}`,\n 'Retention.rate': row.retentionRate,\n 'Retention.retained': row.retainedUsers,\n 'Retention.cohortSize': row.cohortSize,\n 'Retention.segment': row.breakdownValue || 'All Users',\n })) as unknown[]\n }\n // Flow mode returns Sankey chart data directly\n if (isFlowMode && flowQueryResult.data) {\n // Wrap in array for consistency with other modes\n return [flowQueryResult.data] as unknown[]\n }\n // Funnel mode returns chart data directly\n if (isFunnelMode && funnelQueryResult.chartData) {\n return funnelQueryResult.chartData as unknown[]\n }\n if (isMultiMode && multiQueryResult.data) {\n return multiQueryResult.data as unknown[]\n }\n if (singleQueryResult.rawData) {\n return singleQueryResult.rawData\n }\n if (initialData && initialData.length > 0) {\n return initialData\n }\n return null\n }, [singleQueryResult.rawData, multiQueryResult.data, funnelQueryResult.chartData, flowQueryResult.data, retentionQueryResult.chartData, initialData, isMultiMode, isFunnelMode, isFlowMode, isRetentionMode])\n\n // Per-query results for table view (or per-step for funnel)\n const perQueryResults = useMemo(() => {\n // In funnel mode, return step results as per-query data\n if (isFunnelMode && funnelQueryResult.stepResults) {\n return funnelQueryResult.stepResults.map((step) => step.data)\n }\n if (!isMultiMode || !multiQueryResult.perQueryData) return null\n return multiQueryResult.perQueryData\n }, [isMultiMode, isFunnelMode, multiQueryResult.perQueryData, funnelQueryResult.stepResults])\n\n // In funnel mode, provide the executed queries for debug display (legacy)\n const funnelExecutedQueries = isFunnelMode && funnelQueryResult.executedQueries?.length > 0\n ? funnelQueryResult.executedQueries\n : null\n\n // The actual server funnel query (new, preferred)\n const funnelServerQuery = isFunnelMode ? funnelQueryResult.serverQuery : null\n\n // Funnel debug data (unified SQL for funnel mode)\n const funnelDebugData = isFunnelMode ? funnelDryRunResult.debugData : null\n\n // Flow-related values\n const flowServerQuery = isFlowMode ? flowQueryResult.serverQuery : null\n const flowChartData = isFlowMode ? flowQueryResult.data : null\n\n // Flow debug data (unified SQL for flow mode)\n const flowDebugData = isFlowMode ? flowDryRunResult.debugData : null\n\n // Retention-related values\n const retentionServerQuery = isRetentionMode ? (serverRetentionQuery ?? null) : null\n const retentionChartData = isRetentionMode ? retentionQueryResult.chartData : null\n\n // Retention debug data (unified SQL for retention mode)\n const retentionDebugData = isRetentionMode ? retentionDryRunResult.debugData : null\n\n // Aggregate needsRefresh from the appropriate mode hook\n // This determines if the \"needs refresh\" banner should be shown\n // Note: Multi-query mode doesn't have needsRefresh yet (falls back to false)\n const needsRefresh = useMemo(() => {\n if (isRetentionMode) return retentionQueryResult.needsRefresh\n if (isFlowMode) return flowQueryResult.needsRefresh\n if (isFunnelMode) return funnelQueryResult.needsRefresh\n if (isMultiMode) return false // Multi-query mode doesn't support manual refresh yet\n return singleQueryResult.needsRefresh\n }, [isRetentionMode, isFlowMode, isFunnelMode, isMultiMode, retentionQueryResult.needsRefresh, flowQueryResult.needsRefresh, funnelQueryResult.needsRefresh, singleQueryResult.needsRefresh])\n\n // Aggregate warnings from the appropriate mode hook\n // Currently only supported for single-query mode (where useCubeLoadQuery exposes warnings)\n const warnings = useMemo(() => {\n // Single query mode has warnings from useCubeLoadQuery\n if (isSingleMode && singleQueryResult.warnings) {\n return singleQueryResult.warnings\n }\n // TODO: Add warnings support for multi-query, funnel, flow, and retention modes\n return undefined\n }, [isSingleMode, singleQueryResult.warnings])\n\n return {\n executionStatus,\n executionResults,\n perQueryResults,\n isLoading,\n isFetching,\n error,\n debugDataPerQuery: dryRunResult.debugDataPerQuery,\n hasDebounced,\n refetch,\n funnelExecutedQueries,\n funnelServerQuery,\n funnelDebugData,\n flowServerQuery,\n flowChartData,\n flowDebugData,\n retentionServerQuery,\n retentionChartData,\n retentionDebugData,\n retentionValidation: retentionValidation ?? null,\n needsRefresh,\n warnings,\n }\n}\n","/**\n * useAnalysisChartDefaults\n *\n * Manages chart configuration, availability, and smart defaulting.\n * Handles color palette resolution and chart type auto-switching.\n *\n * Returns mode-appropriate chart config based on analysisType:\n * - Query mode: uses chartType, chartConfig, displayConfig\n * - Funnel mode: uses funnelChartType, funnelChartConfig, funnelDisplayConfig\n */\n\nimport { useMemo, useEffect, useRef, useCallback } from 'react'\nimport { useAnalysisBuilderStore, selectChartConfig } from '../stores/analysisBuilderStore'\nimport { useShallow } from 'zustand/react/shallow'\nimport { getAllChartAvailability, getSmartChartDefaults, shouldAutoSwitchChartType } from '../shared/chartDefaults'\nimport { getColorPalette, type ColorPalette } from '../utils/colorPalettes'\nimport type { ChartType, ChartAxisConfig, ChartDisplayConfig } from '../types'\nimport type { MetricItem, BreakdownItem } from '../components/AnalysisBuilder/types'\nimport type { ChartAvailabilityMap } from '../shared/chartDefaults'\n\nexport interface UseAnalysisChartDefaultsOptions {\n /** External color palette (overrides local) */\n externalColorPalette?: string[] | ColorPalette\n /** Combined metrics from all queries */\n combinedMetrics: MetricItem[]\n /** Combined breakdowns from all queries */\n combinedBreakdowns: BreakdownItem[]\n /** Whether query has been debounced (triggers smart defaults) */\n hasDebounced: boolean\n}\n\nexport interface UseAnalysisChartDefaultsResult {\n /** Current chart type */\n chartType: ChartType\n /** Chart axis configuration */\n chartConfig: ChartAxisConfig\n /** Chart display configuration */\n displayConfig: ChartDisplayConfig\n /** Effective color palette */\n colorPalette: ColorPalette\n /** Local palette name (when not using external) */\n localPaletteName: string\n /** Chart availability map */\n chartAvailability: ChartAvailabilityMap\n /** User manually selected chart */\n userManuallySelectedChart: boolean\n\n // Actions\n setChartType: (type: ChartType) => void\n setChartConfig: (config: ChartAxisConfig) => void\n setDisplayConfig: (config: ChartDisplayConfig) => void\n setLocalPaletteName: (name: string) => void\n}\n\nexport function useAnalysisChartDefaults(\n options: UseAnalysisChartDefaultsOptions\n): UseAnalysisChartDefaultsResult {\n const { externalColorPalette, combinedMetrics, combinedBreakdowns, hasDebounced } = options\n\n // Get analysis type to determine which config to use\n const analysisType = useAnalysisBuilderStore((state) => state.analysisType)\n\n // Use the mode-aware selector to get the appropriate chart config\n const { chartType, chartConfig, displayConfig } = useAnalysisBuilderStore(useShallow(selectChartConfig))\n\n // Store state (shared)\n const userManuallySelectedChart = useAnalysisBuilderStore((state) => state.userManuallySelectedChart)\n const localPaletteName = useAnalysisBuilderStore((state) => state.localPaletteName)\n\n // Store actions - Query mode\n const setChartTypeManual = useAnalysisBuilderStore((state) => state.setChartTypeManual)\n const setQueryChartConfig = useAnalysisBuilderStore((state) => state.setChartConfig)\n const setQueryDisplayConfig = useAnalysisBuilderStore((state) => state.setDisplayConfig)\n\n // Store actions - Funnel mode\n const setFunnelChartType = useAnalysisBuilderStore((state) => state.setFunnelChartType)\n const setFunnelChartConfig = useAnalysisBuilderStore((state) => state.setFunnelChartConfig)\n const setFunnelDisplayConfig = useAnalysisBuilderStore((state) => state.setFunnelDisplayConfig)\n\n // Shared actions\n const setLocalPaletteName = useAnalysisBuilderStore((state) => state.setLocalPaletteName)\n const setUserManuallySelectedChart = useAnalysisBuilderStore((state) => state.setUserManuallySelectedChart)\n\n // Mode-aware setters - route to appropriate store action based on analysis type\n const setChartType = useCallback(\n (type: ChartType) => {\n if (analysisType === 'funnel') {\n setFunnelChartType(type)\n } else {\n setChartTypeManual(type)\n const { chartConfig: smartConfig } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n type\n )\n setQueryChartConfig(smartConfig)\n }\n },\n [\n analysisType,\n combinedMetrics,\n combinedBreakdowns,\n setFunnelChartType,\n setChartTypeManual,\n setQueryChartConfig,\n ]\n )\n\n const setChartConfig = useCallback(\n (config: ChartAxisConfig) => {\n if (analysisType === 'funnel') {\n setFunnelChartConfig(config)\n } else {\n setQueryChartConfig(config)\n }\n },\n [analysisType, setFunnelChartConfig, setQueryChartConfig]\n )\n\n const setDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n if (analysisType === 'funnel') {\n setFunnelDisplayConfig(config)\n } else {\n setQueryDisplayConfig(config)\n }\n },\n [analysisType, setFunnelDisplayConfig, setQueryDisplayConfig]\n )\n\n // Chart availability\n const chartAvailability = useMemo(\n () => getAllChartAvailability(combinedMetrics, combinedBreakdowns),\n [combinedMetrics, combinedBreakdowns]\n )\n\n // Effective color palette\n const colorPalette = useMemo((): ColorPalette => {\n if (externalColorPalette) {\n if (Array.isArray(externalColorPalette) && typeof externalColorPalette[0] === 'string') {\n return {\n name: 'custom',\n label: 'Custom',\n colors: externalColorPalette as string[],\n gradient: externalColorPalette as string[],\n }\n }\n return externalColorPalette as ColorPalette\n }\n return getColorPalette(localPaletteName)\n }, [externalColorPalette, localPaletteName])\n\n // Smart chart defaulting\n const prevMetricsBreakdownsRef = useRef<string>('')\n\n useEffect(() => {\n if (!hasDebounced) return\n if (combinedMetrics.length === 0 && combinedBreakdowns.length === 0) return\n\n const currentKey = JSON.stringify({\n metrics: combinedMetrics.map((m) => m.field),\n breakdowns: combinedBreakdowns.map((b) => ({ field: b.field, isTime: b.isTimeDimension })),\n })\n\n if (currentKey === prevMetricsBreakdownsRef.current) return\n prevMetricsBreakdownsRef.current = currentKey\n\n const newChartType = shouldAutoSwitchChartType(\n combinedMetrics,\n combinedBreakdowns,\n chartType,\n userManuallySelectedChart\n )\n\n if (newChartType) {\n const { chartConfig: newConfig } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n newChartType\n )\n setChartType(newChartType)\n setChartConfig(newConfig)\n setUserManuallySelectedChart(false)\n } else if (combinedMetrics.length > 0 || combinedBreakdowns.length > 0) {\n // Apply smart defaults only if chart config is empty\n const isChartConfigEmpty =\n !chartConfig.xAxis?.length &&\n !chartConfig.yAxis?.length &&\n !chartConfig.series?.length\n if (isChartConfigEmpty) {\n const { chartConfig: smartDefaults } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n chartType\n )\n setChartConfig(smartDefaults)\n }\n }\n }, [\n hasDebounced,\n combinedMetrics,\n combinedBreakdowns,\n chartType,\n userManuallySelectedChart,\n chartConfig,\n setChartType,\n setChartConfig,\n setUserManuallySelectedChart,\n ])\n\n return {\n chartType,\n chartConfig,\n displayConfig,\n colorPalette,\n localPaletteName,\n chartAvailability,\n userManuallySelectedChart,\n\n // Actions - mode-aware setters route to appropriate store fields\n setChartType,\n setChartConfig,\n setDisplayConfig,\n setLocalPaletteName,\n }\n}\n","/**\n * useAnalysisUIState\n *\n * Manages UI-only state for AnalysisBuilder:\n * - Active tab selection\n * - View toggle (table/chart)\n * - Field modal state\n * - Display limit\n * - Active table index for multi-query\n */\n\nimport { useState } from 'react'\nimport { useAnalysisBuilderStore, type FieldModalMode } from '../stores/analysisBuilderStore'\nimport type { QueryPanelTab } from '../components/AnalysisBuilder/types'\n\nexport interface UseAnalysisUIStateResult {\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field modal is open */\n showFieldModal: boolean\n /** Field modal mode */\n fieldModalMode: FieldModalMode\n /** Active table index for multi-query */\n activeTableIndex: number\n /** User manually selected chart */\n userManuallySelectedChart: boolean\n\n // Actions\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n closeFieldModal: () => void\n setActiveTableIndex: (index: number) => void\n}\n\nexport function useAnalysisUIState(): UseAnalysisUIStateResult {\n // Store state\n const activeTab = useAnalysisBuilderStore((state) => state.activeTab)\n const activeView = useAnalysisBuilderStore((state) => state.activeView)\n const displayLimit = useAnalysisBuilderStore((state) => state.displayLimit)\n const showFieldModal = useAnalysisBuilderStore((state) => state.showFieldModal)\n const fieldModalMode = useAnalysisBuilderStore((state) => state.fieldModalMode)\n const userManuallySelectedChart = useAnalysisBuilderStore((state) => state.userManuallySelectedChart)\n\n // Store actions\n const setActiveTab = useAnalysisBuilderStore((state) => state.setActiveTab)\n const setActiveView = useAnalysisBuilderStore((state) => state.setActiveView)\n const setDisplayLimit = useAnalysisBuilderStore((state) => state.setDisplayLimit)\n const closeFieldModal = useAnalysisBuilderStore((state) => state.closeFieldModal)\n\n // Local state for table index (not persisted)\n const [activeTableIndex, setActiveTableIndex] = useState(0)\n\n return {\n // State\n activeTab,\n activeView,\n displayLimit,\n showFieldModal,\n fieldModalMode,\n activeTableIndex,\n userManuallySelectedChart,\n\n // Actions\n setActiveTab,\n setActiveView,\n setDisplayLimit,\n closeFieldModal,\n setActiveTableIndex,\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 * Phase 3: Now uses AnalysisConfig format exclusively.\n * Old share URLs will not parse (breaking change as per plan).\n */\n\nimport { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string'\nimport type { AnalysisConfig } from '../types/analysisConfig'\nimport { isValidAnalysisConfig } from '../types/analysisConfig'\n\n// Re-export for backward compatibility during transition\nexport type { AnalysisConfig as ShareableState }\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 AnalysisConfig to URL-safe encoded string\n */\nexport function compressAndEncode(config: AnalysisConfig): string {\n const json = JSON.stringify(config)\n return compressToEncodedURIComponent(json)\n}\n\n/**\n * Decompress URL-safe encoded string back to AnalysisConfig\n * Returns null if decompression, parsing, or validation fails.\n *\n * Note: This does not support legacy share URL formats (breaking change).\n */\nexport function decodeAndDecompress(encoded: string): AnalysisConfig | null {\n try {\n const json = decompressFromEncodedURIComponent(encoded)\n if (!json) return null\n\n const parsed = JSON.parse(json)\n\n // Validate using the AnalysisConfig type guard\n if (!isValidAnalysisConfig(parsed)) {\n console.warn('[shareUtils] Invalid AnalysisConfig in share URL')\n return null\n }\n\n return parsed\n } catch {\n return null\n }\n}\n\n/**\n * Check if compressed config fits within URL length limit\n */\nexport function isShareableSize(config: AnalysisConfig): { ok: boolean; size: number; maxSize: number } {\n const encoded = compressAndEncode(config)\n return {\n ok: encoded.length <= MAX_HASH_LENGTH,\n size: encoded.length,\n maxSize: MAX_HASH_LENGTH\n }\n}\n\n/**\n * Compress config with automatic fallback\n * If full config is too large, tries with query only (preserving essential fields)\n * Returns null encoded if even query-only is too large\n */\nexport function compressWithFallback(config: AnalysisConfig): CompressionResult {\n // Try full config first\n const fullEncoded = compressAndEncode(config)\n if (fullEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: fullEncoded, queryOnly: false }\n }\n\n // Fall back to minimal config (query + essential fields only)\n const minimalConfig: AnalysisConfig = {\n version: config.version,\n analysisType: config.analysisType,\n activeView: config.activeView,\n charts: {}, // Drop chart config to save space\n query: config.query,\n } as AnalysisConfig\n\n const minimalEncoded = compressAndEncode(minimalConfig)\n if (minimalEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: minimalEncoded, queryOnly: true }\n }\n\n // Even minimal is too large\n return { encoded: null, queryOnly: true }\n}\n\n/**\n * Generate full share URL with compressed config in hash\n */\nexport function generateShareUrl(config: AnalysisConfig): string | null {\n const { encoded } = compressWithFallback(config)\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// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Create a share URL from store's save() method output\n * This is the primary entry point for creating share URLs.\n */\nexport function createShareUrl(config: AnalysisConfig): string | null {\n return generateShareUrl(config)\n}\n\n/**\n * Parse and validate share URL, returning AnalysisConfig or null\n * This is the primary entry point for loading from share URLs.\n */\nexport function parseShareUrl(): AnalysisConfig | null {\n const encoded = parseShareHash()\n if (!encoded) return null\n return decodeAndDecompress(encoded)\n}\n","/**\n * useAnalysisInitialization\n *\n * Handles initialization side effects:\n * - URL share loading on mount\n * - Callback forwarding (onQueryChange, onChartConfigChange)\n */\n\nimport { useEffect, useRef } from 'react'\nimport { useAnalysisBuilderStore } from '../stores/analysisBuilderStore'\nimport { parseShareUrl, clearShareHash } from '../utils/shareUtils'\nimport type { CubeQuery, ChartType, ChartAxisConfig, ChartDisplayConfig } from '../types'\n\nexport interface UseAnalysisInitializationOptions {\n /** Current query */\n currentQuery: CubeQuery\n /** Whether query is valid */\n isValidQuery: boolean\n /** Chart type */\n chartType: ChartType\n /** Chart config */\n chartConfig: ChartAxisConfig\n /** Display config */\n displayConfig: ChartDisplayConfig\n /** Callback when query changes */\n onQueryChange?: (query: CubeQuery) => void\n /** Callback when chart config changes */\n onChartConfigChange?: (config: {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }) => void\n}\n\n/**\n * Handles initialization effects - no return value (side-effect only hook)\n */\nexport function useAnalysisInitialization(options: UseAnalysisInitializationOptions): void {\n const {\n currentQuery,\n isValidQuery,\n chartType,\n chartConfig,\n displayConfig,\n onQueryChange,\n onChartConfigChange,\n } = options\n\n // Get store action for loading from share URL\n const load = useAnalysisBuilderStore((state) => state.load)\n\n // URL share loading (on mount only)\n const hasInitializedShareRef = useRef(false)\n\n useEffect(() => {\n if (hasInitializedShareRef.current) return\n hasInitializedShareRef.current = true\n\n // parseShareUrl returns AnalysisConfig | null\n const config = parseShareUrl()\n if (!config) return\n\n load(config)\n clearShareHash()\n }, [load])\n\n // Query change callback\n useEffect(() => {\n if (onQueryChange && isValidQuery) {\n onQueryChange(currentQuery)\n }\n }, [currentQuery, isValidQuery, onQueryChange])\n\n // Chart config change callback\n useEffect(() => {\n if (onChartConfigChange) {\n onChartConfigChange({\n chartType,\n chartConfig,\n displayConfig,\n })\n }\n }, [chartType, chartConfig, displayConfig, onChartConfigChange])\n}\n","/**\n * useAnalysisBuilder - Master Coordination Hook\n *\n * The single hook that provides everything AnalysisBuilder needs.\n * Orchestrates sub-hooks for modular, maintainable code:\n *\n * - useAnalysisQueryBuilder: Query state, building, validation\n * - useAnalysisCombinedFields: Multi-query field merging\n * - useAnalysisQueryExecution: TanStack Query data fetching\n * - useAnalysisChartDefaults: Chart configuration and smart defaults\n * - useAnalysisUIState: UI state (tabs, modals, view toggle)\n * - useAnalysisInitialization: Side effects (URL loading, callbacks)\n *\n * IMPORTANT: This hook must be used within AnalysisBuilderStoreProvider\n */\n\nimport { useCallback, useMemo, useRef } from 'react'\nimport { useCubeFeatures } from '../providers/CubeProvider'\nimport {\n useAnalysisBuilderStore,\n useAnalysisBuilderStoreApi,\n} from '../stores/analysisBuilderStore'\n\n// Sub-hooks\nimport { useAnalysisQueryBuilder } from './useAnalysisQueryBuilder'\nimport { useAnalysisCombinedFields } from './useAnalysisCombinedFields'\nimport { useAnalysisQueryExecution } from './useAnalysisQueryExecution'\nimport { useAnalysisChartDefaults } from './useAnalysisChartDefaults'\nimport { useAnalysisUIState } from './useAnalysisUIState'\nimport { useAnalysisInitialization } from './useAnalysisInitialization'\n\nimport type { ColorPalette } from '../utils/colorPalettes'\nimport type {\n CubeQuery,\n MultiQueryConfig,\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n Filter,\n QueryMergeStrategy,\n FunnelBindingKey,\n AnalysisType,\n FunnelStepState,\n} from '../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n ExecutionStatus,\n QueryPanelTab,\n} from '../components/AnalysisBuilder/types'\nimport type { ChartAvailabilityMap } from '../shared/chartDefaults'\nimport type { DebugDataEntry } from './queries'\nimport type { MultiQueryValidationResult } from '../utils/multiQueryValidation'\nimport type { MetaField } from '../shared/types'\nimport type { ValidationResult } from '../adapters/modeAdapter'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseAnalysisBuilderOptions {\n /** External color palette (overrides local) */\n externalColorPalette?: string[] | ColorPalette\n /** Initial data (skip first fetch) */\n initialData?: unknown[]\n /** Callback when query changes */\n onQueryChange?: (query: CubeQuery) => void\n /** Callback when chart config changes */\n onChartConfigChange?: (config: {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }) => void\n}\n\nexport interface UseAnalysisBuilderResult {\n // Query State\n queryState: AnalysisBuilderState\n queryStates: AnalysisBuilderState[]\n activeQueryIndex: number\n mergeStrategy: QueryMergeStrategy\n isMultiQueryMode: boolean\n mergeKeys: string[] | undefined\n currentQuery: CubeQuery\n allQueries: CubeQuery[]\n multiQueryConfig: MultiQueryConfig | null\n multiQueryValidation: MultiQueryValidationResult | null\n\n // Funnel State (legacy - merge strategy mode)\n funnelBindingKey: FunnelBindingKey | null\n /** Whether funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: boolean\n\n // Analysis Type State (new dedicated mode selection)\n /** Current analysis type (query, multi, funnel) */\n analysisType: AnalysisType\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (when analysisType === 'funnel') */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Chart type for funnel mode (separate from query mode) */\n funnelChartType: ChartType\n /** Chart config for funnel mode (separate from query mode) */\n funnelChartConfig: ChartAxisConfig\n /** Display config for funnel mode (separate from query mode) */\n funnelDisplayConfig: ChartDisplayConfig\n\n // Flow Mode State (when analysisType === 'flow')\n /** Selected cube for flow mode */\n flowCube: string | null\n /** Binding key for flow mode (entity linking) */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for flow mode (event ordering) */\n flowTimeDimension: string | null\n /** Event dimension for flow mode (node labels in Sankey) */\n eventDimension: string | null\n /** Starting step configuration */\n startingStep: import('../types/flow').FlowStartingStep\n /** Number of steps to explore before starting step */\n stepsBefore: number\n /** Number of steps to explore after starting step */\n stepsAfter: number\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n /** Display config for flow mode */\n flowDisplayConfig: ChartDisplayConfig\n\n // Retention State (simplified Mixpanel-style)\n /** Single cube for retention analysis */\n retentionCube: string | null\n /** Binding key for retention mode */\n retentionBindingKey: import('../types/funnel').FunnelBindingKey | null\n /** Single timestamp dimension for retention mode */\n retentionTimeDimension: string | null\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: import('../types/retention').DateRange\n /** Cohort filters for retention mode */\n retentionCohortFilters: import('../types').Filter[]\n /** Activity filters for retention mode */\n retentionActivityFilters: import('../types').Filter[]\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: import('../types/retention').RetentionBreakdownItem[]\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: import('../types/retention').RetentionGranularity\n /** Number of periods for retention mode */\n retentionPeriods: number\n /** Retention calculation type */\n retentionType: import('../types/retention').RetentionType\n /** Display config for retention mode */\n retentionDisplayConfig: ChartDisplayConfig | undefined\n\n // Data Fetching\n executionStatus: ExecutionStatus\n executionResults: unknown[] | null\n perQueryResults: (unknown[] | null)[] | null\n isLoading: boolean\n isFetching: boolean\n error: Error | null\n isValidQuery: boolean\n debugDataPerQuery: DebugDataEntry[]\n /**\n * Whether the current query config differs from the last executed query.\n * Used for manual refresh mode to show \"needs refresh\" indicator.\n */\n needsRefresh: boolean\n /**\n * Query warnings from the server (e.g., fan-out without dimensions).\n * Displayed as a banner above results.\n */\n warnings: import('../shared/types').QueryWarning[] | undefined\n /** In funnel mode, the actually executed queries with binding key dimension and IN filters */\n funnelExecutedQueries: CubeQuery[] | null\n /** In funnel mode, the actual server query { funnel: {...} } sent to the API */\n funnelServerQuery: unknown | null\n /** In funnel mode, unified debug data (SQL, analysis, mode metadata) */\n funnelDebugData: DebugDataEntry | null\n /** In flow mode, the actual server query { flow: {...} } sent to the API */\n flowServerQuery: unknown | null\n /** In flow mode, unified debug data (SQL, analysis, mode metadata) */\n flowDebugData: DebugDataEntry | null\n /** In retention mode, the actual server query { retention: {...} } sent to the API */\n retentionServerQuery: unknown | null\n /** In retention mode, unified debug data (SQL, analysis, mode metadata) */\n retentionDebugData: DebugDataEntry | null\n /** In retention mode, the chart data (cohort × period matrix) */\n retentionChartData: import('../types/retention').RetentionChartData | null\n /** In retention mode, validation result (errors explaining why query cannot be built) */\n retentionValidation: { isValid: boolean; errors: string[]; warnings: string[] } | null\n\n // Chart Configuration\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n colorPalette: ColorPalette\n localPaletteName: string\n chartAvailability: ChartAvailabilityMap\n combinedMetrics: MetricItem[]\n combinedBreakdowns: BreakdownItem[]\n effectiveBreakdowns: BreakdownItem[]\n\n // UI State\n activeTab: QueryPanelTab\n activeView: 'table' | 'chart'\n displayLimit: number\n showFieldModal: boolean\n fieldModalMode: 'metrics' | 'breakdown'\n activeTableIndex: number\n userManuallySelectedChart: boolean\n\n // AI State\n aiState: {\n isOpen: boolean\n userPrompt: string\n isGenerating: boolean\n error: string | null\n hasGeneratedQuery: boolean\n }\n\n // Share State\n shareButtonState: 'idle' | 'copied' | 'copied-no-chart'\n canShare: boolean\n\n // Adapter Validation (NEW - Phase 5)\n /** Validation result from the adapter for the current analysis type */\n adapterValidation: ValidationResult\n\n // Actions\n actions: {\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n openMetricsModal: () => void\n addMetric: (field: string, label?: string) => void\n removeMetric: (id: string) => void\n toggleMetric: (fieldName: string) => void\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n openBreakdownsModal: () => void\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n removeBreakdown: (id: string) => void\n toggleBreakdown: (fieldName: string, isTimeDimension: boolean, granularity?: string) => void\n setBreakdownGranularity: (id: string, granularity: string) => void\n toggleBreakdownComparison: (id: string) => void\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n setFilters: (filters: Filter[]) => void\n dropFieldToFilter: (field: string) => void\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n addQuery: () => void\n removeQuery: (index: number) => void\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n // Analysis Type actions\n setAnalysisType: (type: AnalysisType) => void\n // Funnel Mode actions (when analysisType === 'funnel')\n setFunnelCube: (cube: string | null) => void\n addFunnelStep: () => void\n removeFunnelStep: (index: number) => void\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n setActiveFunnelStepIndex: (index: number) => void\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n setFunnelTimeDimension: (dimension: string | null) => void\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n // Flow Mode actions (when analysisType === 'flow')\n setFlowCube: (cube: string | null) => void\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n setFlowTimeDimension: (dim: string | null) => void\n setEventDimension: (dim: string | null) => void\n setStartingStepName: (name: string) => void\n setStartingStepFilters: (filters: Filter[]) => void\n setStepsBefore: (count: number) => void\n setStepsAfter: (count: number) => void\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n setFlowDisplayConfig: (config: ChartDisplayConfig) => void\n // Retention Mode actions (simplified Mixpanel-style)\n setRetentionCube: (cube: string | null) => void\n setRetentionBindingKey: (key: import('../types/funnel').FunnelBindingKey | null) => void\n setRetentionTimeDimension: (dim: string | null) => void\n setRetentionDateRange: (range: import('../types/retention').DateRange) => void\n setRetentionCohortFilters: (filters: import('../types').Filter[]) => void\n setRetentionActivityFilters: (filters: import('../types').Filter[]) => void\n setRetentionBreakdowns: (breakdowns: import('../types/retention').RetentionBreakdownItem[]) => void\n addRetentionBreakdown: (breakdown: import('../types/retention').RetentionBreakdownItem) => void\n removeRetentionBreakdown: (field: string) => void\n setRetentionViewGranularity: (granularity: import('../types/retention').RetentionGranularity) => void\n setRetentionPeriods: (periods: number) => void\n setRetentionType: (type: import('../types/retention').RetentionType) => void\n setRetentionDisplayConfig: (config: ChartDisplayConfig) => void\n setChartType: (type: ChartType) => void\n setChartConfig: (config: ChartAxisConfig) => void\n setDisplayConfig: (config: ChartDisplayConfig) => void\n setLocalPaletteName: (name: string) => void\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n closeFieldModal: () => void\n setActiveTableIndex: (index: number) => void\n openAI: () => void\n closeAI: () => void\n setAIPrompt: (prompt: string) => void\n generateAI: () => Promise<void>\n acceptAI: () => void\n cancelAI: () => void\n share: () => Promise<void>\n clearQuery: () => void\n clearCurrentMode: () => void\n refetch: (options?: { bustCache?: boolean }) => void\n handleFieldSelected: (\n field: MetaField,\n fieldType: 'measure' | 'dimension' | 'timeDimension',\n cubeName: string,\n keepOpen?: boolean\n ) => void\n }\n\n // Refs (for imperative access)\n getQueryConfig: () => CubeQuery | MultiQueryConfig | import('../types/funnel').ServerFunnelQuery\n getChartConfig: () => {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }\n getAnalysisType: () => AnalysisType\n}\n\n// ============================================================================\n// Hook Implementation\n// ============================================================================\n\nexport function useAnalysisBuilder(\n options: UseAnalysisBuilderOptions = {}\n): UseAnalysisBuilderResult {\n const { initialData, externalColorPalette, onQueryChange, onChartConfigChange } = options\n\n // Get context\n const { features } = useCubeFeatures()\n\n // Get store API for direct access\n const storeApi = useAnalysisBuilderStoreApi()\n\n // =========================================================================\n // Sub-Hooks Orchestration\n // =========================================================================\n\n // 1. Query Builder (query state, building, validation)\n const queryBuilder = useAnalysisQueryBuilder()\n\n // 2. Combined Fields (multi-query field merging)\n const combinedFields = useAnalysisCombinedFields({\n queryState: queryBuilder.queryState,\n queryStates: queryBuilder.queryStates,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n mergeStrategy: queryBuilder.mergeStrategy,\n activeQueryIndex: queryBuilder.activeQueryIndex,\n })\n\n // Get funnel binding key from store for funnel mode\n const funnelBindingKey = useAnalysisBuilderStore((s) => s.funnelBindingKey)\n\n // Get analysis type state (must be before computed values that use it)\n const analysisType = useAnalysisBuilderStore((s) => s.analysisType)\n const funnelCube = useAnalysisBuilderStore((s) => s.funnelCube)\n const funnelSteps = useAnalysisBuilderStore((s) => s.funnelSteps)\n const activeFunnelStepIndex = useAnalysisBuilderStore((s) => s.activeFunnelStepIndex)\n const funnelTimeDimension = useAnalysisBuilderStore((s) => s.funnelTimeDimension)\n\n // Get funnel mode enabled state (computed to avoid function call in selector)\n // This includes filter-only step validation\n const isFunnelModeEnabled = useMemo(() => {\n if (analysisType !== 'funnel') return false\n if (!funnelBindingKey?.dimension) return false\n if (!funnelTimeDimension) return false\n if (!funnelSteps || funnelSteps.length < 2) return false\n // All steps must have at least one filter\n return funnelSteps.every((step) => step.filters.length > 0)\n }, [analysisType, funnelBindingKey, funnelTimeDimension, funnelSteps])\n // Phase 4: Read from charts map instead of legacy fields\n // Use stable selectors to avoid infinite loop from creating new objects\n const funnelChartType = useAnalysisBuilderStore((s) => s.charts.funnel?.chartType) || 'funnel'\n const funnelChartConfigFromStore = useAnalysisBuilderStore((s) => s.charts.funnel?.chartConfig)\n const funnelChartConfig = useMemo(() => funnelChartConfigFromStore || {}, [funnelChartConfigFromStore])\n\n // Get flow mode state\n const flowCube = useAnalysisBuilderStore((s) => s.flowCube)\n const flowBindingKey = useAnalysisBuilderStore((s) => s.flowBindingKey)\n const flowTimeDimension = useAnalysisBuilderStore((s) => s.flowTimeDimension)\n const eventDimension = useAnalysisBuilderStore((s) => s.eventDimension)\n const startingStep = useAnalysisBuilderStore((s) => s.startingStep)\n const stepsBefore = useAnalysisBuilderStore((s) => s.stepsBefore)\n const stepsAfter = useAnalysisBuilderStore((s) => s.stepsAfter)\n const joinStrategy = useAnalysisBuilderStore((s) => s.joinStrategy)\n // Flow display config from charts map - use stable selector to avoid infinite loop\n const flowDisplayConfigFromStore = useAnalysisBuilderStore((state) => state.charts.flow?.displayConfig)\n const flowDisplayConfig = useMemo(\n () => flowDisplayConfigFromStore || { showLegend: true, showGrid: true, showTooltip: true },\n [flowDisplayConfigFromStore]\n )\n // Flow chart type from charts map - needed for outputMode in query\n const flowChartType = useAnalysisBuilderStore((state) => state.charts.flow?.chartType) || 'sankey'\n\n // Build server funnel query from dedicated funnelSteps (when analysisType === 'funnel')\n // Note: funnelSteps must be in dependency array so query rebuilds when filters change\n const buildFunnelQueryFromSteps = useAnalysisBuilderStore((s) => s.buildFunnelQueryFromSteps)\n const serverFunnelQuery = useMemo(() => {\n if (analysisType !== 'funnel') return null\n return buildFunnelQueryFromSteps()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- funnelSteps triggers rebuild when step filters change\n }, [analysisType, buildFunnelQueryFromSteps, funnelSteps])\n\n const buildFlowQuery = useAnalysisBuilderStore((s) => s.buildFlowQuery)\n\n // Build server flow query (when analysisType === 'flow')\n // Note: flowChartType is included because it determines outputMode (sankey vs sunburst aggregation)\n const serverFlowQuery = useMemo(() => {\n if (analysisType !== 'flow') return null\n return buildFlowQuery()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- flow config values trigger rebuild when they change in store\n }, [analysisType, buildFlowQuery, flowCube, flowBindingKey, flowTimeDimension, eventDimension, startingStep, stepsBefore, stepsAfter, flowChartType, joinStrategy])\n\n // Get retention state from store (simplified Mixpanel-style)\n const retentionCube = useAnalysisBuilderStore((s) => s.retentionCube)\n const retentionBindingKey = useAnalysisBuilderStore((s) => s.retentionBindingKey)\n const retentionTimeDimension = useAnalysisBuilderStore((s) => s.retentionTimeDimension)\n const retentionDateRange = useAnalysisBuilderStore((s) => s.retentionDateRange)\n const retentionCohortFilters = useAnalysisBuilderStore((s) => s.retentionCohortFilters)\n const retentionActivityFilters = useAnalysisBuilderStore((s) => s.retentionActivityFilters)\n const retentionBreakdowns = useAnalysisBuilderStore((s) => s.retentionBreakdowns)\n const retentionViewGranularity = useAnalysisBuilderStore((s) => s.retentionViewGranularity)\n const retentionPeriods = useAnalysisBuilderStore((s) => s.retentionPeriods)\n const retentionType = useAnalysisBuilderStore((s) => s.retentionType)\n const buildRetentionQuery = useAnalysisBuilderStore((s) => s.buildRetentionQuery)\n const getRetentionValidation = useAnalysisBuilderStore((s) => s.getRetentionValidation)\n\n // Retention display config from charts map\n const retentionDisplayConfig = useAnalysisBuilderStore((s) => s.charts.retention?.displayConfig)\n\n // Retention actions (simplified Mixpanel-style)\n const setRetentionCube = useAnalysisBuilderStore((s) => s.setRetentionCube)\n const setRetentionBindingKey = useAnalysisBuilderStore((s) => s.setRetentionBindingKey)\n const setRetentionTimeDimension = useAnalysisBuilderStore((s) => s.setRetentionTimeDimension)\n const setRetentionDateRange = useAnalysisBuilderStore((s) => s.setRetentionDateRange)\n const setRetentionCohortFilters = useAnalysisBuilderStore((s) => s.setRetentionCohortFilters)\n const setRetentionActivityFilters = useAnalysisBuilderStore((s) => s.setRetentionActivityFilters)\n const setRetentionBreakdowns = useAnalysisBuilderStore((s) => s.setRetentionBreakdowns)\n const addRetentionBreakdown = useAnalysisBuilderStore((s) => s.addRetentionBreakdown)\n const removeRetentionBreakdown = useAnalysisBuilderStore((s) => s.removeRetentionBreakdown)\n const setRetentionViewGranularity = useAnalysisBuilderStore((s) => s.setRetentionViewGranularity)\n const setRetentionPeriods = useAnalysisBuilderStore((s) => s.setRetentionPeriods)\n const setRetentionType = useAnalysisBuilderStore((s) => s.setRetentionType)\n\n // Build server retention query (when analysisType === 'retention')\n const serverRetentionQuery = useMemo(() => {\n if (analysisType !== 'retention') return null\n return buildRetentionQuery()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- retention config values trigger rebuild when they change in store\n }, [\n analysisType,\n buildRetentionQuery,\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n retentionBreakdowns,\n retentionViewGranularity,\n retentionPeriods,\n retentionType,\n retentionCohortFilters,\n retentionActivityFilters,\n ])\n\n // Get retention validation (memoized based on config changes)\n const retentionValidation = useMemo(() => {\n if (analysisType !== 'retention') return null\n return getRetentionValidation()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- retention config values trigger rebuild\n }, [\n analysisType,\n getRetentionValidation,\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n ])\n\n // Compute effective isValidQuery that considers funnel, flow, and retention modes\n // In funnel mode, the query is valid when serverFunnelQuery is not null\n // In flow mode, the query is valid when serverFlowQuery is not null\n // In retention mode, the query is valid when serverRetentionQuery is not null\n const effectiveIsValidQuery = useMemo(() => {\n if (analysisType === 'retention') {\n // Retention mode: valid when we have a buildable retention query\n return serverRetentionQuery !== null\n }\n if (analysisType === 'flow') {\n // Flow mode: valid when we have a buildable flow query\n return serverFlowQuery !== null\n }\n if (analysisType === 'funnel') {\n // Funnel mode: valid when we have a buildable funnel query\n return serverFunnelQuery !== null\n }\n // Query/Multi mode: use the standard validation\n return queryBuilder.isValidQuery ?? false\n }, [analysisType, serverRetentionQuery, serverFlowQuery, serverFunnelQuery, queryBuilder.isValidQuery])\n\n // 3. Query Execution (TanStack Query integration)\n const queryExecution = useAnalysisQueryExecution({\n currentQuery: queryBuilder.currentQuery,\n allQueries: queryBuilder.allQueries,\n multiQueryConfig: queryBuilder.multiQueryConfig,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n isValidQuery: effectiveIsValidQuery,\n initialData,\n mergeStrategy: queryBuilder.mergeStrategy,\n funnelBindingKey,\n isFunnelModeEnabled,\n // New: pass analysisType and serverFunnelQuery for explicit mode routing\n analysisType,\n serverFunnelQuery,\n // Flow mode: pass serverFlowQuery\n serverFlowQuery,\n // Retention mode: pass serverRetentionQuery\n serverRetentionQuery,\n // Retention mode: pass validation for debug panel\n retentionValidation,\n })\n\n // 4. Chart Defaults (chart config, availability, smart defaults)\n const chartDefaults = useAnalysisChartDefaults({\n externalColorPalette,\n combinedMetrics: combinedFields.combinedMetrics,\n combinedBreakdowns: combinedFields.combinedBreakdowns,\n hasDebounced: queryExecution.hasDebounced,\n })\n\n // 5. UI State (tabs, modals, view toggle)\n const uiState = useAnalysisUIState()\n\n // 6. Initialization (URL loading, callbacks - side effects only)\n useAnalysisInitialization({\n currentQuery: queryBuilder.currentQuery,\n isValidQuery: queryBuilder.isValidQuery ?? false,\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n onQueryChange,\n onChartConfigChange,\n })\n\n // =========================================================================\n // Store Actions (not covered by sub-hooks)\n // =========================================================================\n\n // Metric actions\n const openMetricsModal = useAnalysisBuilderStore((state) => state.openMetricsModal)\n const addMetric = useAnalysisBuilderStore((state) => state.addMetric)\n const removeMetric = useAnalysisBuilderStore((state) => state.removeMetric)\n const toggleMetric = useAnalysisBuilderStore((state) => state.toggleMetric)\n const reorderMetrics = useAnalysisBuilderStore((state) => state.reorderMetrics)\n\n // Breakdown actions\n const openBreakdownsModal = useAnalysisBuilderStore((state) => state.openBreakdownsModal)\n const addBreakdown = useAnalysisBuilderStore((state) => state.addBreakdown)\n const removeBreakdown = useAnalysisBuilderStore((state) => state.removeBreakdown)\n const toggleBreakdown = useAnalysisBuilderStore((state) => state.toggleBreakdown)\n const setBreakdownGranularity = useAnalysisBuilderStore((state) => state.setBreakdownGranularity)\n const toggleBreakdownComparison = useAnalysisBuilderStore((state) => state.toggleBreakdownComparison)\n const reorderBreakdowns = useAnalysisBuilderStore((state) => state.reorderBreakdowns)\n\n // Filter actions\n const setFilters = useAnalysisBuilderStore((state) => state.setFilters)\n const dropFieldToFilter = useAnalysisBuilderStore((state) => state.dropFieldToFilter)\n const setOrder = useAnalysisBuilderStore((state) => state.setOrder)\n\n // Utility actions\n const clearQuery = useAnalysisBuilderStore((state) => state.clearQuery)\n const clearCurrentMode = useAnalysisBuilderStore((state) => state.clearCurrentMode)\n\n // Funnel actions (legacy)\n const setFunnelBindingKey = useAnalysisBuilderStore((state) => state.setFunnelBindingKey)\n\n // Analysis Type actions (new)\n const setAnalysisType = useAnalysisBuilderStore((state) => state.setAnalysisType)\n\n // Funnel Mode actions (new dedicated state)\n const setFunnelCube = useAnalysisBuilderStore((state) => state.setFunnelCube)\n const addFunnelStep = useAnalysisBuilderStore((state) => state.addFunnelStep)\n const removeFunnelStep = useAnalysisBuilderStore((state) => state.removeFunnelStep)\n const updateFunnelStep = useAnalysisBuilderStore((state) => state.updateFunnelStep)\n const setActiveFunnelStepIndex = useAnalysisBuilderStore((state) => state.setActiveFunnelStepIndex)\n const reorderFunnelSteps = useAnalysisBuilderStore((state) => state.reorderFunnelSteps)\n const setFunnelTimeDimension = useAnalysisBuilderStore((state) => state.setFunnelTimeDimension)\n\n // Funnel display config (for Display tab in funnel mode)\n // Phase 4: Read from charts map - use stable selector to avoid infinite loop\n const funnelDisplayConfigFromStore = useAnalysisBuilderStore((state) => state.charts.funnel?.displayConfig)\n const funnelDisplayConfig = useMemo(\n () => funnelDisplayConfigFromStore || { showLegend: true, showGrid: true, showTooltip: true },\n [funnelDisplayConfigFromStore]\n )\n const setFunnelDisplayConfig = useAnalysisBuilderStore((state) => state.setFunnelDisplayConfig)\n\n // Flow Mode actions\n const setFlowCube = useAnalysisBuilderStore((state) => state.setFlowCube)\n const setFlowBindingKey = useAnalysisBuilderStore((state) => state.setFlowBindingKey)\n const setFlowTimeDimension = useAnalysisBuilderStore((state) => state.setFlowTimeDimension)\n const setEventDimension = useAnalysisBuilderStore((state) => state.setEventDimension)\n const setStartingStepName = useAnalysisBuilderStore((state) => state.setStartingStepName)\n const setStartingStepFilters = useAnalysisBuilderStore((state) => state.setStartingStepFilters)\n const setStepsBefore = useAnalysisBuilderStore((state) => state.setStepsBefore)\n const setStepsAfter = useAnalysisBuilderStore((state) => state.setStepsAfter)\n const setJoinStrategy = useAnalysisBuilderStore((state) => state.setJoinStrategy)\n // Flow display config action - creates setFlowDisplayConfig wrapper using charts map pattern\n const setFlowDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n storeApi.setState((state) => ({\n charts: {\n ...state.charts,\n flow: {\n ...(state.charts.flow || { chartType: 'sankey', chartConfig: {}, displayConfig: {} }),\n displayConfig: config,\n },\n },\n }))\n },\n [storeApi]\n )\n\n // Retention display config action - creates setRetentionDisplayConfig wrapper using charts map pattern\n const setRetentionDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n storeApi.setState((state) => ({\n charts: {\n ...state.charts,\n retention: {\n ...(state.charts.retention || { chartType: 'retentionCombined', chartConfig: {}, displayConfig: {} }),\n displayConfig: config,\n },\n },\n }))\n },\n [storeApi]\n )\n\n // AI state and actions\n const aiState = useAnalysisBuilderStore((state) => state.aiState)\n const openAI = useAnalysisBuilderStore((state) => state.openAI)\n const closeAI = useAnalysisBuilderStore((state) => state.closeAI)\n const setAIPrompt = useAnalysisBuilderStore((state) => state.setAIPrompt)\n const setAIGenerating = useAnalysisBuilderStore((state) => state.setAIGenerating)\n const setAIError = useAnalysisBuilderStore((state) => state.setAIError)\n const setAIHasGeneratedQuery = useAnalysisBuilderStore((state) => state.setAIHasGeneratedQuery)\n const saveAIPreviousState = useAnalysisBuilderStore((state) => state.saveAIPreviousState)\n const restoreAIPreviousState = useAnalysisBuilderStore((state) => state.restoreAIPreviousState)\n\n // =========================================================================\n // Share State\n // =========================================================================\n\n const shareButtonStateRef = useRef<'idle' | 'copied' | 'copied-no-chart'>('idle')\n const canShare = effectiveIsValidQuery\n\n // =========================================================================\n // Adapter Validation (NEW - Phase 5)\n // =========================================================================\n\n const getValidation = useAnalysisBuilderStore((state) => state.getValidation)\n // Note: Dependencies trigger recomputation when store values change.\n // getValidation reads values from store closure, but we need the memo to\n // recompute when the underlying state changes.\n const adapterValidation = useMemo(\n () => getValidation(),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n getValidation,\n queryBuilder.queryStates,\n analysisType,\n // Funnel deps\n funnelSteps,\n funnelBindingKey,\n funnelTimeDimension,\n // Flow deps\n flowCube,\n flowBindingKey,\n flowTimeDimension,\n eventDimension,\n startingStep,\n stepsBefore,\n stepsAfter,\n joinStrategy,\n ]\n )\n\n // =========================================================================\n // Action Callbacks\n // =========================================================================\n\n const handleFieldSelected = useCallback(\n (\n field: MetaField,\n fieldType: 'measure' | 'dimension' | 'timeDimension',\n _cubeName: string,\n keepOpen?: boolean\n ) => {\n if (uiState.fieldModalMode === 'metrics' && fieldType === 'measure') {\n toggleMetric(field.name)\n } else if (uiState.fieldModalMode === 'breakdown') {\n // In retention mode, add to retention breakdowns instead of query breakdowns\n if (analysisType === 'retention' && fieldType === 'dimension') {\n addRetentionBreakdown({ field: field.name })\n } else {\n toggleBreakdown(field.name, fieldType === 'timeDimension')\n }\n }\n if (!keepOpen) {\n uiState.closeFieldModal()\n }\n },\n [uiState, toggleMetric, toggleBreakdown, addRetentionBreakdown, analysisType]\n )\n\n const generateAI = useCallback(async () => {\n if (!features?.aiEndpoint) return\n saveAIPreviousState()\n setAIGenerating(true)\n setAIError(null)\n\n try {\n // AI generation logic would go here\n await new Promise((resolve) => setTimeout(resolve, 1000))\n setAIHasGeneratedQuery(true)\n } catch (err) {\n setAIError(err instanceof Error ? err.message : 'Failed to generate query')\n } finally {\n setAIGenerating(false)\n }\n }, [features?.aiEndpoint, saveAIPreviousState, setAIGenerating, setAIError, setAIHasGeneratedQuery])\n\n const acceptAI = useCallback(() => {\n closeAI()\n setAIHasGeneratedQuery(false)\n }, [closeAI, setAIHasGeneratedQuery])\n\n const cancelAI = useCallback(() => {\n restoreAIPreviousState()\n closeAI()\n }, [restoreAIPreviousState, closeAI])\n\n const share = useCallback(async () => {\n shareButtonStateRef.current = 'copied'\n setTimeout(() => {\n shareButtonStateRef.current = 'idle'\n }, 2000)\n }, [])\n\n // =========================================================================\n // Ref API Functions\n // =========================================================================\n\n const getQueryConfig = useCallback(() => {\n const state = storeApi.getState()\n\n // Handle dedicated funnel mode (analysisType === 'funnel')\n if (state.analysisType === 'funnel') {\n // Return ServerFunnelQuery format built from funnelSteps\n const funnelQuery = state.buildFunnelQueryFromSteps()\n if (funnelQuery) {\n return funnelQuery\n }\n // Fallback to single query if funnel isn't properly configured yet\n return state.buildCurrentQuery()\n }\n\n // Handle multi-query mode (legacy funnel mode with mergeStrategy === 'funnel' is included here)\n if (state.queryStates.length > 1) {\n return {\n queries: state.buildAllQueries(),\n mergeStrategy: state.mergeStrategy,\n mergeKeys: state.getMergeKeys(),\n queryLabels: state.queryStates.map((_, i) => `Q${i + 1}`),\n // Include funnel-specific config when in funnel mode\n funnelBindingKey: state.funnelBindingKey,\n stepTimeToConvert: state.stepTimeToConvert,\n }\n }\n\n // Single query mode\n return state.buildCurrentQuery()\n }, [storeApi])\n\n const getChartConfig = useCallback(() => {\n const state = storeApi.getState()\n\n // Phase 4: Read from charts map based on analysis type\n const config = state.charts[state.analysisType]\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n\n // Fallback to defaults\n return {\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n }\n }, [storeApi, chartDefaults.chartType, chartDefaults.chartConfig, chartDefaults.displayConfig])\n\n const getAnalysisType = useCallback(() => {\n return storeApi.getState().analysisType\n }, [storeApi])\n\n // =========================================================================\n // Return Value\n // =========================================================================\n\n return {\n // Query state (from queryBuilder)\n queryState: queryBuilder.queryState,\n queryStates: queryBuilder.queryStates,\n activeQueryIndex: queryBuilder.activeQueryIndex,\n mergeStrategy: queryBuilder.mergeStrategy,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n mergeKeys: queryBuilder.mergeKeys,\n currentQuery: queryBuilder.currentQuery,\n allQueries: queryBuilder.allQueries,\n multiQueryConfig: queryBuilder.multiQueryConfig,\n multiQueryValidation: queryBuilder.multiQueryValidation,\n\n // Funnel state (legacy)\n funnelBindingKey,\n isFunnelModeEnabled,\n\n // Analysis Type state (new)\n analysisType,\n funnelCube,\n funnelSteps,\n activeFunnelStepIndex,\n funnelTimeDimension,\n funnelChartType,\n funnelChartConfig,\n funnelDisplayConfig,\n\n // Flow state (new)\n flowCube,\n flowBindingKey,\n flowTimeDimension,\n eventDimension,\n startingStep,\n stepsBefore,\n stepsAfter,\n joinStrategy,\n flowDisplayConfig,\n\n // Retention state (simplified Mixpanel-style)\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n retentionCohortFilters,\n retentionActivityFilters,\n retentionBreakdowns,\n retentionViewGranularity,\n retentionPeriods,\n retentionType,\n retentionDisplayConfig,\n\n // Data fetching (from queryExecution)\n executionStatus: queryExecution.executionStatus,\n executionResults: queryExecution.executionResults,\n perQueryResults: queryExecution.perQueryResults,\n isLoading: queryExecution.isLoading,\n isFetching: queryExecution.isFetching,\n error: queryExecution.error,\n isValidQuery: effectiveIsValidQuery,\n debugDataPerQuery: queryExecution.debugDataPerQuery,\n needsRefresh: queryExecution.needsRefresh,\n warnings: queryExecution.warnings,\n funnelExecutedQueries: queryExecution.funnelExecutedQueries,\n funnelServerQuery: queryExecution.funnelServerQuery,\n funnelDebugData: queryExecution.funnelDebugData,\n flowServerQuery: queryExecution.flowServerQuery,\n flowDebugData: queryExecution.flowDebugData,\n retentionServerQuery: queryExecution.retentionServerQuery,\n retentionDebugData: queryExecution.retentionDebugData,\n retentionChartData: queryExecution.retentionChartData,\n retentionValidation: queryExecution.retentionValidation,\n\n // Chart configuration (from chartDefaults)\n // Note: Funnel chart type is determined by analysisType === 'funnel', not mergeStrategy\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n colorPalette: chartDefaults.colorPalette,\n localPaletteName: chartDefaults.localPaletteName,\n chartAvailability: chartDefaults.chartAvailability,\n combinedMetrics: combinedFields.combinedMetrics,\n combinedBreakdowns: combinedFields.combinedBreakdowns,\n effectiveBreakdowns: combinedFields.effectiveBreakdowns,\n\n // UI state (from uiState)\n activeTab: uiState.activeTab,\n activeView: uiState.activeView,\n displayLimit: uiState.displayLimit,\n showFieldModal: uiState.showFieldModal,\n fieldModalMode: uiState.fieldModalMode,\n activeTableIndex: uiState.activeTableIndex,\n userManuallySelectedChart: uiState.userManuallySelectedChart,\n\n // AI state\n aiState: {\n isOpen: aiState.isOpen,\n userPrompt: aiState.userPrompt,\n isGenerating: aiState.isGenerating,\n error: aiState.error,\n hasGeneratedQuery: aiState.hasGeneratedQuery,\n },\n\n // Share state\n shareButtonState: shareButtonStateRef.current,\n canShare,\n\n // Adapter validation (NEW - Phase 5)\n adapterValidation,\n\n // Actions\n actions: {\n // Query state (from queryBuilder)\n setActiveQueryIndex: queryBuilder.setActiveQueryIndex,\n setMergeStrategy: queryBuilder.setMergeStrategy,\n\n // Metrics\n openMetricsModal,\n addMetric,\n removeMetric,\n toggleMetric,\n reorderMetrics,\n\n // Breakdowns\n openBreakdownsModal,\n addBreakdown,\n removeBreakdown,\n toggleBreakdown,\n setBreakdownGranularity,\n toggleBreakdownComparison,\n reorderBreakdowns,\n\n // Filters\n setFilters,\n dropFieldToFilter,\n setOrder,\n\n // Multi-query (from queryBuilder)\n addQuery: queryBuilder.addQuery,\n removeQuery: queryBuilder.removeQuery,\n\n // Funnel (legacy)\n setFunnelBindingKey,\n\n // Analysis Type (new)\n setAnalysisType,\n\n // Funnel Mode (new dedicated state)\n setFunnelCube,\n addFunnelStep,\n removeFunnelStep,\n updateFunnelStep,\n setActiveFunnelStepIndex,\n reorderFunnelSteps,\n setFunnelTimeDimension,\n setFunnelDisplayConfig,\n\n // Flow Mode actions\n setFlowCube,\n setFlowBindingKey,\n setFlowTimeDimension,\n setEventDimension,\n setStartingStepName,\n setStartingStepFilters,\n setStepsBefore,\n setStepsAfter,\n setJoinStrategy,\n setFlowDisplayConfig,\n\n // Retention Mode actions (simplified Mixpanel-style)\n setRetentionCube,\n setRetentionBindingKey,\n setRetentionTimeDimension,\n setRetentionDateRange,\n setRetentionCohortFilters,\n setRetentionActivityFilters,\n setRetentionBreakdowns,\n addRetentionBreakdown,\n removeRetentionBreakdown,\n setRetentionViewGranularity,\n setRetentionPeriods,\n setRetentionType,\n setRetentionDisplayConfig,\n\n // Chart (from chartDefaults)\n setChartType: chartDefaults.setChartType,\n setChartConfig: chartDefaults.setChartConfig,\n setDisplayConfig: chartDefaults.setDisplayConfig,\n setLocalPaletteName: chartDefaults.setLocalPaletteName,\n\n // UI (from uiState)\n setActiveTab: uiState.setActiveTab,\n setActiveView: uiState.setActiveView,\n setDisplayLimit: uiState.setDisplayLimit,\n closeFieldModal: uiState.closeFieldModal,\n setActiveTableIndex: uiState.setActiveTableIndex,\n\n // AI\n openAI,\n closeAI,\n setAIPrompt,\n generateAI,\n acceptAI,\n cancelAI,\n\n // Share\n share,\n\n // Utility\n clearQuery,\n clearCurrentMode,\n refetch: queryExecution.refetch,\n handleFieldSelected,\n },\n\n // Refs\n getQueryConfig,\n getChartConfig,\n getAnalysisType,\n }\n}\n","/**\n * Funnel Validation Utilities\n *\n * Provides validation for funnel configurations including:\n * - Binding key validation\n * - Step query validation\n * - Cross-cube compatibility checks\n */\n\nimport type { CubeQuery, CubeMeta } from '../types'\nimport type {\n FunnelBindingKey,\n FunnelConfig,\n FunnelStep,\n FunnelValidationError,\n FunnelValidationResult,\n} from '../types/funnel'\nimport { getCubeNameFromQuery } from './funnelExecution'\n\n/**\n * Validate that a binding key dimension exists in the given cubes\n */\nexport function validateBindingKeyExists(\n bindingKey: FunnelBindingKey,\n meta: CubeMeta | null\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n if (!meta?.cubes) {\n return errors // Can't validate without metadata\n }\n\n if (typeof bindingKey.dimension === 'string') {\n // Simple dimension - check it exists\n const [cubeName, dimName] = bindingKey.dimension.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n\n if (!cube) {\n errors.push({\n type: 'binding_key',\n message: `Cube \"${cubeName}\" not found for binding key`,\n })\n } else {\n const dim = cube.dimensions?.find((d) => d.name === bindingKey.dimension)\n if (!dim) {\n errors.push({\n type: 'binding_key',\n message: `Dimension \"${dimName}\" not found in cube \"${cubeName}\"`,\n })\n }\n }\n } else {\n // Cross-cube mappings - validate each\n for (const mapping of bindingKey.dimension) {\n const cube = meta.cubes.find((c) => c.name === mapping.cube)\n\n if (!cube) {\n errors.push({\n type: 'cross_cube',\n message: `Cube \"${mapping.cube}\" not found for binding key mapping`,\n })\n } else {\n const dim = cube.dimensions?.find((d) => d.name === mapping.dimension)\n if (!dim) {\n errors.push({\n type: 'cross_cube',\n message: `Dimension \"${mapping.dimension}\" not found in cube \"${mapping.cube}\"`,\n })\n }\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate that each step has a valid query\n */\nexport function validateStepQueries(\n steps: FunnelStep[]\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const query = step.query\n\n // Check that query has at least one field\n const hasFields =\n (query.measures && query.measures.length > 0) ||\n (query.dimensions && query.dimensions.length > 0) ||\n (query.timeDimensions && query.timeDimensions.length > 0)\n\n if (!hasFields) {\n errors.push({\n type: 'step_query',\n message: `Step ${i + 1} \"${step.name}\" has no measures, dimensions, or time dimensions`,\n stepIndex: i,\n })\n }\n }\n\n return errors\n}\n\n/**\n * Check if binding key can be resolved for a given query\n */\nexport function canResolveBindingKey(\n bindingKey: FunnelBindingKey,\n query: CubeQuery\n): boolean {\n if (typeof bindingKey.dimension === 'string') {\n // Simple case - binding key applies universally\n return true\n }\n\n // Cross-cube case - check if query's cube has a mapping\n const cubeName = getCubeNameFromQuery(query)\n if (!cubeName) return false\n\n return bindingKey.dimension.some((m) => m.cube === cubeName)\n}\n\n/**\n * Validate binding key for all funnel steps\n */\nexport function validateBindingKeyForSteps(\n bindingKey: FunnelBindingKey,\n steps: FunnelStep[]\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n if (!canResolveBindingKey(bindingKey, step.query)) {\n const cubeName = getCubeNameFromQuery(step.query) || 'unknown'\n errors.push({\n type: 'cross_cube',\n message: `Step ${i + 1} uses cube \"${cubeName}\" but no binding key mapping exists for it`,\n stepIndex: i,\n })\n }\n }\n\n return errors\n}\n\n/**\n * Validate time window format (ISO 8601 duration)\n */\nexport function validateTimeWindow(\n duration: string | undefined\n): FunnelValidationError | null {\n if (!duration) return null\n\n // Basic ISO 8601 duration validation\n // Formats: P1D, P7D, PT1H, PT30M, P1DT12H, etc.\n const durationRegex = /^P(?:\\d+Y)?(?:\\d+M)?(?:\\d+W)?(?:\\d+D)?(?:T(?:\\d+H)?(?:\\d+M)?(?:\\d+S)?)?$/\n\n if (!durationRegex.test(duration)) {\n return {\n type: 'time_window',\n message: `Invalid time window format \"${duration}\". Expected ISO 8601 duration (e.g., P7D, PT1H)`,\n }\n }\n\n return null\n}\n\n/**\n * Validate complete funnel configuration\n */\nexport function validateFunnelConfig(\n config: FunnelConfig,\n meta: CubeMeta | null\n): FunnelValidationResult {\n const errors: FunnelValidationError[] = []\n const warnings: FunnelValidationError[] = []\n\n // Check minimum steps\n if (config.steps.length < 2) {\n errors.push({\n type: 'general',\n message: 'Funnel requires at least 2 steps',\n })\n }\n\n // Validate binding key\n if (!config.bindingKey?.dimension) {\n errors.push({\n type: 'binding_key',\n message: 'Binding key dimension is required',\n })\n } else {\n // Check binding key exists in cubes\n errors.push(...validateBindingKeyExists(config.bindingKey, meta))\n\n // Check binding key can be resolved for all steps\n errors.push(...validateBindingKeyForSteps(config.bindingKey, config.steps))\n }\n\n // Validate step queries\n errors.push(...validateStepQueries(config.steps))\n\n // Validate time windows\n for (let i = 0; i < config.steps.length; i++) {\n const step = config.steps[i]\n const timeError = validateTimeWindow(step.timeToConvert)\n if (timeError) {\n timeError.stepIndex = i\n errors.push(timeError)\n }\n }\n\n // Validate global time window\n const globalTimeError = validateTimeWindow(config.globalTimeWindow)\n if (globalTimeError) {\n errors.push(globalTimeError)\n }\n\n // Add warnings for potential issues\n if (config.steps.length > 5) {\n warnings.push({\n type: 'general',\n message: 'Funnels with more than 5 steps may have reduced performance',\n })\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n}\n\n/**\n * Quick check if minimum funnel requirements are met\n */\nexport function isMinimumFunnelConfigValid(\n bindingKey: FunnelBindingKey | null,\n queryCount: number\n): { isValid: boolean; message?: string } {\n if (queryCount < 2) {\n return { isValid: false, message: 'Add at least 2 steps for funnel' }\n }\n\n if (!bindingKey?.dimension) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n if (typeof bindingKey.dimension === 'string' && !bindingKey.dimension) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n if (Array.isArray(bindingKey.dimension) && bindingKey.dimension.length === 0) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n return { isValid: true }\n}\n\n/**\n * Get available dimensions that can serve as binding keys\n * These should be dimensions that identify entities (e.g., user IDs, order IDs)\n */\nexport function getAvailableBindingKeyDimensions(\n meta: CubeMeta | null\n): Array<{ cube: string; dimension: string; label: string }> {\n if (!meta?.cubes) return []\n\n const dimensions: Array<{ cube: string; dimension: string; label: string }> = []\n\n for (const cube of meta.cubes) {\n if (!cube.dimensions) continue\n\n for (const dim of cube.dimensions) {\n // Only include string/number dimensions (not time dimensions)\n // as potential binding keys\n if (dim.type === 'string' || dim.type === 'number') {\n dimensions.push({\n cube: cube.name,\n dimension: dim.name,\n label: dim.title || dim.shortTitle || dim.name.split('.')[1] || dim.name,\n })\n }\n }\n }\n\n return dimensions\n}\n\n/**\n * Get the display label for a binding key\n */\nexport function getBindingKeyLabel(\n bindingKey: FunnelBindingKey | null\n): string {\n if (!bindingKey?.dimension) return 'Select binding key...'\n\n if (typeof bindingKey.dimension === 'string') {\n const parts = bindingKey.dimension.split('.')\n return parts[1] || bindingKey.dimension\n }\n\n // Cross-cube - show first mapping\n if (bindingKey.dimension.length > 0) {\n const first = bindingKey.dimension[0]\n const parts = first.dimension.split('.')\n return `${parts[1] || first.dimension} (${bindingKey.dimension.length} cubes)`\n }\n\n return 'Select binding key...'\n}\n"],"names":["parseRelativeDateRange","dateRange","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","findDateFilterForField","filters","field","filter","nested","simple","buildCompareDateRangeFromFilter","timeDimensionField","dateFilter","currentPeriod","priorPeriod","removeComparisonDateFilter","acc","groupFilter","cleanedSubFilters","buildCubeQuery","metrics","breakdowns","order","preserveComparisonFilters","comparisonFields","b","filteredFilters","f","shouldIncludeFilter","query","m","td","compareDateRange","STORAGE_KEY","createInitialState","isTimeDimension","breakdown","getFirstTimeDimension","getFirstDimension","getDimensions","getTimeDimensions","getChartAvailability","chartType","measureCount","dimensionCount","timeDimensionCount","totalBreakdowns","getAllChartAvailability","chartTypes","availability","selectBestChartType","currentChartType","hasTimeDimension","hasDimension","hasMeasure","getSmartChartDefaults","chartConfig","buildChartConfig","timeDimension","dimension","dimensions","allBreakdowns","shouldAutoSwitchChartType","userManuallySelected","recommendedType","safeText","value","assessmentColors","severityColors","issueSeverityColors","AssessmentBadge","assessment","reason","labels","jsx","jsxs","IssueItem","issue","CopyButton","text","copied","setCopied","React","err","RecommendationCard","rec","typeLabels","CodeBlock","ExplainAIPanel","analysis","onClose","onClear","handleClose","handleKeyDown","e","i","ExecutionPlanPanel","memo","sql","sqlLoading","sqlError","sqlPlaceholder","explainResult","explainLoading","explainHasRun","explainError","runExplain","aiAnalysis","aiAnalysisLoading","aiAnalysisError","runAIAnalysis","_clearAIAnalysis","enableAI","title","height","useAnalyze","setUseAnalyze","useState","showAIModal","setShowAIModal","formattedSql","handleAIClick","handleCloseModal","aiButton","Fragment","createEmptyQueryState","metricsToMeasures","breakdownsToQuery","timeDimensions","stateToCubeQuery","state","measuresToMetrics","measures","index","generateId","generateMetricLabel","queryToBreakdowns","dim","hasComparison","cubeQueryToState","isMultiQueryConfig","queryModeAdapter","storeState","config","c","queryConfig","multiConfig","queryStates","charts","activeView","queries","errors","warnings","q","qs","prefix","firstBreakdowns","_state","adapters","builtInAdaptersInitialized","ensureBuiltInAdaptersInitialized","funnelModeAdapter","flowModeAdapter","retentionModeAdapter","adapterRegistry","adapter","type","createInitialCoreState","createCoreSlice","set","get","activeViews","mode","currentConfig","name","modeState","currentState","mergedCharts","mergedActiveViews","stateAsRecord","queryAdapter","queryModeState","queryActiveView","funnelAdapter","funnelModeState","funnelActiveView","funnelConfig","flowAdapter","flowModeState","flowActiveView","flowConfig","retentionAdapter","retentionModeState","retentionActiveView","retentionConfig","workspace","createInitialQueryState","createQuerySlice","states","updater","newStates","strategy","newState","_","newActiveIndex","label","newMetric","id","fieldToRemove","newMetrics","newOrder","fieldName","existingIndex","fromIndex","toIndex","movedItem","granularity","newBreakdown","newBreakdowns","mergeStrategy","activeQueryIndex","targetIndex","analysisType","sourceIndex","targetBreakdown","isEnablingComparison","updatedBreakdowns","result","currentFilters","newDateFilter","convertDateRangeTypeToValue","currentChartConfig","existingFilters","newFilter","updatedFilters","group","direction","q1Breakdowns","current","validQueries","createInitialFunnelState","createFunnelSlice","lastStep","newStep","newSteps","updates","removed","bindingKey","cube","updatedSteps","step","validSteps","s","createInitialFlowState","createFlowSlice","key","newFilters","count","FLOW_MIN_DEPTH","FLOW_MAX_DEPTH","mapping","startingStepFilter","outputMode","effectiveStepsBefore","createInitialRetentionState","defaultRetentionSliceState","createRetentionSlice","range","periods","RETENTION_MIN_PERIODS","RETENTION_MAX_PERIODS","startDate","endDate","initialAIState","createInitialUIState","createUISlice","_get","tab","view","limit","prompt","generating","error","hasQuery","prev","queryToState","baseFilters","hasDateFilter","firstRange","optionsToAnalysisConfig","options","defaultFunnelChart","funnelChartConfig","funnelState","defaultFlowChart","flowChartConfig","flowState","defaultRetentionChart","retentionChartConfig","defaultDateRange","getDateRangeFromPreset","DEFAULT_DATE_RANGE_PRESET","retentionState","defaultQueryChart","queryChartConfig","createCrossSliceActions","createAnalysisBuilderStore","initialConfig","storeCreator","store","createStore","devtools","subscribeWithSelector","persist","persisted","isValidAnalysisWorkspace","isValidAnalysisConfig","AnalysisBuilderStoreContext","createContext","AnalysisBuilderStoreProvider","children","initialQuery","initialChartConfig","disableLocalStorage","initialAnalysisType","initialFunnelState","initialFlowState","initialRetentionState","initialActiveView","storeRef","useRef","useAnalysisBuilderStore","selector","useContext","useStore","useAnalysisBuilderStoreApi","selectCurrentState","selectMetrics","selectBreakdowns","selectFilters","selectChartConfig","selectUIState","selectMultiQueryState","selectFunnelState","extractTimeDimensions","validateTimeDimensionAlignment","q1TimeDims","qTimeDims","refTimeDim","matchingDim","validateMergeKeys","mergeKeys","allFields","detectMeasureCollisions","measureCounts","measure","collisions","collisionIndices","indices","detectAsymmetricDateRanges","dateRanges","validateMultiQueryConfig","isMultiQueryValid","getValidationSummary","parts","useAnalysisQueryBuilder","setActiveQueryIndex","setMergeStrategy","addQuery","removeQuery","getCurrentState","getMergeKeys","isMultiQueryModeGetter","queryState","isMultiQueryMode","currentQuery","useMemo","allQueries","multiQueryConfig","multiQueryValidation","isValidQuery","useAnalysisCombinedFields","combinedMetrics","seen","combined","qIndex","metric","combinedBreakdowns","effectiveBreakdowns","useAnalysisQueryExecution","initialData","funnelBindingKey","isFunnelModeEnabled","serverFunnelQuery","serverFlowQuery","serverRetentionQuery","retentionValidation","getFieldLabel","useCubeMeta","isFunnelMode","isFlowMode","isRetentionMode","isMultiMode","isSingleMode","isNewFunnelMode","buildFunnelConfigFromQueries","singleQueryResult","useCubeLoadQuery","multiQueryResult","useMultiCubeLoadQuery","funnelQueryResult","useFunnelQuery","flowQueryResult","useFlowQuery","retentionQueryResult","useRetentionQuery","dryRunResult","useDryRunQueries","funnelDryRunResult","useDryRunQuery","flowDryRunResult","retentionDryRunResult","isLoading","isFetching","hasDebounced","refetch","useCallback","executionStatus","hasResults","executionResults","row","perQueryResults","funnelExecutedQueries","funnelServerQuery","funnelDebugData","flowServerQuery","flowChartData","flowDebugData","retentionServerQuery","retentionChartData","retentionDebugData","needsRefresh","useAnalysisChartDefaults","externalColorPalette","displayConfig","useShallow","userManuallySelectedChart","localPaletteName","setChartTypeManual","setQueryChartConfig","setQueryDisplayConfig","setFunnelChartType","setFunnelChartConfig","setFunnelDisplayConfig","setLocalPaletteName","setUserManuallySelectedChart","setChartType","smartConfig","setChartConfig","setDisplayConfig","chartAvailability","colorPalette","getColorPalette","prevMetricsBreakdownsRef","useEffect","currentKey","newChartType","newConfig","smartDefaults","useAnalysisUIState","activeTab","displayLimit","showFieldModal","fieldModalMode","setActiveTab","setActiveView","setDisplayLimit","closeFieldModal","activeTableIndex","setActiveTableIndex","MAX_HASH_LENGTH","SHARE_PREFIX","compressAndEncode","json","compressToEncodedURIComponent","decodeAndDecompress","encoded","decompressFromEncodedURIComponent","parsed","isShareableSize","compressWithFallback","fullEncoded","minimalConfig","minimalEncoded","generateShareUrl","parseShareHash","hash","clearShareHash","url","parseShareUrl","useAnalysisInitialization","onQueryChange","onChartConfigChange","load","hasInitializedShareRef","useAnalysisBuilder","features","useCubeFeatures","storeApi","queryBuilder","combinedFields","funnelCube","funnelSteps","activeFunnelStepIndex","funnelTimeDimension","funnelChartType","funnelChartConfigFromStore","flowCube","flowBindingKey","flowTimeDimension","eventDimension","startingStep","stepsBefore","stepsAfter","joinStrategy","flowDisplayConfigFromStore","flowDisplayConfig","flowChartType","buildFunnelQueryFromSteps","buildFlowQuery","retentionCube","retentionBindingKey","retentionTimeDimension","retentionDateRange","retentionCohortFilters","retentionActivityFilters","retentionBreakdowns","retentionViewGranularity","retentionPeriods","retentionType","buildRetentionQuery","getRetentionValidation","retentionDisplayConfig","setRetentionCube","setRetentionBindingKey","setRetentionTimeDimension","setRetentionDateRange","setRetentionCohortFilters","setRetentionActivityFilters","setRetentionBreakdowns","addRetentionBreakdown","removeRetentionBreakdown","setRetentionViewGranularity","setRetentionPeriods","setRetentionType","effectiveIsValidQuery","queryExecution","chartDefaults","uiState","openMetricsModal","addMetric","removeMetric","toggleMetric","reorderMetrics","openBreakdownsModal","addBreakdown","removeBreakdown","toggleBreakdown","setBreakdownGranularity","toggleBreakdownComparison","reorderBreakdowns","setFilters","dropFieldToFilter","setOrder","clearQuery","clearCurrentMode","setFunnelBindingKey","setAnalysisType","setFunnelCube","addFunnelStep","removeFunnelStep","updateFunnelStep","setActiveFunnelStepIndex","reorderFunnelSteps","setFunnelTimeDimension","funnelDisplayConfigFromStore","funnelDisplayConfig","setFlowCube","setFlowBindingKey","setFlowTimeDimension","setEventDimension","setStartingStepName","setStartingStepFilters","setStepsBefore","setStepsAfter","setJoinStrategy","setFlowDisplayConfig","setRetentionDisplayConfig","aiState","openAI","closeAI","setAIPrompt","setAIGenerating","setAIError","setAIHasGeneratedQuery","saveAIPreviousState","restoreAIPreviousState","shareButtonStateRef","canShare","getValidation","adapterValidation","handleFieldSelected","fieldType","_cubeName","keepOpen","generateAI","resolve","acceptAI","cancelAI","share","getQueryConfig","funnelQuery","getChartConfig","getAnalysisType","validateBindingKeyExists","meta","cubeName","dimName","d","validateStepQueries","steps","canResolveBindingKey","getCubeNameFromQuery","validateBindingKeyForSteps","validateTimeWindow","duration","validateFunnelConfig","timeError","globalTimeError","isMinimumFunnelConfigValid","queryCount","getAvailableBindingKeyDimensions","getBindingKeyLabel","first"],"mappings":"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"}
1
+ {"version":3,"file":"analysis-builder-shared-CrENEvEk.js","sources":["../../../src/shared/date-utils.ts","../../../src/client/components/AnalysisBuilder/utils/filterUtils.ts","../../../src/client/components/AnalysisBuilder/utils/queryUtils.ts","../../../src/client/components/AnalysisBuilder/utils/storageUtils.ts","../../../src/client/shared/chartDefaults.ts","../../../src/client/components/AnalysisBuilder/ExplainAIPanel.tsx","../../../src/client/components/AnalysisBuilder/ExecutionPlanPanel.tsx","../../../src/client/adapters/queryModeAdapter.ts","../../../src/client/adapters/adapterRegistry.ts","../../../src/client/stores/slices/coreSlice.ts","../../../src/client/stores/slices/querySlice.ts","../../../src/client/stores/slices/funnelSlice.ts","../../../src/client/stores/slices/flowSlice.ts","../../../src/client/stores/slices/retentionSlice.ts","../../../src/client/stores/slices/uiSlice.ts","../../../src/client/stores/analysisBuilderStore.tsx","../../../src/client/utils/multiQueryValidation.ts","../../../src/client/hooks/useAnalysisQueryBuilder.ts","../../../src/client/hooks/useAnalysisCombinedFields.ts","../../../src/client/hooks/useAnalysisQueryExecution.ts","../../../src/client/hooks/useAnalysisChartDefaults.ts","../../../src/client/hooks/useAnalysisUIState.ts","../../../src/client/utils/shareUtils.ts","../../../src/client/hooks/useAnalysisInitialization.ts","../../../src/client/hooks/useAnalysisBuilderHook.ts","../../../src/client/utils/funnelValidation.ts"],"sourcesContent":["/**\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 * Filter Manipulation Utilities for AnalysisBuilder\n *\n * Functions for searching, modifying, and removing filters from filter arrays.\n * These handle both simple filters and nested group filters (AND/OR).\n */\n\nimport type { Filter } from '../../../types'\nimport { parseDateRange, calculatePriorPeriod, formatDateForCube } from '../../../../shared/date-utils'\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 */\nexport function 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 */\nexport function 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 */\nexport function 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 * Query Building Utilities for AnalysisBuilder\n *\n * Functions for constructing CubeQuery objects from builder state.\n */\n\nimport type { CubeQuery, Filter } from '../../../types'\nimport type { MetricItem, BreakdownItem } from '../types'\nimport { removeComparisonDateFilter, buildCompareDateRangeFromFilter } from './filterUtils'\nimport { shouldIncludeFilter } from '../../../utils/filterUtils'\n\n/**\n * Convert metrics and breakdowns to CubeQuery format\n * Handles comparison mode by building compareDateRange for time dimensions\n */\nexport function buildCubeQuery(\n metrics: MetricItem[],\n breakdowns: BreakdownItem[],\n filters: Filter[],\n order?: Record<string, 'asc' | 'desc'>,\n preserveComparisonFilters: boolean = false\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 if (!preserveComparisonFilters) {\n for (const field of comparisonFields) {\n filteredFilters = removeComparisonDateFilter(filteredFilters, field)\n }\n }\n\n // Strip filters with empty values (e.g., {member: \"X.id\", values: [], operator: \"equals\"})\n // These generate AND FALSE conditions on the server\n filteredFilters = filteredFilters.filter(f => shouldIncludeFilter(f))\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 * 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 * State Persistence Utilities for AnalysisBuilder\n *\n * Functions for saving and loading builder state from localStorage.\n */\n\nimport type { Filter } from '../../../types'\nimport type { MetricItem, BreakdownItem, AnalysisBuilderState, AnalysisBuilderStorageState } from '../types'\n\n// Storage key for localStorage persistence\n// v3: Uses slice composition and AnalysisConfig format (clean break from v2)\nexport const STORAGE_KEY = 'drizzle-cube-analysis-builder-v3'\n\n/** @deprecated Use STORAGE_KEY instead */\nexport const STORAGE_KEY_V2 = 'drizzle-cube-analysis-builder-v2'\n\n/**\n * Create initial empty state for AnalysisBuilder\n *\n * Note: Only client-side configuration state is stored.\n * Server state (execution results, loading, errors) is managed by TanStack Query.\n */\nexport function createInitialState(): AnalysisBuilderState {\n return {\n metrics: [],\n breakdowns: [],\n filters: [],\n order: undefined,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Load all state from localStorage once (to avoid repeated parsing)\n */\nexport function 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\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 (legacy format for backward compatibility)\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 * 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 * ExplainAIPanel - Display AI analysis of EXPLAIN plans in a modal\n *\n * Shows:\n * - Assessment badge (good/warning/critical)\n * - Query understanding\n * - Issues identified\n * - Actionable recommendations with code snippets\n *\n * Displayed in a near full-screen modal with scrolling support\n */\n\nimport React from 'react'\nimport type { AIExplainAnalysis, ExplainRecommendation, ExplainIssue } from '../../types'\nimport CodeBlock from '../../shared/components/CodeBlock'\n\ninterface ExplainAIPanelProps {\n /** AI analysis result */\n analysis: AIExplainAnalysis\n /** Callback to close the modal */\n onClose?: () => void\n /** Legacy: Callback to clear/close (backward compatible with old API) */\n onClear?: () => void\n}\n\n/**\n * Helper to safely render text that might be an object from AI\n * AI responses sometimes return objects instead of strings for text fields\n */\nfunction safeText(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'object' && value !== null) return JSON.stringify(value)\n return String(value ?? '')\n}\n\n/**\n * Color classes for assessment badges\n */\nconst assessmentColors = {\n good: 'bg-dc-success-bg text-dc-success border-dc-success',\n warning: 'bg-dc-warning-bg text-dc-warning border-dc-warning',\n critical: 'bg-dc-danger-bg text-dc-error border-dc-error',\n}\n\n/**\n * Color classes for severity badges\n */\nconst severityColors = {\n critical: 'bg-dc-danger-bg text-dc-error',\n warning: 'bg-dc-warning-bg text-dc-warning',\n suggestion: 'bg-dc-accent-bg text-dc-accent',\n}\n\n/**\n * Color classes for issue severity\n */\nconst issueSeverityColors = {\n high: 'text-dc-error',\n medium: 'text-dc-warning',\n low: 'text-dc-text-muted',\n}\n\n/**\n * Assessment badge component\n */\nfunction AssessmentBadge({ assessment, reason }: { assessment: 'good' | 'warning' | 'critical'; reason: unknown }) {\n const labels = {\n good: 'Good',\n warning: 'Warning',\n critical: 'Critical',\n }\n\n return (\n <div className={`dc:p-4 dc:rounded-lg dc:border ${assessmentColors[assessment]}`}>\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:mb-1\">\n <span className=\"dc:font-semibold dc:uppercase dc:text-base\">\n {assessment === 'good' && '✓ '}\n {assessment === 'warning' && '⚠ '}\n {assessment === 'critical' && '✕ '}\n {labels[assessment]}\n </span>\n </div>\n <p className=\"dc:text-sm\">{safeText(reason)}</p>\n </div>\n )\n}\n\n/**\n * Issue item component\n */\nfunction IssueItem({ issue }: { issue: ExplainIssue }) {\n return (\n <div className=\"dc:flex dc:items-start dc:gap-2 dc:py-2\">\n <span className={`dc:text-sm ${issueSeverityColors[issue.severity]}`}>\n {issue.severity === 'high' && '●'}\n {issue.severity === 'medium' && '○'}\n {issue.severity === 'low' && '○'}\n </span>\n <span className=\"dc:text-sm text-dc-text-secondary\">{safeText(issue.description)}</span>\n </div>\n )\n}\n\n/**\n * Copy button component\n */\nfunction CopyButton({ text }: { text: string }) {\n const [copied, setCopied] = React.useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <button\n onClick={handleCopy}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:rounded bg-dc-surface hover:bg-dc-surface-hover text-dc-text-muted\"\n title=\"Copy to clipboard\"\n >\n {copied ? 'Copied!' : 'Copy'}\n </button>\n )\n}\n\n/**\n * Recommendation card component\n */\nfunction RecommendationCard({ rec }: { rec: ExplainRecommendation }) {\n const typeLabels = {\n index: 'INDEX',\n table: 'TABLE',\n cube: 'CUBE',\n general: 'TIP',\n }\n\n return (\n <div className=\"dc:p-4 dc:border border-dc-border dc:rounded-lg bg-dc-surface\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:mb-2\">\n <span\n className={`dc:px-2 dc:py-0.5 dc:text-xs dc:font-medium dc:rounded ${severityColors[rec.severity]}`}\n >\n {typeLabels[rec.type]}\n </span>\n <h5 className=\"dc:font-medium text-dc-text\">{safeText(rec.title)}</h5>\n </div>\n\n {/* Description */}\n <p className=\"dc:text-sm text-dc-text-secondary dc:mb-3\">{safeText(rec.description)}</p>\n\n {/* SQL code for index/table recommendations */}\n {rec.sql && (\n <div className=\"dc:mt-2\">\n <CodeBlock\n code={rec.sql}\n language=\"sql\"\n headerRight={<CopyButton text={rec.sql} />}\n />\n </div>\n )}\n\n {/* TypeScript code for cube recommendations - display as text since CodeBlock doesn't support TS */}\n {rec.cubeCode && (\n <div className=\"dc:mt-2\">\n {rec.cubeName && (\n <p className=\"dc:text-xs text-dc-text-muted dc:mb-1\">\n Add to <code className=\"bg-dc-surface-secondary dc:px-1 dc:rounded\">{rec.cubeName}</code> cube:\n </p>\n )}\n <div className=\"dc:relative\">\n <pre className=\"dc:p-3 dc:text-xs bg-dc-surface-secondary dc:rounded dc:overflow-x-auto dc:font-mono text-dc-text\">\n {rec.cubeCode}\n </pre>\n <div className=\"dc:absolute dc:top-1 dc:right-1\">\n <CopyButton text={rec.cubeCode} />\n </div>\n </div>\n </div>\n )}\n\n {/* Expected impact */}\n {rec.estimatedImpact && (\n <p className=\"dc:text-xs text-dc-text-muted dc:mt-2\">\n <strong>Expected impact:</strong> {safeText(rec.estimatedImpact)}\n </p>\n )}\n </div>\n )\n}\n\n/**\n * ExplainAIPanel - Modal component for displaying AI analysis results\n * Shows in a near full-screen modal with scrolling\n */\nexport function ExplainAIPanel({ analysis, onClose, onClear }: ExplainAIPanelProps) {\n // Support both onClose (new) and onClear (legacy) for backward compatibility\n const handleClose = onClose || onClear\n\n // Close on Escape key\n React.useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && handleClose) {\n handleClose()\n }\n }\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [handleClose])\n\n // Prevent body scroll when modal is open\n React.useEffect(() => {\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = ''\n }\n }, [])\n\n return (\n <div className=\"dc:fixed dc:inset-0 dc:z-50 dc:flex dc:items-center dc:justify-center dc:p-4 bg-black/50\">\n {/* Modal backdrop */}\n <div\n className=\"dc:absolute dc:inset-0\"\n onClick={handleClose}\n aria-hidden=\"true\"\n />\n\n {/* Modal content */}\n <div className=\"dc:relative dc:w-full dc:max-w-4xl dc:max-h-[90vh] bg-dc-surface dc:rounded-lg dc:shadow-xl dc:flex dc:flex-col\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-6 dc:py-4 dc:border-b border-dc-border dc:flex-shrink-0\">\n <div className=\"dc:flex dc:items-center dc:gap-3\">\n <span className=\"dc:text-lg\">✨</span>\n <h3 className=\"dc:text-lg dc:font-semibold text-dc-text\">AI Performance Analysis</h3>\n </div>\n <button\n onClick={handleClose}\n className=\"dc:p-2 dc:rounded-lg hover:bg-dc-surface-hover text-dc-text-secondary hover:text-dc-text dc:transition-colors\"\n aria-label=\"Close\"\n >\n <svg className=\"dc:w-5 dc:h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Scrollable content */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:px-6 dc:py-4 dc:space-y-6\">\n {/* Assessment */}\n <AssessmentBadge\n assessment={analysis.assessment}\n reason={analysis.assessmentReason}\n />\n\n {/* Summary */}\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">Summary</h4>\n <p className=\"text-dc-text\">{safeText(analysis.summary)}</p>\n </div>\n\n {/* Query Understanding */}\n {analysis.queryUnderstanding && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">Query Analysis</h4>\n <p className=\"text-dc-text-secondary\">{safeText(analysis.queryUnderstanding)}</p>\n </div>\n )}\n\n {/* Issues */}\n {analysis.issues && analysis.issues.length > 0 && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-2\">\n Issues Found ({analysis.issues.length})\n </h4>\n <div className=\"dc:space-y-1 bg-dc-surface-secondary dc:rounded-lg dc:p-3\">\n {analysis.issues.map((issue, i) => (\n <IssueItem key={i} issue={issue} />\n ))}\n </div>\n </div>\n )}\n\n {/* Recommendations */}\n {analysis.recommendations && analysis.recommendations.length > 0 && (\n <div>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text-muted dc:uppercase dc:mb-3\">\n Recommendations ({analysis.recommendations.length})\n </h4>\n <div className=\"dc:space-y-4\">\n {analysis.recommendations.map((rec, i) => (\n <RecommendationCard key={i} rec={rec} />\n ))}\n </div>\n </div>\n )}\n\n {/* No recommendations case */}\n {(!analysis.recommendations || analysis.recommendations.length === 0) && (\n <div className=\"text-dc-text-muted dc:italic dc:p-4 bg-dc-surface-secondary dc:rounded-lg\">\n No specific recommendations. The query appears to be well-optimized.\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-6 dc:py-3 dc:border-t border-dc-border dc:flex-shrink-0 bg-dc-surface-secondary\">\n {/* Meta info */}\n {analysis._meta && (\n <div className=\"dc:text-xs text-dc-text-muted\">\n Model: {analysis._meta.model}\n {analysis._meta.usingUserKey && ' (using your API key)'}\n </div>\n )}\n <button\n onClick={handleClose}\n className=\"dc:px-4 dc:py-2 dc:text-sm dc:font-medium dc:rounded-lg bg-dc-primary text-white hover:bg-dc-primary-hover dc:transition-colors\"\n >\n Close\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ExplainAIPanel\n","/**\n * ExecutionPlanPanel - Shared component for SQL display, EXPLAIN plans, and AI analysis\n *\n * Used across all analysis modes (query, funnel, flow) to show:\n * - Generated SQL with copy functionality\n * - Explain Plan button with \"Include timing\" toggle\n * - EXPLAIN results with summary badges\n * - AI Analysis button (in Explain Plan header) and modal\n *\n * This is a composable component - the parent handles the layout,\n * this component handles the SQL -> Explain -> AI workflow.\n */\n\nimport { useState, memo } from 'react'\nimport { CodeBlock } from '../../shared'\nimport { ExplainAIPanel } from './ExplainAIPanel'\nimport type { ExplainResult, AIExplainAnalysis } from '../../types'\n\ninterface ExecutionPlanPanelProps {\n /** The generated SQL to display */\n sql: { sql: string; params?: unknown[] } | null | undefined\n /** Whether SQL is loading */\n sqlLoading?: boolean\n /** Error loading SQL */\n sqlError?: Error | null\n /** Placeholder text when no SQL */\n sqlPlaceholder?: string\n\n /** EXPLAIN plan result */\n explainResult: ExplainResult | null\n /** Whether EXPLAIN is running */\n explainLoading?: boolean\n /** Whether EXPLAIN has been run at least once */\n explainHasRun?: boolean\n /** Error running EXPLAIN */\n explainError?: Error | null\n /** Run EXPLAIN with options */\n runExplain: (options: { analyze: boolean }) => void\n\n /** AI analysis result */\n aiAnalysis?: AIExplainAnalysis | null\n /** Whether AI analysis is in progress */\n aiAnalysisLoading?: boolean\n /** Error from AI analysis */\n aiAnalysisError?: Error | null\n /** Run AI analysis */\n runAIAnalysis?: (explainResult: ExplainResult, query: unknown) => void\n /** Clear AI analysis (unused but kept for interface compatibility) */\n clearAIAnalysis?: () => void\n /** Whether AI is enabled */\n enableAI?: boolean\n\n /** The query object for AI context */\n query?: unknown\n\n /** Title for the SQL block */\n title?: string\n /** Height for the SQL block */\n height?: string\n}\n\n/**\n * ExecutionPlanPanel - Displays SQL, EXPLAIN results, and AI analysis\n */\nexport const ExecutionPlanPanel = memo(function ExecutionPlanPanel({\n sql,\n sqlLoading = false,\n sqlError,\n sqlPlaceholder = 'Add metrics to generate SQL',\n\n explainResult,\n explainLoading = false,\n explainHasRun = false,\n explainError,\n runExplain,\n\n aiAnalysis,\n aiAnalysisLoading = false,\n aiAnalysisError,\n runAIAnalysis,\n clearAIAnalysis: _clearAIAnalysis,\n enableAI = false,\n\n query,\n\n title = 'Generated SQL',\n height = '16rem',\n}: ExecutionPlanPanelProps) {\n const [useAnalyze, setUseAnalyze] = useState(false)\n const [showAIModal, setShowAIModal] = useState(false)\n\n // Format SQL with parameters\n const formattedSql = sql\n ? sql.sql +\n (sql.params && sql.params.length > 0\n ? '\\n\\n-- Parameters:\\n' + JSON.stringify(sql.params, null, 2)\n : '')\n : ''\n\n // Handle AI analysis - always re-run to get fresh results after schema/index changes\n const handleAIClick = () => {\n if (runAIAnalysis && explainResult && query) {\n // Always run fresh analysis - indexes may have been added since last run\n runAIAnalysis(explainResult, query)\n setShowAIModal(true)\n }\n }\n\n // Close modal\n const handleCloseModal = () => {\n setShowAIModal(false)\n }\n\n // Build the AI button for use in Explain Plan header\n const aiButton = enableAI && explainResult ? (\n <button\n onClick={handleAIClick}\n disabled={aiAnalysisLoading}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium dc:rounded bg-dc-accent text-white hover:bg-dc-accent-hover dc:disabled:opacity-50 dc:disabled:cursor-not-allowed dc:flex dc:items-center dc:gap-1\"\n >\n {aiAnalysisLoading ? (\n <>\n <span className=\"dc:animate-spin\">⟳</span>\n Analyzing...\n </>\n ) : (\n <>✨ AI Analysis</>\n )}\n </button>\n ) : null\n\n return (\n <div className=\"dc:space-y-3\">\n {/* SQL Block */}\n {sqlLoading ? (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm dc:animate-pulse\" style={{ height }}>\n Loading SQL...\n </div>\n </>\n ) : sqlError ? (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\" style={{ height }}>\n {sqlError.message}\n </div>\n </>\n ) : sql ? (\n <CodeBlock\n code={formattedSql}\n language=\"sql\"\n title={title}\n height={height}\n headerRight={\n <>\n {/* Include timing checkbox */}\n <label className=\"dc:flex dc:items-center dc:gap-1 dc:text-xs text-dc-text-secondary dc:cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={useAnalyze}\n onChange={(e) => setUseAnalyze(e.target.checked)}\n className=\"dc:w-3 dc:h-3 dc:rounded border-dc-border text-dc-accent focus:ring-dc-accent\"\n />\n Include timing\n </label>\n\n {/* Explain Plan button */}\n <button\n onClick={() => runExplain({ analyze: useAnalyze })}\n disabled={explainLoading}\n className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium dc:rounded dc:border border-dc-border bg-dc-surface hover:bg-dc-surface-hover text-dc-text-secondary hover:text-dc-text dc:transition-colors dc:disabled:opacity-50 dc:disabled:cursor-not-allowed\"\n >\n {explainLoading ? 'Running...' : 'Explain Plan'}\n </button>\n </>\n }\n />\n ) : (\n <>\n <h4 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">{title}</h4>\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm\" style={{ height }}>\n {sqlPlaceholder}\n </div>\n </>\n )}\n\n {/* EXPLAIN Results */}\n {explainHasRun && (\n <div>\n {explainLoading ? (\n <div className=\"bg-dc-surface-secondary dc:border border-dc-border dc:rounded dc:p-3 text-dc-text-muted dc:text-sm dc:animate-pulse\">\n Running EXPLAIN{useAnalyze ? ' ANALYZE' : ''}...\n </div>\n ) : explainError ? (\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\">\n <strong>Explain Error:</strong> {explainError.message}\n </div>\n ) : explainResult ? (\n <div className=\"dc:space-y-3\">\n {/* Summary badges */}\n <div className=\"dc:flex dc:flex-wrap dc:items-center dc:gap-2\">\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-accent text-white dc:rounded\">\n {explainResult.summary.database.toUpperCase()}\n </span>\n {explainResult.summary.hasSequentialScans && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-warning-bg text-dc-warning dc:border border-dc-warning dc:rounded\">\n Sequential Scans Detected\n </span>\n )}\n {explainResult.summary.usedIndexes.length > 0 && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-success-bg text-dc-success dc:border border-dc-success dc:rounded\">\n {explainResult.summary.usedIndexes.length} Index{explainResult.summary.usedIndexes.length !== 1 ? 'es' : ''} Used\n </span>\n )}\n {explainResult.summary.executionTime !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Execution: {explainResult.summary.executionTime.toFixed(2)}ms\n </span>\n )}\n {explainResult.summary.planningTime !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Planning: {explainResult.summary.planningTime.toFixed(2)}ms\n </span>\n )}\n {explainResult.summary.totalCost !== undefined && (\n <span className=\"dc:px-2 dc:py-1 dc:text-xs dc:font-medium bg-dc-surface-secondary text-dc-text-secondary dc:border border-dc-border dc:rounded\">\n Cost: {explainResult.summary.totalCost.toFixed(2)}\n </span>\n )}\n </div>\n\n {/* Index usage details */}\n {explainResult.summary.usedIndexes.length > 0 && (\n <div className=\"dc:text-xs text-dc-text-muted\">\n <strong>Indexes:</strong> {explainResult.summary.usedIndexes.join(', ')}\n </div>\n )}\n\n {/* Raw EXPLAIN output with AI button in header */}\n <CodeBlock\n code={explainResult.raw}\n language=\"sql\"\n title={`Execution Plan (${explainResult.summary.database})`}\n height=\"16rem\"\n headerRight={aiButton}\n />\n </div>\n ) : null}\n </div>\n )}\n\n {/* AI Analysis Error (shown inline) */}\n {aiAnalysisError && (\n <div className=\"text-dc-error dc:text-sm bg-dc-danger-bg dc:p-3 dc:rounded dc:border border-dc-error\">\n <strong>AI Analysis Error:</strong> {aiAnalysisError.message}\n </div>\n )}\n\n {/* AI Analysis Modal */}\n {showAIModal && aiAnalysis && (\n <ExplainAIPanel\n analysis={aiAnalysis}\n onClose={handleCloseModal}\n />\n )}\n </div>\n )\n})\n\nexport default ExecutionPlanPanel\n","/**\n * Query Mode Adapter\n *\n * Handles conversion between UI state and AnalysisConfig for query mode.\n * Supports both single queries and multi-query configurations.\n */\n\nimport type { ModeAdapter, ValidationResult } from './modeAdapter'\nimport type {\n AnalysisConfig,\n QueryAnalysisConfig,\n AnalysisType,\n ChartConfig,\n} from '../types/analysisConfig'\nimport { generateId, generateMetricLabel } from '../components/AnalysisBuilder/utils'\nimport { buildCompareDateRangeFromFilter } from '../components/AnalysisBuilder/utils/filterUtils'\nimport type {\n CubeQuery,\n MultiQueryConfig,\n QueryMergeStrategy,\n Filter,\n} from '../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n} from '../components/AnalysisBuilder/types'\n\n// ============================================================================\n// Query Slice State Type\n// ============================================================================\n\n/**\n * The shape of query mode state in the store.\n * This is what the adapter's load() returns and save() receives.\n */\nexport interface QuerySliceState {\n /** Array of query states (one per query tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the active query tab */\n activeQueryIndex: number\n /** Strategy for combining multiple queries */\n mergeStrategy: QueryMergeStrategy\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create an empty query state\n */\nfunction createEmptyQueryState(): AnalysisBuilderState {\n return {\n metrics: [],\n breakdowns: [],\n filters: [],\n order: undefined,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Convert metrics to CubeQuery measures\n */\nfunction metricsToMeasures(metrics: MetricItem[]): string[] {\n return metrics.map((m) => m.field)\n}\n\n/**\n * Convert breakdowns to CubeQuery dimensions and timeDimensions\n * Includes compareDateRange for time dimensions with comparison enabled\n */\nfunction breakdownsToQuery(\n breakdowns: BreakdownItem[],\n filters: Filter[]\n): {\n dimensions: string[]\n timeDimensions: NonNullable<CubeQuery['timeDimensions']>\n} {\n const dimensions: string[] = []\n const timeDimensions: NonNullable<CubeQuery['timeDimensions']> = []\n\n for (const b of breakdowns) {\n if (b.isTimeDimension) {\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, calculate and include compareDateRange\n if (b.enableComparison) {\n const compareDateRange = buildCompareDateRangeFromFilter(b.field, filters)\n if (compareDateRange) {\n td.compareDateRange = compareDateRange\n }\n }\n\n timeDimensions.push(td)\n } else {\n dimensions.push(b.field)\n }\n }\n\n return { dimensions, timeDimensions }\n}\n\n/**\n * Build a CubeQuery from an AnalysisBuilderState\n */\nfunction stateToCubeQuery(state: AnalysisBuilderState): CubeQuery {\n const { dimensions, timeDimensions } = breakdownsToQuery(\n state.breakdowns,\n state.filters\n )\n\n const query: CubeQuery = {\n measures: metricsToMeasures(state.metrics),\n dimensions,\n }\n\n if (timeDimensions.length > 0) {\n query.timeDimensions = timeDimensions\n }\n\n if (state.filters.length > 0) {\n query.filters = state.filters\n }\n\n if (state.order && Object.keys(state.order).length > 0) {\n query.order = state.order\n }\n\n return query\n}\n\n/**\n * Convert CubeQuery measures to MetricItems\n */\nfunction measuresToMetrics(measures: string[]): MetricItem[] {\n return measures.map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index),\n }))\n}\n\n/**\n * Convert CubeQuery dimensions and timeDimensions to BreakdownItems\n * Restores enableComparison from compareDateRange presence\n */\nfunction queryToBreakdowns(query: CubeQuery): BreakdownItem[] {\n const breakdowns: BreakdownItem[] = []\n\n // Regular dimensions\n if (query.dimensions) {\n for (const dim of query.dimensions) {\n breakdowns.push({\n id: generateId(),\n field: dim,\n isTimeDimension: false,\n })\n }\n }\n\n // Time dimensions\n if (query.timeDimensions) {\n for (const td of query.timeDimensions) {\n // Restore enableComparison if compareDateRange exists\n const hasComparison = Boolean(\n td.compareDateRange && td.compareDateRange.length > 0\n )\n\n breakdowns.push({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true,\n enableComparison: hasComparison,\n })\n }\n }\n\n return breakdowns\n}\n\n/**\n * Convert CubeQuery to AnalysisBuilderState\n */\nfunction cubeQueryToState(query: CubeQuery): AnalysisBuilderState {\n return {\n metrics: measuresToMetrics(query.measures || []),\n breakdowns: queryToBreakdowns(query),\n filters: (query.filters as Filter[]) || [],\n order: query.order,\n validationStatus: 'idle',\n validationError: null,\n }\n}\n\n/**\n * Check if a query object is a MultiQueryConfig\n */\nfunction isMultiQueryConfig(query: unknown): query is MultiQueryConfig {\n return (\n typeof query === 'object' &&\n query !== null &&\n 'queries' in query &&\n Array.isArray((query as MultiQueryConfig).queries)\n )\n}\n\n// ============================================================================\n// Query Mode Adapter\n// ============================================================================\n\nexport const queryModeAdapter: ModeAdapter<QuerySliceState> = {\n type: 'query',\n\n createInitial(): QuerySliceState {\n return {\n queryStates: [createEmptyQueryState()],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n }\n },\n\n extractState(storeState: Record<string, unknown>): QuerySliceState {\n return {\n queryStates: storeState.queryStates as AnalysisBuilderState[],\n activeQueryIndex: storeState.activeQueryIndex as number,\n mergeStrategy: storeState.mergeStrategy as QueryMergeStrategy,\n }\n },\n\n canLoad(config: unknown): config is AnalysisConfig {\n if (!config || typeof config !== 'object') return false\n\n const c = config as Record<string, unknown>\n\n // Check version and analysis type\n if (c.version !== 1) return false\n if (c.analysisType !== 'query') return false\n\n // Check query exists\n if (!c.query || typeof c.query !== 'object') return false\n\n return true\n },\n\n load(config: AnalysisConfig): QuerySliceState {\n // Type guard - ensure it's a query config\n if (config.analysisType !== 'query') {\n throw new Error(\n `Cannot load ${config.analysisType} config with query adapter`\n )\n }\n\n const queryConfig = config as QueryAnalysisConfig\n\n // Handle multi-query config\n if (isMultiQueryConfig(queryConfig.query)) {\n const multiConfig = queryConfig.query\n const queryStates = multiConfig.queries.map(cubeQueryToState)\n\n // Ensure at least one query state\n if (queryStates.length === 0) {\n queryStates.push(createEmptyQueryState())\n }\n\n return {\n queryStates,\n activeQueryIndex: 0,\n mergeStrategy: multiConfig.mergeStrategy || 'concat',\n }\n }\n\n // Handle single query\n return {\n queryStates: [cubeQueryToState(queryConfig.query)],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n }\n },\n\n save(\n state: QuerySliceState,\n charts: Partial<Record<AnalysisType, ChartConfig>>,\n activeView: 'table' | 'chart'\n ): QueryAnalysisConfig {\n // Build queries from state\n const queries = state.queryStates.map(stateToCubeQuery)\n\n // Determine if single or multi-query\n const isSingle = queries.length === 1 && state.mergeStrategy === 'concat'\n\n // Build the query field\n const query: CubeQuery | MultiQueryConfig = isSingle\n ? queries[0]\n : {\n queries,\n mergeStrategy: state.mergeStrategy,\n }\n\n return {\n version: 1,\n analysisType: 'query',\n activeView,\n charts: {\n query: charts.query || this.getDefaultChartConfig(),\n },\n query,\n }\n },\n\n validate(state: QuerySliceState): ValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Check if any query has metrics\n const hasAnyMetrics = state.queryStates.some((q) => q.metrics.length > 0)\n if (!hasAnyMetrics) {\n errors.push('At least one metric is required')\n }\n\n // Check each query state\n state.queryStates.forEach((qs, index) => {\n const prefix = state.queryStates.length > 1 ? `Query ${index + 1}: ` : ''\n\n if (qs.metrics.length === 0 && qs.breakdowns.length === 0) {\n warnings.push(`${prefix}Query is empty`)\n }\n })\n\n // Multi-query specific validation\n if (state.queryStates.length > 1) {\n if (state.mergeStrategy === 'merge') {\n // Check if all queries have compatible dimensions for merging\n const firstBreakdowns = state.queryStates[0].breakdowns.map(\n (b) => b.field\n )\n const allHaveSameBreakdowns = state.queryStates.every((qs) => {\n const breakdowns = qs.breakdowns.map((b) => b.field)\n return (\n breakdowns.length === firstBreakdowns.length &&\n breakdowns.every((b) => firstBreakdowns.includes(b))\n )\n })\n if (!allHaveSameBreakdowns) {\n warnings.push(\n 'Queries have different breakdowns - merge results may be unexpected'\n )\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n },\n\n clear(_state: QuerySliceState): QuerySliceState {\n // Reset to single empty query (ignoring previous state)\n return this.createInitial()\n },\n\n getDefaultChartConfig(): ChartConfig {\n return {\n chartType: 'bar',\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n },\n}\n","/**\n * Adapter Registry\n *\n * A central registry for mode adapters. This allows the store to look up\n * the appropriate adapter based on analysis type without hardcoding\n * conditionals throughout the codebase.\n *\n * The registry uses lazy initialization to ensure adapters are always\n * available, regardless of import order or tree-shaking. Built-in adapters\n * (query, funnel) are registered automatically on first access.\n *\n * Usage:\n * // Lookup (in store) - adapters are auto-initialized\n * const adapter = adapterRegistry.get(state.analysisType)\n * const modeState = adapter.extractState(storeState)\n *\n * // Manual registration (for custom adapters)\n * adapterRegistry.register(customAdapter)\n */\n\nimport type { ModeAdapter } from './modeAdapter'\nimport type { AnalysisType } from '../types/analysisConfig'\nimport { queryModeAdapter } from './queryModeAdapter'\nimport { funnelModeAdapter } from './funnelModeAdapter'\nimport { flowModeAdapter } from './flowModeAdapter'\nimport { retentionModeAdapter } from './retentionModeAdapter'\n\n// Internal storage for registered adapters\nconst adapters = new Map<AnalysisType, ModeAdapter<unknown>>()\n\n// Track if built-in adapters have been initialized\nlet builtInAdaptersInitialized = false\n\n/**\n * Initialize built-in adapters (query, funnel).\n * Called automatically on first registry access.\n * Safe to call multiple times.\n */\nfunction ensureBuiltInAdaptersInitialized(): void {\n if (builtInAdaptersInitialized) return\n\n if (!adapters.has('query')) {\n adapters.set('query', queryModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('funnel')) {\n adapters.set('funnel', funnelModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('flow')) {\n adapters.set('flow', flowModeAdapter as ModeAdapter<unknown>)\n }\n if (!adapters.has('retention')) {\n adapters.set('retention', retentionModeAdapter as ModeAdapter<unknown>)\n }\n\n builtInAdaptersInitialized = true\n}\n\n/**\n * Adapter registry - manages mode adapters\n */\nexport const adapterRegistry = {\n /**\n * Register an adapter for a specific analysis type.\n * Should be called once at app initialization.\n *\n * @param adapter - The adapter to register\n */\n register<T>(adapter: ModeAdapter<T>): void {\n if (adapters.has(adapter.type)) {\n console.warn(\n `[adapterRegistry] Overwriting existing adapter for type: ${adapter.type}`\n )\n }\n adapters.set(adapter.type, adapter as ModeAdapter<unknown>)\n },\n\n /**\n * Get the adapter for a specific analysis type.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @param type - The analysis type to get adapter for\n * @returns The registered adapter\n * @throws Error if no adapter is registered for the type\n */\n get<T>(type: AnalysisType): ModeAdapter<T> {\n ensureBuiltInAdaptersInitialized()\n const adapter = adapters.get(type)\n if (!adapter) {\n throw new Error(\n `[adapterRegistry] No adapter registered for type: ${type}. ` +\n `Available types: ${Array.from(adapters.keys()).join(', ') || 'none'}`\n )\n }\n return adapter as ModeAdapter<T>\n },\n\n /**\n * Check if an adapter is registered for a specific type.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @param type - The analysis type to check\n * @returns True if an adapter is registered\n */\n has(type: AnalysisType): boolean {\n ensureBuiltInAdaptersInitialized()\n return adapters.has(type)\n },\n\n /**\n * Get all registered analysis types.\n * Built-in adapters (query, funnel) are initialized automatically.\n *\n * @returns Array of registered types\n */\n getRegisteredTypes(): AnalysisType[] {\n ensureBuiltInAdaptersInitialized()\n return Array.from(adapters.keys())\n },\n\n /**\n * Clear all registered adapters.\n * Primarily useful for testing.\n * Note: Built-in adapters will be re-initialized on next access.\n */\n clear(): void {\n adapters.clear()\n builtInAdaptersInitialized = false\n },\n}\n","/**\n * Core Slice\n *\n * Handles:\n * - analysisType (mode selection)\n * - charts map (per-mode chart configurations)\n * - save/load delegation to adapters\n *\n * This slice is mode-agnostic - it delegates to the adapter registry\n * for mode-specific logic.\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\n// Import from barrel export to ensure adapters are auto-registered via initializeAdapters()\nimport {\n adapterRegistry,\n queryModeAdapter,\n funnelModeAdapter,\n flowModeAdapter,\n retentionModeAdapter,\n} from '../../adapters'\nimport type {\n AnalysisConfig,\n AnalysisType,\n ChartConfig,\n AnalysisWorkspace,\n QueryAnalysisConfig,\n FunnelAnalysisConfig,\n FlowAnalysisConfig,\n RetentionAnalysisConfig,\n} from '../../types/analysisConfig'\nimport type { ChartType, ChartAxisConfig, ChartDisplayConfig } from '../../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Core slice state\n */\nexport interface CoreSliceState {\n /** Current analysis mode */\n analysisType: AnalysisType\n\n /**\n * Per-mode chart configuration map.\n * Each mode owns its own chart settings.\n * Phase 4: This is now the source of truth for all chart configuration.\n */\n charts: {\n [K in AnalysisType]?: ChartConfig\n }\n\n /**\n * Per-mode active view (table or chart) map.\n * Each mode owns its own view preference.\n * This preserves view preference when switching between modes.\n */\n activeViews: {\n [K in AnalysisType]?: 'table' | 'chart'\n }\n\n /** Whether user manually selected a chart type */\n userManuallySelectedChart: boolean\n /** Color palette name */\n localPaletteName: string\n}\n\n/**\n * Core slice actions\n */\nexport interface CoreSliceActions {\n /** Set the analysis type (switches between Query/Funnel modes) */\n setAnalysisType: (type: AnalysisType) => void\n\n /** Set chart type for current mode */\n setChartType: (type: ChartType) => void\n\n /** Set chart type with manual selection flag */\n setChartTypeManual: (type: ChartType) => void\n\n /** Set chart config for current mode */\n setChartConfig: (config: ChartAxisConfig) => void\n\n /** Set display config for current mode */\n setDisplayConfig: (config: ChartDisplayConfig) => void\n\n /** Set color palette name */\n setLocalPaletteName: (name: string) => void\n\n /** Set user manually selected chart flag */\n setUserManuallySelectedChart: (value: boolean) => void\n\n /**\n * @deprecated Use setChartType() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelChartType: (type: ChartType) => void\n\n /**\n * @deprecated Use setChartConfig() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelChartConfig: (config: ChartAxisConfig) => void\n\n /**\n * @deprecated Use setDisplayConfig() instead - works for any mode via charts map.\n * This setter is kept for backward compatibility but will be removed in a future version.\n */\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n\n /**\n * Save current state to AnalysisConfig format.\n * Delegates to the appropriate adapter based on analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n save: () => AnalysisConfig\n\n /**\n * Load state from AnalysisConfig.\n * Delegates to the appropriate adapter based on config.analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n load: (config: AnalysisConfig) => void\n\n /**\n * Save ALL modes to AnalysisWorkspace format.\n * Used for localStorage persistence to preserve state across mode switches.\n */\n saveWorkspace: () => AnalysisWorkspace\n\n /**\n * Load ALL modes from AnalysisWorkspace.\n * Used for localStorage persistence to restore state for all modes.\n */\n loadWorkspace: (workspace: AnalysisWorkspace) => void\n}\n\nexport type CoreSlice = CoreSliceState & CoreSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialCoreState = (): CoreSliceState => ({\n analysisType: 'query',\n\n // Use adapter defaults as single source of truth for chart configuration\n charts: {\n query: queryModeAdapter.getDefaultChartConfig(),\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n flow: flowModeAdapter.getDefaultChartConfig(),\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n\n // Per-mode active view preference\n activeViews: {\n query: 'chart',\n funnel: 'chart',\n flow: 'chart',\n retention: 'chart',\n },\n\n userManuallySelectedChart: false,\n localPaletteName: 'default',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the core slice.\n * Uses StateCreator pattern for composability with other slices.\n */\nexport const createCoreSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n CoreSlice\n> = (set, get) => ({\n ...createInitialCoreState(),\n\n setAnalysisType: (type) => {\n set((state) => {\n // Ensure the target mode has chart config (apply defaults if missing)\n const charts = { ...state.charts }\n if (!charts[type]) {\n const adapter = adapterRegistry.get(type)\n charts[type] = adapter.getDefaultChartConfig()\n }\n const activeViews = { ...state.activeViews }\n if (!activeViews[type]) {\n activeViews[type] = 'chart'\n }\n return {\n analysisType: type,\n charts,\n activeViews,\n activeView: activeViews[type] ?? 'chart',\n }\n })\n },\n\n setChartType: (type) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartType: type },\n },\n }\n })\n },\n\n setChartTypeManual: (type) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartType: type },\n },\n userManuallySelectedChart: true,\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setChartConfig: (config) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: 'bar',\n chartConfig: config,\n displayConfig: {},\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, chartConfig: config },\n },\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setDisplayConfig: (config) => {\n set((state) => {\n const mode = state.analysisType\n const currentConfig = state.charts[mode] || {\n chartType: 'bar',\n chartConfig: {},\n displayConfig: config,\n }\n\n // Phase 4: Only update charts map (legacy fields removed)\n return {\n charts: {\n ...state.charts,\n [mode]: { ...currentConfig, displayConfig: config },\n },\n activeView: 'chart' as const,\n activeViews: {\n ...state.activeViews,\n [mode]: 'chart' as const,\n },\n }\n })\n },\n\n setLocalPaletteName: (name) => set({ localPaletteName: name }),\n\n setUserManuallySelectedChart: (value) => set({ userManuallySelectedChart: value }),\n\n // @deprecated - Use setChartType() instead\n // Kept for backward compatibility\n setFunnelChartType: (type) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: type,\n chartConfig: {},\n displayConfig: {},\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, chartType: type },\n },\n }\n })\n },\n\n // @deprecated - Use setChartConfig() instead\n // Kept for backward compatibility\n setFunnelChartConfig: (config) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: 'funnel',\n chartConfig: config,\n displayConfig: {},\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, chartConfig: config },\n },\n }\n })\n },\n\n // @deprecated - Use setDisplayConfig() instead\n // Kept for backward compatibility\n setFunnelDisplayConfig: (config) => {\n set((state) => {\n const currentConfig = state.charts.funnel || {\n chartType: 'funnel',\n chartConfig: {},\n displayConfig: config,\n }\n return {\n charts: {\n ...state.charts,\n funnel: { ...currentConfig, displayConfig: config },\n },\n }\n })\n },\n\n save: () => {\n const state = get()\n const adapter = adapterRegistry.get(state.analysisType)\n\n // Use adapter's extractState method for mode-specific state\n const modeState = adapter.extractState(state as unknown as Record<string, unknown>)\n\n // Use per-mode activeView, falling back to legacy activeView\n const activeView = state.activeViews[state.analysisType] ?? state.activeView ?? 'chart'\n\n return adapter.save(modeState, state.charts, activeView)\n },\n\n load: (config) => {\n const adapter = adapterRegistry.get(config.analysisType)\n\n // Validate config can be loaded\n if (!adapter.canLoad(config)) {\n console.warn('[coreSlice] Invalid config, cannot load')\n return\n }\n\n const modeState = adapter.load(config)\n\n // Merge charts to preserve other modes' settings\n const currentState = get()\n const mergedCharts = {\n ...currentState.charts,\n ...config.charts,\n }\n\n // Apply defaults if current mode's chart config is missing\n if (!mergedCharts[config.analysisType]) {\n mergedCharts[config.analysisType] = adapter.getDefaultChartConfig()\n }\n\n // Merge activeViews to preserve other modes' view preferences\n const mergedActiveViews = {\n ...currentState.activeViews,\n [config.analysisType]: config.activeView,\n }\n\n // Update state (mode-agnostic)\n set({\n analysisType: config.analysisType,\n charts: mergedCharts,\n activeView: config.activeView,\n activeViews: mergedActiveViews,\n // Mode-specific state from adapter\n ...(modeState as any),\n })\n },\n\n saveWorkspace: (): AnalysisWorkspace => {\n const state = get()\n const stateAsRecord = state as unknown as Record<string, unknown>\n\n // Save query mode state using adapter's extractState\n const queryAdapter = adapterRegistry.get('query')\n const queryModeState = queryAdapter.extractState(stateAsRecord)\n const queryActiveView = state.activeViews.query ?? state.activeView ?? 'chart'\n const queryConfig = queryAdapter.save(\n queryModeState,\n state.charts,\n queryActiveView\n ) as QueryAnalysisConfig\n\n // Save funnel mode state using adapter's extractState\n const funnelAdapter = adapterRegistry.get('funnel')\n const funnelModeState = funnelAdapter.extractState(stateAsRecord)\n const funnelActiveView = state.activeViews.funnel ?? state.activeView ?? 'chart'\n const funnelConfig = funnelAdapter.save(\n funnelModeState,\n state.charts,\n funnelActiveView\n ) as FunnelAnalysisConfig\n\n // Save flow mode state using adapter's extractState\n const flowAdapter = adapterRegistry.get('flow')\n const flowModeState = flowAdapter.extractState(stateAsRecord)\n const flowActiveView = state.activeViews.flow ?? state.activeView ?? 'chart'\n const flowConfig = flowAdapter.save(\n flowModeState,\n state.charts,\n flowActiveView\n ) as FlowAnalysisConfig\n\n // Save retention mode state using adapter's extractState\n const retentionAdapter = adapterRegistry.get('retention')\n const retentionModeState = retentionAdapter.extractState(stateAsRecord)\n const retentionActiveView = state.activeViews.retention ?? state.activeView ?? 'chart'\n const retentionConfig = retentionAdapter.save(\n retentionModeState,\n state.charts,\n retentionActiveView\n ) as RetentionAnalysisConfig\n\n return {\n version: 1,\n activeType: state.analysisType,\n modes: {\n query: queryConfig,\n funnel: funnelConfig,\n flow: flowConfig,\n retention: retentionConfig,\n },\n }\n },\n\n loadWorkspace: (workspace: AnalysisWorkspace): void => {\n const queryAdapter = adapterRegistry.get('query')\n const funnelAdapter = adapterRegistry.get('funnel')\n const flowAdapter = adapterRegistry.get('flow')\n const retentionAdapter = adapterRegistry.get('retention')\n\n let queryModeState: Record<string, unknown> = {}\n let funnelModeState: Record<string, unknown> = {}\n let flowModeState: Record<string, unknown> = {}\n let retentionModeState: Record<string, unknown> = {}\n let mergedCharts = { ...get().charts }\n let mergedActiveViews = { ...get().activeViews }\n\n // Load query mode if present\n if (workspace.modes.query && queryAdapter.canLoad(workspace.modes.query)) {\n queryModeState = queryAdapter.load(workspace.modes.query) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.query.charts }\n mergedActiveViews.query = workspace.modes.query.activeView ?? 'chart'\n }\n\n // Load funnel mode if present\n if (workspace.modes.funnel && funnelAdapter.canLoad(workspace.modes.funnel)) {\n funnelModeState = funnelAdapter.load(workspace.modes.funnel) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.funnel.charts }\n mergedActiveViews.funnel = workspace.modes.funnel.activeView ?? 'chart'\n }\n\n // Load flow mode if present\n if (workspace.modes.flow && flowAdapter.canLoad(workspace.modes.flow)) {\n flowModeState = flowAdapter.load(workspace.modes.flow) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.flow.charts }\n mergedActiveViews.flow = workspace.modes.flow.activeView ?? 'chart'\n }\n\n // Load retention mode if present\n if (workspace.modes.retention && retentionAdapter.canLoad(workspace.modes.retention)) {\n retentionModeState = retentionAdapter.load(workspace.modes.retention) as Record<string, unknown>\n mergedCharts = { ...mergedCharts, ...workspace.modes.retention.charts }\n mergedActiveViews.retention = workspace.modes.retention.activeView ?? 'chart'\n }\n\n // Determine activeView from the active mode's config\n const activeConfig = workspace.modes[workspace.activeType]\n const activeView = activeConfig?.activeView ?? 'chart'\n\n set({\n analysisType: workspace.activeType,\n charts: mergedCharts,\n activeViews: mergedActiveViews,\n activeView,\n ...queryModeState,\n ...funnelModeState,\n ...flowModeState,\n ...retentionModeState,\n })\n },\n})\n","/**\n * Query Slice\n *\n * Handles query mode state and actions:\n * - queryStates (array of query configurations)\n * - activeQueryIndex (current query tab)\n * - mergeStrategy (how to combine multiple queries)\n * - All metrics, breakdowns, filters actions\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type {\n Filter,\n SimpleFilter,\n QueryMergeStrategy,\n CubeQuery,\n MultiQueryConfig,\n} from '../../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n} from '../../components/AnalysisBuilder/types'\nimport {\n generateId,\n generateMetricLabel,\n createInitialState,\n buildCubeQuery,\n} from '../../components/AnalysisBuilder/utils'\nimport { convertDateRangeTypeToValue } from '../../shared/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Query slice state\n */\nexport interface QuerySliceState {\n /** Array of query states (one per tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the currently active query tab */\n activeQueryIndex: number\n /** Strategy for merging multi-query results */\n mergeStrategy: QueryMergeStrategy\n}\n\n/**\n * Query slice actions\n */\nexport interface QuerySliceActions {\n // Query state management\n setQueryStates: (states: AnalysisBuilderState[]) => void\n updateQueryState: (\n index: number,\n updater: (state: AnalysisBuilderState) => AnalysisBuilderState\n ) => void\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n\n // Multi-query actions\n addQuery: () => void\n removeQuery: (index: number) => void\n\n // Metrics actions\n addMetric: (field: string, label?: string) => void\n removeMetric: (id: string) => void\n toggleMetric: (fieldName: string) => void\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n\n // Breakdowns actions\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n removeBreakdown: (id: string) => void\n toggleBreakdown: (fieldName: string, isTimeDimension: boolean, granularity?: string) => void\n setBreakdownGranularity: (id: string, granularity: string) => void\n toggleBreakdownComparison: (id: string) => void\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n\n // Filters actions\n setFilters: (filters: Filter[]) => void\n dropFieldToFilter: (field: string) => void\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n\n // Utility actions\n getCurrentState: () => AnalysisBuilderState\n getMergeKeys: () => string[] | undefined\n isMultiQueryMode: () => boolean\n buildCurrentQuery: () => CubeQuery\n buildAllQueries: () => CubeQuery[]\n buildMultiQueryConfig: () => MultiQueryConfig | null\n}\n\nexport type QuerySlice = QuerySliceState & QuerySliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialQueryState = (): QuerySliceState => ({\n queryStates: [createInitialState()],\n activeQueryIndex: 0,\n mergeStrategy: 'concat',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the query slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createQuerySlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n QuerySlice\n> = (set, get) => ({\n ...createInitialQueryState(),\n\n // ==========================================================================\n // Query State Management\n // ==========================================================================\n\n setQueryStates: (states) => set({ queryStates: states }),\n\n updateQueryState: (index, updater) =>\n set((state) => {\n const newStates = [...state.queryStates]\n newStates[index] = updater(newStates[index] || createInitialState())\n return { queryStates: newStates }\n }),\n\n setActiveQueryIndex: (index) => set({ activeQueryIndex: index }),\n\n setMergeStrategy: (strategy) => set({ mergeStrategy: strategy }),\n\n // ==========================================================================\n // Multi-Query Actions\n // ==========================================================================\n\n addQuery: () =>\n set((state) => {\n const currentState = state.queryStates[state.activeQueryIndex] || createInitialState()\n const newState: AnalysisBuilderState = {\n ...createInitialState(),\n metrics: [...currentState.metrics],\n breakdowns: [...currentState.breakdowns],\n filters: [...currentState.filters],\n }\n return {\n queryStates: [...state.queryStates, newState],\n activeQueryIndex: state.queryStates.length,\n }\n }),\n\n removeQuery: (index) =>\n set((state) => {\n if (state.queryStates.length <= 1) return state\n const newStates = state.queryStates.filter((_, i) => i !== index)\n let newActiveIndex = state.activeQueryIndex\n if (index === state.activeQueryIndex) {\n newActiveIndex = Math.max(0, state.activeQueryIndex - 1)\n } else if (index < state.activeQueryIndex) {\n newActiveIndex = state.activeQueryIndex - 1\n }\n return { queryStates: newStates, activeQueryIndex: newActiveIndex }\n }),\n\n // ==========================================================================\n // Metrics Actions\n // ==========================================================================\n\n addMetric: (field, label) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newMetric: MetricItem = {\n id: generateId(),\n field,\n label: label || generateMetricLabel(currentState.metrics.length),\n }\n newStates[index] = {\n ...currentState,\n metrics: [...currentState.metrics, newMetric],\n }\n return { queryStates: newStates }\n }),\n\n removeMetric: (id) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const fieldToRemove = currentState.metrics.find((m) => m.id === id)?.field\n const newMetrics = currentState.metrics.filter((m) => m.id !== id)\n\n // Clean up sort order for removed field\n let newOrder = currentState.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 newStates[index] = {\n ...currentState,\n metrics: newMetrics,\n order: newOrder,\n }\n return { queryStates: newStates }\n }),\n\n toggleMetric: (fieldName) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingIndex = currentState.metrics.findIndex((m) => m.field === fieldName)\n\n if (existingIndex >= 0) {\n newStates[index] = {\n ...currentState,\n metrics: currentState.metrics.filter((_, i) => i !== existingIndex),\n }\n } else {\n const newMetric: MetricItem = {\n id: generateId(),\n field: fieldName,\n label: generateMetricLabel(currentState.metrics.length),\n }\n newStates[index] = {\n ...currentState,\n metrics: [...currentState.metrics, newMetric],\n }\n }\n return { queryStates: newStates }\n }),\n\n reorderMetrics: (fromIndex, toIndex) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newMetrics = [...currentState.metrics]\n const [movedItem] = newMetrics.splice(fromIndex, 1)\n newMetrics.splice(toIndex, 0, movedItem)\n newStates[index] = {\n ...currentState,\n metrics: newMetrics,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Breakdowns Actions\n // ==========================================================================\n\n addBreakdown: (field, isTimeDimension, granularity) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n\n // Only allow one time dimension\n if (isTimeDimension) {\n const hasExisting = currentState.breakdowns.some((b) => b.isTimeDimension)\n if (hasExisting) return state\n }\n\n const newBreakdown: BreakdownItem = {\n id: generateId(),\n field,\n isTimeDimension,\n granularity: isTimeDimension ? granularity || 'month' : undefined,\n }\n newStates[index] = {\n ...currentState,\n breakdowns: [...currentState.breakdowns, newBreakdown],\n }\n return { queryStates: newStates }\n }),\n\n removeBreakdown: (id) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const fieldToRemove = currentState.breakdowns.find((b) => b.id === id)?.field\n const newBreakdowns = currentState.breakdowns.filter((b) => b.id !== id)\n\n // Clean up sort order for removed field\n let newOrder = currentState.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 newStates[index] = {\n ...currentState,\n breakdowns: newBreakdowns,\n order: newOrder,\n }\n return { queryStates: newStates }\n }),\n\n toggleBreakdown: (fieldName, isTimeDimension, granularity) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingIndex = currentState.breakdowns.findIndex((b) => b.field === fieldName)\n\n if (existingIndex >= 0) {\n newStates[index] = {\n ...currentState,\n breakdowns: currentState.breakdowns.filter((_, i) => i !== existingIndex),\n }\n } else {\n // Check if we already have a time dimension\n if (isTimeDimension) {\n const hasExisting = currentState.breakdowns.some((b) => b.isTimeDimension)\n if (hasExisting) return state\n }\n\n const newBreakdown: BreakdownItem = {\n id: generateId(),\n field: fieldName,\n isTimeDimension,\n granularity: isTimeDimension ? granularity || 'month' : undefined,\n }\n newStates[index] = {\n ...currentState,\n breakdowns: [...currentState.breakdowns, newBreakdown],\n }\n }\n return { queryStates: newStates }\n }),\n\n setBreakdownGranularity: (id, granularity) =>\n set((state) => {\n const { mergeStrategy, activeQueryIndex, queryStates } = state\n const newStates = [...queryStates]\n\n // In merge mode, granularity changes update Q1 (source of truth)\n const targetIndex = mergeStrategy === 'merge' && activeQueryIndex > 0 ? 0 : activeQueryIndex\n\n newStates[targetIndex] = {\n ...newStates[targetIndex],\n breakdowns: newStates[targetIndex].breakdowns.map((b) =>\n b.id === id ? { ...b, granularity } : b\n ),\n }\n return { queryStates: newStates }\n }),\n\n toggleBreakdownComparison: (id) =>\n set((state) => {\n const { mergeStrategy, activeQueryIndex, queryStates, charts, analysisType } = state\n const newStates = [...queryStates]\n\n // Get source breakdowns based on mode\n const sourceIndex = mergeStrategy === 'merge' && activeQueryIndex > 0 ? 0 : activeQueryIndex\n\n // Find the breakdown being toggled\n const targetBreakdown = newStates[sourceIndex].breakdowns.find((b) => b.id === id)\n const isEnablingComparison = targetBreakdown && !targetBreakdown.enableComparison\n\n // Update breakdowns with comparison toggle\n const updatedBreakdowns = newStates[sourceIndex].breakdowns.map((b) => {\n if (b.id === id) {\n return { ...b, enableComparison: !b.enableComparison }\n }\n // Clear comparison from other time dimensions\n if (b.isTimeDimension && b.enableComparison) {\n return { ...b, enableComparison: false }\n }\n return b\n })\n\n newStates[sourceIndex] = {\n ...newStates[sourceIndex],\n breakdowns: updatedBreakdowns,\n }\n\n // Build result object\n const result: Partial<AnalysisBuilderStore> = { queryStates: newStates }\n\n // If enabling comparison, auto-add date filter if not present\n if (isEnablingComparison && targetBreakdown?.isTimeDimension && targetBreakdown.field) {\n const currentFilters = newStates[sourceIndex].filters || []\n\n // Check if a date filter already exists for this field\n const hasDateFilter = currentFilters.some((f) => {\n if ('member' in f) {\n const simple = f as SimpleFilter\n return simple.member === targetBreakdown.field && simple.operator === 'inDateRange'\n }\n return false\n })\n\n // If no date filter exists, add one with 'this month' as default\n if (!hasDateFilter) {\n const newDateFilter: SimpleFilter = {\n member: targetBreakdown.field,\n operator: 'inDateRange',\n values: [],\n dateRange: convertDateRangeTypeToValue('last_n_months', 3),\n } as SimpleFilter\n\n newStates[sourceIndex] = {\n ...newStates[sourceIndex],\n filters: [...currentFilters, newDateFilter],\n }\n result.queryStates = newStates\n }\n\n // Auto-switch to line chart if not already (line chart is best for comparison)\n const currentChartConfig = charts[analysisType]\n if (currentChartConfig && currentChartConfig.chartType !== 'line') {\n result.charts = {\n ...charts,\n [analysisType]: {\n ...currentChartConfig,\n chartType: 'line',\n },\n }\n result.userManuallySelectedChart = false\n result.activeView = 'chart'\n result.activeViews = {\n ...state.activeViews,\n [analysisType]: 'chart',\n }\n }\n }\n\n return result\n }),\n\n reorderBreakdowns: (fromIndex, toIndex) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newBreakdowns = [...currentState.breakdowns]\n const [movedItem] = newBreakdowns.splice(fromIndex, 1)\n newBreakdowns.splice(toIndex, 0, movedItem)\n newStates[index] = {\n ...currentState,\n breakdowns: newBreakdowns,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Filters Actions\n // ==========================================================================\n\n setFilters: (filters) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n newStates[index] = {\n ...newStates[index],\n filters,\n }\n return { queryStates: newStates }\n }),\n\n dropFieldToFilter: (field) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const existingFilters = currentState.filters || []\n\n // Check if we already have a filter for this field\n const hasFilter = existingFilters.some((f) => 'member' in f && f.member === field)\n if (hasFilter) return state\n\n const newFilter: Filter = {\n member: field,\n operator: 'set',\n values: [],\n }\n\n let updatedFilters: Filter[]\n if (existingFilters.length === 0) {\n updatedFilters = [newFilter]\n } else if (existingFilters.length === 1 && 'type' in existingFilters[0]) {\n const group = existingFilters[0] as { type: 'and' | 'or'; filters: Filter[] }\n updatedFilters = [{ ...group, filters: [...group.filters, newFilter] }]\n } else {\n updatedFilters = [{ type: 'and' as const, filters: [...existingFilters, newFilter] }]\n }\n\n newStates[index] = {\n ...currentState,\n filters: updatedFilters,\n }\n return { queryStates: newStates }\n }),\n\n setOrder: (fieldName, direction) =>\n set((state) => {\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n const currentState = newStates[index] || createInitialState()\n const newOrder = { ...(currentState.order || {}) }\n\n if (direction === null) {\n delete newOrder[fieldName]\n } else {\n newOrder[fieldName] = direction\n }\n\n newStates[index] = {\n ...currentState,\n order: Object.keys(newOrder).length > 0 ? newOrder : undefined,\n }\n return { queryStates: newStates }\n }),\n\n // ==========================================================================\n // Utility Actions\n // ==========================================================================\n\n getCurrentState: () => {\n const state = get()\n return state.queryStates[state.activeQueryIndex] || createInitialState()\n },\n\n getMergeKeys: () => {\n const state = get()\n if (state.mergeStrategy !== 'merge' || state.queryStates.length === 0) {\n return undefined\n }\n const q1Breakdowns = state.queryStates[0].breakdowns\n if (q1Breakdowns.length === 0) return undefined\n return q1Breakdowns.map((b) => b.field)\n },\n\n isMultiQueryMode: () => {\n const state = get()\n if (state.queryStates.length <= 1) return false\n const queriesWithContent = state.queryStates.filter(\n (qs) => qs.metrics.length > 0 || qs.breakdowns.length > 0\n )\n return queriesWithContent.length > 1\n },\n\n buildCurrentQuery: () => {\n const state = get()\n const current = state.queryStates[state.activeQueryIndex] || createInitialState()\n return buildCubeQuery(current.metrics, current.breakdowns, current.filters, current.order)\n },\n\n buildAllQueries: () => {\n const state = get()\n const q1Breakdowns = state.queryStates[0]?.breakdowns || []\n\n return state.queryStates.map((qs, index) => {\n // In merge mode, Q2+ inherit Q1's breakdowns\n const breakdowns =\n state.mergeStrategy === 'merge' && index > 0 ? q1Breakdowns : qs.breakdowns\n\n return buildCubeQuery(qs.metrics, breakdowns, qs.filters, qs.order)\n })\n },\n\n buildMultiQueryConfig: () => {\n const state = get()\n if (!get().isMultiQueryMode()) return null\n\n const allQueries = get().buildAllQueries()\n // Filter to queries that have at least one measure, dimension, or time dimension\n const validQueries = allQueries.filter((q) => {\n return (\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n })\n\n if (validQueries.length < 2) return null\n\n return {\n queries: validQueries,\n mergeStrategy: state.mergeStrategy,\n mergeKeys: get().getMergeKeys(),\n queryLabels: validQueries.map((_, i) => `Q${i + 1}`),\n }\n },\n})\n","/**\n * Funnel Slice\n *\n * Handles funnel mode state and actions:\n * - funnelCube (selected cube for all steps)\n * - funnelSteps (step definitions)\n * - funnelTimeDimension (temporal ordering)\n * - funnelBindingKey (entity linking)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { FunnelStepState, FunnelBindingKey, FunnelConfig } from '../../types'\nimport type { ServerFunnelQuery } from '../../types/funnel'\nimport { generateId } from '../../components/AnalysisBuilder/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Funnel slice state\n */\nexport interface FunnelSliceState {\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (separate from queryStates) */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Binding key dimension that links funnel steps together */\n funnelBindingKey: FunnelBindingKey | null\n /** @deprecated Use funnelSteps[].timeToConvert instead - kept for backward compat */\n stepTimeToConvert: (string | null)[]\n}\n\n/**\n * Funnel slice actions\n */\nexport interface FunnelSliceActions {\n /** Add a new funnel step */\n addFunnelStep: () => void\n /** Remove a funnel step by index */\n removeFunnelStep: (index: number) => void\n /** Update a funnel step by index */\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n /** Set the active funnel step index */\n setActiveFunnelStepIndex: (index: number) => void\n /** Reorder funnel steps */\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n /** Set the time dimension for funnel */\n setFunnelTimeDimension: (dimension: string | null) => void\n /** Set the funnel binding key */\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n /** Set the funnel cube (clears binding key/time dimension, updates all steps) */\n setFunnelCube: (cube: string | null) => void\n /** @deprecated No-op - use updateFunnelStep with timeToConvert instead */\n setStepTimeToConvert: (stepIndex: number, duration: string | null) => void\n /** @deprecated Always returns null - use buildFunnelQueryFromSteps instead */\n buildFunnelConfig: () => FunnelConfig | null\n /** Build ServerFunnelQuery from dedicated funnelSteps */\n buildFunnelQueryFromSteps: () => ServerFunnelQuery | null\n /** Check if in funnel mode (analysisType === 'funnel') */\n isFunnelMode: () => boolean\n /** Check if funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: () => boolean\n}\n\nexport type FunnelSlice = FunnelSliceState & FunnelSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialFunnelState = (): FunnelSliceState => ({\n funnelCube: null,\n funnelSteps: [],\n activeFunnelStepIndex: 0,\n funnelTimeDimension: null,\n funnelBindingKey: null,\n stepTimeToConvert: [], // Deprecated - kept for backward compat\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the funnel slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createFunnelSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n FunnelSlice\n> = (set, get) => ({\n ...createInitialFunnelState(),\n\n addFunnelStep: () =>\n set((state) => {\n // Copy filters and timeToConvert from last step if exists\n const lastStep = state.funnelSteps[state.funnelSteps.length - 1]\n const newStep: FunnelStepState = {\n id: generateId(),\n name: `Step ${state.funnelSteps.length + 1}`,\n cube: state.funnelCube || '',\n // Deep copy filters from previous step, or empty array if first step\n filters: lastStep?.filters ? JSON.parse(JSON.stringify(lastStep.filters)) : [],\n // Copy timeToConvert from previous step\n timeToConvert: lastStep?.timeToConvert,\n }\n return {\n funnelSteps: [...state.funnelSteps, newStep],\n activeFunnelStepIndex: state.funnelSteps.length,\n }\n }),\n\n removeFunnelStep: (index) =>\n set((state) => {\n if (state.funnelSteps.length <= 1) return state\n const newSteps = state.funnelSteps.filter((_, i) => i !== index)\n const newActiveIndex = Math.min(state.activeFunnelStepIndex, newSteps.length - 1)\n return {\n funnelSteps: newSteps,\n activeFunnelStepIndex: newActiveIndex,\n }\n }),\n\n updateFunnelStep: (index, updates) =>\n set((state) => {\n const newSteps = [...state.funnelSteps]\n if (newSteps[index]) {\n newSteps[index] = { ...newSteps[index], ...updates }\n }\n return { funnelSteps: newSteps }\n }),\n\n setActiveFunnelStepIndex: (index) => set({ activeFunnelStepIndex: index }),\n\n reorderFunnelSteps: (fromIndex, toIndex) =>\n set((state) => {\n const newSteps = [...state.funnelSteps]\n const [removed] = newSteps.splice(fromIndex, 1)\n newSteps.splice(toIndex, 0, removed)\n return { funnelSteps: newSteps }\n }),\n\n setFunnelTimeDimension: (dimension) => set({ funnelTimeDimension: dimension }),\n\n setFunnelBindingKey: (bindingKey) => set({ funnelBindingKey: bindingKey }),\n\n setFunnelCube: (cube) =>\n set((state) => {\n // Update all existing steps to use the new cube\n const updatedSteps = state.funnelSteps.map((step) => ({\n ...step,\n cube: cube || '',\n }))\n return {\n funnelCube: cube,\n // Clear binding key and time dimension since they may not exist in new cube\n funnelBindingKey: null,\n funnelTimeDimension: null,\n funnelSteps: updatedSteps,\n }\n }),\n\n // Deprecated: no-op - legacy queryStates-based funnels are no longer supported\n // Use updateFunnelStep with timeToConvert instead\n setStepTimeToConvert: () => {},\n\n // Deprecated: always returns null - legacy queryStates-based funnels are no longer supported\n // Use buildFunnelQueryFromSteps instead\n buildFunnelConfig: () => null,\n\n // New: Build ServerFunnelQuery from dedicated funnelSteps\n buildFunnelQueryFromSteps: () => {\n const state = get()\n if (state.analysisType !== 'funnel') return null\n if (!state.funnelBindingKey) return null\n if (!state.funnelTimeDimension) return null\n if (state.funnelSteps.length < 2) return null\n\n // Validate all steps have a cube and name\n const validSteps = state.funnelSteps.filter((s) => s.cube && s.name)\n if (validSteps.length < 2) return null\n\n return {\n funnel: {\n bindingKey: state.funnelBindingKey.dimension,\n timeDimension: state.funnelTimeDimension,\n steps: validSteps.map((step) => ({\n name: step.name,\n cube: step.cube,\n filter: step.filters.length > 0 ? step.filters : undefined,\n timeToConvert: step.timeToConvert,\n })),\n includeTimeMetrics: true,\n },\n }\n },\n\n isFunnelMode: () => get().analysisType === 'funnel',\n\n isFunnelModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'funnel') return false\n if (!state.funnelBindingKey) return false\n if (!state.funnelTimeDimension) return false\n if (state.funnelSteps.length < 2) return false\n\n // All steps need at least cube and name\n const validSteps = state.funnelSteps.filter((s) => s.cube && s.name)\n return validSteps.length >= 2\n },\n})\n","/**\n * Flow Slice\n *\n * Handles flow mode state and actions:\n * - flowCube (selected cube for flow analysis)\n * - flowBindingKey (entity linking)\n * - flowTimeDimension (temporal ordering)\n * - startingStep (anchor event definition)\n * - stepsBefore/stepsAfter (exploration depth)\n * - eventDimension (event categorization)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { Filter, FunnelBindingKey } from '../../types'\nimport type { ServerFlowQuery, FlowStartingStep } from '../../types/flow'\nimport { FLOW_MIN_DEPTH, FLOW_MAX_DEPTH } from '../../types/flow'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Flow slice state\n */\nexport interface FlowSliceState {\n /** Selected cube for flow mode (must be an eventStream cube) */\n flowCube: string | null\n /** Binding key that links events to entities */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for event ordering */\n flowTimeDimension: string | null\n /** Starting step configuration (anchor point for exploration) */\n startingStep: FlowStartingStep\n /** Number of steps to explore before starting step (0-5) */\n stepsBefore: number\n /** Number of steps to explore after starting step (0-5) */\n stepsAfter: number\n /** Event dimension that categorizes events (node labels) */\n eventDimension: string | null\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n}\n\n/**\n * Flow slice actions\n */\nexport interface FlowSliceActions {\n /** Set the flow cube (clears binding key/time dimension) */\n setFlowCube: (cube: string | null) => void\n /** Set the flow binding key */\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the flow time dimension */\n setFlowTimeDimension: (dim: string | null) => void\n /** Set the event dimension */\n setEventDimension: (dim: string | null) => void\n /** Set the starting step name */\n setStartingStepName: (name: string) => void\n /** Set all starting step filters at once */\n setStartingStepFilters: (filters: Filter[]) => void\n /** Add a filter to the starting step */\n addStartingStepFilter: (filter: Filter) => void\n /** Remove a filter from the starting step by index */\n removeStartingStepFilter: (index: number) => void\n /** Update a filter in the starting step by index */\n updateStartingStepFilter: (index: number, filter: Filter) => void\n /** Set the number of steps to explore before starting step */\n setStepsBefore: (count: number) => void\n /** Set the number of steps to explore after starting step */\n setStepsAfter: (count: number) => void\n /** Set the join strategy */\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n /** Check if in flow mode (analysisType === 'flow') */\n isFlowMode: () => boolean\n /** Check if flow mode is properly configured and ready for execution */\n isFlowModeEnabled: () => boolean\n /** Build ServerFlowQuery from flow state */\n buildFlowQuery: () => ServerFlowQuery | null\n}\n\nexport type FlowSlice = FlowSliceState & FlowSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialFlowState = (): FlowSliceState => ({\n flowCube: null,\n flowBindingKey: null,\n flowTimeDimension: null,\n startingStep: {\n name: '',\n filters: [],\n },\n stepsBefore: 3,\n stepsAfter: 3,\n eventDimension: null,\n joinStrategy: 'auto',\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the flow slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createFlowSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n FlowSlice\n> = (set, get) => ({\n ...createInitialFlowState(),\n\n setFlowCube: (cube) =>\n set(() => ({\n flowCube: cube,\n // Clear binding key and time dimension since they may not exist in new cube\n flowBindingKey: null,\n flowTimeDimension: null,\n eventDimension: null,\n // Reset starting step filters when cube changes\n startingStep: {\n name: '',\n filters: [],\n },\n })),\n\n setFlowBindingKey: (key) => set({ flowBindingKey: key }),\n\n setFlowTimeDimension: (dim) => set({ flowTimeDimension: dim }),\n\n setEventDimension: (dim) => set({ eventDimension: dim }),\n\n setStartingStepName: (name) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n name,\n },\n })),\n\n setStartingStepFilters: (filters) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters,\n },\n })),\n\n addStartingStepFilter: (filter) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters: [...state.startingStep.filters, filter],\n },\n })),\n\n removeStartingStepFilter: (index) =>\n set((state) => ({\n startingStep: {\n ...state.startingStep,\n filters: state.startingStep.filters.filter((_, i) => i !== index),\n },\n })),\n\n updateStartingStepFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.startingStep.filters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return {\n startingStep: {\n ...state.startingStep,\n filters: newFilters,\n },\n }\n }),\n\n setStepsBefore: (count) =>\n set({\n stepsBefore: Math.max(FLOW_MIN_DEPTH, Math.min(FLOW_MAX_DEPTH, count)),\n }),\n\n setStepsAfter: (count) =>\n set({\n stepsAfter: Math.max(FLOW_MIN_DEPTH, Math.min(FLOW_MAX_DEPTH, count)),\n }),\n\n setJoinStrategy: (strategy) =>\n set(() => ({\n joinStrategy: strategy,\n })),\n\n isFlowMode: () => get().analysisType === 'flow',\n\n isFlowModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'flow') return false\n if (!state.flowCube) return false\n if (!state.flowBindingKey?.dimension) return false\n if (!state.flowTimeDimension) return false\n if (!state.eventDimension) return false\n if (state.startingStep.filters.length === 0) return false\n\n return true\n },\n\n buildFlowQuery: () => {\n const state = get()\n\n if (state.analysisType !== 'flow') return null\n if (!state.flowBindingKey?.dimension) return null\n if (!state.flowTimeDimension) return null\n if (!state.eventDimension) return null\n if (state.startingStep.filters.length === 0) return null\n\n // Convert binding key to server format\n let bindingKey: ServerFlowQuery['flow']['bindingKey']\n if (typeof state.flowBindingKey.dimension === 'string') {\n bindingKey = state.flowBindingKey.dimension\n } else if (Array.isArray(state.flowBindingKey.dimension)) {\n bindingKey = state.flowBindingKey.dimension.map((mapping) => ({\n cube: mapping.cube,\n dimension: mapping.dimension,\n }))\n } else {\n return null\n }\n\n // Convert starting step filter to server format\n // Server accepts Filter | Filter[] for multiple filters\n const startingStepFilter: Filter | Filter[] =\n state.startingStep.filters.length === 1\n ? state.startingStep.filters[0]\n : state.startingStep.filters\n\n // Determine output mode based on chart type\n // Sunburst requires path-qualified nodes, sankey allows path convergence\n const flowChartType = state.charts?.flow?.chartType\n const outputMode: 'sankey' | 'sunburst' =\n flowChartType === 'sunburst' ? 'sunburst' : 'sankey'\n const effectiveStepsBefore = outputMode === 'sunburst' ? 0 : state.stepsBefore\n\n return {\n flow: {\n bindingKey,\n timeDimension: state.flowTimeDimension,\n startingStep: {\n name: state.startingStep.name || 'Starting Step',\n filter: startingStepFilter,\n },\n stepsBefore: effectiveStepsBefore,\n stepsAfter: state.stepsAfter,\n eventDimension: state.eventDimension,\n outputMode,\n joinStrategy: state.joinStrategy,\n },\n }\n },\n})\n","/**\n * Retention Slice\n *\n * Simplified Mixpanel-style retention state management:\n * - Single cube for all analysis\n * - Single timestamp dimension\n * - Single cohort with breakdown support\n * - Granularity = viewing periods\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type { Filter, FunnelBindingKey } from '../../types'\nimport type {\n ServerRetentionQuery,\n RetentionSliceState,\n RetentionGranularity,\n RetentionType,\n DateRange,\n RetentionBreakdownItem,\n} from '../../types/retention'\nimport {\n defaultRetentionSliceState,\n RETENTION_MIN_PERIODS,\n RETENTION_MAX_PERIODS,\n} from '../../types/retention'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Retention slice actions\n */\nexport interface RetentionSliceActions {\n /** Set the single cube for retention analysis (clears related fields) */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\nexport type RetentionSlice = RetentionSliceState & RetentionSliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nexport const createInitialRetentionState = (): RetentionSliceState => ({\n ...defaultRetentionSliceState,\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the retention slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createRetentionSlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n RetentionSlice\n> = (set, get) => ({\n ...createInitialRetentionState(),\n\n setRetentionCube: (cube) =>\n set(() => ({\n retentionCube: cube,\n // Clear related fields when cube changes\n retentionTimeDimension: null,\n retentionBindingKey: null,\n retentionCohortFilters: [],\n retentionActivityFilters: [],\n retentionBreakdowns: [],\n })),\n\n setRetentionBindingKey: (key) => set({ retentionBindingKey: key }),\n\n setRetentionTimeDimension: (dim) =>\n set({ retentionTimeDimension: dim }),\n\n setRetentionDateRange: (range) =>\n set({ retentionDateRange: range }),\n\n setRetentionCohortFilters: (filters) =>\n set({ retentionCohortFilters: filters }),\n\n addRetentionCohortFilter: (filter) =>\n set((state) => ({\n retentionCohortFilters: [...state.retentionCohortFilters, filter],\n })),\n\n removeRetentionCohortFilter: (index) =>\n set((state) => ({\n retentionCohortFilters: state.retentionCohortFilters.filter(\n (_, i) => i !== index\n ),\n })),\n\n updateRetentionCohortFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.retentionCohortFilters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return { retentionCohortFilters: newFilters }\n }),\n\n setRetentionActivityFilters: (filters) =>\n set({ retentionActivityFilters: filters }),\n\n addRetentionActivityFilter: (filter) =>\n set((state) => ({\n retentionActivityFilters: [...state.retentionActivityFilters, filter],\n })),\n\n removeRetentionActivityFilter: (index) =>\n set((state) => ({\n retentionActivityFilters: state.retentionActivityFilters.filter(\n (_, i) => i !== index\n ),\n })),\n\n updateRetentionActivityFilter: (index, filter) =>\n set((state) => {\n const newFilters = [...state.retentionActivityFilters]\n if (newFilters[index]) {\n newFilters[index] = filter\n }\n return { retentionActivityFilters: newFilters }\n }),\n\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) =>\n set({ retentionBreakdowns: breakdowns }),\n\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) =>\n set((state) => ({\n retentionBreakdowns: [...state.retentionBreakdowns, breakdown],\n })),\n\n removeRetentionBreakdown: (field: string) =>\n set((state) => ({\n retentionBreakdowns: state.retentionBreakdowns.filter((b) => b.field !== field),\n })),\n\n setRetentionViewGranularity: (granularity) =>\n set({ retentionViewGranularity: granularity }),\n\n setRetentionPeriods: (periods) =>\n set({\n retentionPeriods: Math.max(\n RETENTION_MIN_PERIODS,\n Math.min(RETENTION_MAX_PERIODS, periods)\n ),\n }),\n\n setRetentionType: (type) => set({ retentionType: type }),\n\n isRetentionMode: () => get().analysisType === 'retention',\n\n isRetentionModeEnabled: () => {\n const state = get()\n\n if (state.analysisType !== 'retention') return false\n if (!state.retentionBindingKey?.dimension) return false\n if (!state.retentionTimeDimension) return false\n\n return true\n },\n\n buildRetentionQuery: () => {\n const state = get()\n\n if (state.analysisType !== 'retention') return null\n if (!state.retentionBindingKey?.dimension) return null\n if (!state.retentionTimeDimension) return null\n\n // Convert binding key to server format\n let bindingKey: ServerRetentionQuery['retention']['bindingKey']\n if (typeof state.retentionBindingKey.dimension === 'string') {\n bindingKey = state.retentionBindingKey.dimension\n } else if (Array.isArray(state.retentionBindingKey.dimension)) {\n bindingKey = state.retentionBindingKey.dimension.map((mapping) => ({\n cube: mapping.cube,\n dimension: mapping.dimension,\n }))\n } else {\n return null\n }\n\n // Build base query\n const query: ServerRetentionQuery = {\n retention: {\n timeDimension: state.retentionTimeDimension,\n bindingKey,\n dateRange: state.retentionDateRange,\n granularity: state.retentionViewGranularity,\n periods: state.retentionPeriods,\n retentionType: state.retentionType,\n },\n }\n\n // Add cohort filters if present\n if (state.retentionCohortFilters.length > 0) {\n query.retention.cohortFilters =\n state.retentionCohortFilters.length === 1\n ? state.retentionCohortFilters[0]\n : state.retentionCohortFilters\n }\n\n // Add activity filters if present\n if (state.retentionActivityFilters.length > 0) {\n query.retention.activityFilters =\n state.retentionActivityFilters.length === 1\n ? state.retentionActivityFilters[0]\n : state.retentionActivityFilters\n }\n\n // Add breakdown dimensions if present\n if (state.retentionBreakdowns.length > 0) {\n query.retention.breakdownDimensions = state.retentionBreakdowns.map((b) => b.field)\n }\n\n return query\n },\n\n getRetentionValidation: () => {\n const state = get()\n const errors: string[] = []\n const warnings: string[] = []\n\n if (state.analysisType !== 'retention') {\n return { isValid: true, errors: [], warnings: [] }\n }\n\n // Check cube\n if (!state.retentionCube) {\n errors.push('Select a cube for retention analysis')\n }\n\n // Check binding key\n if (!state.retentionBindingKey?.dimension) {\n errors.push('Select a user identifier (binding key) to track retention')\n }\n\n // Check timestamp dimension\n if (!state.retentionTimeDimension) {\n errors.push('Select a timestamp dimension for the analysis')\n }\n\n // Check date range (REQUIRED)\n if (!state.retentionDateRange?.start || !state.retentionDateRange?.end) {\n errors.push('Date range is required for retention analysis')\n } else {\n // Validate date format\n const startDate = new Date(state.retentionDateRange.start)\n const endDate = new Date(state.retentionDateRange.end)\n if (isNaN(startDate.getTime())) {\n errors.push('Invalid start date format')\n }\n if (isNaN(endDate.getTime())) {\n errors.push('Invalid end date format')\n }\n if (startDate > endDate) {\n errors.push('Start date must be before or equal to end date')\n }\n }\n\n // Check periods\n if (state.retentionPeriods < 1) {\n errors.push('At least 1 retention period is required')\n }\n if (state.retentionPeriods > 52) {\n warnings.push('More than 52 periods may impact performance')\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n },\n})\n","/**\n * UI Slice\n *\n * Handles UI-related state and actions:\n * - activeTab (query panel tab)\n * - activeView (table or chart)\n * - displayLimit (table row limit)\n * - Modal state (field search modal)\n * - AI state (AI panel)\n */\n\nimport type { StateCreator } from 'zustand'\nimport type { AnalysisBuilderStore } from '../analysisBuilderStore'\nimport type {\n QueryPanelTab,\n AIState,\n} from '../../components/AnalysisBuilder/types'\nimport { createInitialState } from '../../components/AnalysisBuilder/utils'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Field modal mode for field search\n */\nexport type FieldModalMode = 'metrics' | 'breakdown'\n\n/**\n * UI slice state\n */\nexport interface UISliceState {\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field search modal is open */\n showFieldModal: boolean\n /** Current mode for field search modal */\n fieldModalMode: FieldModalMode\n /** AI panel state */\n aiState: AIState\n}\n\n/**\n * UI slice actions\n */\nexport interface UISliceActions {\n // Tab/View actions\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n\n // Field modal actions\n openMetricsModal: () => void\n openBreakdownsModal: () => void\n closeFieldModal: () => void\n\n // AI actions\n openAI: () => void\n closeAI: () => void\n setAIPrompt: (prompt: string) => void\n setAIGenerating: (generating: boolean) => void\n setAIError: (error: string | null) => void\n setAIHasGeneratedQuery: (hasQuery: boolean) => void\n saveAIPreviousState: () => void\n restoreAIPreviousState: () => void\n}\n\nexport type UISlice = UISliceState & UISliceActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialAIState: AIState = {\n isOpen: false,\n userPrompt: '',\n isGenerating: false,\n error: null,\n hasGeneratedQuery: false,\n previousState: null,\n}\n\nexport const createInitialUIState = (): UISliceState => ({\n activeTab: 'query',\n activeView: 'chart',\n displayLimit: 100,\n showFieldModal: false,\n fieldModalMode: 'metrics',\n aiState: initialAIState,\n})\n\n// ============================================================================\n// Slice Creator\n// ============================================================================\n\n/**\n * Create the UI slice.\n * Uses StateCreator pattern for composability.\n */\nexport const createUISlice: StateCreator<\n AnalysisBuilderStore,\n [],\n [],\n UISlice\n> = (set, _get) => ({\n ...createInitialUIState(),\n\n // ==========================================================================\n // Tab/View Actions\n // ==========================================================================\n\n setActiveTab: (tab) => set({ activeTab: tab }),\n\n setActiveView: (view) =>\n set((state) => ({\n activeView: view,\n activeViews: {\n ...state.activeViews,\n [state.analysisType]: view,\n },\n })),\n\n setDisplayLimit: (limit) => set({ displayLimit: limit }),\n\n // ==========================================================================\n // Field Modal Actions\n // ==========================================================================\n\n openMetricsModal: () => set({ showFieldModal: true, fieldModalMode: 'metrics' }),\n\n openBreakdownsModal: () => set({ showFieldModal: true, fieldModalMode: 'breakdown' }),\n\n closeFieldModal: () => set({ showFieldModal: false }),\n\n // ==========================================================================\n // AI Actions\n // ==========================================================================\n\n openAI: () =>\n set((state) => ({\n aiState: { ...state.aiState, isOpen: true },\n })),\n\n closeAI: () =>\n set((state) => ({\n aiState: { ...state.aiState, isOpen: false },\n })),\n\n setAIPrompt: (prompt) =>\n set((state) => ({\n aiState: { ...state.aiState, userPrompt: prompt },\n })),\n\n setAIGenerating: (generating) =>\n set((state) => ({\n aiState: { ...state.aiState, isGenerating: generating },\n })),\n\n setAIError: (error) =>\n set((state) => ({\n aiState: { ...state.aiState, error },\n })),\n\n setAIHasGeneratedQuery: (hasQuery) =>\n set((state) => ({\n aiState: { ...state.aiState, hasGeneratedQuery: hasQuery },\n })),\n\n saveAIPreviousState: () =>\n set((state) => {\n const currentState = state.queryStates[state.activeQueryIndex]\n // Get chart config from charts map (Phase 4 - use charts map as source of truth)\n const chartConfig = state.charts[state.analysisType] || {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n return {\n aiState: {\n ...state.aiState,\n previousState: currentState\n ? {\n metrics: [...currentState.metrics],\n breakdowns: [...currentState.breakdowns],\n filters: [...currentState.filters],\n chartType: chartConfig.chartType,\n chartConfig: { ...chartConfig.chartConfig },\n displayConfig: { ...chartConfig.displayConfig },\n }\n : null,\n },\n }\n }),\n\n restoreAIPreviousState: () =>\n set((state) => {\n const prev = state.aiState.previousState\n if (!prev) return state\n\n const index = state.activeQueryIndex\n const newStates = [...state.queryStates]\n newStates[index] = {\n ...(newStates[index] || createInitialState()),\n metrics: prev.metrics,\n breakdowns: prev.breakdowns,\n filters: prev.filters,\n }\n\n // Phase 4: Write to charts map instead of legacy fields\n return {\n queryStates: newStates,\n charts: {\n ...state.charts,\n [state.analysisType]: {\n chartType: prev.chartType,\n chartConfig: prev.chartConfig,\n displayConfig: prev.displayConfig,\n },\n },\n aiState: { ...initialAIState },\n } as any\n }),\n})\n","/**\n * AnalysisBuilder Zustand Store (Instance-based)\n *\n * Centralized state management for AnalysisBuilder, consolidating:\n * - Query state (multi-query support with per-query metrics, breakdowns, filters)\n * - Chart configuration (type, axis config, display config)\n * - UI state (tabs, views, modals)\n * - AI state\n *\n * KEY ARCHITECTURE: Instance-based stores\n * - Each AnalysisBuilder component gets its own store instance\n * - Standalone mode: Uses localStorage persistence\n * - Modal/portlet editing mode: No persistence, initializes from props\n *\n * Uses Zustand's createStore (factory) instead of create (singleton).\n * Store is provided via React Context.\n */\n\nimport { createContext, useContext, useRef, type ReactNode } from 'react'\nimport { createStore, useStore, type StoreApi } from 'zustand'\nimport { devtools, persist, subscribeWithSelector } from 'zustand/middleware'\nimport type {\n Filter,\n SimpleFilter,\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n CubeQuery,\n QueryMergeStrategy,\n MultiQueryConfig,\n FunnelBindingKey,\n FunnelConfig,\n AnalysisType,\n FunnelStepState,\n} from '../types'\nimport type { ServerFunnelQuery } from '../types/funnel'\nimport type { ServerFlowQuery, FlowStartingStep } from '../types/flow'\nimport type {\n ServerRetentionQuery,\n RetentionGranularity,\n RetentionType,\n DateRange,\n RetentionBreakdownItem,\n} from '../types/retention'\nimport { getDateRangeFromPreset, DEFAULT_DATE_RANGE_PRESET } from '../types/retention'\nimport type {\n AnalysisBuilderState,\n QueryPanelTab,\n AIState,\n} from '../components/AnalysisBuilder/types'\nimport {\n generateId,\n generateMetricLabel,\n createInitialState,\n STORAGE_KEY,\n} from '../components/AnalysisBuilder/utils'\nimport { adapterRegistry } from '../adapters/adapterRegistry'\nimport { queryModeAdapter } from '../adapters/queryModeAdapter'\nimport { funnelModeAdapter } from '../adapters/funnelModeAdapter'\nimport { flowModeAdapter } from '../adapters/flowModeAdapter'\nimport { retentionModeAdapter } from '../adapters/retentionModeAdapter'\nimport type { AnalysisConfig, ChartConfig, AnalysisWorkspace } from '../types/analysisConfig'\nimport { isValidAnalysisConfig, isValidAnalysisWorkspace } from '../types/analysisConfig'\nimport {\n createCoreSlice,\n createQuerySlice,\n createFunnelSlice,\n createFlowSlice,\n createRetentionSlice,\n createUISlice,\n createInitialCoreState,\n createInitialQueryState,\n createInitialFunnelState,\n createInitialFlowState,\n createInitialRetentionState,\n} from './slices'\n\n// Note: Adapters are registered in coreSlice.ts (single registration point)\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Field modal mode for field search\n */\nexport type FieldModalMode = 'metrics' | 'breakdown'\n\n/**\n * Complete store state interface\n */\nexport interface AnalysisBuilderStoreState {\n // =========================================================================\n // Analysis Type (Explicit mode selection)\n // =========================================================================\n /** Explicit analysis type - determines which mode is active */\n analysisType: AnalysisType\n\n // =========================================================================\n // Per-Mode Chart Configuration (NEW - Phase 2)\n // =========================================================================\n /**\n * Per-mode chart configuration map.\n * Each mode owns its own chart settings, enabling mode switching\n * without losing chart configurations.\n */\n charts: {\n [K in AnalysisType]?: ChartConfig\n }\n\n /**\n * Per-mode active view (table or chart) map.\n * Each mode owns its own view preference, enabling mode switching\n * without losing view preferences.\n */\n activeViews: {\n [K in AnalysisType]?: 'table' | 'chart'\n }\n\n // =========================================================================\n // Query State (Query/Multi modes)\n // =========================================================================\n /** Array of query states (one per tab) */\n queryStates: AnalysisBuilderState[]\n /** Index of the currently active query tab */\n activeQueryIndex: number\n /** Strategy for merging multi-query results (used when queryStates.length > 1) */\n mergeStrategy: QueryMergeStrategy\n\n // =========================================================================\n // Chart Configuration (unified in charts map - Phase 4 cleanup)\n // =========================================================================\n /** Whether user manually selected chart type (disables auto-switch) */\n userManuallySelectedChart: boolean\n /** Current color palette name */\n localPaletteName: string\n\n // =========================================================================\n // UI State\n // =========================================================================\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field search modal is open */\n showFieldModal: boolean\n /** Current mode for field search modal */\n fieldModalMode: FieldModalMode\n\n // =========================================================================\n // AI State\n // =========================================================================\n /** AI panel state */\n aiState: AIState\n\n // =========================================================================\n // Funnel State (when analysisType === 'funnel')\n // =========================================================================\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (separate from queryStates) */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Binding key dimension that links funnel steps together */\n funnelBindingKey: FunnelBindingKey | null\n /** @deprecated Use funnelSteps[].timeToConvert instead - kept for backward compat */\n stepTimeToConvert: (string | null)[]\n\n // =========================================================================\n // Flow State (when analysisType === 'flow')\n // =========================================================================\n /** Selected cube for flow mode (must be an eventStream cube) */\n flowCube: string | null\n /** Binding key that links events to entities */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for event ordering */\n flowTimeDimension: string | null\n /** Starting step configuration (anchor point for exploration) */\n startingStep: FlowStartingStep\n /** Number of steps to explore before starting step (1-5) */\n stepsBefore: number\n /** Number of steps to explore after starting step (1-5) */\n stepsAfter: number\n /** Event dimension that categorizes events (node labels) */\n eventDimension: string | null\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n\n // =========================================================================\n // Retention State (when analysisType === 'retention')\n // Simplified Mixpanel-style with single global configuration\n // =========================================================================\n /** Single cube for retention analysis */\n retentionCube: string | null\n /** Binding key that identifies entities */\n retentionBindingKey: FunnelBindingKey | null\n /** Single timestamp dimension for cohort entry and activity */\n retentionTimeDimension: string | null\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: DateRange\n /** Filters that define who enters the cohort */\n retentionCohortFilters: Filter[]\n /** Filters that define what counts as a return */\n retentionActivityFilters: Filter[]\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: RetentionBreakdownItem[]\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: RetentionGranularity\n /** Number of periods to analyze (1-52) */\n retentionPeriods: number\n /** Type of retention calculation */\n retentionType: RetentionType\n}\n\n/**\n * Store actions interface\n */\nexport interface AnalysisBuilderStoreActions {\n // =========================================================================\n // Analysis Type Actions\n // =========================================================================\n /** Set the analysis type (switches between Query/Multi/Funnel modes) */\n setAnalysisType: (type: AnalysisType) => void\n\n // =========================================================================\n // Query State Actions (Query/Multi modes)\n // =========================================================================\n /** Set all query states */\n setQueryStates: (states: AnalysisBuilderState[]) => void\n /** Update a specific query state by index */\n updateQueryState: (\n index: number,\n updater: (state: AnalysisBuilderState) => AnalysisBuilderState\n ) => void\n /** Set active query index */\n setActiveQueryIndex: (index: number) => void\n /** Set merge strategy */\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n\n // =========================================================================\n // Metrics Actions\n // =========================================================================\n /** Open field modal in metrics mode */\n openMetricsModal: () => void\n /** Add a metric to current query */\n addMetric: (field: string, label?: string) => void\n /** Remove a metric from current query */\n removeMetric: (id: string) => void\n /** Toggle a metric (add if not present, remove if present) */\n toggleMetric: (fieldName: string) => void\n /** Reorder metrics */\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n\n // =========================================================================\n // Breakdowns Actions\n // =========================================================================\n /** Open field modal in breakdown mode */\n openBreakdownsModal: () => void\n /** Add a breakdown to current query */\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n /** Remove a breakdown from current query */\n removeBreakdown: (id: string) => void\n /** Toggle a breakdown (add if not present, remove if present) */\n toggleBreakdown: (\n fieldName: string,\n isTimeDimension: boolean,\n granularity?: string\n ) => void\n /** Change granularity for a time dimension breakdown */\n setBreakdownGranularity: (id: string, granularity: string) => void\n /** Toggle comparison mode for a time dimension breakdown */\n toggleBreakdownComparison: (id: string) => void\n /** Reorder breakdowns */\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n\n // =========================================================================\n // Filters Actions\n // =========================================================================\n /** Set filters for current query */\n setFilters: (filters: Filter[]) => void\n /** Drop a field to create a filter */\n dropFieldToFilter: (field: string) => void\n /** Set sort order for a field */\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n\n // =========================================================================\n // Multi-Query Actions\n // =========================================================================\n /** Add a new query tab */\n addQuery: () => void\n /** Remove a query tab */\n removeQuery: (index: number) => void\n\n // =========================================================================\n // Chart Actions\n // =========================================================================\n /** Set chart type */\n setChartType: (type: ChartType) => void\n /** Set chart type with manual selection flag */\n setChartTypeManual: (type: ChartType) => void\n /** Set chart config */\n setChartConfig: (config: ChartAxisConfig) => void\n /** Set display config */\n setDisplayConfig: (config: ChartDisplayConfig) => void\n /** Set color palette name */\n setLocalPaletteName: (name: string) => void\n /** Set user manually selected chart flag */\n setUserManuallySelectedChart: (value: boolean) => void\n\n // =========================================================================\n // UI Actions\n // =========================================================================\n /** Set active tab */\n setActiveTab: (tab: QueryPanelTab) => void\n /** Set active view */\n setActiveView: (view: 'table' | 'chart') => void\n /** Set display limit */\n setDisplayLimit: (limit: number) => void\n /** Close field modal */\n closeFieldModal: () => void\n\n // =========================================================================\n // AI Actions\n // =========================================================================\n /** Open AI panel */\n openAI: () => void\n /** Close AI panel */\n closeAI: () => void\n /** Set AI prompt */\n setAIPrompt: (prompt: string) => void\n /** Set AI generating state */\n setAIGenerating: (generating: boolean) => void\n /** Set AI error */\n setAIError: (error: string | null) => void\n /** Set AI has generated query */\n setAIHasGeneratedQuery: (hasQuery: boolean) => void\n /** Save previous state for AI undo */\n saveAIPreviousState: () => void\n /** Restore previous state (AI cancel/undo) */\n restoreAIPreviousState: () => void\n\n // =========================================================================\n // Funnel Actions (when analysisType === 'funnel')\n // =========================================================================\n /** Add a new funnel step */\n addFunnelStep: () => void\n /** Remove a funnel step by index */\n removeFunnelStep: (index: number) => void\n /** Update a funnel step by index */\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n /** Set the active funnel step index */\n setActiveFunnelStepIndex: (index: number) => void\n /** Reorder funnel steps */\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n /** Set the time dimension for funnel */\n setFunnelTimeDimension: (dimension: string | null) => void\n /** Set the funnel binding key */\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n /** Set the funnel cube (clears binding key/time dimension, updates all steps) */\n setFunnelCube: (cube: string | null) => void\n /** @deprecated Set time window for a specific step - use updateFunnelStep instead */\n setStepTimeToConvert: (stepIndex: number, duration: string | null) => void\n /** @deprecated Build FunnelConfig from queryStates - use buildFunnelQueryFromSteps instead */\n buildFunnelConfig: () => FunnelConfig | null\n /** Build ServerFunnelQuery from dedicated funnelSteps */\n buildFunnelQueryFromSteps: () => ServerFunnelQuery | null\n /** Check if in funnel mode (analysisType === 'funnel') */\n isFunnelMode: () => boolean\n /** Check if funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: () => boolean\n /** Set funnel chart type */\n setFunnelChartType: (type: ChartType) => void\n /** Set funnel chart config */\n setFunnelChartConfig: (config: ChartAxisConfig) => void\n /** Set funnel display config */\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n\n // =========================================================================\n // Flow Actions (when analysisType === 'flow')\n // =========================================================================\n /** Set the flow cube (clears binding key/time dimension) */\n setFlowCube: (cube: string | null) => void\n /** Set the flow binding key */\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the flow time dimension */\n setFlowTimeDimension: (dim: string | null) => void\n /** Set the event dimension */\n setEventDimension: (dim: string | null) => void\n /** Set the starting step name */\n setStartingStepName: (name: string) => void\n /** Set all starting step filters at once */\n setStartingStepFilters: (filters: Filter[]) => void\n /** Add a filter to the starting step */\n addStartingStepFilter: (filter: Filter) => void\n /** Remove a filter from the starting step by index */\n removeStartingStepFilter: (index: number) => void\n /** Update a filter in the starting step by index */\n updateStartingStepFilter: (index: number, filter: Filter) => void\n /** Set the number of steps to explore before starting step */\n setStepsBefore: (count: number) => void\n /** Set the number of steps to explore after starting step */\n setStepsAfter: (count: number) => void\n /** Set the join strategy for flow execution */\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n /** Check if in flow mode (analysisType === 'flow') */\n isFlowMode: () => boolean\n /** Check if flow mode is properly configured and ready for execution */\n isFlowModeEnabled: () => boolean\n /** Build ServerFlowQuery from flow state */\n buildFlowQuery: () => ServerFlowQuery | null\n\n // =========================================================================\n // Retention Actions (when analysisType === 'retention')\n // Simplified Mixpanel-style with single global configuration\n // =========================================================================\n /** Set the single cube for retention analysis (clears related fields) */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n\n // =========================================================================\n // Utility Actions\n // =========================================================================\n /** Clear only the current mode's state (preserves other modes) */\n clearCurrentMode: () => void\n /** @deprecated Clear the current query - use clearCurrentMode instead */\n clearQuery: () => void\n /** Get current state (helper accessor) */\n getCurrentState: () => AnalysisBuilderState\n /** Get merge keys (computed from Q1 breakdowns) */\n getMergeKeys: () => string[] | undefined\n /** Check if in multi-query mode */\n isMultiQueryMode: () => boolean\n /** Build current CubeQuery */\n buildCurrentQuery: () => CubeQuery\n /** Build all queries */\n buildAllQueries: () => CubeQuery[]\n /** Build MultiQueryConfig */\n buildMultiQueryConfig: () => MultiQueryConfig | null\n /** Reset store to initial state */\n reset: () => void\n\n // =========================================================================\n // Save/Load Actions (NEW - Phase 2)\n // =========================================================================\n /**\n * Save current state to AnalysisConfig format.\n * Delegates to the appropriate adapter based on analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n save: () => AnalysisConfig\n\n /**\n * Load state from AnalysisConfig.\n * Delegates to the appropriate adapter based on config.analysisType.\n * Use for share URLs and portlets (single-mode).\n */\n load: (config: AnalysisConfig) => void\n\n /**\n * Save ALL modes to AnalysisWorkspace format.\n * Used for localStorage persistence to preserve state across mode switches.\n */\n saveWorkspace: () => AnalysisWorkspace\n\n /**\n * Load ALL modes from AnalysisWorkspace.\n * Used for localStorage persistence to restore state for all modes.\n */\n loadWorkspace: (workspace: AnalysisWorkspace) => void\n\n // =========================================================================\n // Validation Actions (NEW - Phase 5)\n // =========================================================================\n /**\n * Validate current state using the adapter for the current analysis type.\n * Returns validation errors and warnings that can be displayed to the user.\n */\n getValidation: () => import('../adapters/modeAdapter').ValidationResult\n}\n\n/**\n * Combined store type\n */\nexport type AnalysisBuilderStore = AnalysisBuilderStoreState &\n AnalysisBuilderStoreActions\n\n/**\n * Initial funnel state for creating a store instance.\n * Chart configuration is handled via CreateStoreOptions.initialChartConfig instead.\n */\nexport interface InitialFunnelState {\n funnelCube?: string | null\n funnelSteps?: FunnelStepState[]\n funnelTimeDimension?: string | null\n funnelBindingKey?: FunnelBindingKey | null\n}\n\nexport interface InitialFlowState {\n flowCube?: string | null\n flowBindingKey?: FunnelBindingKey | null\n flowTimeDimension?: string | null\n startingStep?: FlowStartingStep\n stepsBefore?: number\n stepsAfter?: number\n eventDimension?: string | null\n joinStrategy?: 'auto' | 'lateral' | 'window'\n}\n\nexport interface InitialRetentionState {\n retentionCube?: string | null\n retentionBindingKey?: FunnelBindingKey | null\n retentionTimeDimension?: string | null\n retentionDateRange?: DateRange\n retentionCohortFilters?: Filter[]\n retentionActivityFilters?: Filter[]\n retentionBreakdowns?: RetentionBreakdownItem[]\n retentionViewGranularity?: RetentionGranularity\n retentionPeriods?: number\n retentionType?: RetentionType\n}\n\n/**\n * Options for creating a store instance\n */\nexport interface CreateStoreOptions {\n /** Initial query configuration */\n initialQuery?: CubeQuery | MultiQueryConfig\n /** Initial chart configuration */\n initialChartConfig?: {\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n }\n /** Disable localStorage persistence */\n disableLocalStorage?: boolean\n /** Initial analysis type (query or funnel) */\n initialAnalysisType?: AnalysisType\n /** Initial funnel state (when analysisType === 'funnel') */\n initialFunnelState?: InitialFunnelState\n /** Initial flow state (when analysisType === 'flow') */\n initialFlowState?: InitialFlowState\n /** Initial retention state (when analysisType === 'retention') */\n initialRetentionState?: InitialRetentionState\n /** Initial active view (table or chart) - used to prevent flash when loading from share */\n initialActiveView?: 'table' | 'chart'\n}\n\n// Note: Initial state is now handled by slice initializers\n// (createInitialCoreState, createInitialQueryState, createInitialFunnelState, createInitialUIState)\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Convert CubeQuery to AnalysisBuilderState\n */\nfunction queryToState(query: CubeQuery): AnalysisBuilderState {\n const baseFilters = query.filters ? [...query.filters] : []\n\n const timeDimensions = query.timeDimensions || []\n const breakdowns = [\n ...(query.dimensions || []).map((field) => ({\n id: generateId(),\n field,\n isTimeDimension: false,\n })),\n ...timeDimensions.map((td) => ({\n id: generateId(),\n field: td.dimension,\n granularity: td.granularity,\n isTimeDimension: true,\n enableComparison: Boolean(td.compareDateRange && td.compareDateRange.length > 0),\n })),\n ]\n\n let filters = baseFilters\n\n // Restore date filters for comparison-enabled time dimensions when missing.\n for (const td of timeDimensions) {\n if (!td.compareDateRange || td.compareDateRange.length === 0) continue\n\n const hasDateFilter = filters.some(\n (filter) =>\n 'member' in filter &&\n (filter as SimpleFilter).member === td.dimension &&\n (filter as SimpleFilter).operator === 'inDateRange'\n )\n\n const firstRange = td.compareDateRange[0]\n const dateRange =\n Array.isArray(firstRange) || typeof firstRange === 'string'\n ? firstRange\n : undefined\n\n if (!dateRange) continue\n\n if (!hasDateFilter) {\n filters = [\n ...filters,\n {\n member: td.dimension,\n operator: 'inDateRange',\n values: [],\n dateRange,\n } as SimpleFilter,\n ]\n continue\n }\n\n filters = filters.map((filter) => {\n if (\n 'member' in filter &&\n (filter as SimpleFilter).member === td.dimension &&\n (filter as SimpleFilter).operator === 'inDateRange' &&\n !(filter as SimpleFilter).dateRange\n ) {\n return { ...(filter as SimpleFilter), dateRange }\n }\n return filter\n })\n }\n\n return {\n ...createInitialState(),\n metrics: (query.measures || []).map((field, index) => ({\n id: generateId(),\n field,\n label: generateMetricLabel(index),\n })),\n breakdowns,\n filters,\n order: query.order,\n }\n}\n\n/**\n * Check if config is MultiQueryConfig\n */\nfunction isMultiQueryConfig(config: CubeQuery | MultiQueryConfig): config is MultiQueryConfig {\n return 'queries' in config && Array.isArray(config.queries)\n}\n\n/**\n * Convert store creation options to AnalysisConfig.\n * Returns null if no meaningful options are provided (use defaults).\n */\nfunction optionsToAnalysisConfig(options: CreateStoreOptions): AnalysisConfig | null {\n // Handle funnel mode with funnel state\n if (options.initialAnalysisType === 'funnel' && options.initialFunnelState) {\n const defaultFunnelChart = funnelModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings (legacy funnel chart fields removed)\n const funnelChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultFunnelChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultFunnelChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultFunnelChart.displayConfig,\n }\n\n // Build funnel config via adapter's save method structure\n const funnelState = {\n funnelCube: options.initialFunnelState.funnelCube ?? null,\n funnelSteps: options.initialFunnelState.funnelSteps || [],\n activeFunnelStepIndex: 0,\n funnelTimeDimension: options.initialFunnelState.funnelTimeDimension ?? null,\n funnelBindingKey: options.initialFunnelState.funnelBindingKey ?? null,\n }\n\n return funnelModeAdapter.save(\n funnelState,\n { funnel: funnelChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle flow mode with flow state\n if (options.initialAnalysisType === 'flow' && options.initialFlowState) {\n const defaultFlowChart = flowModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings\n const flowChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultFlowChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultFlowChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultFlowChart.displayConfig,\n }\n\n // Build flow config via adapter's save method structure\n const flowState = {\n flowCube: options.initialFlowState.flowCube ?? null,\n flowBindingKey: options.initialFlowState.flowBindingKey ?? null,\n flowTimeDimension: options.initialFlowState.flowTimeDimension ?? null,\n startingStep: options.initialFlowState.startingStep || { name: '', filters: [] },\n stepsBefore: options.initialFlowState.stepsBefore ?? 3,\n stepsAfter: options.initialFlowState.stepsAfter ?? 3,\n eventDimension: options.initialFlowState.eventDimension ?? null,\n joinStrategy: options.initialFlowState.joinStrategy ?? 'auto',\n }\n\n return flowModeAdapter.save(\n flowState,\n { flow: flowChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle retention mode with retention state\n if (options.initialAnalysisType === 'retention' && options.initialRetentionState) {\n const defaultRetentionChart = retentionModeAdapter.getDefaultChartConfig()\n // Use initialChartConfig for chart settings\n const retentionChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultRetentionChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultRetentionChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultRetentionChart.displayConfig,\n }\n\n // Build retention state - use default date range for fallback\n const defaultDateRange = getDateRangeFromPreset(DEFAULT_DATE_RANGE_PRESET)\n\n const retentionState = {\n retentionCube: options.initialRetentionState.retentionCube ?? null,\n retentionBindingKey: options.initialRetentionState.retentionBindingKey ?? null,\n retentionTimeDimension: options.initialRetentionState.retentionTimeDimension ?? null,\n retentionDateRange: options.initialRetentionState.retentionDateRange ?? defaultDateRange,\n retentionCohortFilters: options.initialRetentionState.retentionCohortFilters || [],\n retentionActivityFilters: options.initialRetentionState.retentionActivityFilters || [],\n retentionBreakdowns: options.initialRetentionState.retentionBreakdowns || [],\n retentionViewGranularity: options.initialRetentionState.retentionViewGranularity ?? 'week',\n retentionPeriods: options.initialRetentionState.retentionPeriods ?? 12,\n retentionType: options.initialRetentionState.retentionType ?? 'classic',\n }\n\n return retentionModeAdapter.save(\n retentionState,\n { retention: retentionChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle query mode with initial query\n if (options.initialQuery) {\n const query = options.initialQuery\n let queryStates: AnalysisBuilderState[]\n let mergeStrategy: QueryMergeStrategy = 'concat'\n\n if (isMultiQueryConfig(query)) {\n queryStates = query.queries.map(queryToState)\n if (query.mergeStrategy) {\n mergeStrategy = query.mergeStrategy\n }\n } else {\n queryStates = [queryToState(query)]\n }\n\n const defaultQueryChart = queryModeAdapter.getDefaultChartConfig()\n const queryChartConfig: ChartConfig = {\n chartType: options.initialChartConfig?.chartType || defaultQueryChart.chartType,\n chartConfig: options.initialChartConfig?.chartConfig || defaultQueryChart.chartConfig,\n displayConfig: options.initialChartConfig?.displayConfig || defaultQueryChart.displayConfig,\n }\n\n return queryModeAdapter.save(\n { queryStates, activeQueryIndex: 0, mergeStrategy },\n { query: queryChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle just chart config (no query)\n if (options.initialChartConfig) {\n const defaultQueryChart = queryModeAdapter.getDefaultChartConfig()\n const queryChartConfig: ChartConfig = {\n chartType: options.initialChartConfig.chartType || defaultQueryChart.chartType,\n chartConfig: options.initialChartConfig.chartConfig || defaultQueryChart.chartConfig,\n displayConfig: options.initialChartConfig.displayConfig || defaultQueryChart.displayConfig,\n }\n\n return queryModeAdapter.save(\n { queryStates: [createInitialState()], activeQueryIndex: 0, mergeStrategy: 'concat' },\n { query: queryChartConfig },\n options.initialActiveView || 'chart'\n )\n }\n\n // Handle just active view\n if (options.initialActiveView) {\n // Return a minimal config with just activeView set\n return queryModeAdapter.save(\n { queryStates: [createInitialState()], activeQueryIndex: 0, mergeStrategy: 'concat' },\n { query: queryModeAdapter.getDefaultChartConfig() },\n options.initialActiveView\n )\n }\n\n // No meaningful options - use store defaults\n return null\n}\n\n// NOTE: createStoreActions has been replaced by slice composition.\n// See createAnalysisBuilderStore below which composes:\n// - createCoreSlice\n// - createQuerySlice\n// - createFunnelSlice\n// - createUISlice\n// - createCrossSliceActions\n\n\n// ============================================================================\n// Cross-Slice Actions\n// ============================================================================\n\n/**\n * Cross-slice actions that coordinate state across multiple slices.\n * These can't be in individual slices because they need to update state\n * from multiple slices atomically.\n */\ninterface CrossSliceActions {\n reset: () => void\n clearCurrentMode: () => void\n clearQuery: () => void\n getValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\nfunction createCrossSliceActions(\n set: (\n partial:\n | Partial<AnalysisBuilderStore>\n | ((state: AnalysisBuilderStore) => Partial<AnalysisBuilderStore>)\n ) => void,\n get: () => AnalysisBuilderStore\n): CrossSliceActions {\n return {\n reset: () => {\n // Reset to default state using slice initializers\n set({\n ...createInitialCoreState(),\n ...createInitialQueryState(),\n ...createInitialFunnelState(),\n ...createInitialFlowState(),\n ...createInitialRetentionState(),\n // Apply adapter defaults for charts (may differ from slice defaults)\n charts: {\n query: queryModeAdapter.getDefaultChartConfig(),\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n flow: flowModeAdapter.getDefaultChartConfig(),\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n activeViews: {\n query: 'chart',\n funnel: 'chart',\n flow: 'chart',\n retention: 'chart',\n },\n } as Partial<AnalysisBuilderStore>)\n },\n\n clearCurrentMode: () =>\n set((state) => {\n switch (state.analysisType) {\n case 'funnel':\n // Use slice initializer for funnel state\n return {\n ...createInitialFunnelState(),\n charts: {\n ...state.charts,\n funnel: funnelModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'flow':\n // Use slice initializer for flow state\n return {\n ...createInitialFlowState(),\n charts: {\n ...state.charts,\n flow: flowModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'retention':\n // Use slice initializer for retention state\n return {\n ...createInitialRetentionState(),\n charts: {\n ...state.charts,\n retention: retentionModeAdapter.getDefaultChartConfig(),\n },\n }\n case 'query':\n default:\n // Use slice initializer for query state\n return {\n ...createInitialQueryState(),\n userManuallySelectedChart: false,\n charts: {\n ...state.charts,\n query: queryModeAdapter.getDefaultChartConfig(),\n },\n }\n }\n }),\n\n clearQuery: () =>\n set((state) => {\n const newStates = [...state.queryStates]\n newStates[state.activeQueryIndex] = createInitialState()\n return {\n queryStates: newStates,\n userManuallySelectedChart: false,\n charts: {\n ...state.charts,\n query: queryModeAdapter.getDefaultChartConfig(),\n },\n }\n }),\n\n getValidation: () => {\n const state = get()\n const adapter = adapterRegistry.get(state.analysisType)\n\n // Use adapter's extractState method for mode-specific state\n const modeState = adapter.extractState(state as unknown as Record<string, unknown>)\n\n return adapter.validate(modeState)\n },\n }\n}\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\n/**\n * Create a new store instance with optional persistence.\n * Composes slices: coreSlice, querySlice, funnelSlice, uiSlice.\n */\nexport function createAnalysisBuilderStore(options: CreateStoreOptions = {}) {\n // Convert options to AnalysisConfig for loading\n const initialConfig = optionsToAnalysisConfig(options)\n\n // Store creator function that composes all slices\n const storeCreator = (\n set: (\n partial:\n | Partial<AnalysisBuilderStore>\n | ((state: AnalysisBuilderStore) => Partial<AnalysisBuilderStore>)\n ) => void,\n get: () => AnalysisBuilderStore,\n store: StoreApi<AnalysisBuilderStore>\n ) => ({\n // Compose slices - they provide default state and actions\n ...createCoreSlice(set, get, store),\n ...createQuerySlice(set, get, store),\n ...createFunnelSlice(set, get, store),\n ...createFlowSlice(set, get, store),\n ...createRetentionSlice(set, get, store),\n ...createUISlice(set, get, store),\n\n // Cross-slice actions\n ...createCrossSliceActions(set, get),\n })\n\n // Create store with or without persistence\n if (options.disableLocalStorage) {\n // No persistence - for modal/portlet editing\n const store = createStore<AnalysisBuilderStore>()(\n devtools(subscribeWithSelector(storeCreator), {\n name: 'AnalysisBuilderStore (no-persist)',\n })\n )\n\n // Apply initial config if provided\n if (initialConfig) {\n store.getState().load(initialConfig)\n }\n\n return store\n }\n\n // With persistence - for standalone mode\n return createStore<AnalysisBuilderStore>()(\n devtools(\n subscribeWithSelector(\n persist(storeCreator, {\n name: STORAGE_KEY,\n // Use workspace format to preserve ALL modes' state\n partialize: (state) => state.saveWorkspace(),\n merge: (persisted, current) => {\n // Try workspace format first (new format)\n if (persisted && isValidAnalysisWorkspace(persisted)) {\n return {\n ...current,\n _persistedWorkspace: persisted,\n } as typeof current\n }\n // Backward compat: single AnalysisConfig (migrate to workspace on next save)\n if (persisted && isValidAnalysisConfig(persisted)) {\n return {\n ...current,\n _persistedConfig: persisted,\n } as typeof current\n }\n // Invalid/legacy format - use current (fresh start)\n // Also preserve initialConfig to apply if provided\n if (initialConfig) {\n return {\n ...current,\n _initialConfig: initialConfig,\n } as typeof current\n }\n return current\n },\n onRehydrateStorage: () => (state) => {\n // After rehydration, call loadWorkspace/load with persisted or initial config\n if (state) {\n if ((state as any)._persistedWorkspace) {\n // New workspace format - load all modes\n const workspace = (state as any)._persistedWorkspace as AnalysisWorkspace\n delete (state as any)._persistedWorkspace\n delete (state as any)._persistedConfig\n delete (state as any)._initialConfig\n state.loadWorkspace(workspace)\n } else if ((state as any)._persistedConfig) {\n // Legacy single-mode format - load only that mode\n // Will be migrated to workspace on next save\n const config = (state as any)._persistedConfig\n delete (state as any)._persistedConfig\n delete (state as any)._initialConfig\n state.load(config)\n } else if ((state as any)._initialConfig) {\n const config = (state as any)._initialConfig\n delete (state as any)._initialConfig\n state.load(config)\n }\n }\n },\n })\n ),\n { name: 'AnalysisBuilderStore' }\n )\n )\n}\n\n// ============================================================================\n// React Context & Provider\n// ============================================================================\n\n/**\n * Context for the store instance\n */\nconst AnalysisBuilderStoreContext = createContext<StoreApi<AnalysisBuilderStore> | null>(null)\n\n/**\n * Provider props\n */\nexport interface AnalysisBuilderStoreProviderProps {\n children: ReactNode\n /** Initial query configuration */\n initialQuery?: CubeQuery | MultiQueryConfig\n /** Initial chart configuration */\n initialChartConfig?: {\n chartType?: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n }\n /** Disable localStorage persistence */\n disableLocalStorage?: boolean\n /** Initial analysis type (query or funnel) */\n initialAnalysisType?: AnalysisType\n /** Initial funnel state (when analysisType === 'funnel') */\n initialFunnelState?: InitialFunnelState\n /** Initial flow state (when analysisType === 'flow') */\n initialFlowState?: InitialFlowState\n /** Initial retention state (when analysisType === 'retention') */\n initialRetentionState?: InitialRetentionState\n /** Initial active view (table or chart) - used to prevent flash when loading from share */\n initialActiveView?: 'table' | 'chart'\n}\n\n/**\n * Provider component that creates a store instance per AnalysisBuilder\n */\nexport function AnalysisBuilderStoreProvider({\n children,\n initialQuery,\n initialChartConfig,\n disableLocalStorage,\n initialAnalysisType,\n initialFunnelState,\n initialFlowState,\n initialRetentionState,\n initialActiveView,\n}: AnalysisBuilderStoreProviderProps) {\n // Create store instance once per provider mount\n const storeRef = useRef<StoreApi<AnalysisBuilderStore> | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createAnalysisBuilderStore({\n initialQuery,\n initialChartConfig,\n disableLocalStorage,\n initialAnalysisType,\n initialFunnelState,\n initialFlowState,\n initialRetentionState,\n initialActiveView,\n })\n }\n\n return (\n <AnalysisBuilderStoreContext.Provider value={storeRef.current}>\n {children}\n </AnalysisBuilderStoreContext.Provider>\n )\n}\n\n/**\n * Hook to access the store from context\n * @throws Error if used outside of provider\n */\nexport function useAnalysisBuilderStore<T>(selector: (state: AnalysisBuilderStore) => T): T {\n const store = useContext(AnalysisBuilderStoreContext)\n if (!store) {\n throw new Error('useAnalysisBuilderStore must be used within AnalysisBuilderStoreProvider')\n }\n return useStore(store, selector)\n}\n\n/**\n * Hook to get the raw store API (for actions that need direct access)\n */\nexport function useAnalysisBuilderStoreApi(): StoreApi<AnalysisBuilderStore> {\n const store = useContext(AnalysisBuilderStoreContext)\n if (!store) {\n throw new Error('useAnalysisBuilderStoreApi must be used within AnalysisBuilderStoreProvider')\n }\n return store\n}\n\n// ============================================================================\n// Selectors (for optimized re-renders)\n// ============================================================================\n\n/**\n * Select current query state\n */\nexport const selectCurrentState = (state: AnalysisBuilderStore) =>\n state.queryStates[state.activeQueryIndex] || createInitialState()\n\n/**\n * Select current metrics\n */\nexport const selectMetrics = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).metrics\n\n/**\n * Select current breakdowns\n */\nexport const selectBreakdowns = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).breakdowns\n\n/**\n * Select current filters\n */\nexport const selectFilters = (state: AnalysisBuilderStore) =>\n selectCurrentState(state).filters\n\n/**\n * Select current chart config from the charts map (NEW - Phase 2)\n * This is the preferred way to access chart configuration.\n * Falls back to default chart config if mode's config is missing.\n */\nexport const selectCurrentChartConfig = (state: AnalysisBuilderStore): ChartConfig => {\n const config = state.charts[state.analysisType]\n if (config) return config\n\n // Fallback to adapter default (shouldn't happen in normal usage)\n return adapterRegistry.get(state.analysisType).getDefaultChartConfig()\n}\n\n/**\n * Select chart type from current mode's chart config\n */\nexport const selectChartType = (state: AnalysisBuilderStore): ChartType =>\n selectCurrentChartConfig(state).chartType\n\n/**\n * Select chart axis config from current mode's chart config\n */\nexport const selectChartAxisConfig = (state: AnalysisBuilderStore): ChartAxisConfig =>\n selectCurrentChartConfig(state).chartConfig\n\n/**\n * Select display config from current mode's chart config\n */\nexport const selectChartDisplayConfig = (state: AnalysisBuilderStore): ChartDisplayConfig =>\n selectCurrentChartConfig(state).displayConfig\n\n/**\n * Select chart configuration (returns mode-appropriate config)\n * @deprecated Use selectCurrentChartConfig instead (reads from charts map)\n */\nexport const selectChartConfig = (state: AnalysisBuilderStore) => {\n // Use charts map (Phase 2 approach)\n const config = state.charts[state.analysisType]\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n\n // No fallback - charts map is the source of truth (Phase 4 cleanup)\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select query mode chart configuration (always returns query mode config)\n */\nexport const selectQueryModeChartConfig = (state: AnalysisBuilderStore) => {\n // charts map is the source of truth (Phase 4 cleanup)\n const config = state.charts.query\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'bar' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select funnel mode chart configuration (always returns funnel mode config)\n */\nexport const selectFunnelModeChartConfig = (state: AnalysisBuilderStore) => {\n // charts map is the source of truth (Phase 4 cleanup)\n const config = state.charts.funnel\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n // Return defaults if config is missing (shouldn't happen in practice)\n return {\n chartType: 'funnel' as const,\n chartConfig: {},\n displayConfig: { showLegend: true, showGrid: true, showTooltip: true },\n }\n}\n\n/**\n * Select UI state\n */\nexport const selectUIState = (state: AnalysisBuilderStore) => ({\n activeTab: state.activeTab,\n activeView: state.activeView,\n displayLimit: state.displayLimit,\n showFieldModal: state.showFieldModal,\n fieldModalMode: state.fieldModalMode,\n})\n\n/**\n * Select analysis type\n */\nexport const selectAnalysisType = (state: AnalysisBuilderStore) => state.analysisType\n\n/**\n * Select multi-query state\n */\nexport const selectMultiQueryState = (state: AnalysisBuilderStore) => ({\n queryStates: state.queryStates,\n activeQueryIndex: state.activeQueryIndex,\n mergeStrategy: state.mergeStrategy,\n // Multi-query mode is when we have more than one query in 'query' analysis type\n isMultiQueryMode: state.analysisType === 'query' && state.queryStates.length > 1,\n})\n\n/**\n * Select funnel cube\n */\nexport const selectFunnelCube = (state: AnalysisBuilderStore) => state.funnelCube\n\n/**\n * Select funnel state (new dedicated state)\n */\nexport const selectFunnelState = (state: AnalysisBuilderStore) => ({\n funnelCube: state.funnelCube,\n funnelSteps: state.funnelSteps,\n activeFunnelStepIndex: state.activeFunnelStepIndex,\n funnelTimeDimension: state.funnelTimeDimension,\n funnelBindingKey: state.funnelBindingKey,\n isFunnelMode: state.analysisType === 'funnel',\n // Deprecated field kept for backward compat\n stepTimeToConvert: state.stepTimeToConvert,\n})\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, QueryMergeStrategy } 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' and 'funnel' strategies: only warnings\n */\nexport function validateMultiQueryConfig(\n queries: CubeQuery[],\n mergeStrategy: QueryMergeStrategy,\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 * useAnalysisQueryBuilder\n *\n * Builds and validates queries from Zustand store state.\n * Handles single-query and multi-query modes.\n */\n\nimport { useMemo } from 'react'\nimport { useAnalysisBuilderStore } from '../stores/analysisBuilderStore'\nimport { validateMultiQueryConfig, type MultiQueryValidationResult } from '../utils/multiQueryValidation'\nimport { buildCubeQuery } from '../components/AnalysisBuilder/utils'\nimport type { CubeQuery, MultiQueryConfig, QueryMergeStrategy } from '../types'\nimport type { AnalysisBuilderState } from '../components/AnalysisBuilder/types'\n\nexport interface UseAnalysisQueryBuilderResult {\n /** Current query state (active query) */\n queryState: AnalysisBuilderState\n /** All query states (for multi-query mode) */\n queryStates: AnalysisBuilderState[]\n /** Active query index */\n activeQueryIndex: number\n /** Merge strategy for multi-query */\n mergeStrategy: QueryMergeStrategy\n /** Whether in multi-query mode */\n isMultiQueryMode: boolean\n /** Merge keys (computed from Q1 breakdowns) */\n mergeKeys: string[] | undefined\n /** Current query as CubeQuery */\n currentQuery: CubeQuery\n /** All queries as CubeQuery[] */\n allQueries: CubeQuery[]\n /** MultiQueryConfig (if in multi-query mode) */\n multiQueryConfig: MultiQueryConfig | null\n /** Multi-query validation result */\n multiQueryValidation: MultiQueryValidationResult | null\n /** Whether current query is valid */\n isValidQuery: boolean | undefined\n\n // Actions\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n addQuery: () => void\n removeQuery: (index: number) => void\n}\n\nexport function useAnalysisQueryBuilder(): UseAnalysisQueryBuilderResult {\n // Store state\n const queryStates = useAnalysisBuilderStore((state) => state.queryStates)\n const activeQueryIndex = useAnalysisBuilderStore((state) => state.activeQueryIndex)\n const mergeStrategy = useAnalysisBuilderStore((state) => state.mergeStrategy)\n\n // Store actions\n const setActiveQueryIndex = useAnalysisBuilderStore((state) => state.setActiveQueryIndex)\n const setMergeStrategy = useAnalysisBuilderStore((state) => state.setMergeStrategy)\n const addQuery = useAnalysisBuilderStore((state) => state.addQuery)\n const removeQuery = useAnalysisBuilderStore((state) => state.removeQuery)\n\n // Store getters\n const getCurrentState = useAnalysisBuilderStore((state) => state.getCurrentState)\n const getMergeKeys = useAnalysisBuilderStore((state) => state.getMergeKeys)\n const isMultiQueryModeGetter = useAnalysisBuilderStore((state) => state.isMultiQueryMode)\n // Derived state\n const queryState = getCurrentState()\n const isMultiQueryMode = isMultiQueryModeGetter()\n const mergeKeys = getMergeKeys()\n\n // Build current query from active state\n const currentQuery = useMemo(() => {\n const current = queryStates[activeQueryIndex] || queryState\n return buildCubeQuery(current.metrics, current.breakdowns, current.filters, current.order)\n }, [queryStates, activeQueryIndex, queryState])\n\n // Build all queries (respect merge mode for shared breakdowns)\n const allQueries = useMemo(() => {\n const q1Breakdowns = queryStates[0]?.breakdowns || []\n return queryStates.map((qs, index) => {\n const breakdowns = mergeStrategy === 'merge' && index > 0 ? q1Breakdowns : qs.breakdowns\n return buildCubeQuery(qs.metrics, breakdowns, qs.filters, qs.order)\n })\n }, [queryStates, mergeStrategy])\n\n // Build multi-query config from queries\n const multiQueryConfig = useMemo(() => {\n if (queryStates.length <= 1) return null\n\n // Filter to queries that have at least one measure, dimension, or time dimension\n // Note: Legacy mergeStrategy === 'funnel' is no longer supported\n const validQueries = allQueries.filter((q) => {\n return (\n (q.measures && q.measures.length > 0) ||\n (q.dimensions && q.dimensions.length > 0) ||\n (q.timeDimensions && q.timeDimensions.length > 0)\n )\n })\n\n if (validQueries.length < 2) return null\n\n return {\n queries: validQueries,\n mergeStrategy,\n mergeKeys,\n queryLabels: validQueries.map((_, i) => `Q${i + 1}`),\n }\n }, [allQueries, queryStates.length, mergeStrategy, mergeKeys])\n\n // Validate multi-query configuration\n const multiQueryValidation = useMemo((): MultiQueryValidationResult | null => {\n if (!isMultiQueryMode) return null\n return validateMultiQueryConfig(allQueries, mergeStrategy, mergeKeys || [])\n }, [isMultiQueryMode, allQueries, mergeStrategy, mergeKeys])\n\n // Check if query is valid\n const isValidQuery = useMemo(() => {\n return (\n (currentQuery.measures && currentQuery.measures.length > 0) ||\n (currentQuery.dimensions && currentQuery.dimensions.length > 0) ||\n (currentQuery.timeDimensions && currentQuery.timeDimensions.length > 0)\n )\n }, [currentQuery])\n\n return {\n queryState,\n queryStates,\n activeQueryIndex,\n mergeStrategy,\n isMultiQueryMode,\n mergeKeys,\n currentQuery,\n allQueries,\n multiQueryConfig,\n multiQueryValidation,\n isValidQuery,\n\n // Actions\n setActiveQueryIndex,\n setMergeStrategy,\n addQuery,\n removeQuery,\n }\n}\n","/**\n * useAnalysisCombinedFields\n *\n * Computes combined metrics and breakdowns from all queries in multi-query mode.\n * In single-query mode, returns the current query's metrics and breakdowns.\n */\n\nimport { useMemo } from 'react'\nimport type { AnalysisBuilderState, MetricItem, BreakdownItem } from '../components/AnalysisBuilder/types'\nimport type { QueryMergeStrategy } from '../types'\n\nexport interface UseAnalysisCombinedFieldsOptions {\n queryState: AnalysisBuilderState\n queryStates: AnalysisBuilderState[]\n isMultiQueryMode: boolean\n mergeStrategy: QueryMergeStrategy\n activeQueryIndex: number\n}\n\nexport interface UseAnalysisCombinedFieldsResult {\n /** Combined metrics from all queries (for chart config) */\n combinedMetrics: MetricItem[]\n /** Combined breakdowns from all queries (for chart config) */\n combinedBreakdowns: BreakdownItem[]\n /** Effective breakdowns for display (Q1's in merge mode, otherwise current query's) */\n effectiveBreakdowns: BreakdownItem[]\n}\n\nexport function useAnalysisCombinedFields(\n options: UseAnalysisCombinedFieldsOptions\n): UseAnalysisCombinedFieldsResult {\n const { queryState, queryStates, isMultiQueryMode, mergeStrategy, activeQueryIndex } = options\n\n // Combined metrics from all queries\n const combinedMetrics = useMemo(() => {\n if (!isMultiQueryMode) return queryState.metrics\n const seen = new Set<string>()\n const combined: MetricItem[] = []\n for (let qIndex = 0; qIndex < queryStates.length; qIndex++) {\n const qs = queryStates[qIndex]\n for (const metric of qs.metrics) {\n const key = `Q${qIndex + 1}:${metric.field}`\n if (!seen.has(key)) {\n seen.add(key)\n combined.push({\n ...metric,\n label: `${metric.label} (Q${qIndex + 1})`,\n })\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, queryState.metrics])\n\n // Combined breakdowns from all queries\n const combinedBreakdowns = useMemo(() => {\n if (!isMultiQueryMode) return queryState.breakdowns\n const seen = new Set<string>()\n const combined: BreakdownItem[] = []\n for (const qs of queryStates) {\n for (const breakdown of qs.breakdowns) {\n if (!seen.has(breakdown.field)) {\n seen.add(breakdown.field)\n combined.push(breakdown)\n }\n }\n }\n return combined\n }, [isMultiQueryMode, queryStates, queryState.breakdowns])\n\n // Effective breakdowns for the current view\n // In merge mode, Q2+ should visually show Q1's breakdowns since they're shared\n const effectiveBreakdowns = useMemo(() => {\n if (mergeStrategy === 'merge' && activeQueryIndex > 0) {\n // Show Q1's breakdowns for Q2+ in merge mode\n return queryStates[0]?.breakdowns || []\n }\n return queryState.breakdowns\n }, [mergeStrategy, activeQueryIndex, queryStates, queryState.breakdowns])\n\n return {\n combinedMetrics,\n combinedBreakdowns,\n effectiveBreakdowns,\n }\n}\n","/**\n * useAnalysisQueryExecution\n *\n * Coordinates TanStack Query execution for single, multi-query, and funnel modes.\n * Provides unified loading states, results, and refetch functionality.\n */\n\nimport { useMemo, useCallback } from 'react'\nimport {\n useCubeLoadQuery,\n useMultiCubeLoadQuery,\n useFunnelQuery,\n useFlowQuery,\n useRetentionQuery,\n useDryRunQuery,\n useDryRunQueries,\n type DebugDataEntry,\n} from './queries'\nimport { useCubeMeta } from '../providers/CubeProvider'\nimport type { CubeQuery, MultiQueryConfig, FunnelBindingKey, QueryMergeStrategy, AnalysisType } from '../types'\nimport type { ExecutionStatus } from '../components/AnalysisBuilder/types'\nimport type { ServerFunnelQuery } from '../types/funnel'\nimport type { ServerFlowQuery, FlowChartData } from '../types/flow'\nimport type { ServerRetentionQuery, RetentionChartData } from '../types/retention'\nimport { buildFunnelConfigFromQueries } from '../utils/funnelExecution'\n\nexport interface UseAnalysisQueryExecutionOptions {\n /** Current query (for single-query mode) */\n currentQuery: CubeQuery\n /** All queries (for dry-run and multi-query) */\n allQueries: CubeQuery[]\n /** Multi-query config (null if single-query mode) */\n multiQueryConfig: MultiQueryConfig | null\n /** Whether in multi-query mode */\n isMultiQueryMode: boolean\n /** Whether current query is valid */\n isValidQuery: boolean\n /** Initial data (skip first fetch) */\n initialData?: unknown[]\n /** Merge strategy (for detecting funnel mode - legacy) */\n mergeStrategy?: QueryMergeStrategy\n /** Funnel binding key (required for funnel mode) */\n funnelBindingKey?: FunnelBindingKey | null\n /**\n * Whether funnel mode is properly configured (from store).\n * This includes filter-only step validation that isMultiQueryMode doesn't provide.\n * @deprecated Use analysisType === 'funnel' instead\n */\n isFunnelModeEnabled?: boolean\n /**\n * Analysis type for explicit mode routing.\n * When provided, takes precedence over legacy mode detection.\n */\n analysisType?: AnalysisType\n /**\n * Pre-built server funnel query from store's buildFunnelQueryFromSteps().\n * Used when analysisType === 'funnel' with the new dedicated funnel state.\n */\n serverFunnelQuery?: ServerFunnelQuery | null\n /**\n * Pre-built server flow query from store's buildFlowQuery().\n * Used when analysisType === 'flow' with the new dedicated flow state.\n */\n serverFlowQuery?: ServerFlowQuery | null\n /**\n * Pre-built server retention query from store's buildRetentionQuery().\n * Used when analysisType === 'retention' with the new dedicated retention state.\n */\n serverRetentionQuery?: ServerRetentionQuery | null\n /**\n * Validation result for retention mode from store's getRetentionValidation().\n * Used to display specific errors in the debug panel.\n */\n retentionValidation?: { isValid: boolean; errors: string[]; warnings: string[] } | null\n}\n\nexport interface UseAnalysisQueryExecutionResult {\n /** Query execution status */\n executionStatus: ExecutionStatus\n /** Query results (merged for multi-query) */\n executionResults: unknown[] | null\n /** Per-query results (for table view in multi-query mode) */\n perQueryResults: (unknown[] | null)[] | null\n /** Whether query is loading */\n isLoading: boolean\n /** Whether query is fetching (includes refetch) */\n isFetching: boolean\n /** Query error */\n error: Error | null\n /** Debug data per query (for non-funnel modes) */\n debugDataPerQuery: DebugDataEntry[]\n /** Whether query has been debounced (for smart defaults trigger) */\n hasDebounced: boolean\n /** Refetch function. Pass { bustCache: true } to bypass client and server caches. */\n refetch: (options?: { bustCache?: boolean }) => void\n /**\n * In funnel mode, these are the actually executed queries with:\n * - Binding key dimension auto-added\n * - IN filter applied for steps 2+\n * Use these for debug display instead of the original queries.\n * @deprecated Server-side funnel uses a unified query. Use funnelServerQuery instead.\n */\n funnelExecutedQueries: CubeQuery[] | null\n /**\n * The actual server funnel query { funnel: {...} }\n * This is the unified query sent to the server (not per-step queries).\n */\n funnelServerQuery: ServerFunnelQuery | null\n /**\n * Debug data specifically for funnel mode\n * Contains unified dry-run SQL and mode metadata.\n */\n funnelDebugData: DebugDataEntry | null\n /**\n * The server flow query being executed (when analysisType === 'flow')\n */\n flowServerQuery: ServerFlowQuery | null\n /**\n * Flow chart data (nodes and links for Sankey visualization)\n */\n flowChartData: FlowChartData | null\n /**\n * Debug data specifically for flow mode\n * Contains unified dry-run SQL and mode metadata.\n */\n flowDebugData: DebugDataEntry | null\n /**\n * The server retention query being executed (when analysisType === 'retention')\n */\n retentionServerQuery: ServerRetentionQuery | null\n /**\n * Retention chart data (cohort × period matrix)\n */\n retentionChartData: RetentionChartData | null\n /**\n * Debug data specifically for retention mode\n * Contains unified dry-run SQL and mode metadata.\n */\n retentionDebugData: DebugDataEntry | null\n /**\n * Retention validation result (errors explaining why query cannot be built)\n */\n retentionValidation: { isValid: boolean; errors: string[]; warnings: string[] } | null\n /**\n * Whether the current query config differs from the last executed query.\n * Used for manual refresh mode to show \"needs refresh\" indicator.\n */\n needsRefresh: boolean\n /**\n * Query warnings from the server (e.g., fan-out without dimensions).\n * Displayed as a banner above results.\n */\n warnings: import('../shared/types').QueryWarning[] | undefined\n}\n\nexport function useAnalysisQueryExecution(\n options: UseAnalysisQueryExecutionOptions\n): UseAnalysisQueryExecutionResult {\n const {\n currentQuery,\n allQueries,\n multiQueryConfig,\n isMultiQueryMode,\n isValidQuery,\n initialData,\n mergeStrategy: _mergeStrategy, // Unused - legacy mergeStrategy === 'funnel' is no longer supported\n funnelBindingKey,\n isFunnelModeEnabled,\n analysisType,\n serverFunnelQuery,\n serverFlowQuery,\n serverRetentionQuery,\n retentionValidation,\n } = options\n\n // Get field label resolver from cube context (for human-readable labels)\n const { getFieldLabel } = useCubeMeta()\n\n // Determine execution mode based on analysisType\n // Note: Legacy mergeStrategy === 'funnel' is no longer supported\n // Funnel mode is now exclusively determined by analysisType === 'funnel'\n const isFunnelMode = analysisType === 'funnel' || isFunnelModeEnabled\n\n // Flow mode is exclusively determined by analysisType === 'flow'\n const isFlowMode = analysisType === 'flow'\n\n // Retention mode is exclusively determined by analysisType === 'retention'\n const isRetentionMode = analysisType === 'retention'\n\n // Multi mode is 'query' analysis type with multiple queries\n const isMultiMode = analysisType === 'query' && isMultiQueryMode\n\n // Single mode is 'query' analysis type without multiple queries\n const isSingleMode = analysisType === 'query' && !isMultiQueryMode\n\n // Check if we're using the new dedicated funnel mode (with serverFunnelQuery)\n const isNewFunnelMode = analysisType === 'funnel' && !!serverFunnelQuery\n\n // Build funnel config when in funnel mode (legacy - from queryStates)\n // Skip when using new dedicated funnel mode with serverFunnelQuery\n const funnelConfig = useMemo(() => {\n // If using new funnel mode with prebuilt query, skip legacy config building\n if (isNewFunnelMode) return null\n if (!isFunnelMode || !funnelBindingKey || allQueries.length < 2) return null\n return buildFunnelConfigFromQueries(allQueries, funnelBindingKey)\n }, [isNewFunnelMode, isFunnelMode, funnelBindingKey, allQueries])\n\n // Single query execution (only when analysisType is 'query' or legacy single mode)\n const singleQueryResult = useCubeLoadQuery(currentQuery, {\n skip: !isValidQuery || !isSingleMode,\n debounceMs: 300,\n })\n\n // Multi-query execution (only when analysisType is 'multi' or legacy multi mode)\n const multiQueryResult = useMultiCubeLoadQuery(multiQueryConfig, {\n skip: !multiQueryConfig || !isMultiMode,\n debounceMs: 300,\n })\n\n // Funnel query execution\n // Use prebuiltServerQuery when in new funnel mode, otherwise use funnelConfig\n const funnelQueryResult = useFunnelQuery(funnelConfig, {\n skip: !isFunnelMode || (!funnelConfig && !serverFunnelQuery),\n debounceMs: 300,\n prebuiltServerQuery: isNewFunnelMode ? serverFunnelQuery : undefined,\n })\n\n // Flow query execution\n const flowQueryResult = useFlowQuery(serverFlowQuery ?? null, {\n skip: !isFlowMode || !serverFlowQuery,\n debounceMs: 300,\n })\n\n // Retention query execution\n const retentionQueryResult = useRetentionQuery(serverRetentionQuery ?? null, {\n skip: !isRetentionMode || !serverRetentionQuery,\n debounceMs: 300,\n getFieldLabel, // Pass label resolver for human-readable binding key display\n })\n\n // Dry-run queries for debug data (skip in funnel, flow, and retention mode)\n const dryRunResult = useDryRunQueries({\n queries: isMultiQueryMode ? allQueries : [currentQuery],\n isMultiQueryMode,\n skip: !isValidQuery || isFunnelMode || isFlowMode || isRetentionMode,\n })\n\n // Funnel dry-run query (only in funnel mode)\n // Use the serverQuery from useFunnelQuery to get the unified funnel SQL\n const funnelDryRunResult = useDryRunQuery(\n funnelQueryResult.serverQuery as CubeQuery | null,\n { skip: !isFunnelMode || !funnelQueryResult.serverQuery }\n )\n\n // Flow dry-run query (only in flow mode)\n // Use the serverQuery from useFlowQuery to get the unified flow SQL\n const flowDryRunResult = useDryRunQuery(\n flowQueryResult.serverQuery as CubeQuery | null,\n { skip: !isFlowMode || !flowQueryResult.serverQuery }\n )\n\n // Retention dry-run query (only in retention mode)\n // Use the serverRetentionQuery input to get the unified retention SQL\n const retentionDryRunResult = useDryRunQuery(\n serverRetentionQuery as CubeQuery | null,\n { skip: !isRetentionMode || !serverRetentionQuery }\n )\n\n // Unify results based on mode\n const isLoading = isRetentionMode\n ? retentionQueryResult.isLoading || retentionQueryResult.isDebouncing\n : isFlowMode\n ? flowQueryResult.isLoading || flowQueryResult.isDebouncing\n : isFunnelMode\n ? funnelQueryResult.isExecuting || funnelQueryResult.isDebouncing\n : isMultiMode\n ? multiQueryResult.isLoading\n : singleQueryResult.isLoading\n const isFetching = isRetentionMode\n ? retentionQueryResult.isFetching\n : isFlowMode\n ? flowQueryResult.isFetching\n : isFunnelMode\n ? funnelQueryResult.isExecuting\n : isMultiMode\n ? multiQueryResult.isFetching\n : singleQueryResult.isFetching\n const error = isRetentionMode\n ? retentionQueryResult.error\n : isFlowMode\n ? flowQueryResult.error\n : isFunnelMode\n ? funnelQueryResult.error\n : isMultiMode\n ? multiQueryResult.error\n : singleQueryResult.error\n\n // Has debounced (for smart defaults trigger)\n const hasDebounced = Boolean(\n singleQueryResult.debouncedQuery ||\n multiQueryResult.debouncedConfig ||\n !funnelQueryResult.isDebouncing || // Funnel has debounced when not debouncing\n !flowQueryResult.isDebouncing || // Flow has debounced when not debouncing\n !retentionQueryResult.isDebouncing // Retention has debounced when not debouncing\n )\n\n // Unified refetch function\n // Pass options (including bustCache) through to underlying hooks\n const refetch = useCallback((options?: { bustCache?: boolean }) => {\n if (isRetentionMode) {\n // Retention uses execute for bustCache support\n retentionQueryResult.execute(options)\n } else if (isFlowMode) {\n flowQueryResult.refetch(options)\n } else if (isFunnelMode) {\n funnelQueryResult.execute(options)\n } else if (isMultiMode) {\n multiQueryResult.refetch(options)\n } else {\n singleQueryResult.refetch(options)\n }\n }, [isRetentionMode, isFlowMode, isFunnelMode, isMultiMode, retentionQueryResult, flowQueryResult, funnelQueryResult, multiQueryResult, singleQueryResult])\n\n // Execution status\n const executionStatus: ExecutionStatus = useMemo(() => {\n const hasResults = isRetentionMode\n ? retentionQueryResult.chartData\n : isFlowMode\n ? flowQueryResult.data\n : isFunnelMode\n ? funnelQueryResult.chartData\n : isMultiMode\n ? multiQueryResult.data\n : singleQueryResult.rawData\n if (initialData && initialData.length > 0 && !hasResults) return 'success'\n if (!isValidQuery) return 'idle'\n if (isLoading && !hasResults) return 'loading'\n if (isFetching && hasResults) return 'refreshing'\n if (error) return 'error'\n if (hasResults) return 'success'\n return 'idle'\n }, [isValidQuery, isLoading, isFetching, error, singleQueryResult.rawData, multiQueryResult.data, funnelQueryResult.chartData, flowQueryResult.data, retentionQueryResult.chartData, initialData, isMultiMode, isFunnelMode, isFlowMode, isRetentionMode])\n\n // Execution results\n const executionResults = useMemo(() => {\n // Retention mode returns transformed flat data for chart compatibility\n if (isRetentionMode && retentionQueryResult.chartData) {\n // Transform RetentionChartData to flat rows\n // Format: [{ \"Retention.period\": \"P0\", \"Retention.rate\": 0.45, \"Retention.segment\": \"US\", ... }]\n return retentionQueryResult.chartData.rows.map(row => ({\n 'Retention.period': `P${row.period}`,\n 'Retention.rate': row.retentionRate,\n 'Retention.retained': row.retainedUsers,\n 'Retention.cohortSize': row.cohortSize,\n 'Retention.segment': row.breakdownValue || 'All Users',\n })) as unknown[]\n }\n // Flow mode returns Sankey chart data directly\n if (isFlowMode && flowQueryResult.data) {\n // Wrap in array for consistency with other modes\n return [flowQueryResult.data] as unknown[]\n }\n // Funnel mode returns chart data directly\n if (isFunnelMode && funnelQueryResult.chartData) {\n return funnelQueryResult.chartData as unknown[]\n }\n if (isMultiMode && multiQueryResult.data) {\n return multiQueryResult.data as unknown[]\n }\n if (singleQueryResult.rawData) {\n return singleQueryResult.rawData\n }\n if (initialData && initialData.length > 0) {\n return initialData\n }\n return null\n }, [singleQueryResult.rawData, multiQueryResult.data, funnelQueryResult.chartData, flowQueryResult.data, retentionQueryResult.chartData, initialData, isMultiMode, isFunnelMode, isFlowMode, isRetentionMode])\n\n // Per-query results for table view (or per-step for funnel)\n const perQueryResults = useMemo(() => {\n // In funnel mode, return step results as per-query data\n if (isFunnelMode && funnelQueryResult.stepResults) {\n return funnelQueryResult.stepResults.map((step) => step.data)\n }\n if (!isMultiMode || !multiQueryResult.perQueryData) return null\n return multiQueryResult.perQueryData\n }, [isMultiMode, isFunnelMode, multiQueryResult.perQueryData, funnelQueryResult.stepResults])\n\n // In funnel mode, provide the executed queries for debug display (legacy)\n const funnelExecutedQueries = isFunnelMode && funnelQueryResult.executedQueries?.length > 0\n ? funnelQueryResult.executedQueries\n : null\n\n // The actual server funnel query (new, preferred)\n const funnelServerQuery = isFunnelMode ? funnelQueryResult.serverQuery : null\n\n // Funnel debug data (unified SQL for funnel mode)\n const funnelDebugData = isFunnelMode ? funnelDryRunResult.debugData : null\n\n // Flow-related values\n const flowServerQuery = isFlowMode ? flowQueryResult.serverQuery : null\n const flowChartData = isFlowMode ? flowQueryResult.data : null\n\n // Flow debug data (unified SQL for flow mode)\n const flowDebugData = isFlowMode ? flowDryRunResult.debugData : null\n\n // Retention-related values\n const retentionServerQuery = isRetentionMode ? (serverRetentionQuery ?? null) : null\n const retentionChartData = isRetentionMode ? retentionQueryResult.chartData : null\n\n // Retention debug data (unified SQL for retention mode)\n const retentionDebugData = isRetentionMode ? retentionDryRunResult.debugData : null\n\n // Aggregate needsRefresh from the appropriate mode hook\n // This determines if the \"needs refresh\" banner should be shown\n // Note: Multi-query mode doesn't have needsRefresh yet (falls back to false)\n const needsRefresh = useMemo(() => {\n if (isRetentionMode) return retentionQueryResult.needsRefresh\n if (isFlowMode) return flowQueryResult.needsRefresh\n if (isFunnelMode) return funnelQueryResult.needsRefresh\n if (isMultiMode) return false // Multi-query mode doesn't support manual refresh yet\n return singleQueryResult.needsRefresh\n }, [isRetentionMode, isFlowMode, isFunnelMode, isMultiMode, retentionQueryResult.needsRefresh, flowQueryResult.needsRefresh, funnelQueryResult.needsRefresh, singleQueryResult.needsRefresh])\n\n // Aggregate warnings from the appropriate mode hook\n // Currently only supported for single-query mode (where useCubeLoadQuery exposes warnings)\n const warnings = useMemo(() => {\n // Single query mode has warnings from useCubeLoadQuery\n if (isSingleMode && singleQueryResult.warnings) {\n return singleQueryResult.warnings\n }\n // TODO: Add warnings support for multi-query, funnel, flow, and retention modes\n return undefined\n }, [isSingleMode, singleQueryResult.warnings])\n\n return {\n executionStatus,\n executionResults,\n perQueryResults,\n isLoading,\n isFetching,\n error,\n debugDataPerQuery: dryRunResult.debugDataPerQuery,\n hasDebounced,\n refetch,\n funnelExecutedQueries,\n funnelServerQuery,\n funnelDebugData,\n flowServerQuery,\n flowChartData,\n flowDebugData,\n retentionServerQuery,\n retentionChartData,\n retentionDebugData,\n retentionValidation: retentionValidation ?? null,\n needsRefresh,\n warnings,\n }\n}\n","/**\n * useAnalysisChartDefaults\n *\n * Manages chart configuration, availability, and smart defaulting.\n * Handles color palette resolution and chart type auto-switching.\n *\n * Returns mode-appropriate chart config based on analysisType:\n * - Query mode: uses chartType, chartConfig, displayConfig\n * - Funnel mode: uses funnelChartType, funnelChartConfig, funnelDisplayConfig\n */\n\nimport { useMemo, useEffect, useRef, useCallback } from 'react'\nimport { useAnalysisBuilderStore, selectChartConfig } from '../stores/analysisBuilderStore'\nimport { useShallow } from 'zustand/react/shallow'\nimport { getAllChartAvailability, getSmartChartDefaults, shouldAutoSwitchChartType } from '../shared/chartDefaults'\nimport { getColorPalette, type ColorPalette } from '../utils/colorPalettes'\nimport type { ChartType, ChartAxisConfig, ChartDisplayConfig } from '../types'\nimport type { MetricItem, BreakdownItem } from '../components/AnalysisBuilder/types'\nimport type { ChartAvailabilityMap } from '../shared/chartDefaults'\n\nexport interface UseAnalysisChartDefaultsOptions {\n /** External color palette (overrides local) */\n externalColorPalette?: string[] | ColorPalette\n /** Combined metrics from all queries */\n combinedMetrics: MetricItem[]\n /** Combined breakdowns from all queries */\n combinedBreakdowns: BreakdownItem[]\n /** Whether query has been debounced (triggers smart defaults) */\n hasDebounced: boolean\n}\n\nexport interface UseAnalysisChartDefaultsResult {\n /** Current chart type */\n chartType: ChartType\n /** Chart axis configuration */\n chartConfig: ChartAxisConfig\n /** Chart display configuration */\n displayConfig: ChartDisplayConfig\n /** Effective color palette */\n colorPalette: ColorPalette\n /** Local palette name (when not using external) */\n localPaletteName: string\n /** Chart availability map */\n chartAvailability: ChartAvailabilityMap\n /** User manually selected chart */\n userManuallySelectedChart: boolean\n\n // Actions\n setChartType: (type: ChartType) => void\n setChartConfig: (config: ChartAxisConfig) => void\n setDisplayConfig: (config: ChartDisplayConfig) => void\n setLocalPaletteName: (name: string) => void\n}\n\nexport function useAnalysisChartDefaults(\n options: UseAnalysisChartDefaultsOptions\n): UseAnalysisChartDefaultsResult {\n const { externalColorPalette, combinedMetrics, combinedBreakdowns, hasDebounced } = options\n\n // Get analysis type to determine which config to use\n const analysisType = useAnalysisBuilderStore((state) => state.analysisType)\n\n // Use the mode-aware selector to get the appropriate chart config\n const { chartType, chartConfig, displayConfig } = useAnalysisBuilderStore(useShallow(selectChartConfig))\n\n // Store state (shared)\n const userManuallySelectedChart = useAnalysisBuilderStore((state) => state.userManuallySelectedChart)\n const localPaletteName = useAnalysisBuilderStore((state) => state.localPaletteName)\n\n // Store actions - Query mode\n const setChartTypeManual = useAnalysisBuilderStore((state) => state.setChartTypeManual)\n const setQueryChartConfig = useAnalysisBuilderStore((state) => state.setChartConfig)\n const setQueryDisplayConfig = useAnalysisBuilderStore((state) => state.setDisplayConfig)\n\n // Store actions - Funnel mode\n const setFunnelChartType = useAnalysisBuilderStore((state) => state.setFunnelChartType)\n const setFunnelChartConfig = useAnalysisBuilderStore((state) => state.setFunnelChartConfig)\n const setFunnelDisplayConfig = useAnalysisBuilderStore((state) => state.setFunnelDisplayConfig)\n\n // Shared actions\n const setLocalPaletteName = useAnalysisBuilderStore((state) => state.setLocalPaletteName)\n const setUserManuallySelectedChart = useAnalysisBuilderStore((state) => state.setUserManuallySelectedChart)\n\n // Mode-aware setters - route to appropriate store action based on analysis type\n const setChartType = useCallback(\n (type: ChartType) => {\n if (analysisType === 'funnel') {\n setFunnelChartType(type)\n } else {\n setChartTypeManual(type)\n const { chartConfig: smartConfig } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n type\n )\n setQueryChartConfig(smartConfig)\n }\n },\n [\n analysisType,\n combinedMetrics,\n combinedBreakdowns,\n setFunnelChartType,\n setChartTypeManual,\n setQueryChartConfig,\n ]\n )\n\n const setChartConfig = useCallback(\n (config: ChartAxisConfig) => {\n if (analysisType === 'funnel') {\n setFunnelChartConfig(config)\n } else {\n setQueryChartConfig(config)\n }\n },\n [analysisType, setFunnelChartConfig, setQueryChartConfig]\n )\n\n const setDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n if (analysisType === 'funnel') {\n setFunnelDisplayConfig(config)\n } else {\n setQueryDisplayConfig(config)\n }\n },\n [analysisType, setFunnelDisplayConfig, setQueryDisplayConfig]\n )\n\n // Chart availability\n const chartAvailability = useMemo(\n () => getAllChartAvailability(combinedMetrics, combinedBreakdowns),\n [combinedMetrics, combinedBreakdowns]\n )\n\n // Effective color palette\n const colorPalette = useMemo((): ColorPalette => {\n if (externalColorPalette) {\n if (Array.isArray(externalColorPalette) && typeof externalColorPalette[0] === 'string') {\n return {\n name: 'custom',\n label: 'Custom',\n colors: externalColorPalette as string[],\n gradient: externalColorPalette as string[],\n }\n }\n return externalColorPalette as ColorPalette\n }\n return getColorPalette(localPaletteName)\n }, [externalColorPalette, localPaletteName])\n\n // Smart chart defaulting\n const prevMetricsBreakdownsRef = useRef<string>('')\n\n useEffect(() => {\n if (!hasDebounced) return\n if (combinedMetrics.length === 0 && combinedBreakdowns.length === 0) return\n\n const currentKey = JSON.stringify({\n metrics: combinedMetrics.map((m) => m.field),\n breakdowns: combinedBreakdowns.map((b) => ({ field: b.field, isTime: b.isTimeDimension })),\n })\n\n if (currentKey === prevMetricsBreakdownsRef.current) return\n prevMetricsBreakdownsRef.current = currentKey\n\n const newChartType = shouldAutoSwitchChartType(\n combinedMetrics,\n combinedBreakdowns,\n chartType,\n userManuallySelectedChart\n )\n\n if (newChartType) {\n const { chartConfig: newConfig } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n newChartType\n )\n setChartType(newChartType)\n setChartConfig(newConfig)\n setUserManuallySelectedChart(false)\n } else if (combinedMetrics.length > 0 || combinedBreakdowns.length > 0) {\n // Apply smart defaults only if chart config is empty\n const isChartConfigEmpty =\n !chartConfig.xAxis?.length &&\n !chartConfig.yAxis?.length &&\n !chartConfig.series?.length\n if (isChartConfigEmpty) {\n const { chartConfig: smartDefaults } = getSmartChartDefaults(\n combinedMetrics,\n combinedBreakdowns,\n chartType\n )\n setChartConfig(smartDefaults)\n }\n }\n }, [\n hasDebounced,\n combinedMetrics,\n combinedBreakdowns,\n chartType,\n userManuallySelectedChart,\n chartConfig,\n setChartType,\n setChartConfig,\n setUserManuallySelectedChart,\n ])\n\n return {\n chartType,\n chartConfig,\n displayConfig,\n colorPalette,\n localPaletteName,\n chartAvailability,\n userManuallySelectedChart,\n\n // Actions - mode-aware setters route to appropriate store fields\n setChartType,\n setChartConfig,\n setDisplayConfig,\n setLocalPaletteName,\n }\n}\n","/**\n * useAnalysisUIState\n *\n * Manages UI-only state for AnalysisBuilder:\n * - Active tab selection\n * - View toggle (table/chart)\n * - Field modal state\n * - Display limit\n * - Active table index for multi-query\n */\n\nimport { useState } from 'react'\nimport { useAnalysisBuilderStore, type FieldModalMode } from '../stores/analysisBuilderStore'\nimport type { QueryPanelTab } from '../components/AnalysisBuilder/types'\n\nexport interface UseAnalysisUIStateResult {\n /** Active tab in query panel */\n activeTab: QueryPanelTab\n /** Active view (table or chart) */\n activeView: 'table' | 'chart'\n /** Display limit for table */\n displayLimit: number\n /** Whether field modal is open */\n showFieldModal: boolean\n /** Field modal mode */\n fieldModalMode: FieldModalMode\n /** Active table index for multi-query */\n activeTableIndex: number\n /** User manually selected chart */\n userManuallySelectedChart: boolean\n\n // Actions\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n closeFieldModal: () => void\n setActiveTableIndex: (index: number) => void\n}\n\nexport function useAnalysisUIState(): UseAnalysisUIStateResult {\n // Store state\n const activeTab = useAnalysisBuilderStore((state) => state.activeTab)\n const activeView = useAnalysisBuilderStore((state) => state.activeView)\n const displayLimit = useAnalysisBuilderStore((state) => state.displayLimit)\n const showFieldModal = useAnalysisBuilderStore((state) => state.showFieldModal)\n const fieldModalMode = useAnalysisBuilderStore((state) => state.fieldModalMode)\n const userManuallySelectedChart = useAnalysisBuilderStore((state) => state.userManuallySelectedChart)\n\n // Store actions\n const setActiveTab = useAnalysisBuilderStore((state) => state.setActiveTab)\n const setActiveView = useAnalysisBuilderStore((state) => state.setActiveView)\n const setDisplayLimit = useAnalysisBuilderStore((state) => state.setDisplayLimit)\n const closeFieldModal = useAnalysisBuilderStore((state) => state.closeFieldModal)\n\n // Local state for table index (not persisted)\n const [activeTableIndex, setActiveTableIndex] = useState(0)\n\n return {\n // State\n activeTab,\n activeView,\n displayLimit,\n showFieldModal,\n fieldModalMode,\n activeTableIndex,\n userManuallySelectedChart,\n\n // Actions\n setActiveTab,\n setActiveView,\n setDisplayLimit,\n closeFieldModal,\n setActiveTableIndex,\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 * Phase 3: Now uses AnalysisConfig format exclusively.\n * Old share URLs will not parse (breaking change as per plan).\n */\n\nimport { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string'\nimport type { AnalysisConfig } from '../types/analysisConfig'\nimport { isValidAnalysisConfig } from '../types/analysisConfig'\n\n// Re-export for backward compatibility during transition\nexport type { AnalysisConfig as ShareableState }\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 AnalysisConfig to URL-safe encoded string\n */\nexport function compressAndEncode(config: AnalysisConfig): string {\n const json = JSON.stringify(config)\n return compressToEncodedURIComponent(json)\n}\n\n/**\n * Decompress URL-safe encoded string back to AnalysisConfig\n * Returns null if decompression, parsing, or validation fails.\n *\n * Note: This does not support legacy share URL formats (breaking change).\n */\nexport function decodeAndDecompress(encoded: string): AnalysisConfig | null {\n try {\n const json = decompressFromEncodedURIComponent(encoded)\n if (!json) return null\n\n const parsed = JSON.parse(json)\n\n // Validate using the AnalysisConfig type guard\n if (!isValidAnalysisConfig(parsed)) {\n console.warn('[shareUtils] Invalid AnalysisConfig in share URL')\n return null\n }\n\n return parsed\n } catch {\n return null\n }\n}\n\n/**\n * Check if compressed config fits within URL length limit\n */\nexport function isShareableSize(config: AnalysisConfig): { ok: boolean; size: number; maxSize: number } {\n const encoded = compressAndEncode(config)\n return {\n ok: encoded.length <= MAX_HASH_LENGTH,\n size: encoded.length,\n maxSize: MAX_HASH_LENGTH\n }\n}\n\n/**\n * Compress config with automatic fallback\n * If full config is too large, tries with query only (preserving essential fields)\n * Returns null encoded if even query-only is too large\n */\nexport function compressWithFallback(config: AnalysisConfig): CompressionResult {\n // Try full config first\n const fullEncoded = compressAndEncode(config)\n if (fullEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: fullEncoded, queryOnly: false }\n }\n\n // Fall back to minimal config (query + essential fields only)\n const minimalConfig: AnalysisConfig = {\n version: config.version,\n analysisType: config.analysisType,\n activeView: config.activeView,\n charts: {}, // Drop chart config to save space\n query: config.query,\n } as AnalysisConfig\n\n const minimalEncoded = compressAndEncode(minimalConfig)\n if (minimalEncoded.length <= MAX_HASH_LENGTH) {\n return { encoded: minimalEncoded, queryOnly: true }\n }\n\n // Even minimal is too large\n return { encoded: null, queryOnly: true }\n}\n\n/**\n * Generate full share URL with compressed config in hash\n */\nexport function generateShareUrl(config: AnalysisConfig): string | null {\n const { encoded } = compressWithFallback(config)\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// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Create a share URL from store's save() method output\n * This is the primary entry point for creating share URLs.\n */\nexport function createShareUrl(config: AnalysisConfig): string | null {\n return generateShareUrl(config)\n}\n\n/**\n * Parse and validate share URL, returning AnalysisConfig or null\n * This is the primary entry point for loading from share URLs.\n */\nexport function parseShareUrl(): AnalysisConfig | null {\n const encoded = parseShareHash()\n if (!encoded) return null\n return decodeAndDecompress(encoded)\n}\n","/**\n * useAnalysisInitialization\n *\n * Handles initialization side effects:\n * - URL share loading on mount\n * - Callback forwarding (onQueryChange, onChartConfigChange)\n */\n\nimport { useEffect, useRef } from 'react'\nimport { useAnalysisBuilderStore } from '../stores/analysisBuilderStore'\nimport { parseShareUrl, clearShareHash } from '../utils/shareUtils'\nimport type { CubeQuery, ChartType, ChartAxisConfig, ChartDisplayConfig } from '../types'\n\nexport interface UseAnalysisInitializationOptions {\n /** Current query */\n currentQuery: CubeQuery\n /** Whether query is valid */\n isValidQuery: boolean\n /** Chart type */\n chartType: ChartType\n /** Chart config */\n chartConfig: ChartAxisConfig\n /** Display config */\n displayConfig: ChartDisplayConfig\n /** Callback when query changes */\n onQueryChange?: (query: CubeQuery) => void\n /** Callback when chart config changes */\n onChartConfigChange?: (config: {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }) => void\n}\n\n/**\n * Handles initialization effects - no return value (side-effect only hook)\n */\nexport function useAnalysisInitialization(options: UseAnalysisInitializationOptions): void {\n const {\n currentQuery,\n isValidQuery,\n chartType,\n chartConfig,\n displayConfig,\n onQueryChange,\n onChartConfigChange,\n } = options\n\n // Get store action for loading from share URL\n const load = useAnalysisBuilderStore((state) => state.load)\n\n // URL share loading (on mount only)\n const hasInitializedShareRef = useRef(false)\n\n useEffect(() => {\n if (hasInitializedShareRef.current) return\n hasInitializedShareRef.current = true\n\n // parseShareUrl returns AnalysisConfig | null\n const config = parseShareUrl()\n if (!config) return\n\n load(config)\n clearShareHash()\n }, [load])\n\n // Query change callback\n useEffect(() => {\n if (onQueryChange && isValidQuery) {\n onQueryChange(currentQuery)\n }\n }, [currentQuery, isValidQuery, onQueryChange])\n\n // Chart config change callback\n useEffect(() => {\n if (onChartConfigChange) {\n onChartConfigChange({\n chartType,\n chartConfig,\n displayConfig,\n })\n }\n }, [chartType, chartConfig, displayConfig, onChartConfigChange])\n}\n","/**\n * useAnalysisBuilder - Master Coordination Hook\n *\n * The single hook that provides everything AnalysisBuilder needs.\n * Orchestrates sub-hooks for modular, maintainable code:\n *\n * - useAnalysisQueryBuilder: Query state, building, validation\n * - useAnalysisCombinedFields: Multi-query field merging\n * - useAnalysisQueryExecution: TanStack Query data fetching\n * - useAnalysisChartDefaults: Chart configuration and smart defaults\n * - useAnalysisUIState: UI state (tabs, modals, view toggle)\n * - useAnalysisInitialization: Side effects (URL loading, callbacks)\n *\n * IMPORTANT: This hook must be used within AnalysisBuilderStoreProvider\n */\n\nimport { useCallback, useMemo, useRef } from 'react'\nimport { useCubeFeatures } from '../providers/CubeProvider'\nimport {\n useAnalysisBuilderStore,\n useAnalysisBuilderStoreApi,\n} from '../stores/analysisBuilderStore'\n\n// Sub-hooks\nimport { useAnalysisQueryBuilder } from './useAnalysisQueryBuilder'\nimport { useAnalysisCombinedFields } from './useAnalysisCombinedFields'\nimport { useAnalysisQueryExecution } from './useAnalysisQueryExecution'\nimport { useAnalysisChartDefaults } from './useAnalysisChartDefaults'\nimport { useAnalysisUIState } from './useAnalysisUIState'\nimport { useAnalysisInitialization } from './useAnalysisInitialization'\n\nimport type { ColorPalette } from '../utils/colorPalettes'\nimport type {\n CubeQuery,\n MultiQueryConfig,\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n Filter,\n QueryMergeStrategy,\n FunnelBindingKey,\n AnalysisType,\n FunnelStepState,\n} from '../types'\nimport type {\n AnalysisBuilderState,\n MetricItem,\n BreakdownItem,\n ExecutionStatus,\n QueryPanelTab,\n} from '../components/AnalysisBuilder/types'\nimport type { ChartAvailabilityMap } from '../shared/chartDefaults'\nimport type { DebugDataEntry } from './queries'\nimport type { MultiQueryValidationResult } from '../utils/multiQueryValidation'\nimport type { MetaField } from '../shared/types'\nimport type { ValidationResult } from '../adapters/modeAdapter'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseAnalysisBuilderOptions {\n /** External color palette (overrides local) */\n externalColorPalette?: string[] | ColorPalette\n /** Initial data (skip first fetch) */\n initialData?: unknown[]\n /** Callback when query changes */\n onQueryChange?: (query: CubeQuery) => void\n /** Callback when chart config changes */\n onChartConfigChange?: (config: {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }) => void\n}\n\nexport interface UseAnalysisBuilderResult {\n // Query State\n queryState: AnalysisBuilderState\n queryStates: AnalysisBuilderState[]\n activeQueryIndex: number\n mergeStrategy: QueryMergeStrategy\n isMultiQueryMode: boolean\n mergeKeys: string[] | undefined\n currentQuery: CubeQuery\n allQueries: CubeQuery[]\n multiQueryConfig: MultiQueryConfig | null\n multiQueryValidation: MultiQueryValidationResult | null\n\n // Funnel State (legacy - merge strategy mode)\n funnelBindingKey: FunnelBindingKey | null\n /** Whether funnel mode is properly configured and ready for execution */\n isFunnelModeEnabled: boolean\n\n // Analysis Type State (new dedicated mode selection)\n /** Current analysis type (query, multi, funnel) */\n analysisType: AnalysisType\n /** Selected cube for funnel mode (all steps use this cube) */\n funnelCube: string | null\n /** Dedicated funnel steps (when analysisType === 'funnel') */\n funnelSteps: FunnelStepState[]\n /** Index of currently active funnel step */\n activeFunnelStepIndex: number\n /** Time dimension for funnel temporal ordering */\n funnelTimeDimension: string | null\n /** Chart type for funnel mode (separate from query mode) */\n funnelChartType: ChartType\n /** Chart config for funnel mode (separate from query mode) */\n funnelChartConfig: ChartAxisConfig\n /** Display config for funnel mode (separate from query mode) */\n funnelDisplayConfig: ChartDisplayConfig\n\n // Flow Mode State (when analysisType === 'flow')\n /** Selected cube for flow mode */\n flowCube: string | null\n /** Binding key for flow mode (entity linking) */\n flowBindingKey: FunnelBindingKey | null\n /** Time dimension for flow mode (event ordering) */\n flowTimeDimension: string | null\n /** Event dimension for flow mode (node labels in Sankey) */\n eventDimension: string | null\n /** Starting step configuration */\n startingStep: import('../types/flow').FlowStartingStep\n /** Number of steps to explore before starting step */\n stepsBefore: number\n /** Number of steps to explore after starting step */\n stepsAfter: number\n /** Join strategy for flow execution */\n joinStrategy: 'auto' | 'lateral' | 'window'\n /** Display config for flow mode */\n flowDisplayConfig: ChartDisplayConfig\n\n // Retention State (simplified Mixpanel-style)\n /** Single cube for retention analysis */\n retentionCube: string | null\n /** Binding key for retention mode */\n retentionBindingKey: import('../types/funnel').FunnelBindingKey | null\n /** Single timestamp dimension for retention mode */\n retentionTimeDimension: string | null\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: import('../types/retention').DateRange\n /** Cohort filters for retention mode */\n retentionCohortFilters: import('../types').Filter[]\n /** Activity filters for retention mode */\n retentionActivityFilters: import('../types').Filter[]\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: import('../types/retention').RetentionBreakdownItem[]\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: import('../types/retention').RetentionGranularity\n /** Number of periods for retention mode */\n retentionPeriods: number\n /** Retention calculation type */\n retentionType: import('../types/retention').RetentionType\n /** Display config for retention mode */\n retentionDisplayConfig: ChartDisplayConfig | undefined\n\n // Data Fetching\n executionStatus: ExecutionStatus\n executionResults: unknown[] | null\n perQueryResults: (unknown[] | null)[] | null\n isLoading: boolean\n isFetching: boolean\n error: Error | null\n isValidQuery: boolean\n debugDataPerQuery: DebugDataEntry[]\n /**\n * Whether the current query config differs from the last executed query.\n * Used for manual refresh mode to show \"needs refresh\" indicator.\n */\n needsRefresh: boolean\n /**\n * Query warnings from the server (e.g., fan-out without dimensions).\n * Displayed as a banner above results.\n */\n warnings: import('../shared/types').QueryWarning[] | undefined\n /** In funnel mode, the actually executed queries with binding key dimension and IN filters */\n funnelExecutedQueries: CubeQuery[] | null\n /** In funnel mode, the actual server query { funnel: {...} } sent to the API */\n funnelServerQuery: unknown | null\n /** In funnel mode, unified debug data (SQL, analysis, mode metadata) */\n funnelDebugData: DebugDataEntry | null\n /** In flow mode, the actual server query { flow: {...} } sent to the API */\n flowServerQuery: unknown | null\n /** In flow mode, unified debug data (SQL, analysis, mode metadata) */\n flowDebugData: DebugDataEntry | null\n /** In retention mode, the actual server query { retention: {...} } sent to the API */\n retentionServerQuery: unknown | null\n /** In retention mode, unified debug data (SQL, analysis, mode metadata) */\n retentionDebugData: DebugDataEntry | null\n /** In retention mode, the chart data (cohort × period matrix) */\n retentionChartData: import('../types/retention').RetentionChartData | null\n /** In retention mode, validation result (errors explaining why query cannot be built) */\n retentionValidation: { isValid: boolean; errors: string[]; warnings: string[] } | null\n\n // Chart Configuration\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n colorPalette: ColorPalette\n localPaletteName: string\n chartAvailability: ChartAvailabilityMap\n combinedMetrics: MetricItem[]\n combinedBreakdowns: BreakdownItem[]\n effectiveBreakdowns: BreakdownItem[]\n\n // UI State\n activeTab: QueryPanelTab\n activeView: 'table' | 'chart'\n displayLimit: number\n showFieldModal: boolean\n fieldModalMode: 'metrics' | 'breakdown'\n activeTableIndex: number\n userManuallySelectedChart: boolean\n\n // AI State\n aiState: {\n isOpen: boolean\n userPrompt: string\n isGenerating: boolean\n error: string | null\n hasGeneratedQuery: boolean\n }\n\n // Share State\n shareButtonState: 'idle' | 'copied' | 'copied-no-chart'\n canShare: boolean\n\n // Adapter Validation (NEW - Phase 5)\n /** Validation result from the adapter for the current analysis type */\n adapterValidation: ValidationResult\n\n // Actions\n actions: {\n setActiveQueryIndex: (index: number) => void\n setMergeStrategy: (strategy: QueryMergeStrategy) => void\n openMetricsModal: () => void\n addMetric: (field: string, label?: string) => void\n removeMetric: (id: string) => void\n toggleMetric: (fieldName: string) => void\n reorderMetrics: (fromIndex: number, toIndex: number) => void\n openBreakdownsModal: () => void\n addBreakdown: (field: string, isTimeDimension: boolean, granularity?: string) => void\n removeBreakdown: (id: string) => void\n toggleBreakdown: (fieldName: string, isTimeDimension: boolean, granularity?: string) => void\n setBreakdownGranularity: (id: string, granularity: string) => void\n toggleBreakdownComparison: (id: string) => void\n reorderBreakdowns: (fromIndex: number, toIndex: number) => void\n setFilters: (filters: Filter[]) => void\n dropFieldToFilter: (field: string) => void\n setOrder: (fieldName: string, direction: 'asc' | 'desc' | null) => void\n addQuery: () => void\n removeQuery: (index: number) => void\n setFunnelBindingKey: (bindingKey: FunnelBindingKey | null) => void\n // Analysis Type actions\n setAnalysisType: (type: AnalysisType) => void\n // Funnel Mode actions (when analysisType === 'funnel')\n setFunnelCube: (cube: string | null) => void\n addFunnelStep: () => void\n removeFunnelStep: (index: number) => void\n updateFunnelStep: (index: number, updates: Partial<FunnelStepState>) => void\n setActiveFunnelStepIndex: (index: number) => void\n reorderFunnelSteps: (fromIndex: number, toIndex: number) => void\n setFunnelTimeDimension: (dimension: string | null) => void\n setFunnelDisplayConfig: (config: ChartDisplayConfig) => void\n // Flow Mode actions (when analysisType === 'flow')\n setFlowCube: (cube: string | null) => void\n setFlowBindingKey: (key: FunnelBindingKey | null) => void\n setFlowTimeDimension: (dim: string | null) => void\n setEventDimension: (dim: string | null) => void\n setStartingStepName: (name: string) => void\n setStartingStepFilters: (filters: Filter[]) => void\n setStepsBefore: (count: number) => void\n setStepsAfter: (count: number) => void\n setJoinStrategy: (strategy: 'auto' | 'lateral' | 'window') => void\n setFlowDisplayConfig: (config: ChartDisplayConfig) => void\n // Retention Mode actions (simplified Mixpanel-style)\n setRetentionCube: (cube: string | null) => void\n setRetentionBindingKey: (key: import('../types/funnel').FunnelBindingKey | null) => void\n setRetentionTimeDimension: (dim: string | null) => void\n setRetentionDateRange: (range: import('../types/retention').DateRange) => void\n setRetentionCohortFilters: (filters: import('../types').Filter[]) => void\n setRetentionActivityFilters: (filters: import('../types').Filter[]) => void\n setRetentionBreakdowns: (breakdowns: import('../types/retention').RetentionBreakdownItem[]) => void\n addRetentionBreakdown: (breakdown: import('../types/retention').RetentionBreakdownItem) => void\n removeRetentionBreakdown: (field: string) => void\n setRetentionViewGranularity: (granularity: import('../types/retention').RetentionGranularity) => void\n setRetentionPeriods: (periods: number) => void\n setRetentionType: (type: import('../types/retention').RetentionType) => void\n setRetentionDisplayConfig: (config: ChartDisplayConfig) => void\n setChartType: (type: ChartType) => void\n setChartConfig: (config: ChartAxisConfig) => void\n setDisplayConfig: (config: ChartDisplayConfig) => void\n setLocalPaletteName: (name: string) => void\n setActiveTab: (tab: QueryPanelTab) => void\n setActiveView: (view: 'table' | 'chart') => void\n setDisplayLimit: (limit: number) => void\n closeFieldModal: () => void\n setActiveTableIndex: (index: number) => void\n openAI: () => void\n closeAI: () => void\n setAIPrompt: (prompt: string) => void\n generateAI: () => Promise<void>\n acceptAI: () => void\n cancelAI: () => void\n share: () => Promise<void>\n clearQuery: () => void\n clearCurrentMode: () => void\n refetch: (options?: { bustCache?: boolean }) => void\n handleFieldSelected: (\n field: MetaField,\n fieldType: 'measure' | 'dimension' | 'timeDimension',\n cubeName: string,\n keepOpen?: boolean\n ) => void\n }\n\n // Refs (for imperative access)\n getQueryConfig: () => CubeQuery | MultiQueryConfig | import('../types/funnel').ServerFunnelQuery\n getChartConfig: () => {\n chartType: ChartType\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n }\n getAnalysisType: () => AnalysisType\n}\n\n// ============================================================================\n// Hook Implementation\n// ============================================================================\n\nexport function useAnalysisBuilder(\n options: UseAnalysisBuilderOptions = {}\n): UseAnalysisBuilderResult {\n const { initialData, externalColorPalette, onQueryChange, onChartConfigChange } = options\n\n // Get context\n const { features } = useCubeFeatures()\n\n // Get store API for direct access\n const storeApi = useAnalysisBuilderStoreApi()\n\n // =========================================================================\n // Sub-Hooks Orchestration\n // =========================================================================\n\n // 1. Query Builder (query state, building, validation)\n const queryBuilder = useAnalysisQueryBuilder()\n\n // 2. Combined Fields (multi-query field merging)\n const combinedFields = useAnalysisCombinedFields({\n queryState: queryBuilder.queryState,\n queryStates: queryBuilder.queryStates,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n mergeStrategy: queryBuilder.mergeStrategy,\n activeQueryIndex: queryBuilder.activeQueryIndex,\n })\n\n // Get funnel binding key from store for funnel mode\n const funnelBindingKey = useAnalysisBuilderStore((s) => s.funnelBindingKey)\n\n // Get analysis type state (must be before computed values that use it)\n const analysisType = useAnalysisBuilderStore((s) => s.analysisType)\n const funnelCube = useAnalysisBuilderStore((s) => s.funnelCube)\n const funnelSteps = useAnalysisBuilderStore((s) => s.funnelSteps)\n const activeFunnelStepIndex = useAnalysisBuilderStore((s) => s.activeFunnelStepIndex)\n const funnelTimeDimension = useAnalysisBuilderStore((s) => s.funnelTimeDimension)\n\n // Get funnel mode enabled state (computed to avoid function call in selector)\n // This includes filter-only step validation\n const isFunnelModeEnabled = useMemo(() => {\n if (analysisType !== 'funnel') return false\n if (!funnelBindingKey?.dimension) return false\n if (!funnelTimeDimension) return false\n if (!funnelSteps || funnelSteps.length < 2) return false\n // All steps must have at least one filter\n return funnelSteps.every((step) => step.filters.length > 0)\n }, [analysisType, funnelBindingKey, funnelTimeDimension, funnelSteps])\n // Phase 4: Read from charts map instead of legacy fields\n // Use stable selectors to avoid infinite loop from creating new objects\n const funnelChartType = useAnalysisBuilderStore((s) => s.charts.funnel?.chartType) || 'funnel'\n const funnelChartConfigFromStore = useAnalysisBuilderStore((s) => s.charts.funnel?.chartConfig)\n const funnelChartConfig = useMemo(() => funnelChartConfigFromStore || {}, [funnelChartConfigFromStore])\n\n // Get flow mode state\n const flowCube = useAnalysisBuilderStore((s) => s.flowCube)\n const flowBindingKey = useAnalysisBuilderStore((s) => s.flowBindingKey)\n const flowTimeDimension = useAnalysisBuilderStore((s) => s.flowTimeDimension)\n const eventDimension = useAnalysisBuilderStore((s) => s.eventDimension)\n const startingStep = useAnalysisBuilderStore((s) => s.startingStep)\n const stepsBefore = useAnalysisBuilderStore((s) => s.stepsBefore)\n const stepsAfter = useAnalysisBuilderStore((s) => s.stepsAfter)\n const joinStrategy = useAnalysisBuilderStore((s) => s.joinStrategy)\n // Flow display config from charts map - use stable selector to avoid infinite loop\n const flowDisplayConfigFromStore = useAnalysisBuilderStore((state) => state.charts.flow?.displayConfig)\n const flowDisplayConfig = useMemo(\n () => flowDisplayConfigFromStore || { showLegend: true, showGrid: true, showTooltip: true },\n [flowDisplayConfigFromStore]\n )\n // Flow chart type from charts map - needed for outputMode in query\n const flowChartType = useAnalysisBuilderStore((state) => state.charts.flow?.chartType) || 'sankey'\n\n // Build server funnel query from dedicated funnelSteps (when analysisType === 'funnel')\n // Note: funnelSteps must be in dependency array so query rebuilds when filters change\n const buildFunnelQueryFromSteps = useAnalysisBuilderStore((s) => s.buildFunnelQueryFromSteps)\n const serverFunnelQuery = useMemo(() => {\n if (analysisType !== 'funnel') return null\n return buildFunnelQueryFromSteps()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- funnelSteps triggers rebuild when step filters change\n }, [analysisType, buildFunnelQueryFromSteps, funnelSteps])\n\n const buildFlowQuery = useAnalysisBuilderStore((s) => s.buildFlowQuery)\n\n // Build server flow query (when analysisType === 'flow')\n // Note: flowChartType is included because it determines outputMode (sankey vs sunburst aggregation)\n const serverFlowQuery = useMemo(() => {\n if (analysisType !== 'flow') return null\n return buildFlowQuery()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- flow config values trigger rebuild when they change in store\n }, [analysisType, buildFlowQuery, flowCube, flowBindingKey, flowTimeDimension, eventDimension, startingStep, stepsBefore, stepsAfter, flowChartType, joinStrategy])\n\n // Get retention state from store (simplified Mixpanel-style)\n const retentionCube = useAnalysisBuilderStore((s) => s.retentionCube)\n const retentionBindingKey = useAnalysisBuilderStore((s) => s.retentionBindingKey)\n const retentionTimeDimension = useAnalysisBuilderStore((s) => s.retentionTimeDimension)\n const retentionDateRange = useAnalysisBuilderStore((s) => s.retentionDateRange)\n const retentionCohortFilters = useAnalysisBuilderStore((s) => s.retentionCohortFilters)\n const retentionActivityFilters = useAnalysisBuilderStore((s) => s.retentionActivityFilters)\n const retentionBreakdowns = useAnalysisBuilderStore((s) => s.retentionBreakdowns)\n const retentionViewGranularity = useAnalysisBuilderStore((s) => s.retentionViewGranularity)\n const retentionPeriods = useAnalysisBuilderStore((s) => s.retentionPeriods)\n const retentionType = useAnalysisBuilderStore((s) => s.retentionType)\n const buildRetentionQuery = useAnalysisBuilderStore((s) => s.buildRetentionQuery)\n const getRetentionValidation = useAnalysisBuilderStore((s) => s.getRetentionValidation)\n\n // Retention display config from charts map\n const retentionDisplayConfig = useAnalysisBuilderStore((s) => s.charts.retention?.displayConfig)\n\n // Retention actions (simplified Mixpanel-style)\n const setRetentionCube = useAnalysisBuilderStore((s) => s.setRetentionCube)\n const setRetentionBindingKey = useAnalysisBuilderStore((s) => s.setRetentionBindingKey)\n const setRetentionTimeDimension = useAnalysisBuilderStore((s) => s.setRetentionTimeDimension)\n const setRetentionDateRange = useAnalysisBuilderStore((s) => s.setRetentionDateRange)\n const setRetentionCohortFilters = useAnalysisBuilderStore((s) => s.setRetentionCohortFilters)\n const setRetentionActivityFilters = useAnalysisBuilderStore((s) => s.setRetentionActivityFilters)\n const setRetentionBreakdowns = useAnalysisBuilderStore((s) => s.setRetentionBreakdowns)\n const addRetentionBreakdown = useAnalysisBuilderStore((s) => s.addRetentionBreakdown)\n const removeRetentionBreakdown = useAnalysisBuilderStore((s) => s.removeRetentionBreakdown)\n const setRetentionViewGranularity = useAnalysisBuilderStore((s) => s.setRetentionViewGranularity)\n const setRetentionPeriods = useAnalysisBuilderStore((s) => s.setRetentionPeriods)\n const setRetentionType = useAnalysisBuilderStore((s) => s.setRetentionType)\n\n // Build server retention query (when analysisType === 'retention')\n const serverRetentionQuery = useMemo(() => {\n if (analysisType !== 'retention') return null\n return buildRetentionQuery()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- retention config values trigger rebuild when they change in store\n }, [\n analysisType,\n buildRetentionQuery,\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n retentionBreakdowns,\n retentionViewGranularity,\n retentionPeriods,\n retentionType,\n retentionCohortFilters,\n retentionActivityFilters,\n ])\n\n // Get retention validation (memoized based on config changes)\n const retentionValidation = useMemo(() => {\n if (analysisType !== 'retention') return null\n return getRetentionValidation()\n // eslint-disable-next-line react-hooks/exhaustive-deps -- retention config values trigger rebuild\n }, [\n analysisType,\n getRetentionValidation,\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n ])\n\n // Compute effective isValidQuery that considers funnel, flow, and retention modes\n // In funnel mode, the query is valid when serverFunnelQuery is not null\n // In flow mode, the query is valid when serverFlowQuery is not null\n // In retention mode, the query is valid when serverRetentionQuery is not null\n const effectiveIsValidQuery = useMemo(() => {\n if (analysisType === 'retention') {\n // Retention mode: valid when we have a buildable retention query\n return serverRetentionQuery !== null\n }\n if (analysisType === 'flow') {\n // Flow mode: valid when we have a buildable flow query\n return serverFlowQuery !== null\n }\n if (analysisType === 'funnel') {\n // Funnel mode: valid when we have a buildable funnel query\n return serverFunnelQuery !== null\n }\n // Query/Multi mode: use the standard validation\n return queryBuilder.isValidQuery ?? false\n }, [analysisType, serverRetentionQuery, serverFlowQuery, serverFunnelQuery, queryBuilder.isValidQuery])\n\n // 3. Query Execution (TanStack Query integration)\n const queryExecution = useAnalysisQueryExecution({\n currentQuery: queryBuilder.currentQuery,\n allQueries: queryBuilder.allQueries,\n multiQueryConfig: queryBuilder.multiQueryConfig,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n isValidQuery: effectiveIsValidQuery,\n initialData,\n mergeStrategy: queryBuilder.mergeStrategy,\n funnelBindingKey,\n isFunnelModeEnabled,\n // New: pass analysisType and serverFunnelQuery for explicit mode routing\n analysisType,\n serverFunnelQuery,\n // Flow mode: pass serverFlowQuery\n serverFlowQuery,\n // Retention mode: pass serverRetentionQuery\n serverRetentionQuery,\n // Retention mode: pass validation for debug panel\n retentionValidation,\n })\n\n // 4. Chart Defaults (chart config, availability, smart defaults)\n const chartDefaults = useAnalysisChartDefaults({\n externalColorPalette,\n combinedMetrics: combinedFields.combinedMetrics,\n combinedBreakdowns: combinedFields.combinedBreakdowns,\n hasDebounced: queryExecution.hasDebounced,\n })\n\n // 5. UI State (tabs, modals, view toggle)\n const uiState = useAnalysisUIState()\n\n // 6. Initialization (URL loading, callbacks - side effects only)\n useAnalysisInitialization({\n currentQuery: queryBuilder.currentQuery,\n isValidQuery: queryBuilder.isValidQuery ?? false,\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n onQueryChange,\n onChartConfigChange,\n })\n\n // =========================================================================\n // Store Actions (not covered by sub-hooks)\n // =========================================================================\n\n // Metric actions\n const openMetricsModal = useAnalysisBuilderStore((state) => state.openMetricsModal)\n const addMetric = useAnalysisBuilderStore((state) => state.addMetric)\n const removeMetric = useAnalysisBuilderStore((state) => state.removeMetric)\n const toggleMetric = useAnalysisBuilderStore((state) => state.toggleMetric)\n const reorderMetrics = useAnalysisBuilderStore((state) => state.reorderMetrics)\n\n // Breakdown actions\n const openBreakdownsModal = useAnalysisBuilderStore((state) => state.openBreakdownsModal)\n const addBreakdown = useAnalysisBuilderStore((state) => state.addBreakdown)\n const removeBreakdown = useAnalysisBuilderStore((state) => state.removeBreakdown)\n const toggleBreakdown = useAnalysisBuilderStore((state) => state.toggleBreakdown)\n const setBreakdownGranularity = useAnalysisBuilderStore((state) => state.setBreakdownGranularity)\n const toggleBreakdownComparison = useAnalysisBuilderStore((state) => state.toggleBreakdownComparison)\n const reorderBreakdowns = useAnalysisBuilderStore((state) => state.reorderBreakdowns)\n\n // Filter actions\n const setFilters = useAnalysisBuilderStore((state) => state.setFilters)\n const dropFieldToFilter = useAnalysisBuilderStore((state) => state.dropFieldToFilter)\n const setOrder = useAnalysisBuilderStore((state) => state.setOrder)\n\n // Utility actions\n const clearQuery = useAnalysisBuilderStore((state) => state.clearQuery)\n const clearCurrentMode = useAnalysisBuilderStore((state) => state.clearCurrentMode)\n\n // Funnel actions (legacy)\n const setFunnelBindingKey = useAnalysisBuilderStore((state) => state.setFunnelBindingKey)\n\n // Analysis Type actions (new)\n const setAnalysisType = useAnalysisBuilderStore((state) => state.setAnalysisType)\n\n // Funnel Mode actions (new dedicated state)\n const setFunnelCube = useAnalysisBuilderStore((state) => state.setFunnelCube)\n const addFunnelStep = useAnalysisBuilderStore((state) => state.addFunnelStep)\n const removeFunnelStep = useAnalysisBuilderStore((state) => state.removeFunnelStep)\n const updateFunnelStep = useAnalysisBuilderStore((state) => state.updateFunnelStep)\n const setActiveFunnelStepIndex = useAnalysisBuilderStore((state) => state.setActiveFunnelStepIndex)\n const reorderFunnelSteps = useAnalysisBuilderStore((state) => state.reorderFunnelSteps)\n const setFunnelTimeDimension = useAnalysisBuilderStore((state) => state.setFunnelTimeDimension)\n\n // Funnel display config (for Display tab in funnel mode)\n // Phase 4: Read from charts map - use stable selector to avoid infinite loop\n const funnelDisplayConfigFromStore = useAnalysisBuilderStore((state) => state.charts.funnel?.displayConfig)\n const funnelDisplayConfig = useMemo(\n () => funnelDisplayConfigFromStore || { showLegend: true, showGrid: true, showTooltip: true },\n [funnelDisplayConfigFromStore]\n )\n const setFunnelDisplayConfig = useAnalysisBuilderStore((state) => state.setFunnelDisplayConfig)\n\n // Flow Mode actions\n const setFlowCube = useAnalysisBuilderStore((state) => state.setFlowCube)\n const setFlowBindingKey = useAnalysisBuilderStore((state) => state.setFlowBindingKey)\n const setFlowTimeDimension = useAnalysisBuilderStore((state) => state.setFlowTimeDimension)\n const setEventDimension = useAnalysisBuilderStore((state) => state.setEventDimension)\n const setStartingStepName = useAnalysisBuilderStore((state) => state.setStartingStepName)\n const setStartingStepFilters = useAnalysisBuilderStore((state) => state.setStartingStepFilters)\n const setStepsBefore = useAnalysisBuilderStore((state) => state.setStepsBefore)\n const setStepsAfter = useAnalysisBuilderStore((state) => state.setStepsAfter)\n const setJoinStrategy = useAnalysisBuilderStore((state) => state.setJoinStrategy)\n // Flow display config action - creates setFlowDisplayConfig wrapper using charts map pattern\n const setFlowDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n storeApi.setState((state) => ({\n charts: {\n ...state.charts,\n flow: {\n ...(state.charts.flow || { chartType: 'sankey', chartConfig: {}, displayConfig: {} }),\n displayConfig: config,\n },\n },\n }))\n },\n [storeApi]\n )\n\n // Retention display config action - creates setRetentionDisplayConfig wrapper using charts map pattern\n const setRetentionDisplayConfig = useCallback(\n (config: ChartDisplayConfig) => {\n storeApi.setState((state) => ({\n charts: {\n ...state.charts,\n retention: {\n ...(state.charts.retention || { chartType: 'retentionCombined', chartConfig: {}, displayConfig: {} }),\n displayConfig: config,\n },\n },\n }))\n },\n [storeApi]\n )\n\n // AI state and actions\n const aiState = useAnalysisBuilderStore((state) => state.aiState)\n const openAI = useAnalysisBuilderStore((state) => state.openAI)\n const closeAI = useAnalysisBuilderStore((state) => state.closeAI)\n const setAIPrompt = useAnalysisBuilderStore((state) => state.setAIPrompt)\n const setAIGenerating = useAnalysisBuilderStore((state) => state.setAIGenerating)\n const setAIError = useAnalysisBuilderStore((state) => state.setAIError)\n const setAIHasGeneratedQuery = useAnalysisBuilderStore((state) => state.setAIHasGeneratedQuery)\n const saveAIPreviousState = useAnalysisBuilderStore((state) => state.saveAIPreviousState)\n const restoreAIPreviousState = useAnalysisBuilderStore((state) => state.restoreAIPreviousState)\n\n // =========================================================================\n // Share State\n // =========================================================================\n\n const shareButtonStateRef = useRef<'idle' | 'copied' | 'copied-no-chart'>('idle')\n const canShare = effectiveIsValidQuery\n\n // =========================================================================\n // Adapter Validation (NEW - Phase 5)\n // =========================================================================\n\n const getValidation = useAnalysisBuilderStore((state) => state.getValidation)\n // Note: Dependencies trigger recomputation when store values change.\n // getValidation reads values from store closure, but we need the memo to\n // recompute when the underlying state changes.\n const adapterValidation = useMemo(\n () => getValidation(),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n getValidation,\n queryBuilder.queryStates,\n analysisType,\n // Funnel deps\n funnelSteps,\n funnelBindingKey,\n funnelTimeDimension,\n // Flow deps\n flowCube,\n flowBindingKey,\n flowTimeDimension,\n eventDimension,\n startingStep,\n stepsBefore,\n stepsAfter,\n joinStrategy,\n ]\n )\n\n // =========================================================================\n // Action Callbacks\n // =========================================================================\n\n const handleFieldSelected = useCallback(\n (\n field: MetaField,\n fieldType: 'measure' | 'dimension' | 'timeDimension',\n _cubeName: string,\n keepOpen?: boolean\n ) => {\n if (uiState.fieldModalMode === 'metrics' && fieldType === 'measure') {\n toggleMetric(field.name)\n } else if (uiState.fieldModalMode === 'breakdown') {\n // In retention mode, add to retention breakdowns instead of query breakdowns\n if (analysisType === 'retention' && fieldType === 'dimension') {\n addRetentionBreakdown({ field: field.name })\n } else {\n toggleBreakdown(field.name, fieldType === 'timeDimension')\n }\n }\n if (!keepOpen) {\n uiState.closeFieldModal()\n }\n },\n [uiState, toggleMetric, toggleBreakdown, addRetentionBreakdown, analysisType]\n )\n\n const generateAI = useCallback(async () => {\n if (!features?.aiEndpoint) return\n saveAIPreviousState()\n setAIGenerating(true)\n setAIError(null)\n\n try {\n // AI generation logic would go here\n await new Promise((resolve) => setTimeout(resolve, 1000))\n setAIHasGeneratedQuery(true)\n } catch (err) {\n setAIError(err instanceof Error ? err.message : 'Failed to generate query')\n } finally {\n setAIGenerating(false)\n }\n }, [features?.aiEndpoint, saveAIPreviousState, setAIGenerating, setAIError, setAIHasGeneratedQuery])\n\n const acceptAI = useCallback(() => {\n closeAI()\n setAIHasGeneratedQuery(false)\n }, [closeAI, setAIHasGeneratedQuery])\n\n const cancelAI = useCallback(() => {\n restoreAIPreviousState()\n closeAI()\n }, [restoreAIPreviousState, closeAI])\n\n const share = useCallback(async () => {\n shareButtonStateRef.current = 'copied'\n setTimeout(() => {\n shareButtonStateRef.current = 'idle'\n }, 2000)\n }, [])\n\n // =========================================================================\n // Ref API Functions\n // =========================================================================\n\n const getQueryConfig = useCallback(() => {\n const state = storeApi.getState()\n\n // Handle dedicated funnel mode (analysisType === 'funnel')\n if (state.analysisType === 'funnel') {\n // Return ServerFunnelQuery format built from funnelSteps\n const funnelQuery = state.buildFunnelQueryFromSteps()\n if (funnelQuery) {\n return funnelQuery\n }\n // Fallback to single query if funnel isn't properly configured yet\n return state.buildCurrentQuery()\n }\n\n // Handle multi-query mode (legacy funnel mode with mergeStrategy === 'funnel' is included here)\n if (state.queryStates.length > 1) {\n return {\n queries: state.buildAllQueries(),\n mergeStrategy: state.mergeStrategy,\n mergeKeys: state.getMergeKeys(),\n queryLabels: state.queryStates.map((_, i) => `Q${i + 1}`),\n // Include funnel-specific config when in funnel mode\n funnelBindingKey: state.funnelBindingKey,\n stepTimeToConvert: state.stepTimeToConvert,\n }\n }\n\n // Single query mode\n return state.buildCurrentQuery()\n }, [storeApi])\n\n const getChartConfig = useCallback(() => {\n const state = storeApi.getState()\n\n // Phase 4: Read from charts map based on analysis type\n const config = state.charts[state.analysisType]\n if (config) {\n return {\n chartType: config.chartType,\n chartConfig: config.chartConfig,\n displayConfig: config.displayConfig,\n }\n }\n\n // Fallback to defaults\n return {\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n }\n }, [storeApi, chartDefaults.chartType, chartDefaults.chartConfig, chartDefaults.displayConfig])\n\n const getAnalysisType = useCallback(() => {\n return storeApi.getState().analysisType\n }, [storeApi])\n\n // =========================================================================\n // Return Value\n // =========================================================================\n\n return {\n // Query state (from queryBuilder)\n queryState: queryBuilder.queryState,\n queryStates: queryBuilder.queryStates,\n activeQueryIndex: queryBuilder.activeQueryIndex,\n mergeStrategy: queryBuilder.mergeStrategy,\n isMultiQueryMode: queryBuilder.isMultiQueryMode,\n mergeKeys: queryBuilder.mergeKeys,\n currentQuery: queryBuilder.currentQuery,\n allQueries: queryBuilder.allQueries,\n multiQueryConfig: queryBuilder.multiQueryConfig,\n multiQueryValidation: queryBuilder.multiQueryValidation,\n\n // Funnel state (legacy)\n funnelBindingKey,\n isFunnelModeEnabled,\n\n // Analysis Type state (new)\n analysisType,\n funnelCube,\n funnelSteps,\n activeFunnelStepIndex,\n funnelTimeDimension,\n funnelChartType,\n funnelChartConfig,\n funnelDisplayConfig,\n\n // Flow state (new)\n flowCube,\n flowBindingKey,\n flowTimeDimension,\n eventDimension,\n startingStep,\n stepsBefore,\n stepsAfter,\n joinStrategy,\n flowDisplayConfig,\n\n // Retention state (simplified Mixpanel-style)\n retentionCube,\n retentionBindingKey,\n retentionTimeDimension,\n retentionDateRange,\n retentionCohortFilters,\n retentionActivityFilters,\n retentionBreakdowns,\n retentionViewGranularity,\n retentionPeriods,\n retentionType,\n retentionDisplayConfig,\n\n // Data fetching (from queryExecution)\n executionStatus: queryExecution.executionStatus,\n executionResults: queryExecution.executionResults,\n perQueryResults: queryExecution.perQueryResults,\n isLoading: queryExecution.isLoading,\n isFetching: queryExecution.isFetching,\n error: queryExecution.error,\n isValidQuery: effectiveIsValidQuery,\n debugDataPerQuery: queryExecution.debugDataPerQuery,\n needsRefresh: queryExecution.needsRefresh,\n warnings: queryExecution.warnings,\n funnelExecutedQueries: queryExecution.funnelExecutedQueries,\n funnelServerQuery: queryExecution.funnelServerQuery,\n funnelDebugData: queryExecution.funnelDebugData,\n flowServerQuery: queryExecution.flowServerQuery,\n flowDebugData: queryExecution.flowDebugData,\n retentionServerQuery: queryExecution.retentionServerQuery,\n retentionDebugData: queryExecution.retentionDebugData,\n retentionChartData: queryExecution.retentionChartData,\n retentionValidation: queryExecution.retentionValidation,\n\n // Chart configuration (from chartDefaults)\n // Note: Funnel chart type is determined by analysisType === 'funnel', not mergeStrategy\n chartType: chartDefaults.chartType,\n chartConfig: chartDefaults.chartConfig,\n displayConfig: chartDefaults.displayConfig,\n colorPalette: chartDefaults.colorPalette,\n localPaletteName: chartDefaults.localPaletteName,\n chartAvailability: chartDefaults.chartAvailability,\n combinedMetrics: combinedFields.combinedMetrics,\n combinedBreakdowns: combinedFields.combinedBreakdowns,\n effectiveBreakdowns: combinedFields.effectiveBreakdowns,\n\n // UI state (from uiState)\n activeTab: uiState.activeTab,\n activeView: uiState.activeView,\n displayLimit: uiState.displayLimit,\n showFieldModal: uiState.showFieldModal,\n fieldModalMode: uiState.fieldModalMode,\n activeTableIndex: uiState.activeTableIndex,\n userManuallySelectedChart: uiState.userManuallySelectedChart,\n\n // AI state\n aiState: {\n isOpen: aiState.isOpen,\n userPrompt: aiState.userPrompt,\n isGenerating: aiState.isGenerating,\n error: aiState.error,\n hasGeneratedQuery: aiState.hasGeneratedQuery,\n },\n\n // Share state\n shareButtonState: shareButtonStateRef.current,\n canShare,\n\n // Adapter validation (NEW - Phase 5)\n adapterValidation,\n\n // Actions\n actions: {\n // Query state (from queryBuilder)\n setActiveQueryIndex: queryBuilder.setActiveQueryIndex,\n setMergeStrategy: queryBuilder.setMergeStrategy,\n\n // Metrics\n openMetricsModal,\n addMetric,\n removeMetric,\n toggleMetric,\n reorderMetrics,\n\n // Breakdowns\n openBreakdownsModal,\n addBreakdown,\n removeBreakdown,\n toggleBreakdown,\n setBreakdownGranularity,\n toggleBreakdownComparison,\n reorderBreakdowns,\n\n // Filters\n setFilters,\n dropFieldToFilter,\n setOrder,\n\n // Multi-query (from queryBuilder)\n addQuery: queryBuilder.addQuery,\n removeQuery: queryBuilder.removeQuery,\n\n // Funnel (legacy)\n setFunnelBindingKey,\n\n // Analysis Type (new)\n setAnalysisType,\n\n // Funnel Mode (new dedicated state)\n setFunnelCube,\n addFunnelStep,\n removeFunnelStep,\n updateFunnelStep,\n setActiveFunnelStepIndex,\n reorderFunnelSteps,\n setFunnelTimeDimension,\n setFunnelDisplayConfig,\n\n // Flow Mode actions\n setFlowCube,\n setFlowBindingKey,\n setFlowTimeDimension,\n setEventDimension,\n setStartingStepName,\n setStartingStepFilters,\n setStepsBefore,\n setStepsAfter,\n setJoinStrategy,\n setFlowDisplayConfig,\n\n // Retention Mode actions (simplified Mixpanel-style)\n setRetentionCube,\n setRetentionBindingKey,\n setRetentionTimeDimension,\n setRetentionDateRange,\n setRetentionCohortFilters,\n setRetentionActivityFilters,\n setRetentionBreakdowns,\n addRetentionBreakdown,\n removeRetentionBreakdown,\n setRetentionViewGranularity,\n setRetentionPeriods,\n setRetentionType,\n setRetentionDisplayConfig,\n\n // Chart (from chartDefaults)\n setChartType: chartDefaults.setChartType,\n setChartConfig: chartDefaults.setChartConfig,\n setDisplayConfig: chartDefaults.setDisplayConfig,\n setLocalPaletteName: chartDefaults.setLocalPaletteName,\n\n // UI (from uiState)\n setActiveTab: uiState.setActiveTab,\n setActiveView: uiState.setActiveView,\n setDisplayLimit: uiState.setDisplayLimit,\n closeFieldModal: uiState.closeFieldModal,\n setActiveTableIndex: uiState.setActiveTableIndex,\n\n // AI\n openAI,\n closeAI,\n setAIPrompt,\n generateAI,\n acceptAI,\n cancelAI,\n\n // Share\n share,\n\n // Utility\n clearQuery,\n clearCurrentMode,\n refetch: queryExecution.refetch,\n handleFieldSelected,\n },\n\n // Refs\n getQueryConfig,\n getChartConfig,\n getAnalysisType,\n }\n}\n","/**\n * Funnel Validation Utilities\n *\n * Provides validation for funnel configurations including:\n * - Binding key validation\n * - Step query validation\n * - Cross-cube compatibility checks\n */\n\nimport type { CubeQuery, CubeMeta } from '../types'\nimport type {\n FunnelBindingKey,\n FunnelConfig,\n FunnelStep,\n FunnelValidationError,\n FunnelValidationResult,\n} from '../types/funnel'\nimport { getCubeNameFromQuery } from './funnelExecution'\n\n/**\n * Validate that a binding key dimension exists in the given cubes\n */\nexport function validateBindingKeyExists(\n bindingKey: FunnelBindingKey,\n meta: CubeMeta | null\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n if (!meta?.cubes) {\n return errors // Can't validate without metadata\n }\n\n if (typeof bindingKey.dimension === 'string') {\n // Simple dimension - check it exists\n const [cubeName, dimName] = bindingKey.dimension.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n\n if (!cube) {\n errors.push({\n type: 'binding_key',\n message: `Cube \"${cubeName}\" not found for binding key`,\n })\n } else {\n const dim = cube.dimensions?.find((d) => d.name === bindingKey.dimension)\n if (!dim) {\n errors.push({\n type: 'binding_key',\n message: `Dimension \"${dimName}\" not found in cube \"${cubeName}\"`,\n })\n }\n }\n } else {\n // Cross-cube mappings - validate each\n for (const mapping of bindingKey.dimension) {\n const cube = meta.cubes.find((c) => c.name === mapping.cube)\n\n if (!cube) {\n errors.push({\n type: 'cross_cube',\n message: `Cube \"${mapping.cube}\" not found for binding key mapping`,\n })\n } else {\n const dim = cube.dimensions?.find((d) => d.name === mapping.dimension)\n if (!dim) {\n errors.push({\n type: 'cross_cube',\n message: `Dimension \"${mapping.dimension}\" not found in cube \"${mapping.cube}\"`,\n })\n }\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate that each step has a valid query\n */\nexport function validateStepQueries(\n steps: FunnelStep[]\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const query = step.query\n\n // Check that query has at least one field\n const hasFields =\n (query.measures && query.measures.length > 0) ||\n (query.dimensions && query.dimensions.length > 0) ||\n (query.timeDimensions && query.timeDimensions.length > 0)\n\n if (!hasFields) {\n errors.push({\n type: 'step_query',\n message: `Step ${i + 1} \"${step.name}\" has no measures, dimensions, or time dimensions`,\n stepIndex: i,\n })\n }\n }\n\n return errors\n}\n\n/**\n * Check if binding key can be resolved for a given query\n */\nexport function canResolveBindingKey(\n bindingKey: FunnelBindingKey,\n query: CubeQuery\n): boolean {\n if (typeof bindingKey.dimension === 'string') {\n // Simple case - binding key applies universally\n return true\n }\n\n // Cross-cube case - check if query's cube has a mapping\n const cubeName = getCubeNameFromQuery(query)\n if (!cubeName) return false\n\n return bindingKey.dimension.some((m) => m.cube === cubeName)\n}\n\n/**\n * Validate binding key for all funnel steps\n */\nexport function validateBindingKeyForSteps(\n bindingKey: FunnelBindingKey,\n steps: FunnelStep[]\n): FunnelValidationError[] {\n const errors: FunnelValidationError[] = []\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n if (!canResolveBindingKey(bindingKey, step.query)) {\n const cubeName = getCubeNameFromQuery(step.query) || 'unknown'\n errors.push({\n type: 'cross_cube',\n message: `Step ${i + 1} uses cube \"${cubeName}\" but no binding key mapping exists for it`,\n stepIndex: i,\n })\n }\n }\n\n return errors\n}\n\n/**\n * Validate time window format (ISO 8601 duration)\n */\nexport function validateTimeWindow(\n duration: string | undefined\n): FunnelValidationError | null {\n if (!duration) return null\n\n // Basic ISO 8601 duration validation\n // Formats: P1D, P7D, PT1H, PT30M, P1DT12H, etc.\n const durationRegex = /^P(?:\\d+Y)?(?:\\d+M)?(?:\\d+W)?(?:\\d+D)?(?:T(?:\\d+H)?(?:\\d+M)?(?:\\d+S)?)?$/\n\n if (!durationRegex.test(duration)) {\n return {\n type: 'time_window',\n message: `Invalid time window format \"${duration}\". Expected ISO 8601 duration (e.g., P7D, PT1H)`,\n }\n }\n\n return null\n}\n\n/**\n * Validate complete funnel configuration\n */\nexport function validateFunnelConfig(\n config: FunnelConfig,\n meta: CubeMeta | null\n): FunnelValidationResult {\n const errors: FunnelValidationError[] = []\n const warnings: FunnelValidationError[] = []\n\n // Check minimum steps\n if (config.steps.length < 2) {\n errors.push({\n type: 'general',\n message: 'Funnel requires at least 2 steps',\n })\n }\n\n // Validate binding key\n if (!config.bindingKey?.dimension) {\n errors.push({\n type: 'binding_key',\n message: 'Binding key dimension is required',\n })\n } else {\n // Check binding key exists in cubes\n errors.push(...validateBindingKeyExists(config.bindingKey, meta))\n\n // Check binding key can be resolved for all steps\n errors.push(...validateBindingKeyForSteps(config.bindingKey, config.steps))\n }\n\n // Validate step queries\n errors.push(...validateStepQueries(config.steps))\n\n // Validate time windows\n for (let i = 0; i < config.steps.length; i++) {\n const step = config.steps[i]\n const timeError = validateTimeWindow(step.timeToConvert)\n if (timeError) {\n timeError.stepIndex = i\n errors.push(timeError)\n }\n }\n\n // Validate global time window\n const globalTimeError = validateTimeWindow(config.globalTimeWindow)\n if (globalTimeError) {\n errors.push(globalTimeError)\n }\n\n // Add warnings for potential issues\n if (config.steps.length > 5) {\n warnings.push({\n type: 'general',\n message: 'Funnels with more than 5 steps may have reduced performance',\n })\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n }\n}\n\n/**\n * Quick check if minimum funnel requirements are met\n */\nexport function isMinimumFunnelConfigValid(\n bindingKey: FunnelBindingKey | null,\n queryCount: number\n): { isValid: boolean; message?: string } {\n if (queryCount < 2) {\n return { isValid: false, message: 'Add at least 2 steps for funnel' }\n }\n\n if (!bindingKey?.dimension) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n if (typeof bindingKey.dimension === 'string' && !bindingKey.dimension) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n if (Array.isArray(bindingKey.dimension) && bindingKey.dimension.length === 0) {\n return { isValid: false, message: 'Select a binding key dimension' }\n }\n\n return { isValid: true }\n}\n\n/**\n * Get available dimensions that can serve as binding keys\n * These should be dimensions that identify entities (e.g., user IDs, order IDs)\n */\nexport function getAvailableBindingKeyDimensions(\n meta: CubeMeta | null\n): Array<{ cube: string; dimension: string; label: string }> {\n if (!meta?.cubes) return []\n\n const dimensions: Array<{ cube: string; dimension: string; label: string }> = []\n\n for (const cube of meta.cubes) {\n if (!cube.dimensions) continue\n\n for (const dim of cube.dimensions) {\n // Only include string/number dimensions (not time dimensions)\n // as potential binding keys\n if (dim.type === 'string' || dim.type === 'number') {\n dimensions.push({\n cube: cube.name,\n dimension: dim.name,\n label: dim.title || dim.shortTitle || dim.name.split('.')[1] || dim.name,\n })\n }\n }\n }\n\n return dimensions\n}\n\n/**\n * Get the display label for a binding key\n */\nexport function getBindingKeyLabel(\n bindingKey: FunnelBindingKey | null\n): string {\n if (!bindingKey?.dimension) return 'Select binding key...'\n\n if (typeof bindingKey.dimension === 'string') {\n const parts = bindingKey.dimension.split('.')\n return parts[1] || bindingKey.dimension\n }\n\n // Cross-cube - show first mapping\n if (bindingKey.dimension.length > 0) {\n const first = bindingKey.dimension[0]\n const parts = first.dimension.split('.')\n return `${parts[1] || first.dimension} (${bindingKey.dimension.length} cubes)`\n }\n\n return 'Select binding key...'\n}\n"],"names":["parseRelativeDateRange","dateRange","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","findDateFilterForField","filters","field","filter","nested","simple","buildCompareDateRangeFromFilter","timeDimensionField","dateFilter","currentPeriod","priorPeriod","removeComparisonDateFilter","acc","groupFilter","cleanedSubFilters","buildCubeQuery","metrics","breakdowns","order","preserveComparisonFilters","comparisonFields","b","filteredFilters","f","shouldIncludeFilter","query","m","td","compareDateRange","STORAGE_KEY","createInitialState","isTimeDimension","breakdown","getFirstTimeDimension","getFirstDimension","getDimensions","getTimeDimensions","getChartAvailability","chartType","measureCount","dimensionCount","timeDimensionCount","totalBreakdowns","getAllChartAvailability","chartTypes","availability","selectBestChartType","currentChartType","hasTimeDimension","hasDimension","hasMeasure","getSmartChartDefaults","chartConfig","buildChartConfig","timeDimension","dimension","dimensions","allBreakdowns","shouldAutoSwitchChartType","userManuallySelected","recommendedType","safeText","value","assessmentColors","severityColors","issueSeverityColors","AssessmentBadge","assessment","reason","labels","jsx","jsxs","IssueItem","issue","CopyButton","text","copied","setCopied","React","err","RecommendationCard","rec","typeLabels","CodeBlock","ExplainAIPanel","analysis","onClose","onClear","handleClose","handleKeyDown","e","i","ExecutionPlanPanel","memo","sql","sqlLoading","sqlError","sqlPlaceholder","explainResult","explainLoading","explainHasRun","explainError","runExplain","aiAnalysis","aiAnalysisLoading","aiAnalysisError","runAIAnalysis","_clearAIAnalysis","enableAI","title","height","useAnalyze","setUseAnalyze","useState","showAIModal","setShowAIModal","formattedSql","handleAIClick","handleCloseModal","aiButton","Fragment","createEmptyQueryState","metricsToMeasures","breakdownsToQuery","timeDimensions","stateToCubeQuery","state","measuresToMetrics","measures","index","generateId","generateMetricLabel","queryToBreakdowns","dim","hasComparison","cubeQueryToState","isMultiQueryConfig","queryModeAdapter","storeState","config","c","queryConfig","multiConfig","queryStates","charts","activeView","queries","errors","warnings","q","qs","prefix","firstBreakdowns","_state","adapters","builtInAdaptersInitialized","ensureBuiltInAdaptersInitialized","funnelModeAdapter","flowModeAdapter","retentionModeAdapter","adapterRegistry","adapter","type","createInitialCoreState","createCoreSlice","set","get","activeViews","mode","currentConfig","name","modeState","currentState","mergedCharts","mergedActiveViews","stateAsRecord","queryAdapter","queryModeState","queryActiveView","funnelAdapter","funnelModeState","funnelActiveView","funnelConfig","flowAdapter","flowModeState","flowActiveView","flowConfig","retentionAdapter","retentionModeState","retentionActiveView","retentionConfig","workspace","createInitialQueryState","createQuerySlice","states","updater","newStates","strategy","newState","_","newActiveIndex","label","newMetric","id","fieldToRemove","newMetrics","newOrder","fieldName","existingIndex","fromIndex","toIndex","movedItem","granularity","newBreakdown","newBreakdowns","mergeStrategy","activeQueryIndex","targetIndex","analysisType","sourceIndex","targetBreakdown","isEnablingComparison","updatedBreakdowns","result","currentFilters","newDateFilter","convertDateRangeTypeToValue","currentChartConfig","existingFilters","newFilter","updatedFilters","group","direction","q1Breakdowns","current","validQueries","createInitialFunnelState","createFunnelSlice","lastStep","newStep","newSteps","updates","removed","bindingKey","cube","updatedSteps","step","validSteps","s","createInitialFlowState","createFlowSlice","key","newFilters","count","FLOW_MIN_DEPTH","FLOW_MAX_DEPTH","mapping","startingStepFilter","outputMode","effectiveStepsBefore","createInitialRetentionState","defaultRetentionSliceState","createRetentionSlice","range","periods","RETENTION_MIN_PERIODS","RETENTION_MAX_PERIODS","startDate","endDate","initialAIState","createInitialUIState","createUISlice","_get","tab","view","limit","prompt","generating","error","hasQuery","prev","queryToState","baseFilters","hasDateFilter","firstRange","optionsToAnalysisConfig","options","defaultFunnelChart","funnelChartConfig","funnelState","defaultFlowChart","flowChartConfig","flowState","defaultRetentionChart","retentionChartConfig","defaultDateRange","getDateRangeFromPreset","DEFAULT_DATE_RANGE_PRESET","retentionState","defaultQueryChart","queryChartConfig","createCrossSliceActions","createAnalysisBuilderStore","initialConfig","storeCreator","store","createStore","devtools","subscribeWithSelector","persist","persisted","isValidAnalysisWorkspace","isValidAnalysisConfig","AnalysisBuilderStoreContext","createContext","AnalysisBuilderStoreProvider","children","initialQuery","initialChartConfig","disableLocalStorage","initialAnalysisType","initialFunnelState","initialFlowState","initialRetentionState","initialActiveView","storeRef","useRef","useAnalysisBuilderStore","selector","useContext","useStore","useAnalysisBuilderStoreApi","selectCurrentState","selectMetrics","selectBreakdowns","selectFilters","selectChartConfig","selectUIState","selectMultiQueryState","selectFunnelState","extractTimeDimensions","validateTimeDimensionAlignment","q1TimeDims","qTimeDims","refTimeDim","matchingDim","validateMergeKeys","mergeKeys","allFields","detectMeasureCollisions","measureCounts","measure","collisions","collisionIndices","indices","detectAsymmetricDateRanges","dateRanges","validateMultiQueryConfig","isMultiQueryValid","getValidationSummary","parts","useAnalysisQueryBuilder","setActiveQueryIndex","setMergeStrategy","addQuery","removeQuery","getCurrentState","getMergeKeys","isMultiQueryModeGetter","queryState","isMultiQueryMode","currentQuery","useMemo","allQueries","multiQueryConfig","multiQueryValidation","isValidQuery","useAnalysisCombinedFields","combinedMetrics","seen","combined","qIndex","metric","combinedBreakdowns","effectiveBreakdowns","useAnalysisQueryExecution","initialData","funnelBindingKey","isFunnelModeEnabled","serverFunnelQuery","serverFlowQuery","serverRetentionQuery","retentionValidation","getFieldLabel","useCubeMeta","isFunnelMode","isFlowMode","isRetentionMode","isMultiMode","isSingleMode","isNewFunnelMode","buildFunnelConfigFromQueries","singleQueryResult","useCubeLoadQuery","multiQueryResult","useMultiCubeLoadQuery","funnelQueryResult","useFunnelQuery","flowQueryResult","useFlowQuery","retentionQueryResult","useRetentionQuery","dryRunResult","useDryRunQueries","funnelDryRunResult","useDryRunQuery","flowDryRunResult","retentionDryRunResult","isLoading","isFetching","hasDebounced","refetch","useCallback","executionStatus","hasResults","executionResults","row","perQueryResults","funnelExecutedQueries","funnelServerQuery","funnelDebugData","flowServerQuery","flowChartData","flowDebugData","retentionServerQuery","retentionChartData","retentionDebugData","needsRefresh","useAnalysisChartDefaults","externalColorPalette","displayConfig","useShallow","userManuallySelectedChart","localPaletteName","setChartTypeManual","setQueryChartConfig","setQueryDisplayConfig","setFunnelChartType","setFunnelChartConfig","setFunnelDisplayConfig","setLocalPaletteName","setUserManuallySelectedChart","setChartType","smartConfig","setChartConfig","setDisplayConfig","chartAvailability","colorPalette","getColorPalette","prevMetricsBreakdownsRef","useEffect","currentKey","newChartType","newConfig","smartDefaults","useAnalysisUIState","activeTab","displayLimit","showFieldModal","fieldModalMode","setActiveTab","setActiveView","setDisplayLimit","closeFieldModal","activeTableIndex","setActiveTableIndex","MAX_HASH_LENGTH","SHARE_PREFIX","compressAndEncode","json","compressToEncodedURIComponent","decodeAndDecompress","encoded","decompressFromEncodedURIComponent","parsed","isShareableSize","compressWithFallback","fullEncoded","minimalConfig","minimalEncoded","generateShareUrl","parseShareHash","hash","clearShareHash","url","parseShareUrl","useAnalysisInitialization","onQueryChange","onChartConfigChange","load","hasInitializedShareRef","useAnalysisBuilder","features","useCubeFeatures","storeApi","queryBuilder","combinedFields","funnelCube","funnelSteps","activeFunnelStepIndex","funnelTimeDimension","funnelChartType","funnelChartConfigFromStore","flowCube","flowBindingKey","flowTimeDimension","eventDimension","startingStep","stepsBefore","stepsAfter","joinStrategy","flowDisplayConfigFromStore","flowDisplayConfig","flowChartType","buildFunnelQueryFromSteps","buildFlowQuery","retentionCube","retentionBindingKey","retentionTimeDimension","retentionDateRange","retentionCohortFilters","retentionActivityFilters","retentionBreakdowns","retentionViewGranularity","retentionPeriods","retentionType","buildRetentionQuery","getRetentionValidation","retentionDisplayConfig","setRetentionCube","setRetentionBindingKey","setRetentionTimeDimension","setRetentionDateRange","setRetentionCohortFilters","setRetentionActivityFilters","setRetentionBreakdowns","addRetentionBreakdown","removeRetentionBreakdown","setRetentionViewGranularity","setRetentionPeriods","setRetentionType","effectiveIsValidQuery","queryExecution","chartDefaults","uiState","openMetricsModal","addMetric","removeMetric","toggleMetric","reorderMetrics","openBreakdownsModal","addBreakdown","removeBreakdown","toggleBreakdown","setBreakdownGranularity","toggleBreakdownComparison","reorderBreakdowns","setFilters","dropFieldToFilter","setOrder","clearQuery","clearCurrentMode","setFunnelBindingKey","setAnalysisType","setFunnelCube","addFunnelStep","removeFunnelStep","updateFunnelStep","setActiveFunnelStepIndex","reorderFunnelSteps","setFunnelTimeDimension","funnelDisplayConfigFromStore","funnelDisplayConfig","setFlowCube","setFlowBindingKey","setFlowTimeDimension","setEventDimension","setStartingStepName","setStartingStepFilters","setStepsBefore","setStepsAfter","setJoinStrategy","setFlowDisplayConfig","setRetentionDisplayConfig","aiState","openAI","closeAI","setAIPrompt","setAIGenerating","setAIError","setAIHasGeneratedQuery","saveAIPreviousState","restoreAIPreviousState","shareButtonStateRef","canShare","getValidation","adapterValidation","handleFieldSelected","fieldType","_cubeName","keepOpen","generateAI","resolve","acceptAI","cancelAI","share","getQueryConfig","funnelQuery","getChartConfig","getAnalysisType","validateBindingKeyExists","meta","cubeName","dimName","d","validateStepQueries","steps","canResolveBindingKey","getCubeNameFromQuery","validateBindingKeyForSteps","validateTimeWindow","duration","validateFunnelConfig","timeError","globalTimeError","isMinimumFunnelConfigValid","queryCount","getAvailableBindingKeyDimensions","getBindingKeyLabel","first"],"mappings":"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"}