drizzle-cube 0.4.41 → 0.4.43

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 (188) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/express/index.cjs +1 -1
  3. package/dist/adapters/express/index.js +2 -2
  4. package/dist/adapters/fastify/index.cjs +1 -1
  5. package/dist/adapters/fastify/index.js +2 -2
  6. package/dist/adapters/{handler-dHHEEbG9.cjs → handler-BneUGY0k.cjs} +1 -1
  7. package/dist/adapters/{handler-fto6TSVn.js → handler-CiQoQsnP.js} +1 -1
  8. package/dist/adapters/hono/index.cjs +1 -1
  9. package/dist/adapters/hono/index.js +5 -5
  10. package/dist/adapters/{mcp-transport-tB5a7Het.js → mcp-transport-CC3hQOnb.js} +1099 -1338
  11. package/dist/adapters/mcp-transport-mmuPvjfR.cjs +255 -0
  12. package/dist/adapters/nextjs/index.cjs +1 -1
  13. package/dist/adapters/nextjs/index.js +2 -2
  14. package/dist/adapters/{openai-Ckpe7iU7.js → openai-CQfaz257.js} +1 -1
  15. package/dist/{server/openai-DKpZPCay.cjs → adapters/openai-CZ74gWd4.cjs} +1 -1
  16. package/dist/adapters/{openai-Bc8qwEKW.cjs → openai-DLfardui.cjs} +1 -1
  17. package/dist/adapters/{openai-DxeVtl8X.js → openai-DaxuhJLS.js} +1 -1
  18. package/dist/client/charts.js +12 -12
  19. package/dist/client/chunks/{DashboardEditModal-D_7J62sG.js → DashboardEditModal-BTdV528l.js} +1421 -1396
  20. package/dist/client/chunks/DashboardEditModal-BTdV528l.js.map +1 -0
  21. package/dist/client/chunks/{FieldSearchModal-5Qz6vvTz.js → FieldSearchModal-D75vy4Wb.js} +4 -4
  22. package/dist/client/chunks/{FieldSearchModal-5Qz6vvTz.js.map → FieldSearchModal-D75vy4Wb.js.map} +1 -1
  23. package/dist/client/chunks/KpiDelta-Bk8bzKYM.js +2 -0
  24. package/dist/client/chunks/KpiNumber-CKF-8e_T.js +2 -0
  25. package/dist/client/chunks/KpiText-Iz1vIvu_.js +2 -0
  26. package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js → RetentionCombinedChart-DIhK5pD8.js} +3 -3
  27. package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js.map → RetentionCombinedChart-DIhK5pD8.js.map} +1 -1
  28. package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js → RetentionHeatmap-CyREolyP.js} +1 -1
  29. package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js.map → RetentionHeatmap-CyREolyP.js.map} +1 -1
  30. package/dist/client/chunks/SchemaVisualization-B1GUT-FM.js +2 -0
  31. package/dist/client/chunks/SchemaVisualizationLazy-DymwT34e.js +2 -0
  32. package/dist/client/chunks/{analysis-builder-DPJJiHVx.js → analysis-builder-C1CJ0c7L.js} +415 -406
  33. package/dist/client/chunks/analysis-builder-C1CJ0c7L.js.map +1 -0
  34. package/dist/client/chunks/{analysis-builder-shared-C-C-rOgu.js → analysis-builder-shared-rkjJfWLT.js} +9 -9
  35. package/dist/client/chunks/{analysis-builder-shared-C-C-rOgu.js.map → analysis-builder-shared-rkjJfWLT.js.map} +1 -1
  36. package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js → chart-activity-grid-DLktOINm.js} +2 -2
  37. package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js.map → chart-activity-grid-DLktOINm.js.map} +1 -1
  38. package/dist/client/chunks/{chart-area-e9ysnatQ.js → chart-area-BwYaflNk.js} +3 -3
  39. package/dist/client/chunks/{chart-area-e9ysnatQ.js.map → chart-area-BwYaflNk.js.map} +1 -1
  40. package/dist/client/chunks/{chart-bar-DVzmau1G.js → chart-bar-BiENfFgE.js} +4 -4
  41. package/dist/client/chunks/{chart-bar-DVzmau1G.js.map → chart-bar-BiENfFgE.js.map} +1 -1
  42. package/dist/client/chunks/{chart-box-plot-CCmbHv1Y.js → chart-box-plot-BJF1tBXC.js} +3 -3
  43. package/dist/client/chunks/{chart-box-plot-CCmbHv1Y.js.map → chart-box-plot-BJF1tBXC.js.map} +1 -1
  44. package/dist/client/chunks/{chart-bubble-S6qSwWdK.js → chart-bubble-DQQhGVDJ.js} +3 -3
  45. package/dist/client/chunks/{chart-bubble-S6qSwWdK.js.map → chart-bubble-DQQhGVDJ.js.map} +1 -1
  46. package/dist/client/chunks/{chart-candlestick-BNKbDruo.js → chart-candlestick-C2UuXbLe.js} +3 -3
  47. package/dist/client/chunks/{chart-candlestick-BNKbDruo.js.map → chart-candlestick-C2UuXbLe.js.map} +1 -1
  48. package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js → chart-config-activity-grid-DJOU3TEz.js} +2 -2
  49. package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js.map → chart-config-activity-grid-DJOU3TEz.js.map} +1 -1
  50. package/dist/client/chunks/{chart-config-area-DKwgcHp4.js → chart-config-area-CWnWVT6a.js} +2 -2
  51. package/dist/client/chunks/{chart-config-area-DKwgcHp4.js.map → chart-config-area-CWnWVT6a.js.map} +1 -1
  52. package/dist/client/chunks/{chart-config-bar-deTjEhap.js → chart-config-bar-C-7Dr1Ho.js} +2 -2
  53. package/dist/client/chunks/{chart-config-bar-deTjEhap.js.map → chart-config-bar-C-7Dr1Ho.js.map} +1 -1
  54. package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js → chart-config-box-plot-mVOwmLdu.js} +2 -2
  55. package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js.map → chart-config-box-plot-mVOwmLdu.js.map} +1 -1
  56. package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js → chart-config-bubble-BPE2CeiD.js} +2 -2
  57. package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js.map → chart-config-bubble-BPE2CeiD.js.map} +1 -1
  58. package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js → chart-config-candlestick-BSB9DRy2.js} +2 -2
  59. package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js.map → chart-config-candlestick-BSB9DRy2.js.map} +1 -1
  60. package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js → chart-config-data-table-Bhdx5Hem.js} +2 -2
  61. package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js.map → chart-config-data-table-Bhdx5Hem.js.map} +1 -1
  62. package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js → chart-config-funnel-Cl-v-bm1.js} +2 -2
  63. package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js.map → chart-config-funnel-Cl-v-bm1.js.map} +1 -1
  64. package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js → chart-config-gauge-CdrUTJMJ.js} +2 -2
  65. package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js.map → chart-config-gauge-CdrUTJMJ.js.map} +1 -1
  66. package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js → chart-config-heat-map-DGE3NzoF.js} +2 -2
  67. package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js.map → chart-config-heat-map-DGE3NzoF.js.map} +1 -1
  68. package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js → chart-config-kpi-delta-DMrQerUW.js} +2 -2
  69. package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js.map → chart-config-kpi-delta-DMrQerUW.js.map} +1 -1
  70. package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js → chart-config-kpi-number-DCytCytn.js} +2 -2
  71. package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js.map → chart-config-kpi-number-DCytCytn.js.map} +1 -1
  72. package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js → chart-config-kpi-text-KdKQUvHo.js} +2 -2
  73. package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js.map → chart-config-kpi-text-KdKQUvHo.js.map} +1 -1
  74. package/dist/client/chunks/{chart-config-line--j7-dLue.js → chart-config-line-Bl9VDAdz.js} +2 -2
  75. package/dist/client/chunks/{chart-config-line--j7-dLue.js.map → chart-config-line-Bl9VDAdz.js.map} +1 -1
  76. package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js → chart-config-markdown-BX26b94i.js} +2 -2
  77. package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js.map → chart-config-markdown-BX26b94i.js.map} +1 -1
  78. package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js → chart-config-measure-profile-DwtRhEFh.js} +2 -2
  79. package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js.map → chart-config-measure-profile-DwtRhEFh.js.map} +1 -1
  80. package/dist/client/chunks/{chart-config-pie-yU4jipl9.js → chart-config-pie-BzBcqPMJ.js} +2 -2
  81. package/dist/client/chunks/{chart-config-pie-yU4jipl9.js.map → chart-config-pie-BzBcqPMJ.js.map} +1 -1
  82. package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js → chart-config-radar-6ZOgt__z.js} +2 -2
  83. package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js.map → chart-config-radar-6ZOgt__z.js.map} +1 -1
  84. package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js → chart-config-radial-bar-Df6Eta7N.js} +2 -2
  85. package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js.map → chart-config-radial-bar-Df6Eta7N.js.map} +1 -1
  86. package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js → chart-config-sankey-DgqKBFvN.js} +2 -2
  87. package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js.map → chart-config-sankey-DgqKBFvN.js.map} +1 -1
  88. package/dist/client/chunks/{chart-config-scatter-MVUFupub.js → chart-config-scatter-D5nVLDvi.js} +2 -2
  89. package/dist/client/chunks/{chart-config-scatter-MVUFupub.js.map → chart-config-scatter-D5nVLDvi.js.map} +1 -1
  90. package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js → chart-config-sunburst-Ca3FX9nW.js} +2 -2
  91. package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js.map → chart-config-sunburst-Ca3FX9nW.js.map} +1 -1
  92. package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js → chart-config-tree-map-Bjy4QNa3.js} +2 -2
  93. package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js.map → chart-config-tree-map-Bjy4QNa3.js.map} +1 -1
  94. package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js → chart-config-waterfall-C5K2eqR7.js} +2 -2
  95. package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js.map → chart-config-waterfall-C5K2eqR7.js.map} +1 -1
  96. package/dist/client/chunks/{chart-data-table-D4s27-U3.js → chart-data-table-2iCsn0CF.js} +1099 -933
  97. package/dist/client/chunks/chart-data-table-2iCsn0CF.js.map +1 -0
  98. package/dist/client/chunks/{chart-funnel-C9JRW79j.js → chart-funnel-poyOf7-e.js} +3 -3
  99. package/dist/client/chunks/{chart-funnel-C9JRW79j.js.map → chart-funnel-poyOf7-e.js.map} +1 -1
  100. package/dist/client/chunks/{chart-gauge-BFhc4i_f.js → chart-gauge-D5J4gRky.js} +3 -3
  101. package/dist/client/chunks/{chart-gauge-BFhc4i_f.js.map → chart-gauge-D5J4gRky.js.map} +1 -1
  102. package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js → chart-heat-map-BAMVhLGG.js} +3 -3
  103. package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js.map → chart-heat-map-BAMVhLGG.js.map} +1 -1
  104. package/dist/client/chunks/{chart-kpi-delta-DzGNnIcW.js → chart-kpi-delta-KQjUIeal.js} +71 -73
  105. package/dist/client/chunks/{chart-kpi-delta-DzGNnIcW.js.map → chart-kpi-delta-KQjUIeal.js.map} +1 -1
  106. package/dist/client/chunks/{chart-kpi-number-sHtgbE_f.js → chart-kpi-number-CsQgV_x3.js} +62 -63
  107. package/dist/client/chunks/{chart-kpi-number-sHtgbE_f.js.map → chart-kpi-number-CsQgV_x3.js.map} +1 -1
  108. package/dist/client/chunks/{chart-kpi-text-Bmk-GzVJ.js → chart-kpi-text-BR0IyeUU.js} +26 -27
  109. package/dist/client/chunks/{chart-kpi-text-Bmk-GzVJ.js.map → chart-kpi-text-BR0IyeUU.js.map} +1 -1
  110. package/dist/client/chunks/{chart-line-Bkl5WQAw.js → chart-line-B5_WntY5.js} +4 -4
  111. package/dist/client/chunks/{chart-line-Bkl5WQAw.js.map → chart-line-B5_WntY5.js.map} +1 -1
  112. package/dist/client/chunks/{chart-markdown-7MNetRtX.js → chart-markdown-B6bENbel.js} +648 -645
  113. package/dist/client/chunks/chart-markdown-B6bENbel.js.map +1 -0
  114. package/dist/client/chunks/{chart-measure-profile-B7h6vQo4.js → chart-measure-profile-yWk-obNb.js} +4 -4
  115. package/dist/client/chunks/{chart-measure-profile-B7h6vQo4.js.map → chart-measure-profile-yWk-obNb.js.map} +1 -1
  116. package/dist/client/chunks/{chart-pie-Do2YnCxl.js → chart-pie-BodrUoHv.js} +4 -4
  117. package/dist/client/chunks/{chart-pie-Do2YnCxl.js.map → chart-pie-BodrUoHv.js.map} +1 -1
  118. package/dist/client/chunks/{chart-radar-C7gQkH70.js → chart-radar-gG3zfLud.js} +4 -4
  119. package/dist/client/chunks/{chart-radar-C7gQkH70.js.map → chart-radar-gG3zfLud.js.map} +1 -1
  120. package/dist/client/chunks/{chart-radial-bar-DHqCck3x.js → chart-radial-bar-C2IPCV8c.js} +4 -4
  121. package/dist/client/chunks/{chart-radial-bar-DHqCck3x.js.map → chart-radial-bar-C2IPCV8c.js.map} +1 -1
  122. package/dist/client/chunks/{chart-sankey-8nRYnupt.js → chart-sankey-BOyxfG1Q.js} +3 -3
  123. package/dist/client/chunks/{chart-sankey-8nRYnupt.js.map → chart-sankey-BOyxfG1Q.js.map} +1 -1
  124. package/dist/client/chunks/{chart-scatter-YSHOUfXf.js → chart-scatter-B8OwlsAX.js} +4 -4
  125. package/dist/client/chunks/{chart-scatter-YSHOUfXf.js.map → chart-scatter-B8OwlsAX.js.map} +1 -1
  126. package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js → chart-sunburst-D9lGEOCc.js} +4 -4
  127. package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js.map → chart-sunburst-D9lGEOCc.js.map} +1 -1
  128. package/dist/client/chunks/{chart-tree-map-BlhcXK1F.js → chart-tree-map-DZaKy9he.js} +4 -4
  129. package/dist/client/chunks/{chart-tree-map-BlhcXK1F.js.map → chart-tree-map-DZaKy9he.js.map} +1 -1
  130. package/dist/client/chunks/{chart-waterfall-BWCAzlPq.js → chart-waterfall-BCdUx4DC.js} +4 -4
  131. package/dist/client/chunks/{chart-waterfall-BWCAzlPq.js.map → chart-waterfall-BCdUx4DC.js.map} +1 -1
  132. package/dist/client/chunks/{charts-core-Cy3rHADX.js → charts-core-C5Yokk-x.js} +2 -2
  133. package/dist/client/chunks/{charts-core-Cy3rHADX.js.map → charts-core-C5Yokk-x.js.map} +1 -1
  134. package/dist/client/chunks/{core-BdWfCZ3y.js → core-DcfMGTVa.js} +2 -2
  135. package/dist/client/chunks/{core-BdWfCZ3y.js.map → core-DcfMGTVa.js.map} +1 -1
  136. package/dist/client/chunks/{dist-BWPE2m_X.js → dist-eZurnOde.js} +1 -1
  137. package/dist/client/chunks/{dist-BWPE2m_X.js.map → dist-eZurnOde.js.map} +1 -1
  138. package/dist/client/chunks/exceljs.min-CcjgM-qg.js +31986 -0
  139. package/dist/client/chunks/exceljs.min-CcjgM-qg.js.map +1 -0
  140. package/dist/client/chunks/{javascript-O1RIRkZr.js → javascript-DFvvCuoP.js} +1 -1
  141. package/dist/client/chunks/{javascript-O1RIRkZr.js.map → javascript-DFvvCuoP.js.map} +1 -1
  142. package/dist/client/chunks/{json-C5bX2tt1.js → json-BBm9TlrA.js} +1 -1
  143. package/dist/client/chunks/{json-C5bX2tt1.js.map → json-BBm9TlrA.js.map} +1 -1
  144. package/dist/client/chunks/{rolldown-runtime-lc2dmIiU.js → rolldown-runtime-CCl2IeXn.js} +5 -2
  145. package/dist/client/chunks/{schema-visualization-BJ8HrNqB.js → schema-visualization-t1KiOORo.js} +259 -267
  146. package/dist/client/chunks/schema-visualization-t1KiOORo.js.map +1 -0
  147. package/dist/client/chunks/{sql-D2qikO5q.js → sql-k0GA6oZ_.js} +1 -1
  148. package/dist/client/chunks/{sql-D2qikO5q.js.map → sql-k0GA6oZ_.js.map} +1 -1
  149. package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js → syntaxHighlighting-CnDujqwg.js} +2 -2
  150. package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js.map → syntaxHighlighting-CnDujqwg.js.map} +1 -1
  151. package/dist/client/chunks/{useDebounce-EWynD0lC.js → useDebounce-CKqkM42n.js} +11 -14
  152. package/dist/client/chunks/{useDebounce-EWynD0lC.js.map → useDebounce-CKqkM42n.js.map} +1 -1
  153. package/dist/client/chunks/{useExplainAI-BBTJWQVu.js → useExplainAI-DBIfYwz-.js} +12 -12
  154. package/dist/client/chunks/{useExplainAI-BBTJWQVu.js.map → useExplainAI-DBIfYwz-.js.map} +1 -1
  155. package/dist/client/chunks/{utils-DMyRayr_.js → utils--qCr8Yn5.js} +2 -2
  156. package/dist/client/chunks/utils--qCr8Yn5.js.map +1 -0
  157. package/dist/client/chunks/{vendor-iY25ogTA.js → vendor-BRlsCGnK.js} +46 -46
  158. package/dist/client/chunks/{vendor-iY25ogTA.js.map → vendor-BRlsCGnK.js.map} +1 -1
  159. package/dist/client/components.js +3 -3
  160. package/dist/client/hooks.js +3 -3
  161. package/dist/client/icons/types.d.ts +1 -0
  162. package/dist/client/icons.js +1 -1
  163. package/dist/client/index.d.ts +2 -2
  164. package/dist/client/index.js +168 -169
  165. package/dist/client/index.js.map +1 -1
  166. package/dist/client/providers.js +1 -1
  167. package/dist/client/schema.d.ts +13 -0
  168. package/dist/client/schema.js +2 -0
  169. package/dist/client/styles.css +1 -1
  170. package/dist/client/types.d.ts +6 -0
  171. package/dist/client/utils/exportXlsx.d.ts +20 -0
  172. package/dist/client/utils/index.d.ts +1 -0
  173. package/dist/client/utils.js +7 -7
  174. package/dist/client-bundle-stats.html +1 -1
  175. package/dist/server/index.cjs +1 -1
  176. package/dist/server/index.js +1 -1
  177. package/dist/server/{openai-DqCEogm0.js → openai-CqZg6zYL.js} +1 -1
  178. package/dist/server/{openai-0HbLlZq6.cjs → openai-D9Zjuby1.cjs} +1 -1
  179. package/dist/{adapters/openai-C96O8M75.cjs → server/openai-DmuEbFd6.cjs} +1 -1
  180. package/dist/server/{openai-DnGeU9PT.js → openai-rwauPzCT.js} +1 -1
  181. package/package.json +10 -1
  182. package/dist/adapters/mcp-transport-ro4OL4BW.cjs +0 -255
  183. package/dist/client/chunks/DashboardEditModal-D_7J62sG.js.map +0 -1
  184. package/dist/client/chunks/analysis-builder-DPJJiHVx.js.map +0 -1
  185. package/dist/client/chunks/chart-data-table-D4s27-U3.js.map +0 -1
  186. package/dist/client/chunks/chart-markdown-7MNetRtX.js.map +0 -1
  187. package/dist/client/chunks/schema-visualization-BJ8HrNqB.js.map +0 -1
  188. package/dist/client/chunks/utils-DMyRayr_.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/client/stores/notebookStore.tsx","../../src/client/components/AgenticNotebook/NotebookPortletBlock.tsx","../../src/client/components/AgenticNotebook/NotebookMarkdownBlock.tsx","../../src/client/components/AgenticNotebook/NotebookCanvas.tsx","../../src/client/hooks/useAgentChat.ts","../../src/client/components/AgenticNotebook/ChatMessage.tsx","../../src/client/components/AgenticNotebook/ChatInput.tsx","../../src/client/components/AgenticNotebook/AgentChatPanel.tsx","../../src/client/components/AgenticNotebook/index.tsx","../../src/client/components/AnalyticsPage.tsx","../../src/client/stores/dataBrowserStore.tsx","../../src/client/hooks/useDataBrowser.ts","../../src/client/components/DataBrowser/DataBrowserSidebar.tsx","../../src/client/components/DataBrowser/DataBrowserToolbar.tsx","../../src/client/components/DataBrowser/DataBrowserTable.tsx","../../src/client/components/DataBrowser/index.tsx","../../src/client/components/DashboardThumbnailPlaceholder.tsx"],"sourcesContent":["/**\n * Notebook Zustand Store (Instance-based)\n *\n * State management for the AgenticNotebook component, consolidating:\n * - Notebook blocks (portlets + markdown)\n * - Chat messages\n * - Session state\n * - UI state\n *\n * KEY ARCHITECTURE: Instance-based stores\n * - Each AgenticNotebook gets its own store instance via Context\n * - No server state (data fetching is handled by portlets via TanStack Query)\n * - State is per-notebook session\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, subscribeWithSelector } from 'zustand/middleware'\nimport type {\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n} from '../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A portlet block in the notebook\n */\nexport interface PortletBlock {\n id: string\n type: 'portlet'\n title: string\n query: string\n chartType: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n}\n\n/**\n * A markdown text block in the notebook\n */\nexport interface MarkdownBlock {\n id: string\n type: 'markdown'\n title?: string\n content: string\n}\n\n/**\n * A block in the notebook canvas\n */\nexport type NotebookBlock = PortletBlock | MarkdownBlock\n\n/**\n * A tool call record for display in chat messages\n */\nexport interface ToolCallRecord {\n id: string\n name: string\n input?: unknown\n result?: unknown\n status: 'running' | 'complete' | 'error'\n}\n\n/**\n * A chat message\n */\nexport interface ChatMessage {\n id: string\n role: 'user' | 'assistant'\n content: string\n error?: string\n toolCalls?: ToolCallRecord[]\n timestamp: number\n}\n\n/**\n * Serializable notebook config for save/load\n */\nexport interface NotebookConfig {\n blocks: NotebookBlock[]\n messages: ChatMessage[]\n}\n\n// ============================================================================\n// Store State\n// ============================================================================\n\nexport interface NotebookStoreState {\n /** Ordered array of notebook blocks */\n blocks: NotebookBlock[]\n\n /** Chat message history */\n messages: ChatMessage[]\n\n /** Whether the agent is currently streaming a response */\n isStreaming: boolean\n\n /** Agent SDK session ID for multi-turn conversations */\n sessionId: string | null\n\n /** Chat input value */\n inputValue: string\n}\n\n// ============================================================================\n// Store Actions\n// ============================================================================\n\nexport interface NotebookStoreActions {\n // Block actions\n addBlock: (block: NotebookBlock) => void\n removeBlock: (id: string) => void\n moveBlock: (id: string, direction: 'up' | 'down') => void\n updateBlock: (id: string, updates: Partial<Omit<PortletBlock, 'id' | 'type'>>) => void\n\n // Chat actions\n addMessage: (message: ChatMessage) => void\n appendToLastAssistantMessage: (text: string) => void\n setLastAssistantError: (error: string) => void\n addToolCallToLastAssistant: (toolCall: ToolCallRecord) => void\n updateLastToolCall: (update: Partial<ToolCallRecord>) => void\n\n // Session/UI actions\n setIsStreaming: (streaming: boolean) => void\n setSessionId: (id: string | null) => void\n setInputValue: (value: string) => void\n\n // Persistence\n save: () => NotebookConfig\n load: (config: NotebookConfig) => void\n\n // Reset\n reset: () => void\n}\n\n/**\n * Combined store type\n */\nexport type NotebookStore = NotebookStoreState & NotebookStoreActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst createDefaultState = (): NotebookStoreState => ({\n blocks: [],\n messages: [],\n isStreaming: false,\n sessionId: null,\n inputValue: '',\n})\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\nfunction createStoreActions(\n set: (\n partial:\n | Partial<NotebookStore>\n | ((state: NotebookStore) => Partial<NotebookStore>)\n ) => void,\n get: () => NotebookStore\n): NotebookStoreActions {\n return {\n // Block actions\n addBlock: (block) =>\n set((state) => ({\n blocks: [...state.blocks, block],\n })),\n\n removeBlock: (id) =>\n set((state) => ({\n blocks: state.blocks.filter((b) => b.id !== id),\n })),\n\n moveBlock: (id, direction) =>\n set((state) => {\n const idx = state.blocks.findIndex((b) => b.id === id)\n if (idx === -1) return {}\n if (direction === 'up' && idx === 0) return {}\n if (direction === 'down' && idx === state.blocks.length - 1) return {}\n\n const newBlocks = [...state.blocks]\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n ;[newBlocks[idx], newBlocks[swapIdx]] = [newBlocks[swapIdx], newBlocks[idx]]\n return { blocks: newBlocks }\n }),\n\n updateBlock: (id, updates) =>\n set((state) => ({\n blocks: state.blocks.map((b) =>\n b.id === id && b.type === 'portlet' ? { ...b, ...updates } : b\n ),\n })),\n\n // Chat actions\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n\n appendToLastAssistantMessage: (text) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = {\n ...lastMsg,\n content: lastMsg.content + text,\n }\n }\n return { messages }\n }),\n\n setLastAssistantError: (error) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = { ...lastMsg, error }\n }\n return { messages }\n }),\n\n addToolCallToLastAssistant: (toolCall) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = {\n ...lastMsg,\n toolCalls: [...(lastMsg.toolCalls || []), toolCall],\n }\n }\n return { messages }\n }),\n\n updateLastToolCall: (update) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg?.role === 'assistant' && lastMsg.toolCalls?.length) {\n const toolCalls = [...lastMsg.toolCalls]\n // Find by ID if provided, otherwise fall back to last\n const idx = update.id\n ? toolCalls.findIndex((tc) => tc.id === update.id)\n : toolCalls.length - 1\n if (idx !== -1) {\n toolCalls[idx] = { ...toolCalls[idx], ...update }\n messages[messages.length - 1] = { ...lastMsg, toolCalls }\n }\n }\n return { messages }\n }),\n\n // Session/UI actions\n setIsStreaming: (streaming) => set({ isStreaming: streaming }),\n setSessionId: (id) => set({ sessionId: id }),\n setInputValue: (value) => set({ inputValue: value }),\n\n // Persistence\n save: () => {\n const state = get()\n return {\n blocks: state.blocks,\n messages: state.messages,\n }\n },\n\n load: (config) =>\n set({\n blocks: config.blocks || [],\n messages: config.messages || [],\n }),\n\n // Reset\n reset: () => set(createDefaultState()),\n }\n}\n\n/**\n * Create a new notebook store instance\n */\nexport function createNotebookStore() {\n const initialState = createDefaultState()\n\n return createStore<NotebookStore>()(\n devtools(\n subscribeWithSelector((set, get) => ({\n ...initialState,\n ...createStoreActions(set, get),\n })),\n { name: 'NotebookStore' }\n )\n )\n}\n\n// ============================================================================\n// React Context & Provider\n// ============================================================================\n\nconst NotebookStoreContext = createContext<StoreApi<NotebookStore> | null>(null)\n\nexport interface NotebookStoreProviderProps {\n children: ReactNode\n /** Initial config to load */\n initialConfig?: NotebookConfig\n}\n\n/**\n * Provider component that creates a store instance per AgenticNotebook\n */\nexport function NotebookStoreProvider({\n children,\n initialConfig,\n}: NotebookStoreProviderProps) {\n const storeRef = useRef<StoreApi<NotebookStore> | null>(null)\n\n if (!storeRef.current) {\n const store = createNotebookStore()\n if (initialConfig) {\n store.getState().load(initialConfig)\n }\n storeRef.current = store\n }\n\n return (\n <NotebookStoreContext.Provider value={storeRef.current}>\n {children}\n </NotebookStoreContext.Provider>\n )\n}\n\n/**\n * Hook to access the notebook store from context\n * @throws Error if used outside of provider\n */\nexport function useNotebookStore<T>(selector: (state: NotebookStore) => T): T {\n const store = useContext(NotebookStoreContext)\n if (!store) {\n throw new Error('useNotebookStore must be used within NotebookStoreProvider')\n }\n return useStore(store, selector)\n}\n\n// ============================================================================\n// Selectors\n// ============================================================================\n\nexport const selectBlocks = (state: NotebookStore) => state.blocks\nexport const selectMessages = (state: NotebookStore) => state.messages\nexport const selectIsStreaming = (state: NotebookStore) => state.isStreaming\nexport const selectSessionId = (state: NotebookStore) => state.sessionId\nexport const selectInputValue = (state: NotebookStore) => state.inputValue\n\nexport const selectChatState = (state: NotebookStore) => ({\n messages: state.messages,\n isStreaming: state.isStreaming,\n inputValue: state.inputValue,\n})\n\nexport const selectChatActions = (state: NotebookStore) => ({\n addMessage: state.addMessage,\n appendToLastAssistantMessage: state.appendToLastAssistantMessage,\n setLastAssistantError: state.setLastAssistantError,\n addToolCallToLastAssistant: state.addToolCallToLastAssistant,\n updateLastToolCall: state.updateLastToolCall,\n setIsStreaming: state.setIsStreaming,\n setInputValue: state.setInputValue,\n setSessionId: state.setSessionId,\n})\n\nexport const selectBlockActions = (state: NotebookStore) => ({\n addBlock: state.addBlock,\n removeBlock: state.removeBlock,\n moveBlock: state.moveBlock,\n updateBlock: state.updateBlock,\n})\n","/**\n * NotebookPortletBlock - Wraps AnalyticsPortlet for notebook display\n *\n * Uses the same header pattern as DashboardPortletCard for consistency:\n * - Title on the left with DebugModal inline\n * - Action buttons on the right (move, edit, delete)\n */\n\nimport React, { useState, useCallback } from 'react'\nimport type { CSSProperties } from 'react'\nimport type { PortletBlock } from '../../stores/notebookStore'\nimport type { ChartAxisConfig, ChartDisplayConfig, ChartType } from '../../types'\nimport type { ColorPalette } from '../../utils/colorPalettes'\nimport type { FlowChartData } from '../../types/flow'\nimport type { RetentionChartData } from '../../types/retention'\nimport { getIcon } from '../../icons/registry'\nimport AnalyticsPortlet from '../AnalyticsPortlet'\nimport DebugModal from '../DebugModal'\n\nconst ICON_STYLE: CSSProperties = { width: '16px', height: '16px', color: 'currentColor' }\n\ninterface DebugData {\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n queryObject: unknown\n data: unknown[] | FlowChartData | RetentionChartData\n chartType: ChartType\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number } | null\n drillState?: unknown\n}\n\ninterface NotebookPortletBlockProps {\n block: PortletBlock\n colorPalette?: ColorPalette\n onRemove: (id: string) => void\n onMoveUp: (id: string) => void\n onMoveDown: (id: string) => void\n onEdit: (block: PortletBlock) => void\n isFirst: boolean\n isLast: boolean\n}\n\nconst ChevronUpIcon = getIcon('chevronUp')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst EditIcon = getIcon('edit')\nconst DeleteIcon = getIcon('delete')\n\nconst NotebookPortletBlock = React.memo(function NotebookPortletBlock({\n block,\n colorPalette,\n onRemove,\n onMoveUp,\n onMoveDown,\n onEdit,\n isFirst,\n isLast,\n}: NotebookPortletBlockProps) {\n const [debugData, setDebugData] = useState<DebugData | null>(null)\n\n const handleDebugDataReady = useCallback((data: DebugData) => {\n setDebugData(data)\n }, [])\n\n return (\n <div className=\"dc:relative dc:mb-4 bg-dc-surface dc:border border-dc-border dc:rounded-lg dc:flex dc:flex-col\">\n {/* Header - same pattern as DashboardPortletCard */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-3 dc:py-1.5 dc:border-b border-dc-border dc:shrink-0 bg-dc-surface-secondary dc:rounded-t-lg\">\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:flex-1 dc:min-w-0\">\n <h3 className=\"dc:font-semibold dc:text-sm text-dc-text dc:truncate\">\n {block.title || 'Untitled'}\n </h3>\n {debugData && (\n <DebugModal\n chartConfig={debugData.chartConfig}\n displayConfig={debugData.displayConfig}\n queryObject={debugData.queryObject}\n data={debugData.data}\n chartType={debugData.chartType}\n cacheInfo={debugData.cacheInfo ?? undefined}\n />\n )}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-1 dc:shrink-0 dc:ml-4 dc:-mr-2\">\n {!isFirst && (\n <button\n onClick={() => onMoveUp(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move up\"\n >\n <ChevronUpIcon style={ICON_STYLE} />\n </button>\n )}\n {!isLast && (\n <button\n onClick={() => onMoveDown(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move down\"\n >\n <ChevronDownIcon style={ICON_STYLE} />\n </button>\n )}\n <button\n onClick={() => onEdit(block)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Edit visualization\"\n >\n <EditIcon style={ICON_STYLE} />\n </button>\n <button\n onClick={() => onRemove(block.id)}\n className=\"dc:p-1 dc:mr-0.5 dc:bg-transparent dc:border-none dc:rounded-sm dc:cursor-pointer dc:hover:bg-dc-danger-bg text-dc-danger dc:transition-colors\"\n title=\"Remove\"\n >\n <DeleteIcon style={ICON_STYLE} />\n </button>\n </div>\n </div>\n\n {/* Portlet body */}\n <div className=\"dc:flex-1 dc:min-h-0\">\n <AnalyticsPortlet\n query={block.query}\n chartType={block.chartType}\n chartConfig={block.chartConfig}\n displayConfig={block.displayConfig}\n colorPalette={colorPalette}\n height={400}\n eagerLoad={true}\n onDebugDataReady={handleDebugDataReady}\n />\n </div>\n </div>\n )\n})\n\nexport default NotebookPortletBlock\n","/**\n * NotebookMarkdownBlock - Renders a markdown text block in the notebook\n * Uses markdown-to-jsx for full GFM support including tables\n *\n * Header matches NotebookPortletBlock pattern for visual consistency.\n */\n\nimport React from 'react'\nimport type { CSSProperties } from 'react'\nimport Markdown from 'markdown-to-jsx'\nimport type { MarkdownBlock } from '../../stores/notebookStore'\nimport { getIcon } from '../../icons/registry'\n\nconst ICON_STYLE: CSSProperties = { width: '16px', height: '16px', color: 'currentColor' }\n\nconst DocumentTextIcon = getIcon('documentText')\nconst ChevronUpIcon = getIcon('chevronUp')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst DeleteIcon = getIcon('delete')\n\ninterface NotebookMarkdownBlockProps {\n block: MarkdownBlock\n onRemove: (id: string) => void\n onMoveUp: (id: string) => void\n onMoveDown: (id: string) => void\n isFirst: boolean\n isLast: boolean\n}\n\n/** Scrollable table wrapper so wide tables don't overflow the block */\nfunction ScrollableTable({ children, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return (\n <div className=\"dc:overflow-x-auto dc:my-2\">\n <table {...props}>{children}</table>\n </div>\n )\n}\n\n/** markdown-to-jsx options with dc: themed overrides */\nconst markdownOptions = {\n overrides: {\n h1: { props: { className: 'dc:text-lg dc:font-bold text-dc-text dc:mb-2 dc:mt-3' } },\n h2: { props: { className: 'dc:text-base dc:font-semibold text-dc-text dc:mb-2 dc:mt-3' } },\n h3: { props: { className: 'dc:text-sm dc:font-semibold text-dc-text dc:mb-2 dc:mt-3' } },\n p: { props: { className: 'dc:text-sm dc:leading-relaxed text-dc-text dc:mb-2' } },\n strong: { props: { className: 'dc:font-semibold' } },\n a: { props: { className: 'text-dc-accent dc:hover:underline', target: '_blank', rel: 'noopener noreferrer' } },\n code: { props: { className: 'dc:px-1 dc:py-0.5 dc:rounded dc:text-xs bg-dc-surface-secondary text-dc-accent dc:font-mono' } },\n pre: { props: { className: 'dc:rounded-lg dc:p-3 dc:my-2 dc:overflow-x-auto dc:text-xs bg-dc-surface-secondary text-dc-text dc:font-mono' } },\n ul: { props: { className: 'dc:list-disc dc:ml-5 dc:mb-2 dc:text-sm text-dc-text dc:space-y-1' } },\n ol: { props: { className: 'dc:list-decimal dc:ml-5 dc:mb-2 dc:text-sm text-dc-text dc:space-y-1' } },\n li: { props: { className: 'dc:text-sm text-dc-text' } },\n hr: { props: { className: 'dc:my-3 border-dc-border' } },\n blockquote: { props: { className: 'dc:border-l-4 border-dc-accent dc:pl-3 dc:my-2 dc:italic text-dc-text-secondary dc:text-sm' } },\n table: { component: ScrollableTable, props: { className: 'dc:w-full dc:border-collapse dc:text-sm' } },\n thead: { props: { className: 'bg-dc-surface-secondary' } },\n th: { props: { className: 'dc:px-3 dc:py-2 dc:text-left dc:font-semibold dc:text-xs text-dc-text-secondary dc:uppercase dc:tracking-wider border-dc-border dc:border-b' } },\n td: { props: { className: 'dc:px-3 dc:py-2 dc:text-sm text-dc-text border-dc-border dc:border-b' } },\n tr: { props: { className: 'dc:hover:opacity-80' } },\n },\n}\n\nconst NotebookMarkdownBlock = React.memo(function NotebookMarkdownBlock({\n block,\n onRemove,\n onMoveUp,\n onMoveDown,\n isFirst,\n isLast,\n}: NotebookMarkdownBlockProps) {\n return (\n <div className=\"dc:relative dc:mb-4 bg-dc-surface dc:border border-dc-border dc:rounded-lg dc:flex dc:flex-col\">\n {/* Header - same pattern as NotebookPortletBlock / DashboardPortletCard */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-3 dc:py-1.5 dc:border-b border-dc-border dc:shrink-0 bg-dc-surface-secondary dc:rounded-t-lg\">\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:flex-1 dc:min-w-0\">\n <DocumentTextIcon style={ICON_STYLE} />\n <h3 className=\"dc:font-semibold dc:text-sm text-dc-text dc:truncate\">\n {block.title || 'Markdown'}\n </h3>\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-1 dc:shrink-0 dc:ml-4 dc:-mr-2\">\n {!isFirst && (\n <button\n onClick={() => onMoveUp(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move up\"\n >\n <ChevronUpIcon style={ICON_STYLE} />\n </button>\n )}\n {!isLast && (\n <button\n onClick={() => onMoveDown(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move down\"\n >\n <ChevronDownIcon style={ICON_STYLE} />\n </button>\n )}\n <button\n onClick={() => onRemove(block.id)}\n className=\"dc:p-1 dc:mr-0.5 dc:bg-transparent dc:border-none dc:rounded-sm dc:cursor-pointer dc:hover:bg-dc-danger-bg text-dc-danger dc:transition-colors\"\n title=\"Remove\"\n >\n <DeleteIcon style={ICON_STYLE} />\n </button>\n </div>\n </div>\n\n {/* Markdown content */}\n <div className=\"dc:p-4 dc:min-w-0 dc:overflow-hidden\">\n <Markdown options={markdownOptions}>\n {block.content}\n </Markdown>\n </div>\n </div>\n )\n})\n\nexport default NotebookMarkdownBlock\n","/**\n * NotebookCanvas - Left panel displaying notebook blocks\n */\n\nimport React, { useCallback, useRef, useEffect, useState } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useNotebookStore, selectBlocks, selectBlockActions } from '../../stores/notebookStore'\nimport type { PortletBlock } from '../../stores/notebookStore'\nimport type { PortletConfig } from '../../types'\nimport type { ColorPalette } from '../../utils/colorPalettes'\nimport { getColorPalette } from '../../utils/colorPalettes'\nimport { ensureAnalysisConfig } from '../../utils/configMigration'\nimport NotebookPortletBlock from './NotebookPortletBlock'\nimport NotebookMarkdownBlock from './NotebookMarkdownBlock'\nimport PortletAnalysisModal from '../PortletAnalysisModal'\n\nconst NotebookCanvas = React.memo(function NotebookCanvas({ colorPalette }: { colorPalette?: ColorPalette }) {\n const resolvedPalette = colorPalette ?? getColorPalette()\n const blocks = useNotebookStore(selectBlocks)\n const { removeBlock, moveBlock, updateBlock } = useNotebookStore(useShallow(selectBlockActions))\n const endRef = useRef<HTMLDivElement>(null)\n\n // Edit modal state\n const [editingBlock, setEditingBlock] = useState<PortletBlock | null>(null)\n\n // Auto-scroll only when NEW blocks are added (not on initial load)\n const prevCountRef = useRef(blocks.length)\n useEffect(() => {\n if (blocks.length > prevCountRef.current) {\n endRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n prevCountRef.current = blocks.length\n }, [blocks.length])\n\n const handleRemove = useCallback((id: string) => removeBlock(id), [removeBlock])\n const handleMoveUp = useCallback((id: string) => moveBlock(id, 'up'), [moveBlock])\n const handleMoveDown = useCallback((id: string) => moveBlock(id, 'down'), [moveBlock])\n const handleEdit = useCallback((block: PortletBlock) => setEditingBlock(block), [])\n\n const handleEditSave = useCallback((portletData: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'>) => {\n if (!editingBlock) return\n\n // Normalize to ensure analysisConfig exists\n const normalized = ensureAnalysisConfig(portletData as PortletConfig)\n const { analysisConfig } = normalized\n\n if (analysisConfig) {\n const chartModeConfig = analysisConfig.charts[analysisConfig.analysisType]\n updateBlock(editingBlock.id, {\n title: portletData.title,\n query: JSON.stringify(analysisConfig.query),\n chartType: chartModeConfig?.chartType || 'bar',\n chartConfig: chartModeConfig?.chartConfig,\n displayConfig: chartModeConfig?.displayConfig,\n })\n }\n\n setEditingBlock(null)\n }, [editingBlock, updateBlock])\n\n if (blocks.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center dc:max-w-sm dc:px-6\">\n <h3 className=\"dc:text-base dc:font-semibold text-dc-text dc:mb-2\">\n Your notebook is empty\n </h3>\n <p className=\"dc:text-sm text-dc-text-secondary\">\n Ask the AI assistant a question about your data.\n Charts and insights will appear here as the assistant analyzes your data.\n </p>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:h-full dc:overflow-y-auto dc:p-4\">\n {blocks.map((block, index) => {\n const isFirst = index === 0\n const isLast = index === blocks.length - 1\n\n if (block.type === 'portlet') {\n return (\n <NotebookPortletBlock\n key={block.id}\n block={block}\n colorPalette={resolvedPalette}\n onRemove={handleRemove}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n onEdit={handleEdit}\n isFirst={isFirst}\n isLast={isLast}\n />\n )\n }\n\n if (block.type === 'markdown') {\n return (\n <NotebookMarkdownBlock\n key={block.id}\n block={block}\n onRemove={handleRemove}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n isFirst={isFirst}\n isLast={isLast}\n />\n )\n }\n\n return null\n })}\n <div ref={endRef} />\n\n {/* Edit modal */}\n <PortletAnalysisModal\n isOpen={!!editingBlock}\n onClose={() => setEditingBlock(null)}\n onSave={handleEditSave}\n colorPalette={resolvedPalette}\n portlet={editingBlock ? {\n id: editingBlock.id,\n title: editingBlock.title,\n query: editingBlock.query,\n chartType: editingBlock.chartType,\n chartConfig: editingBlock.chartConfig,\n displayConfig: editingBlock.displayConfig,\n w: 5, h: 4, x: 0, y: 0,\n } : null}\n title=\"Edit Visualization\"\n submitText=\"Update\"\n />\n </div>\n )\n})\n\nexport default NotebookCanvas\n","/**\n * useAgentChat Hook\n * SSE streaming hook for the agentic notebook chat interface\n */\n\nimport { useRef, useCallback, useState } from 'react'\nimport { useCubeApi } from '../providers/CubeProvider'\nimport type { PortletBlock, MarkdownBlock } from '../stores/notebookStore'\n\n/** Clean up raw API errors into user-friendly messages */\nfunction formatUserFacingError(message: string): string {\n // Detect raw JSON error payloads (e.g. from Anthropic API)\n if (message.startsWith('{') || message.includes('\"type\":\"error\"')) {\n try {\n const parsed = JSON.parse(message.replace(/^Error:\\s*/, ''))\n const errorType = parsed.error?.type || parsed.type || ''\n const friendly: Record<string, string> = {\n overloaded_error: 'The AI service is temporarily busy. Please try again in a moment.',\n rate_limit_error: 'Too many requests. Please wait a moment and try again.',\n api_error: 'The AI service encountered an error. Please try again.',\n authentication_error: 'Authentication failed. Please check your configuration.',\n }\n return friendly[errorType] || 'The AI service encountered an error. Please try again.'\n } catch {\n return 'The AI service encountered an error. Please try again.'\n }\n }\n // HTTP status errors\n if (message.startsWith('Agent request failed:')) {\n const status = message.match(/\\d+/)?.[0]\n if (status === '429') return 'Too many requests. Please wait a moment and try again.'\n if (status === '503' || status === '529') return 'The AI service is temporarily busy. Please try again in a moment.'\n return 'The AI service is temporarily unavailable. Please try again.'\n }\n return message\n}\n\ninterface AgentSSEEvent {\n type: 'text_delta' | 'tool_use_start' | 'tool_use_result' | 'add_portlet' | 'add_markdown' | 'dashboard_saved' | 'turn_complete' | 'done' | 'error'\n data: any\n}\n\nexport interface UseAgentChatOptions {\n /** Override default agent endpoint (default: apiUrl + '/agent/chat') */\n agentEndpoint?: string\n /** Client-side API key for demo/try-site use */\n agentApiKey?: string\n /** Override LLM provider (anthropic | openai | google) */\n agentProvider?: string\n /** Override LLM model (e.g. 'gpt-4o', 'gemini-2.0-flash') */\n agentModel?: string\n /** Override provider endpoint URL (for OpenAI-compatible services) */\n agentProviderEndpoint?: string\n /** Called when agent adds a portlet to the notebook */\n onAddPortlet: (data: PortletBlock) => void\n /** Called when agent adds a markdown block to the notebook */\n onAddMarkdown: (data: MarkdownBlock) => void\n /** Called when the agent saves a dashboard configuration */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when streaming text arrives */\n onTextDelta: (text: string) => void\n /** Called when a tool call starts */\n onToolStart: (id: string, name: string, input?: unknown) => void\n /** Called when a tool call completes */\n onToolResult: (id: string, name: string, result?: unknown, isError?: boolean) => void\n /** Called when the agent completes with session ID and optional trace ID */\n onDone: (sessionId: string, traceId?: string) => void\n /** Called when a turn completes (between agentic turns) */\n onTurnComplete?: () => void\n /** Called on error */\n onError: (message: string) => void\n}\n\n/** Simplified message format for sending conversation history */\nexport interface AgentHistoryMessage {\n role: 'user' | 'assistant'\n content: string\n toolCalls?: Array<{\n id: string\n name: string\n input?: unknown\n result?: unknown\n status: 'running' | 'complete' | 'error'\n }>\n}\n\nexport interface UseAgentChatResult {\n /** Send a message to the agent, optionally with prior conversation history */\n sendMessage: (content: string, sessionId?: string | null, history?: AgentHistoryMessage[]) => Promise<void>\n /** Whether the agent is currently streaming */\n isStreaming: boolean\n /** Abort the current stream */\n abort: () => void\n}\n\n/**\n * Hook for streaming chat with the agentic notebook backend.\n * Uses fetch() with ReadableStream to consume SSE events.\n */\nexport function useAgentChat(options: UseAgentChatOptions): UseAgentChatResult {\n const { agentEndpoint, agentApiKey, agentProvider, agentModel, agentProviderEndpoint } = options\n\n const { cubeApi } = useCubeApi()\n const abortControllerRef = useRef<AbortController | null>(null)\n const [isStreaming, setIsStreaming] = useState(false)\n\n // Store callbacks in a ref so handleEvent always reads the latest\n // without causing sendMessage to be recreated on every render\n const callbacksRef = useRef(options)\n callbacksRef.current = options\n\n const sendMessage = useCallback(async (content: string, sessionId?: string | null, history?: AgentHistoryMessage[]) => {\n function handleEvent(event: AgentSSEEvent) {\n const cb = callbacksRef.current\n switch (event.type) {\n case 'text_delta':\n cb.onTextDelta(event.data)\n break\n case 'tool_use_start':\n cb.onToolStart(event.data.id, event.data.name, event.data.input)\n break\n case 'tool_use_result':\n cb.onToolResult(event.data.id, event.data.name, event.data.result, event.data.isError)\n break\n case 'add_portlet':\n cb.onAddPortlet({\n ...event.data,\n type: 'portlet',\n })\n break\n case 'add_markdown':\n cb.onAddMarkdown({\n ...event.data,\n type: 'markdown',\n })\n break\n case 'dashboard_saved':\n cb.onDashboardSaved?.(event.data)\n break\n case 'turn_complete':\n cb.onTurnComplete?.()\n break\n case 'done':\n cb.onDone(event.data.sessionId, event.data.traceId)\n break\n case 'error':\n cb.onError(event.data.message)\n break\n }\n }\n\n // Abort any existing stream\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n\n const controller = new AbortController()\n abortControllerRef.current = controller\n setIsStreaming(true)\n\n try {\n // Build endpoint URL from CubeClient's API URL\n const apiUrl = (cubeApi as any).apiUrl || '/cubejs-api/v1'\n const endpoint = agentEndpoint || `${apiUrl}/agent/chat`\n\n // Build headers matching CubeClient's auth pattern\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(cubeApi as any).headers,\n }\n\n // Add agent API key if provided\n if (agentApiKey) {\n headers['X-Agent-Api-Key'] = agentApiKey\n }\n if (agentProvider) {\n headers['X-Agent-Provider'] = agentProvider\n }\n if (agentModel) {\n headers['X-Agent-Model'] = agentModel\n }\n if (agentProviderEndpoint) {\n headers['X-Agent-Provider-Endpoint'] = agentProviderEndpoint\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n credentials: (cubeApi as any).credentials ?? 'include',\n body: JSON.stringify({\n message: content,\n ...(sessionId ? { sessionId } : {}),\n ...(history && history.length > 0 ? { history } : {}),\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error || `Agent request failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body received')\n }\n\n // Read SSE stream\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Process complete SSE events (delimited by double newline)\n const events = buffer.split('\\n\\n')\n buffer = events.pop() || '' // Keep incomplete last chunk\n\n for (const eventStr of events) {\n const lines = eventStr.trim().split('\\n')\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event: AgentSSEEvent = JSON.parse(line.slice(6))\n handleEvent(event)\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n }\n\n // Process any remaining buffer\n if (buffer.trim()) {\n const lines = buffer.trim().split('\\n')\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event: AgentSSEEvent = JSON.parse(line.slice(6))\n handleEvent(event)\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const raw = error instanceof Error ? error.message : 'Stream failed'\n callbacksRef.current.onError(formatUserFacingError(raw))\n }\n } finally {\n setIsStreaming(false)\n abortControllerRef.current = null\n }\n }, [cubeApi, agentEndpoint, agentApiKey, agentProvider, agentModel, agentProviderEndpoint])\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n abortControllerRef.current = null\n setIsStreaming(false)\n }\n }, [])\n\n return {\n sendMessage,\n isStreaming,\n abort,\n }\n}\n","/**\n * ChatMessage - Renders individual user and assistant messages\n */\n\nimport React, { useState } from 'react'\nimport type { ChatMessage as ChatMessageType, ToolCallRecord } from '../../stores/notebookStore'\nimport LoadingIndicator from '../LoadingIndicator'\n\n/** Simple inline markdown parser for bold, italic, and code in chat text */\nfunction renderInlineMarkdown(text: string): React.ReactNode[] {\n const nodes: React.ReactNode[] = []\n let remaining = text\n let key = 0\n\n while (remaining) {\n // Code inline `text`\n const codeMatch = remaining.match(/^(.*?)`([^`]+)`(.*)$/)\n if (codeMatch) {\n const [, before, code, after] = codeMatch\n if (before) nodes.push(<span key={key++}>{before}</span>)\n nodes.push(\n <code key={key++} className=\"dc:px-1 dc:py-0.5 dc:rounded dc:text-xs bg-dc-surface dc:font-mono\">\n {code}\n </code>\n )\n remaining = after\n continue\n }\n\n // Bold **text**\n const boldMatch = remaining.match(/^(.*?)\\*\\*([^*]+)\\*\\*(.*)$/)\n if (boldMatch) {\n const [, before, bold, after] = boldMatch\n if (before) nodes.push(<span key={key++}>{before}</span>)\n nodes.push(<strong key={key++} className=\"dc:font-semibold\">{bold}</strong>)\n remaining = after\n continue\n }\n\n // Plain text\n nodes.push(<span key={key}>{remaining}</span>)\n break\n }\n\n return nodes\n}\n\ninterface ChatMessageProps {\n message: ChatMessageType\n /** Custom loading indicator for tool call spinners */\n loadingComponent?: React.ReactNode\n}\n\n/** Tool call label mapping for user-friendly display */\nconst TOOL_LABELS: Record<string, string> = {\n discover_cubes: 'Discovering cubes',\n get_cube_metadata: 'Reading metadata',\n execute_query: 'Executing query',\n add_portlet: 'Adding visualization',\n add_markdown: 'Adding explanation',\n}\n\nfunction ToolCallIndicator({ toolCall, loadingComponent }: { toolCall: ToolCallRecord; loadingComponent?: React.ReactNode }) {\n const [expanded, setExpanded] = useState(false)\n const label = TOOL_LABELS[toolCall.name] || toolCall.name\n const isRunning = toolCall.status === 'running'\n\n return (\n <div className=\"dc:my-1 dc:text-xs\">\n <button\n onClick={() => setExpanded(!expanded)}\n className=\"dc:flex dc:items-center dc:gap-1.5 text-dc-text-secondary dc:hover:opacity-80 dc:transition-opacity\"\n >\n {isRunning ? (\n loadingComponent\n ? <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:h-3 dc:w-3\">{loadingComponent}</span>\n : <LoadingIndicator size=\"xs\" />\n ) : (\n <span className=\"dc:text-xs\">\n {toolCall.status === 'error' ? '\\u2717' : '\\u2713'}\n </span>\n )}\n <span>{label}{isRunning ? '...' : ''}</span>\n {!isRunning && (\n <span className=\"dc:text-[10px] dc:opacity-60\">\n {expanded ? '\\u25B2' : '\\u25BC'}\n </span>\n )}\n </button>\n {expanded && toolCall.result != null && (\n <pre className=\"dc:mt-1 dc:p-2 dc:rounded dc:text-[11px] dc:overflow-x-auto dc:max-h-32 dc:overflow-y-auto bg-dc-surface-secondary text-dc-text-secondary\">\n {typeof toolCall.result === 'string'\n ? toolCall.result\n : JSON.stringify(toolCall.result, null, 2)}\n </pre>\n )}\n </div>\n )\n}\n\nconst MSG_FADE_IN: React.CSSProperties = {\n animation: 'dc-msg-in 100ms ease-out',\n}\n\nconst ChatMessage = React.memo(function ChatMessage({ message, loadingComponent }: ChatMessageProps) {\n const isUser = message.role === 'user'\n const hasContent = !!message.content?.trim()\n const hasError = !!message.error\n const hasToolCalls = message.toolCalls && message.toolCalls.length > 0\n\n // Don't render empty assistant messages\n if (!isUser && !hasContent && !hasError && !hasToolCalls) return null\n\n return (\n <div\n className={`dc:flex dc:mb-3 ${isUser ? 'dc:justify-end' : 'dc:justify-start'}`}\n style={MSG_FADE_IN}\n >\n <div\n className={`dc:max-w-[85%] dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm ${\n isUser\n ? 'bg-dc-accent text-dc-accent-text dc:rounded-br-sm'\n : hasError && !hasContent\n ? 'bg-dc-warning-bg text-dc-text dc:rounded-bl-sm'\n : 'bg-dc-surface-secondary text-dc-text dc:rounded-bl-sm'\n }`}\n >\n {/* Message text */}\n {hasContent && (\n <div className=\"dc:whitespace-pre-wrap dc:break-words\">\n {isUser ? message.content : renderInlineMarkdown(message.content)}\n </div>\n )}\n\n {/* Error display */}\n {hasError && (\n <div className={`dc:flex dc:items-start dc:gap-2 ${hasContent ? 'dc:mt-2 dc:pt-2 dc:border-t dc:border-current dc:border-opacity-10' : ''}`}>\n <span className=\"dc:text-base dc:leading-none dc:mt-0.5 text-dc-warning dc:flex-shrink-0\">{'\\u26A0'}</span>\n <span className=\"text-dc-text-secondary\">{message.error}</span>\n </div>\n )}\n\n {/* Tool call indicators */}\n {hasToolCalls && (\n <div className={hasContent || hasError ? 'dc:mt-1 dc:border-t dc:border-current dc:border-opacity-10 dc:pt-1' : ''}>\n {message.toolCalls!.map((tc, i) => (\n <ToolCallIndicator key={tc.id || i} toolCall={tc} loadingComponent={loadingComponent} />\n ))}\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default ChatMessage\n","/**\n * ChatInput - Text input for sending messages to the agent\n */\n\nimport React, { useCallback, useRef, useEffect } from 'react'\n\ninterface ChatInputProps {\n value: string\n onChange: (value: string) => void\n onSend: () => void\n onStop?: () => void\n onContinue?: () => void\n isStreaming?: boolean\n showContinue?: boolean\n disabled?: boolean\n placeholder?: string\n}\n\nconst ChatInput = React.memo(function ChatInput({\n value,\n onChange,\n onSend,\n onStop,\n onContinue,\n isStreaming = false,\n showContinue = false,\n disabled = false,\n placeholder = 'Ask about your data...',\n}: ChatInputProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current\n if (textarea) {\n textarea.style.height = 'auto'\n textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`\n }\n }, [value])\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (!disabled && value.trim()) {\n onSend()\n }\n }\n },\n [disabled, value, onSend]\n )\n\n return (\n <div className=\"dc:flex dc:gap-2 dc:items-end dc:p-3 border-dc-border dc:border-t\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n className=\"dc:flex-1 dc:resize-none dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm bg-dc-surface-secondary text-dc-text border-dc-border dc:border dc:outline-none dc:focus:ring-1 focus:ring-dc-accent dc:disabled:opacity-50\"\n />\n {isStreaming ? (\n <button\n onClick={onStop}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors text-dc-error border-dc-border dc:border dc:hover:opacity-80 dc:shrink-0\"\n >\n Stop\n </button>\n ) : (\n <>\n {showContinue && !value.trim() && (\n <button\n onClick={() => {\n onContinue?.()\n textareaRef.current?.focus()\n }}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors border-dc-border dc:border text-dc-text-secondary dc:hover:opacity-80 dc:shrink-0\"\n >\n Continue\n </button>\n )}\n <button\n onClick={onSend}\n disabled={disabled || !value.trim()}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors bg-dc-accent text-dc-accent-text dc:hover:opacity-90 dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:shrink-0\"\n >\n Send\n </button>\n </>\n )}\n </div>\n )\n})\n\nexport default ChatInput\n","/**\n * AgentChatPanel - Right panel containing chat messages and input\n */\n\nimport React, { useRef, useEffect, useCallback, useState } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useNotebookStore, selectChatState, selectChatActions } from '../../stores/notebookStore'\nimport { useAgentChat } from '../../hooks/useAgentChat'\nimport type { PortletBlock, MarkdownBlock, ChatMessage as ChatMessageType } from '../../stores/notebookStore'\nimport ChatMessage from './ChatMessage'\nimport ChatInput from './ChatInput'\nimport LoadingIndicator from '../LoadingIndicator'\nimport { getIcon } from '../../icons'\n\nconst ThumbUpIcon = getIcon('thumbUp')\nconst ThumbDownIcon = getIcon('thumbDown')\n\ninterface AgentChatPanelProps {\n agentEndpoint?: string\n agentApiKey?: string\n agentProvider?: string\n agentModel?: string\n agentProviderEndpoint?: string\n onClear?: () => void\n /** Called when the agent saves a dashboard. Presence enables the \"Save as Dashboard\" button. */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when user submits feedback (thumbs up/down) */\n onScore?: (data: { traceId: string; value: number; comment?: string }) => void\n /** Custom loading indicator for tool call spinners */\n loadingComponent?: React.ReactNode\n /** Initial prompt to auto-send on mount */\n initialPrompt?: string\n}\n\nconst AgentChatPanel = React.memo(function AgentChatPanel({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onClear,\n onDashboardSaved,\n onScore,\n loadingComponent,\n initialPrompt,\n}: AgentChatPanelProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null)\n const initialPromptSentRef = useRef(false)\n const [lastTraceId, setLastTraceId] = useState<string | null>(null)\n const [scoredTraceIds, setScoredTraceIds] = useState<Set<string>>(new Set())\n const [isThinking, setIsThinking] = useState(false)\n\n // Track whether the next content should start a new assistant message\n // (set after turn_complete, cleared when first content of new turn arrives)\n const needsNewMessageRef = useRef(false)\n\n // Store state\n const { messages, isStreaming, inputValue } = useNotebookStore(useShallow(selectChatState))\n const {\n addMessage,\n appendToLastAssistantMessage,\n setLastAssistantError,\n addToolCallToLastAssistant,\n updateLastToolCall,\n setIsStreaming,\n setInputValue,\n setSessionId,\n } = useNotebookStore(useShallow(selectChatActions))\n\n const sessionId = useNotebookStore((s) => s.sessionId)\n const addBlock = useNotebookStore((s) => s.addBlock)\n const reset = useNotebookStore((s) => s.reset)\n const portletBlockCount = useNotebookStore((s) => s.blocks.filter((b) => b.type === 'portlet').length)\n\n // Refs for values doSend reads at call-time (avoids recreating callbacks on every text delta)\n const messagesRef = useRef(messages)\n messagesRef.current = messages\n const isStreamingRef = useRef(isStreaming)\n isStreamingRef.current = isStreaming\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n // Lazily create a new assistant message when needed (between turns)\n const ensureNewMessage = useCallback(() => {\n if (needsNewMessageRef.current) {\n needsNewMessageRef.current = false\n addMessage({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: '',\n toolCalls: [],\n timestamp: Date.now(),\n })\n }\n }, [addMessage])\n\n // Auto-scroll only when NEW messages arrive or thinking starts (not on initial load)\n const prevMsgCountRef = useRef(messages.length)\n useEffect(() => {\n if (messages.length > prevMsgCountRef.current) {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n prevMsgCountRef.current = messages.length\n }, [messages])\n\n useEffect(() => {\n if (isThinking) {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n }, [isThinking])\n\n // Agent chat hook\n const { sendMessage, abort } = useAgentChat({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onTextDelta: useCallback((text: string) => {\n setIsThinking(false)\n ensureNewMessage()\n appendToLastAssistantMessage(text)\n }, [ensureNewMessage, appendToLastAssistantMessage]),\n onToolStart: useCallback((id: string, name: string, input?: unknown) => {\n setIsThinking(false)\n ensureNewMessage()\n addToolCallToLastAssistant({ id, name, input, status: 'running' })\n }, [ensureNewMessage, addToolCallToLastAssistant]),\n onToolResult: useCallback((id: string, _name: string, result?: unknown, isError?: boolean) => {\n updateLastToolCall({ id, status: isError ? 'error' : 'complete', result })\n }, [updateLastToolCall]),\n onAddPortlet: useCallback((data: PortletBlock) => {\n addBlock(data)\n }, [addBlock]),\n onAddMarkdown: useCallback((data: MarkdownBlock) => {\n addBlock(data)\n }, [addBlock]),\n onDashboardSaved,\n onTurnComplete: useCallback(() => {\n // Don't create a new message yet — just flag that the next turn\n // should start a new bubble (created lazily by ensureNewMessage)\n needsNewMessageRef.current = true\n setIsThinking(true)\n }, []),\n onDone: useCallback((sid: string, traceId?: string) => {\n needsNewMessageRef.current = false\n setSessionId(sid)\n setIsStreaming(false)\n setIsThinking(false)\n if (traceId) setLastTraceId(traceId)\n }, [setSessionId, setIsStreaming]),\n onError: useCallback((message: string) => {\n setIsThinking(false)\n ensureNewMessage()\n setLastAssistantError(message)\n setIsStreaming(false)\n }, [ensureNewMessage, setLastAssistantError, setIsStreaming]),\n })\n\n // Send a message (used by both Send and Continue)\n // Reads messages/isStreaming/sessionId from refs to avoid recreating on every text delta\n const doSend = useCallback((content: string) => {\n if (!content || isStreamingRef.current) return\n\n needsNewMessageRef.current = false\n\n // Capture current messages as history BEFORE adding the new ones\n const history = messagesRef.current.map((m: ChatMessageType) => ({\n role: m.role,\n content: m.content,\n ...(m.toolCalls && m.toolCalls.length > 0 ? { toolCalls: m.toolCalls } : {}),\n }))\n\n // Add user message\n addMessage({\n id: `msg-${Date.now()}`,\n role: 'user',\n content,\n timestamp: Date.now(),\n })\n\n // Create empty assistant message for first turn's streaming\n addMessage({\n id: `msg-${Date.now() + 1}`,\n role: 'assistant',\n content: '',\n toolCalls: [],\n timestamp: Date.now(),\n })\n\n setInputValue('')\n setIsStreaming(true)\n setIsThinking(true)\n\n // Send to agent with conversation history for session continuity\n sendMessage(content, sessionIdRef.current, history)\n }, [addMessage, setInputValue, setIsStreaming, sendMessage])\n\n // Auto-send initial prompt on mount (doSend is stable so this won't re-trigger)\n // Reset ref on cleanup so React StrictMode's double-mount doesn't block the real mount\n useEffect(() => {\n if (initialPrompt && !initialPromptSentRef.current && messages.length === 0) {\n initialPromptSentRef.current = true\n // Small delay to ensure chat hook is fully initialized\n const timer = setTimeout(() => doSend(initialPrompt), 100)\n return () => {\n clearTimeout(timer)\n initialPromptSentRef.current = false\n }\n }\n }, [initialPrompt, messages.length, doSend])\n\n const inputValueRef = useRef(inputValue)\n inputValueRef.current = inputValue\n\n const handleSend = useCallback(() => {\n doSend(inputValueRef.current.trim())\n }, [doSend])\n\n const handleStop = useCallback(() => {\n abort()\n setIsStreaming(false)\n }, [abort, setIsStreaming])\n\n const handleContinue = useCallback(() => {\n // Just set placeholder text — user types their own follow-up and sends\n setInputValue('')\n }, [setInputValue])\n\n const handleClear = useCallback(() => {\n abort()\n setIsStreaming(false)\n setIsThinking(false)\n reset()\n setLastTraceId(null)\n setScoredTraceIds(new Set())\n onClear?.()\n }, [abort, setIsStreaming, reset, onClear])\n\n const handleSaveAsDashboard = useCallback(() => {\n doSend(\n 'Save the current notebook as a dashboard with a professional layout, section headers, and appropriate filters.'\n )\n }, [doSend])\n\n const handleScore = useCallback((value: number) => {\n if (!lastTraceId || !onScore) return\n onScore({ traceId: lastTraceId, value })\n setScoredTraceIds(prev => new Set(prev).add(lastTraceId))\n }, [lastTraceId, onScore])\n\n const showSaveAsDashboard = !!onDashboardSaved && !isStreaming && portletBlockCount > 0 && messages.length > 0\n const showFeedback = !!onScore && !isStreaming && lastTraceId && messages.length > 0 && !scoredTraceIds.has(lastTraceId)\n const lastScored = lastTraceId ? scoredTraceIds.has(lastTraceId) : false\n\n return (\n <div className=\"dc:flex dc:flex-col dc:h-full bg-dc-surface\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-4 dc:py-3 border-dc-border dc:border-b\">\n <h3 className=\"dc:text-sm dc:font-semibold text-dc-text\">AI Assistant</h3>\n <div className=\"dc:flex dc:items-center dc:gap-1\">\n {showSaveAsDashboard && (\n <button\n onClick={handleSaveAsDashboard}\n className=\"dc:text-xs dc:px-2 dc:py-1 dc:rounded text-dc-accent dc:hover:opacity-80\"\n title=\"Save notebook as a dashboard\"\n >\n Save as Dashboard\n </button>\n )}\n {(messages.length > 0) && (\n <button\n onClick={handleClear}\n disabled={isStreaming}\n className=\"dc:text-xs dc:px-2 dc:py-1 dc:rounded text-dc-text-secondary dc:hover:opacity-80 dc:disabled:opacity-40\"\n title=\"Clear notebook and chat\"\n >\n Clear\n </button>\n )}\n </div>\n </div>\n\n {/* Messages */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:px-4 dc:py-3\">\n {messages.length === 0 ? (\n <EmptyState />\n ) : (\n messages.map((msg) => (\n <ChatMessage\n key={msg.id}\n message={msg}\n loadingComponent={loadingComponent}\n />\n ))\n )}\n {/* Thinking indicator (between turns or waiting for first response) */}\n {isThinking && <ThinkingBubble loadingComponent={loadingComponent} />}\n\n {/* Feedback (thumbs up/down) */}\n {(showFeedback || lastScored) && (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:gap-3 dc:py-4 dc:mt-2\">\n {lastScored ? (\n <span className=\"dc:text-sm text-dc-text-secondary\">Thanks for your feedback!</span>\n ) : (\n <>\n <span className=\"dc:text-sm text-dc-text-secondary\">Was this helpful?</span>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <button\n onClick={() => handleScore(1)}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-3 dc:py-1.5 dc:rounded-lg dc:text-sm dc:font-medium border-dc-border dc:border text-dc-success hover:bg-dc-success-bg dc:transition-colors bg-dc-surface dc:cursor-pointer\"\n >\n <ThumbUpIcon className=\"dc:w-4 dc:h-4\" />\n Yes\n </button>\n <button\n onClick={() => handleScore(0)}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-3 dc:py-1.5 dc:rounded-lg dc:text-sm dc:font-medium border-dc-border dc:border text-dc-error hover:bg-dc-danger-bg dc:transition-colors bg-dc-surface dc:cursor-pointer\"\n >\n <ThumbDownIcon className=\"dc:w-4 dc:h-4\" />\n No\n </button>\n </div>\n </>\n )}\n </div>\n )}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <ChatInput\n value={inputValue}\n onChange={setInputValue}\n onSend={handleSend}\n onStop={handleStop}\n onContinue={handleContinue}\n isStreaming={isStreaming}\n showContinue={!isStreaming && messages.length > 0}\n />\n </div>\n )\n})\n\nfunction ThinkingBubble({ loadingComponent }: { loadingComponent?: React.ReactNode }) {\n return (\n <div\n className=\"dc:flex dc:mb-3 dc:justify-start\"\n style={{ animation: 'dc-msg-in 100ms ease-out' }}\n >\n <div className=\"dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm bg-dc-surface-secondary text-dc-text-secondary dc:rounded-bl-sm dc:flex dc:items-center dc:gap-2\">\n {loadingComponent\n ? <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:h-4 dc:w-4\">{loadingComponent}</span>\n : <LoadingIndicator size=\"xs\" />}\n <span>Thinking...</span>\n </div>\n </div>\n )\n}\n\nfunction EmptyState() {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center dc:max-w-xs\">\n <div className=\"dc:text-lg dc:font-semibold text-dc-text dc:mb-2\">\n Data Analysis Assistant\n </div>\n <p className=\"dc:text-sm text-dc-text-secondary dc:mb-4\">\n Ask me about your data and I'll create visualizations and insights.\n </p>\n <div className=\"dc:space-y-2 dc:text-xs text-dc-text-muted\">\n <p>\"Show me employee productivity trends\"</p>\n <p>\"What are the top departments by headcount?\"</p>\n <p>\"Compare revenue across product categories\"</p>\n </div>\n </div>\n </div>\n )\n}\n\nexport default AgentChatPanel\n","/**\n * AgenticNotebook - AI-powered data analysis notebook\n *\n * Top-level component combining a notebook canvas (left) with a chat panel (right).\n * The AI agent discovers available data, executes queries, creates visualizations,\n * and explains findings within a single conversational flow.\n *\n * Responsive behavior:\n * - Wide (>= 768px): Drag-resizable two-column layout\n * - Narrow (< 768px): Toggle between collapsed icon strip + expanded panel\n *\n * Requires:\n * - CubeProvider wrapping this component\n * - Server configured with `agent` option in HonoAdapterOptions\n * - @anthropic-ai/claude-agent-sdk installed on the server\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n NotebookStoreProvider,\n useNotebookStore,\n type NotebookBlock,\n type NotebookConfig,\n} from '../../stores/notebookStore'\nimport NotebookCanvas from './NotebookCanvas'\nimport AgentChatPanel from './AgentChatPanel'\nimport { useNotebookLayout } from '../../hooks/useNotebookLayout'\nimport { getChartTypeIcon, getIcon } from '../../icons/registry'\nimport type { ColorPalette } from '../../types'\nimport type { ReactNode } from 'react'\n\nexport interface AgenticNotebookProps {\n /** Initial config to restore (saved notebooks) */\n config?: NotebookConfig\n /** Override default agent endpoint (default: apiUrl + '/agent/chat') */\n agentEndpoint?: string\n /** Client-side API key (for demo/try-site use) */\n agentApiKey?: string\n /** Override LLM provider (anthropic | openai | google) */\n agentProvider?: string\n /** Override LLM model (e.g. 'gpt-4o', 'gemini-2.0-flash') */\n agentModel?: string\n /** Override provider endpoint URL (for OpenAI-compatible services) */\n agentProviderEndpoint?: string\n /** Callback when notebook state changes (for persistence) */\n onSave?: (config: NotebookConfig) => void | Promise<void>\n /** Callback when dirty state changes */\n onDirtyStateChange?: (isDirty: boolean) => void\n /** Color palette for charts */\n colorPalette?: ColorPalette\n /** Called when the agent saves a dashboard. Presence enables the \"Save as Dashboard\" button. */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when user submits feedback (thumbs up/down). Receives traceId from the last agent response. */\n onScore?: (data: { traceId: string; value: number; comment?: string }) => void\n /** Custom loading indicator for tool call spinners (defaults to LoadingIndicator) */\n loadingComponent?: ReactNode\n /** Additional CSS class name */\n className?: string\n /** Initial prompt to auto-send on mount */\n initialPrompt?: string\n}\n\n/**\n * Collapsed strip showing notebook block icons (shown in narrow mode when chat is expanded)\n */\nfunction CollapsedNotebookStrip({\n blocks,\n pulsingBlockId,\n nudge,\n onExpand,\n}: {\n blocks: NotebookBlock[]\n pulsingBlockId: string | null\n nudge: boolean\n onExpand: () => void\n}) {\n const BookOpenIcon = getIcon('bookOpen')\n const DocumentIcon = getIcon('documentText')\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n className=\"dc:h-full dc:flex-shrink-0 dc:flex dc:flex-col dc:items-center dc:pt-3 dc:gap-2 bg-dc-surface border-dc-border dc:border-r dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n style={\n nudge\n ? { animation: 'dc-strip-nudge 0.8s ease-in-out 2', width: 48 }\n : { width: 48 }\n }\n title=\"Expand notebook\"\n >\n <BookOpenIcon className=\"dc:w-5 dc:h-5 text-dc-text-muted\" />\n <div\n className=\"dc:flex dc:flex-col dc:items-center dc:gap-1.5 dc:flex-1 dc:overflow-y-auto dc:py-1\"\n style={{ scrollbarWidth: 'none' }}\n >\n {blocks.length === 0 ? (\n <span\n className=\"dc:text-[9px] text-dc-text-disabled dc:writing-vertical-lr dc:mt-2\"\n style={{ writingMode: 'vertical-lr' }}\n >\n No blocks\n </span>\n ) : (\n blocks.map((block) => {\n const isPulsing = block.id === pulsingBlockId\n let Icon: React.ComponentType<{ className?: string }>\n if (block.type === 'portlet') {\n Icon = getChartTypeIcon(block.chartType)\n } else {\n Icon = DocumentIcon\n }\n return (\n <div\n key={block.id}\n className=\"dc:w-6 dc:h-6 dc:flex dc:items-center dc:justify-center dc:rounded\"\n style={\n isPulsing\n ? { animation: 'dc-icon-pulse 0.6s ease-in-out 3' }\n : undefined\n }\n title={block.type === 'portlet' ? block.title : (block.title || 'Markdown')}\n >\n <Icon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </div>\n )\n })\n )}\n </div>\n </button>\n )\n}\n\n/**\n * Collapsed strip showing AI chat icon (shown in narrow mode when notebook is expanded)\n */\nfunction CollapsedChatStrip({ onExpand }: { onExpand: () => void }) {\n const SparklesIcon = getIcon('sparkles')\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n className=\"dc:w-12 dc:h-full dc:flex-shrink-0 dc:flex dc:flex-col dc:items-center dc:pt-3 dc:gap-2 bg-dc-surface border-dc-border dc:border-l dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Expand AI chat\"\n >\n <SparklesIcon className=\"dc:w-5 dc:h-5 text-dc-accent\" />\n <span\n className=\"dc:text-[10px] dc:font-medium text-dc-text-muted\"\n style={{ writingMode: 'vertical-lr' }}\n >\n AI Chat\n </span>\n </button>\n )\n}\n\n/**\n * Inner component that uses the notebook store (must be inside provider)\n */\nfunction AgenticNotebookInner({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onSave,\n onDirtyStateChange,\n onDashboardSaved,\n onScore,\n colorPalette,\n loadingComponent,\n className,\n initialPrompt,\n}: Omit<AgenticNotebookProps, 'config'>) {\n const [dividerPosition, setDividerPosition] = useState(60) // 60% left, 40% right\n const dividerContainerRef = useRef<HTMLDivElement | null>(null)\n const isDraggingRef = useRef(false)\n\n // Responsive layout\n const { containerRef: layoutRef, layoutMode } = useNotebookLayout()\n const [expandedPanel, setExpandedPanel] = useState<'chat' | 'notebook'>('chat')\n const [pulsingBlockId, setPulsingBlockId] = useState<string | null>(null)\n const [nudgeStrip, setNudgeStrip] = useState(false)\n const prevLayoutModeRef = useRef(layoutMode)\n\n const blocks = useNotebookStore((s) => s.blocks)\n const blockCount = blocks.length\n const messageCount = useNotebookStore((s) => s.messages.length)\n const isStreaming = useNotebookStore((s) => s.isStreaming)\n const save = useNotebookStore((s) => s.save)\n\n // Reset to chat when crossing from narrow → wide\n useEffect(() => {\n if (prevLayoutModeRef.current === 'narrow' && layoutMode === 'wide') {\n setExpandedPanel('chat')\n }\n prevLayoutModeRef.current = layoutMode\n }, [layoutMode])\n\n // Detect new blocks added while notebook is collapsed → pulse the icon\n const prevBlockCountRef = useRef(blockCount)\n useEffect(() => {\n if (\n layoutMode === 'narrow' &&\n expandedPanel === 'chat' &&\n blockCount > prevBlockCountRef.current\n ) {\n // Find the newest block (last in the array)\n const newestBlock = blocks[blocks.length - 1]\n if (newestBlock) {\n setPulsingBlockId(newestBlock.id)\n const timer = setTimeout(() => setPulsingBlockId(null), 2000)\n return () => clearTimeout(timer)\n }\n }\n prevBlockCountRef.current = blockCount\n }, [blockCount, blocks, layoutMode, expandedPanel])\n\n // Nudge the notebook strip when streaming ends while collapsed and there are blocks\n const wasStreamingRef = useRef(false)\n useEffect(() => {\n if (isStreaming) {\n wasStreamingRef.current = true\n } else if (\n wasStreamingRef.current &&\n layoutMode === 'narrow' &&\n expandedPanel === 'chat' &&\n blockCount > 0\n ) {\n wasStreamingRef.current = false\n setNudgeStrip(true)\n const timer = setTimeout(() => setNudgeStrip(false), 1700)\n return () => clearTimeout(timer)\n }\n }, [isStreaming, layoutMode, expandedPanel, blockCount])\n\n // Merge refs: layoutRef (RefCallback) + dividerContainerRef (for drag calculations)\n const mergedRef = useCallback(\n (node: HTMLDivElement | null) => {\n layoutRef(node)\n dividerContainerRef.current = node\n },\n [layoutRef],\n )\n\n // Track dirty state\n const initialRef = useRef({ blockCount, msgCount: messageCount })\n useEffect(() => {\n const isDirty =\n blockCount !== initialRef.current.blockCount ||\n messageCount !== initialRef.current.msgCount\n onDirtyStateChange?.(isDirty)\n }, [blockCount, messageCount, onDirtyStateChange])\n\n // Debounced save - fires 1s after blocks/messages count stabilizes\n // Waits until streaming completes to avoid saving partial content\n const saveTimeoutRef = useRef<ReturnType<typeof setTimeout>>()\n const pendingSaveRef = useRef(false)\n const onSaveRef = useRef(onSave)\n onSaveRef.current = onSave\n // Track whether we've ever had content (so we save empty state on Clear but not on initial mount)\n const hasHadContentRef = useRef(blockCount > 0 || messageCount > 0)\n useEffect(() => {\n if (blockCount > 0 || messageCount > 0) {\n hasHadContentRef.current = true\n }\n if (!onSaveRef.current || !hasHadContentRef.current) return\n\n if (isStreaming) {\n // Mark that a save is needed once streaming completes\n pendingSaveRef.current = true\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n return\n }\n\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n saveTimeoutRef.current = setTimeout(() => {\n pendingSaveRef.current = false\n const config = save()\n onSaveRef.current?.(config)\n }, 1000)\n\n return () => {\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n }\n }, [blockCount, messageCount, isStreaming, save])\n\n // Flush pending save when streaming ends\n useEffect(() => {\n if (!isStreaming && pendingSaveRef.current && onSaveRef.current && hasHadContentRef.current) {\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n saveTimeoutRef.current = setTimeout(() => {\n pendingSaveRef.current = false\n const config = save()\n onSaveRef.current?.(config)\n }, 1000)\n }\n }, [isStreaming, save])\n\n // Explicit clear handler — save immediately with empty state\n const handleClear = useCallback(() => {\n if (onSaveRef.current) {\n // Cancel any pending debounced save\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n onSaveRef.current({ blocks: [], messages: [] })\n }\n }, [])\n\n // Divider drag handlers\n const handleDividerMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault()\n isDraggingRef.current = true\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n if (!isDraggingRef.current || !dividerContainerRef.current) return\n const rect = dividerContainerRef.current.getBoundingClientRect()\n const newPos = ((moveEvent.clientX - rect.left) / rect.width) * 100\n setDividerPosition(Math.min(Math.max(newPos, 30), 80))\n }\n\n const handleMouseUp = () => {\n isDraggingRef.current = false\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }, [])\n\n const chatPanel = (\n <AgentChatPanel\n agentEndpoint={agentEndpoint}\n agentApiKey={agentApiKey}\n agentProvider={agentProvider}\n agentModel={agentModel}\n agentProviderEndpoint={agentProviderEndpoint}\n onClear={handleClear}\n onDashboardSaved={onDashboardSaved}\n onScore={onScore}\n loadingComponent={loadingComponent}\n initialPrompt={initialPrompt}\n />\n )\n\n // --- Narrow mode: collapsed strip + expanded panel ---\n if (layoutMode === 'narrow') {\n return (\n <div\n ref={mergedRef}\n className={`dc:flex dc:h-full dc:w-full dc:overflow-hidden bg-dc-surface-secondary ${className || ''}`}\n >\n {expandedPanel === 'chat' ? (\n <>\n <CollapsedNotebookStrip\n blocks={blocks}\n pulsingBlockId={pulsingBlockId}\n nudge={nudgeStrip}\n onExpand={() => setExpandedPanel('notebook')}\n />\n <div className=\"dc:h-full dc:overflow-hidden dc:flex-1\">\n {chatPanel}\n </div>\n </>\n ) : (\n <>\n <div className=\"dc:h-full dc:overflow-hidden dc:flex-1\">\n <NotebookCanvas colorPalette={colorPalette} />\n </div>\n <CollapsedChatStrip onExpand={() => setExpandedPanel('chat')} />\n </>\n )}\n </div>\n )\n }\n\n // --- Wide mode: existing drag-resizable two-column layout ---\n return (\n <div\n ref={mergedRef}\n className={`dc:flex dc:h-full dc:w-full dc:overflow-hidden bg-dc-surface-secondary ${className || ''}`}\n >\n {/* Left: Notebook Canvas */}\n <div\n className=\"dc:h-full dc:overflow-hidden\"\n style={{ width: `${dividerPosition}%` }}\n >\n <NotebookCanvas colorPalette={colorPalette} />\n </div>\n\n {/* Resizable Divider */}\n <div\n className=\"dc:w-1 dc:h-full dc:cursor-col-resize dc:flex-shrink-0 dc:transition-colors bg-dc-border dc:hover:bg-dc-accent\"\n onMouseDown={handleDividerMouseDown}\n />\n\n {/* Right: Chat Panel */}\n <div\n className=\"dc:h-full dc:overflow-hidden\"\n style={{ width: `${100 - dividerPosition}%` }}\n >\n {chatPanel}\n </div>\n </div>\n )\n}\n\n/**\n * AgenticNotebook - AI-powered data analysis notebook\n *\n * @example\n * ```tsx\n * <CubeProvider apiOptions={{ apiUrl: '/api/cubejs-api/v1' }} token={token}>\n * <AgenticNotebook\n * agentApiKey=\"sk-...\"\n * onSave={(config) => saveToDatabase(config)}\n * />\n * </CubeProvider>\n * ```\n */\nconst AgenticNotebook = React.memo(function AgenticNotebook({\n config,\n colorPalette,\n ...props\n}: AgenticNotebookProps) {\n return (\n <NotebookStoreProvider initialConfig={config}>\n <AgenticNotebookInner {...props} colorPalette={colorPalette} />\n </NotebookStoreProvider>\n )\n})\n\nexport default AgenticNotebook\n","// Placeholder component - will be implemented in Phase 4\nexport function AnalyticsPage() {\n return <div>Analytics Page - Coming in Phase 4</div>\n}","/**\n * Data Browser Zustand Store (Instance-based)\n *\n * Manages UI state for the DataBrowser component:\n * - Selected cube and visible columns\n * - Sorting, pagination, and filters\n * - Column picker and filter bar visibility\n *\n * Uses Zustand's createStore (factory) for instance isolation.\n */\n\nimport { createContext, useContext, useRef, type ReactNode } from 'react'\nimport { createStore, useStore, type StoreApi } from 'zustand'\nimport type { Filter } from '../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DataBrowserStore {\n // Selected cube\n selectedCube: string | null\n\n // Visible columns (fully qualified: 'CubeName.fieldName')\n visibleColumns: string[]\n\n // Sorting\n sortColumn: string | null\n sortDirection: 'asc' | 'desc'\n\n // Pagination\n page: number\n pageSize: number\n\n // Filters\n filters: Filter[]\n\n // UI state\n showFilterBar: boolean\n showColumnPicker: boolean\n\n // Column widths (purely cosmetic — never affects queries)\n columnWidths: Record<string, number>\n\n // Actions\n selectCube: (cubeName: string, allDimensions: string[]) => void\n setVisibleColumns: (columns: string[]) => void\n toggleColumn: (column: string) => void\n setSort: (column: string) => void\n clearSort: () => void\n setPage: (page: number) => void\n setPageSize: (size: number) => void\n setFilters: (filters: Filter[]) => void\n toggleFilterBar: () => void\n setShowColumnPicker: (show: boolean) => void\n setColumnWidth: (column: string, width: number) => void\n setColumnWidths: (widths: Record<string, number>) => void\n}\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\ninterface DataBrowserStoreOptions {\n defaultPageSize?: number\n defaultCube?: string\n defaultColumns?: string[]\n}\n\nconst COLUMN_WIDTHS_STORAGE_KEY = 'dc-data-browser-column-widths'\n\nfunction loadColumnWidths(cubeName: string): Record<string, number> {\n try {\n const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY)\n if (!raw) return {}\n const all = JSON.parse(raw)\n return all[cubeName] ?? {}\n } catch {\n return {}\n }\n}\n\nfunction saveColumnWidths(cubeName: string, widths: Record<string, number>): void {\n try {\n const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY)\n const all = raw ? JSON.parse(raw) : {}\n all[cubeName] = widths\n localStorage.setItem(COLUMN_WIDTHS_STORAGE_KEY, JSON.stringify(all))\n } catch {\n // localStorage unavailable — silently ignore\n }\n}\n\nfunction createDataBrowserStore(options: DataBrowserStoreOptions = {}) {\n return createStore<DataBrowserStore>()((set, get) => ({\n // Initial state\n selectedCube: options.defaultCube ?? null,\n visibleColumns: options.defaultColumns ?? [],\n sortColumn: null,\n sortDirection: 'asc',\n page: 0,\n pageSize: options.defaultPageSize ?? 20,\n filters: [],\n showFilterBar: false,\n showColumnPicker: false,\n columnWidths: options.defaultCube ? loadColumnWidths(options.defaultCube) : {},\n\n // Actions\n selectCube: (cubeName, allDimensions) =>\n set({\n selectedCube: cubeName,\n visibleColumns: allDimensions,\n sortColumn: null,\n sortDirection: 'asc',\n page: 0,\n filters: [],\n showFilterBar: false,\n columnWidths: loadColumnWidths(cubeName),\n }),\n\n setVisibleColumns: (columns) =>\n set({ visibleColumns: columns, page: 0 }),\n\n toggleColumn: (column) =>\n set((state) => {\n const idx = state.visibleColumns.indexOf(column)\n const next =\n idx >= 0\n ? state.visibleColumns.filter((c) => c !== column)\n : [...state.visibleColumns, column]\n return {\n visibleColumns: next,\n page: 0,\n // Clear sort if the sorted column was removed\n sortColumn: idx >= 0 && state.sortColumn === column ? null : state.sortColumn,\n }\n }),\n\n setSort: (column) =>\n set((state) => {\n if (state.sortColumn === column) {\n // Toggle direction, or clear if already desc\n if (state.sortDirection === 'asc') {\n return { sortDirection: 'desc' as const, page: 0 }\n }\n return { sortColumn: null, sortDirection: 'asc' as const, page: 0 }\n }\n return { sortColumn: column, sortDirection: 'asc' as const, page: 0 }\n }),\n\n clearSort: () => set({ sortColumn: null, sortDirection: 'asc', page: 0 }),\n\n setPage: (page) => set({ page }),\n\n setPageSize: (size) => set({ pageSize: size, page: 0 }),\n\n setFilters: (filters) => set({ filters, page: 0 }),\n\n toggleFilterBar: () =>\n set((state) => ({ showFilterBar: !state.showFilterBar })),\n\n setShowColumnPicker: (show) => set({ showColumnPicker: show }),\n\n setColumnWidth: (column, width) =>\n set((state) => {\n const updated = { ...state.columnWidths, [column]: width }\n if (state.selectedCube) saveColumnWidths(state.selectedCube, updated)\n return { columnWidths: updated }\n }),\n\n setColumnWidths: (widths) => {\n const cube = get().selectedCube\n if (cube) saveColumnWidths(cube, widths)\n set({ columnWidths: widths })\n },\n }))\n}\n\n// ============================================================================\n// React Context + Provider\n// ============================================================================\n\nconst DataBrowserStoreContext = createContext<StoreApi<DataBrowserStore> | null>(null)\n\nexport interface DataBrowserStoreProviderProps {\n children: ReactNode\n defaultPageSize?: number\n defaultCube?: string\n defaultColumns?: string[]\n}\n\nexport function DataBrowserStoreProvider({\n children,\n defaultPageSize,\n defaultCube,\n defaultColumns,\n}: DataBrowserStoreProviderProps) {\n const storeRef = useRef<StoreApi<DataBrowserStore> | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createDataBrowserStore({\n defaultPageSize,\n defaultCube,\n defaultColumns,\n })\n }\n\n return (\n <DataBrowserStoreContext.Provider value={storeRef.current}>\n {children}\n </DataBrowserStoreContext.Provider>\n )\n}\n\nexport function useDataBrowserStore<T>(selector: (state: DataBrowserStore) => T): T {\n const store = useContext(DataBrowserStoreContext)\n if (!store) {\n throw new Error('useDataBrowserStore must be used within DataBrowserStoreProvider')\n }\n return useStore(store, selector)\n}\n","/**\n * useDataBrowser Master Hook\n *\n * Coordinates DataBrowser store state with query building and data fetching.\n * Builds ungrouped SemanticQueries from the store's selected cube, columns,\n * sort, pagination, and filter state.\n */\n\nimport { useMemo } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useDataBrowserStore } from '../stores/dataBrowserStore'\nimport { useCubeMeta } from '../providers/CubeProvider'\nimport { useCubeLoadQuery } from './queries/useCubeLoadQuery'\nimport type { CubeQuery } from '../types'\n\n/**\n * Determine whether a field is a dimension on a given cube from metadata\n */\nfunction isDimension(fieldName: string, meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string }> }> } | null): boolean {\n if (!meta) return true // default to dimension if no meta\n const [cubeName, field] = fieldName.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return true\n return cube.dimensions.some((d) => d.name === `${cubeName}.${field}`)\n}\n\n/**\n * Get field type from metadata\n */\nexport function getFieldType(\n fieldName: string,\n meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string; type: string }>; measures: Array<{ name: string; type: string }> }> } | null\n): string {\n if (!meta) return 'string'\n const [cubeName] = fieldName.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return 'string'\n const dim = cube.dimensions.find((d) => d.name === fieldName)\n if (dim) return dim.type\n const meas = cube.measures.find((m) => m.name === fieldName)\n if (meas) return meas.type\n return 'string'\n}\n\n/**\n * Get all browsable columns for a cube (dimensions + ungrouped-compatible measures)\n */\nexport function getCubeColumns(\n cubeName: string,\n meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string }>; measures: Array<{ name: string; type: string }> }> } | null\n): { dimensions: string[]; measures: string[] } {\n if (!meta) return { dimensions: [], measures: [] }\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return { dimensions: [], measures: [] }\n\n const ungroupedCompatible = new Set(['sum', 'avg', 'min', 'max', 'number'])\n const dimensions = cube.dimensions.map((d) => d.name)\n const measures = cube.measures\n .filter((m) => ungroupedCompatible.has(m.type))\n .map((m) => m.name)\n\n return { dimensions, measures }\n}\n\nexport function useDataBrowser() {\n // Store state\n const selectedCube = useDataBrowserStore((s) => s.selectedCube)\n const visibleColumns = useDataBrowserStore((s) => s.visibleColumns)\n const sortColumn = useDataBrowserStore((s) => s.sortColumn)\n const sortDirection = useDataBrowserStore((s) => s.sortDirection)\n const page = useDataBrowserStore((s) => s.page)\n const pageSize = useDataBrowserStore((s) => s.pageSize)\n const filters = useDataBrowserStore((s) => s.filters)\n const showFilterBar = useDataBrowserStore((s) => s.showFilterBar)\n const showColumnPicker = useDataBrowserStore((s) => s.showColumnPicker)\n\n // Actions\n const actions = useDataBrowserStore(\n useShallow((s) => ({\n selectCube: s.selectCube,\n setVisibleColumns: s.setVisibleColumns,\n toggleColumn: s.toggleColumn,\n setSort: s.setSort,\n clearSort: s.clearSort,\n setPage: s.setPage,\n setPageSize: s.setPageSize,\n setFilters: s.setFilters,\n toggleFilterBar: s.toggleFilterBar,\n setShowColumnPicker: s.setShowColumnPicker,\n }))\n )\n\n // Metadata\n const { meta, getFieldLabel } = useCubeMeta()\n\n // Determine default sort: first primary key dimension, or first dimension\n const defaultSortColumn = useMemo(() => {\n if (!meta || !selectedCube) return null\n const cube = meta.cubes.find((c) => c.name === selectedCube)\n if (!cube) return null\n // Look for a primary key dimension first\n const pkDim = cube.dimensions.find((d: any) => d.primaryKey)\n if (pkDim) return pkDim.name\n // Fall back to first dimension\n if (cube.dimensions.length > 0) return cube.dimensions[0].name\n return null\n }, [meta, selectedCube])\n\n const effectiveSortColumn = sortColumn ?? defaultSortColumn\n const effectiveSortDirection = sortColumn ? sortDirection : 'asc'\n\n // Build query from store state\n const query = useMemo<CubeQuery | null>(() => {\n if (!selectedCube || visibleColumns.length === 0) return null\n\n const dimensions = visibleColumns.filter((col) => isDimension(col, meta))\n const measures = visibleColumns.filter((col) => !isDimension(col, meta))\n\n if (dimensions.length === 0) return null // ungrouped requires at least one dimension\n\n const q: CubeQuery = {\n dimensions,\n ungrouped: true,\n limit: pageSize,\n offset: page * pageSize,\n }\n\n if (measures.length > 0) q.measures = measures\n if (filters.length > 0) q.filters = filters\n if (effectiveSortColumn) q.order = { [effectiveSortColumn]: effectiveSortDirection }\n\n return q\n }, [selectedCube, visibleColumns, filters, effectiveSortColumn, effectiveSortDirection, page, pageSize, meta])\n\n // Fetch data — keepPreviousData ON so pagination/sort keeps showing\n // stale data while new page loads. We detect cube switches by checking\n // if the data keys match the current columns.\n const {\n rawData: rawDataFromQuery,\n isLoading,\n isFetching,\n isDebouncing,\n error,\n refetch,\n } = useCubeLoadQuery(query, {\n skip: !query,\n debounceMs: 400,\n keepPreviousData: true,\n staleTime: 60000, // 1 minute — prevent unnecessary refetches\n })\n\n // Detect stale data from a different cube by checking if data keys\n // match the current visible columns. This handles cube switches\n // (keys won't match) while preserving data during pagination/sort\n // (keys still match since it's the same cube).\n const rawData = (() => {\n if (!rawDataFromQuery || rawDataFromQuery.length === 0) return rawDataFromQuery\n const dataKeys = Object.keys(rawDataFromQuery[0] as Record<string, unknown>)\n const matches = visibleColumns.some(col => dataKeys.includes(col))\n return matches ? rawDataFromQuery : null\n })()\n\n // Loading when: TanStack is loading, or debouncing with no valid data\n const effectiveIsLoading = isLoading || (!rawData && (isDebouncing || isFetching))\n\n // Compute total page info\n const rowCount = rawData?.length ?? 0\n const hasNextPage = rowCount === pageSize // if we got a full page, there might be more\n const hasPrevPage = page > 0\n\n return {\n // State\n selectedCube,\n visibleColumns,\n sortColumn: effectiveSortColumn,\n sortDirection: effectiveSortDirection,\n page,\n pageSize,\n filters,\n showFilterBar,\n showColumnPicker,\n\n // Data\n rawData,\n isLoading: effectiveIsLoading,\n isFetching,\n error,\n query,\n rowCount,\n hasNextPage,\n hasPrevPage,\n\n // Metadata\n meta,\n getFieldLabel,\n\n // Actions\n ...actions,\n refetch,\n }\n}\n","/**\n * DataBrowserSidebar\n *\n * Left panel showing a searchable list of cubes.\n * Clicking a cube loads its dimensions into the table view.\n */\n\nimport { useState, useMemo } from 'react'\nimport { getIcon } from '../../icons'\n\nconst SearchIcon = getIcon('search')\nconst CubeIcon = getIcon('cube')\n\ninterface DataBrowserSidebarProps {\n cubes: Array<{ name: string; title: string }>\n selectedCube: string | null\n onSelectCube: (cubeName: string) => void\n}\n\nexport default function DataBrowserSidebar({\n cubes,\n selectedCube,\n onSelectCube,\n}: DataBrowserSidebarProps) {\n const [search, setSearch] = useState('')\n\n const filteredCubes = useMemo(() => {\n const sorted = [...cubes].sort((a, b) =>\n (a.title || a.name).localeCompare(b.title || b.name)\n )\n if (!search) return sorted\n const lower = search.toLowerCase()\n return sorted.filter(\n (c) =>\n c.name.toLowerCase().includes(lower) ||\n c.title.toLowerCase().includes(lower)\n )\n }, [cubes, search])\n\n return (\n <div className=\"dc:flex dc:flex-col dc:h-full dc:border-r border-dc-border bg-dc-surface dc:w-60 dc:shrink-0\">\n {/* Header */}\n <div className=\"dc:px-3 dc:py-3 dc:border-b border-dc-border\">\n <h2 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">Cubes</h2>\n {/* Search */}\n <div className=\"dc:relative\">\n <SearchIcon className=\"dc:absolute dc:left-2 dc:top-1/2 dc:-translate-y-1/2 dc:w-3.5 dc:h-3.5 text-dc-text-muted\" />\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search...\"\n className=\"dc:w-full dc:pl-7 dc:pr-2 dc:py-1.5 dc:text-xs dc:rounded border-dc-border dc:border bg-dc-surface text-dc-text dc:outline-none dc:focus:ring-1 focus:ring-dc-accent\"\n />\n </div>\n </div>\n\n {/* Cube list */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:py-1\">\n {filteredCubes.map((cube) => (\n <button\n key={cube.name}\n onClick={() => onSelectCube(cube.name)}\n className={`dc:flex dc:items-center dc:gap-2 dc:w-full dc:px-3 dc:py-1.5 dc:text-left dc:text-sm dc:transition-colors ${\n selectedCube === cube.name\n ? 'bg-dc-accent-bg text-dc-accent dc:font-medium'\n : 'text-dc-text dc:hover:bg-dc-surface-hover'\n }`}\n >\n <CubeIcon className=\"dc:w-4 dc:h-4 dc:shrink-0 text-dc-text-muted\" />\n <span className=\"dc:truncate\">{cube.title || cube.name}</span>\n </button>\n ))}\n\n {filteredCubes.length === 0 && (\n <div className=\"dc:px-3 dc:py-4 dc:text-xs text-dc-text-muted dc:text-center\">\n No cubes found\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * DataBrowserToolbar\n *\n * Top toolbar with filter toggle, column picker, row count, and pagination.\n */\n\nimport { getIcon } from '../../icons'\n\nconst FilterIcon = getIcon('filter')\nconst ColumnsIcon = getIcon('settings')\nconst ChevronLeftIcon = getIcon('chevronLeft')\nconst ChevronRightIcon = getIcon('chevronRight')\nconst RefreshIcon = getIcon('refresh')\n\ninterface DataBrowserToolbarProps {\n // Filter state\n showFilterBar: boolean\n filterCount: number\n onToggleFilterBar: () => void\n\n // Column picker\n onToggleColumnPicker: () => void\n\n // Pagination\n page: number\n pageSize: number\n rowCount: number\n hasNextPage: boolean\n hasPrevPage: boolean\n onPageChange: (page: number) => void\n onPageSizeChange: (size: number) => void\n\n // Status\n isFetching: boolean\n onRefresh: () => void\n}\n\nexport default function DataBrowserToolbar({\n showFilterBar,\n filterCount,\n onToggleFilterBar,\n onToggleColumnPicker,\n page,\n pageSize,\n rowCount,\n hasNextPage,\n hasPrevPage,\n onPageChange,\n onPageSizeChange,\n isFetching,\n onRefresh,\n}: DataBrowserToolbarProps) {\n return (\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:px-3 dc:py-2 dc:border-b border-dc-border bg-dc-surface-secondary\">\n {/* Filter toggle */}\n <button\n onClick={onToggleFilterBar}\n className={`dc:flex dc:items-center dc:gap-1.5 dc:px-2.5 dc:py-1.5 dc:text-xs dc:font-medium dc:rounded dc:border dc:transition-colors ${\n showFilterBar\n ? 'border-dc-accent bg-dc-accent-bg text-dc-accent'\n : 'border-dc-border bg-dc-surface text-dc-text dc:hover:bg-dc-surface-hover'\n }`}\n >\n <FilterIcon className=\"dc:w-3.5 dc:h-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:w-4 dc:h-4 dc:text-[10px] dc:font-bold dc:rounded-full bg-dc-accent text-dc-surface\">\n {filterCount}\n </span>\n )}\n </button>\n\n {/* Columns button */}\n <button\n onClick={onToggleColumnPicker}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-2.5 dc:py-1.5 dc:text-xs dc:font-medium dc:rounded dc:border border-dc-border bg-dc-surface text-dc-text dc:hover:bg-dc-surface-hover dc:transition-colors\"\n >\n <ColumnsIcon className=\"dc:w-3.5 dc:h-3.5\" />\n Columns\n </button>\n\n {/* Spacer */}\n <div className=\"dc:flex-1\" />\n\n {/* Row count */}\n <span className=\"dc:text-xs text-dc-text-muted\">\n {rowCount} rows\n </span>\n\n {/* Refresh */}\n <button\n onClick={onRefresh}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Refresh\"\n >\n <RefreshIcon className={`dc:w-3.5 dc:h-3.5 text-dc-text-muted ${isFetching ? 'dc:animate-spin' : ''}`} />\n </button>\n\n {/* Page size selector */}\n <select\n value={pageSize}\n onChange={(e) => onPageSizeChange(Number(e.target.value))}\n className=\"dc:text-xs dc:px-1.5 dc:py-1 dc:rounded dc:border border-dc-border bg-dc-surface text-dc-text dc:outline-none\"\n >\n <option value={20}>20</option>\n <option value={50}>50</option>\n <option value={100}>100</option>\n </select>\n\n {/* Pagination */}\n <div className=\"dc:flex dc:items-center dc:gap-1\">\n <button\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPrevPage}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:disabled:opacity-30 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n <ChevronLeftIcon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </button>\n <span className=\"dc:text-xs dc:font-medium text-dc-text dc:min-w-[2rem] dc:text-center\">\n {page + 1}\n </span>\n <button\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:disabled:opacity-30 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n <ChevronRightIcon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </button>\n </div>\n </div>\n )\n}\n","/**\n * DataBrowserTable\n *\n * Sortable data table with resizable columns, type badges, and click-to-sort headers.\n * Designed for browsing raw row-level data from ungrouped queries.\n *\n * Column widths are stored in the Zustand store (cosmetic-only slice)\n * and never affect query construction or data fetching.\n */\n\nimport React, { useCallback, useRef } from 'react'\nimport { getIcon } from '../../icons'\nimport { getFieldType } from '../../hooks/useDataBrowser'\nimport { useDataBrowserStore } from '../../stores/dataBrowserStore'\nimport LoadingIndicator from '../LoadingIndicator'\n\nconst SortAscIcon = getIcon('chevronUp')\nconst SortDescIcon = getIcon('chevronDown')\n\ninterface DataBrowserTableProps {\n data: unknown[] | null\n columns: string[]\n sortColumn: string | null\n sortDirection: 'asc' | 'desc'\n onSort: (column: string) => void\n getFieldLabel: (field: string) => string\n meta: any\n isLoading: boolean\n isFetching: boolean\n selectedCube: string | null\n loadingComponent?: React.ReactNode\n}\n\nfunction getTypeLabel(fieldName: string, meta: any): string {\n const type = getFieldType(fieldName, meta)\n const typeMap: Record<string, string> = {\n string: 'text',\n number: 'num',\n time: 'time',\n boolean: 'bool',\n sum: 'num',\n avg: 'num',\n min: 'num',\n max: 'num',\n }\n return typeMap[type] || type\n}\n\nfunction isNumericType(fieldName: string, meta: any): boolean {\n return getTypeLabel(fieldName, meta) === 'num'\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value == null) return ''\n if (typeof value === 'number') return value.toLocaleString()\n if (typeof value === 'boolean') return value ? 'true' : 'false'\n if (value instanceof Date) return value.toISOString()\n return String(value)\n}\n\nconst MIN_COL_WIDTH = 60\nconst DEFAULT_COL_WIDTH = 150\n\nexport default React.memo(function DataBrowserTable({\n data,\n columns,\n sortColumn,\n sortDirection,\n onSort,\n getFieldLabel,\n meta,\n isLoading,\n isFetching,\n selectedCube,\n loadingComponent,\n}: DataBrowserTableProps) {\n // Column widths from store (cosmetic only — never affects queries)\n const columnWidths = useDataBrowserStore((s) => s.columnWidths)\n const storeSetColumnWidth = useDataBrowserStore((s) => s.setColumnWidth)\n const storeSetColumnWidths = useDataBrowserStore((s) => s.setColumnWidths)\n\n const tableRef = useRef<HTMLTableElement>(null)\n // Suppress the next click on <th> after a resize drag\n const didResizeRef = useRef(false)\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent, column: string) => {\n e.preventDefault()\n e.stopPropagation()\n\n const startX = e.clientX\n didResizeRef.current = false\n\n // Snapshot all column widths from the DOM so other columns stay fixed\n const table = tableRef.current\n if (table) {\n const ths = table.querySelectorAll('thead th')\n const snapshot: Record<string, number> = {}\n ths.forEach((th, idx) => {\n const col = columns[idx]\n if (col) snapshot[col] = th.getBoundingClientRect().width\n })\n storeSetColumnWidths(snapshot)\n }\n\n const th = (e.target as HTMLElement).closest('th')\n const startWidth = th ? th.getBoundingClientRect().width : DEFAULT_COL_WIDTH\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const diff = moveEvent.clientX - startX\n if (Math.abs(diff) > 2) didResizeRef.current = true\n const newWidth = Math.max(MIN_COL_WIDTH, startWidth + diff)\n storeSetColumnWidth(column, newWidth)\n }\n\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n document.body.style.cursor = ''\n document.body.style.userSelect = ''\n // Keep didResizeRef true briefly so the click handler can check it\n requestAnimationFrame(() => { didResizeRef.current = false })\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n document.body.style.cursor = 'col-resize'\n document.body.style.userSelect = 'none'\n },\n [columns, storeSetColumnWidth, storeSetColumnWidths]\n )\n\n const handleHeaderClick = useCallback(\n (column: string) => {\n if (didResizeRef.current) return // suppress click after resize drag\n onSort(column)\n },\n [onSort]\n )\n\n // Compute table width when column widths are explicitly set\n const hasExplicitWidths = Object.keys(columnWidths).length > 0\n const tableWidth = hasExplicitWidths\n ? columns.reduce((sum, col) => sum + (columnWidths[col] ?? DEFAULT_COL_WIDTH), 0)\n : undefined\n\n // No cube selected\n if (!selectedCube) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-base dc:font-semibold dc:mb-1\">Select a cube</div>\n <div className=\"dc:text-sm text-dc-text-secondary\">\n Choose a cube from the sidebar to browse its data\n </div>\n </div>\n </div>\n )\n }\n\n // Loading: no data yet (initial load, cube switch, or fetching)\n if (!data) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:h-full dc:gap-3\">\n {loadingComponent ?? (\n <>\n <LoadingIndicator size=\"md\" />\n <div className=\"dc:text-sm text-dc-text-muted\">Loading data...</div>\n </>\n )}\n </div>\n )\n }\n\n // Empty result set (query completed but returned no rows)\n if (data.length === 0 && !isLoading && !isFetching) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No rows returned for this query</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:relative dc:flex-1 dc:overflow-auto\">\n {isFetching && (\n <div className=\"dc:absolute dc:inset-0 bg-dc-surface dc:opacity-40 dc:z-10 dc:pointer-events-none\" />\n )}\n\n <table ref={tableRef} className=\"dc:border-collapse\" style={{ tableLayout: 'fixed', width: tableWidth, minWidth: '100%' }}>\n <colgroup>\n {columns.map((column) => (\n <col key={column} style={{ width: columnWidths[column] ?? DEFAULT_COL_WIDTH }} />\n ))}\n </colgroup>\n <thead className=\"dc:sticky dc:top-0 dc:z-20\" style={{ backgroundColor: 'var(--dc-surface-secondary)' }}>\n <tr>\n {columns.map((column, colIdx) => {\n const isSorted = sortColumn === column\n const label = getFieldLabel(column)\n const typeLabel = getTypeLabel(column, meta)\n const isLast = colIdx === columns.length - 1\n const isNumeric = isNumericType(column, meta)\n\n return (\n <th\n key={column}\n onClick={() => handleHeaderClick(column)}\n className={`dc:relative dc:px-3 dc:py-2 dc:text-xs dc:font-normal dc:cursor-pointer dc:select-none dc:border-b border-dc-border dc:transition-colors${!isLast ? ' dc:border-r' : ''}${isNumeric ? ' dc:text-right' : ' dc:text-left'}`}\n style={{ color: 'var(--dc-text-muted)' }}\n >\n <div className={`dc:flex dc:items-center dc:gap-1.5 dc:overflow-hidden${isNumeric ? ' dc:justify-end' : ''}`}>\n <span className=\"dc:font-medium dc:truncate\" style={{ color: 'var(--dc-text)' }}>{label}</span>\n <span className=\"dc:text-[10px] dc:opacity-50 dc:shrink-0\">{typeLabel}</span>\n {isSorted && (\n sortDirection === 'asc'\n ? <SortAscIcon className=\"dc:w-3 dc:h-3 text-dc-accent dc:shrink-0\" />\n : <SortDescIcon className=\"dc:w-3 dc:h-3 text-dc-accent dc:shrink-0\" />\n )}\n </div>\n {/* Resize handle */}\n <div\n onMouseDown={(e) => handleResizeStart(e, column)}\n className=\"dc:absolute dc:top-0 dc:right-0 dc:w-1.5 dc:h-full dc:cursor-col-resize dc:hover:bg-dc-accent dc:opacity-0 dc:hover:opacity-100 dc:transition-opacity\"\n style={{ zIndex: 30 }}\n />\n </th>\n )\n })}\n </tr>\n </thead>\n <tbody>\n {(data as Record<string, unknown>[]).map((row, rowIdx) => (\n <tr\n key={rowIdx}\n className=\"dc:border-b border-dc-border\"\n style={{ transition: 'background-color 0.1s' }}\n onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = 'var(--dc-surface-hover, rgba(0,0,0,0.02))' }}\n onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = '' }}\n >\n {columns.map((column, colIdx) => {\n const isLast = colIdx === columns.length - 1\n const isNumeric = isNumericType(column, meta)\n return (\n <td\n key={column}\n className={`dc:px-3 dc:py-1.5 dc:text-sm dc:overflow-hidden dc:text-ellipsis dc:whitespace-nowrap${!isLast ? ' dc:border-r border-dc-border' : ''}${isNumeric ? ' dc:text-right dc:tabular-nums' : ''}`}\n style={{ color: 'var(--dc-text)' }}\n >\n {formatCellValue(row[column])}\n </td>\n )\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n})\n","/**\n * DataBrowser Component\n *\n * A Neon-style full-page data browser for exploring raw cube data.\n * Uses ungrouped queries to display row-level data with:\n * - Cube list sidebar (left)\n * - Sortable data table (right)\n * - Filter bar and column picker\n * - Server-side pagination\n *\n * Must be wrapped in a CubeProvider.\n */\n\nimport { useMemo, useCallback } from 'react'\nimport { DataBrowserStoreProvider } from '../../stores/dataBrowserStore'\nimport { useDataBrowser, getCubeColumns } from '../../hooks/useDataBrowser'\nimport DataBrowserSidebar from './DataBrowserSidebar'\nimport DataBrowserToolbar from './DataBrowserToolbar'\nimport DataBrowserTable from './DataBrowserTable'\nimport AnalysisFilterSection from '../AnalysisBuilder/AnalysisFilterSection'\nimport FieldSearchModal from '../AnalysisBuilder/FieldSearchModal'\nimport type { MetaResponse, MetaField } from '../../shared/types'\n\nexport interface DataBrowserProps {\n /** Additional CSS classes */\n className?: string\n /** Initially selected cube */\n defaultCube?: string\n /** Default page size (default: 20) */\n defaultPageSize?: number\n /** Max height for the component (default: '100vh') */\n maxHeight?: string\n /** Custom loading indicator (defaults to LoadingIndicator) */\n loadingComponent?: import('react').ReactNode\n}\n\n/**\n * Inner component (must be inside store provider)\n */\nfunction DataBrowserInner({ className = '', maxHeight = '100vh', loadingComponent }: Omit<DataBrowserProps, 'defaultCube' | 'defaultPageSize'>) {\n const {\n selectedCube,\n visibleColumns,\n sortColumn,\n sortDirection,\n page,\n pageSize,\n filters,\n showFilterBar,\n showColumnPicker,\n rawData,\n isLoading,\n isFetching,\n rowCount,\n hasNextPage,\n hasPrevPage,\n meta,\n getFieldLabel,\n selectCube,\n setSort,\n setPage,\n setPageSize,\n setFilters,\n toggleFilterBar,\n setShowColumnPicker,\n toggleColumn,\n refetch,\n } = useDataBrowser()\n\n // Build cube list from metadata\n const cubeList = useMemo(() => {\n if (!meta) return []\n return meta.cubes.map((c) => ({ name: c.name, title: c.title || c.name }))\n }, [meta])\n\n // Handle cube selection — auto-populate with all dimensions\n const handleSelectCube = useCallback(\n (cubeName: string) => {\n const { dimensions } = getCubeColumns(cubeName, meta)\n selectCube(cubeName, dimensions)\n },\n [meta, selectCube]\n )\n\n // Filter count\n const filterCount = useMemo(() => {\n function count(fs: typeof filters): number {\n return fs.reduce((n, f) => {\n if ('member' in f) return n + 1\n if ('type' in f && 'filters' in f) return n + count(f.filters)\n return n\n }, 0)\n }\n return count(filters)\n }, [filters])\n\n // Schema for filter section and field search modal\n // Cast to MetaResponse since the components handle optional description gracefully\n const schema = useMemo<MetaResponse | null>(() => {\n if (!meta) return null\n if (selectedCube) {\n const cube = meta.cubes.find((c) => c.name === selectedCube)\n return cube ? { cubes: [cube] } as unknown as MetaResponse : null\n }\n return meta as unknown as MetaResponse\n }, [meta, selectedCube])\n\n // Handle column toggle from FieldSearchModal\n const handleColumnSelect = useCallback(\n (field: MetaField, _fieldType: string, _cubeName: string, keepOpen?: boolean) => {\n void keepOpen\n toggleColumn(field.name)\n },\n [toggleColumn]\n )\n\n return (\n <div\n className={`dc:flex dc:border border-dc-border dc:rounded-lg dc:overflow-hidden bg-dc-surface ${className}`}\n style={{ height: maxHeight }}\n >\n {/* Sidebar */}\n <DataBrowserSidebar\n cubes={cubeList}\n selectedCube={selectedCube}\n onSelectCube={handleSelectCube}\n />\n\n {/* Main content */}\n <div className=\"dc:flex dc:flex-col dc:flex-1 dc:min-w-0\">\n {/* Toolbar */}\n {selectedCube && (\n <DataBrowserToolbar\n showFilterBar={showFilterBar}\n filterCount={filterCount}\n onToggleFilterBar={toggleFilterBar}\n onToggleColumnPicker={() => setShowColumnPicker(!showColumnPicker)}\n page={page}\n pageSize={pageSize}\n rowCount={rowCount}\n hasNextPage={hasNextPage}\n hasPrevPage={hasPrevPage}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n isFetching={isFetching}\n onRefresh={() => refetch()}\n />\n )}\n\n {/* Filter bar (collapsible) */}\n {selectedCube && showFilterBar && (\n <div className=\"dc:px-3 dc:py-2 dc:border-b border-dc-border bg-dc-surface\">\n <AnalysisFilterSection\n filters={filters}\n schema={schema}\n onFiltersChange={setFilters}\n />\n </div>\n )}\n\n {/* Data table */}\n <DataBrowserTable\n data={rawData}\n columns={visibleColumns}\n sortColumn={sortColumn}\n sortDirection={sortDirection}\n onSort={setSort}\n getFieldLabel={getFieldLabel}\n meta={meta}\n isLoading={isLoading}\n isFetching={isFetching}\n selectedCube={selectedCube}\n loadingComponent={loadingComponent}\n />\n </div>\n\n {/* Column picker modal */}\n {showColumnPicker && schema && (\n <FieldSearchModal\n isOpen={showColumnPicker}\n onClose={() => setShowColumnPicker(false)}\n onSelect={handleColumnSelect}\n mode=\"breakdown\"\n schema={schema}\n selectedFields={visibleColumns}\n />\n )}\n </div>\n )\n}\n\n/**\n * DataBrowser — standalone data browsing component\n */\nexport default function DataBrowser({\n className,\n defaultCube,\n defaultPageSize = 20,\n maxHeight,\n loadingComponent,\n}: DataBrowserProps) {\n return (\n <DataBrowserStoreProvider defaultPageSize={defaultPageSize} defaultCube={defaultCube}>\n <DataBrowserInner className={className} maxHeight={maxHeight} loadingComponent={loadingComponent} />\n </DataBrowserStoreProvider>\n )\n}\n","/**\n * DashboardThumbnailPlaceholder\n *\n * A placeholder component shown when a dashboard thumbnail doesn't exist\n * but the thumbnail feature is enabled. Displays a simple grid icon\n * with \"No preview\" text.\n */\n\nimport { getIcon } from '../icons'\n\nconst GridIcon = getIcon('segment')\n\nexport interface DashboardThumbnailPlaceholderProps {\n /** Additional CSS classes */\n className?: string\n}\n\nexport function DashboardThumbnailPlaceholder({\n className = ''\n}: DashboardThumbnailPlaceholderProps) {\n return (\n <div\n className={`dc:flex dc:items-center dc:justify-center bg-dc-bg-secondary ${className}`}\n >\n <div className=\"dc:text-center\">\n <GridIcon\n className=\"dc:w-8 dc:h-8 dc:mx-auto dc:mb-2 text-dc-text-muted dc:opacity-50\"\n />\n <span className=\"dc:text-xs text-dc-text-muted\">No preview</span>\n </div>\n </div>\n )\n}\n\nexport default DashboardThumbnailPlaceholder\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/client/stores/notebookStore.tsx","../../src/client/components/AgenticNotebook/NotebookPortletBlock.tsx","../../src/client/components/AgenticNotebook/NotebookMarkdownBlock.tsx","../../src/client/components/AgenticNotebook/NotebookCanvas.tsx","../../src/client/hooks/useAgentChat.ts","../../src/client/components/AgenticNotebook/ChatMessage.tsx","../../src/client/components/AgenticNotebook/ChatInput.tsx","../../src/client/components/AgenticNotebook/AgentChatPanel.tsx","../../src/client/components/AgenticNotebook/index.tsx","../../src/client/components/AnalyticsPage.tsx","../../src/client/stores/dataBrowserStore.tsx","../../src/client/hooks/useDataBrowser.ts","../../src/client/components/DataBrowser/DataBrowserSidebar.tsx","../../src/client/components/DataBrowser/DataBrowserToolbar.tsx","../../src/client/components/DataBrowser/DataBrowserTable.tsx","../../src/client/components/DataBrowser/index.tsx","../../src/client/components/DashboardThumbnailPlaceholder.tsx"],"sourcesContent":["/**\n * Notebook Zustand Store (Instance-based)\n *\n * State management for the AgenticNotebook component, consolidating:\n * - Notebook blocks (portlets + markdown)\n * - Chat messages\n * - Session state\n * - UI state\n *\n * KEY ARCHITECTURE: Instance-based stores\n * - Each AgenticNotebook gets its own store instance via Context\n * - No server state (data fetching is handled by portlets via TanStack Query)\n * - State is per-notebook session\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, subscribeWithSelector } from 'zustand/middleware'\nimport type {\n ChartType,\n ChartAxisConfig,\n ChartDisplayConfig,\n} from '../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A portlet block in the notebook\n */\nexport interface PortletBlock {\n id: string\n type: 'portlet'\n title: string\n query: string\n chartType: ChartType\n chartConfig?: ChartAxisConfig\n displayConfig?: ChartDisplayConfig\n}\n\n/**\n * A markdown text block in the notebook\n */\nexport interface MarkdownBlock {\n id: string\n type: 'markdown'\n title?: string\n content: string\n}\n\n/**\n * A block in the notebook canvas\n */\nexport type NotebookBlock = PortletBlock | MarkdownBlock\n\n/**\n * A tool call record for display in chat messages\n */\nexport interface ToolCallRecord {\n id: string\n name: string\n input?: unknown\n result?: unknown\n status: 'running' | 'complete' | 'error'\n}\n\n/**\n * A chat message\n */\nexport interface ChatMessage {\n id: string\n role: 'user' | 'assistant'\n content: string\n error?: string\n toolCalls?: ToolCallRecord[]\n timestamp: number\n}\n\n/**\n * Serializable notebook config for save/load\n */\nexport interface NotebookConfig {\n blocks: NotebookBlock[]\n messages: ChatMessage[]\n}\n\n// ============================================================================\n// Store State\n// ============================================================================\n\nexport interface NotebookStoreState {\n /** Ordered array of notebook blocks */\n blocks: NotebookBlock[]\n\n /** Chat message history */\n messages: ChatMessage[]\n\n /** Whether the agent is currently streaming a response */\n isStreaming: boolean\n\n /** Agent SDK session ID for multi-turn conversations */\n sessionId: string | null\n\n /** Chat input value */\n inputValue: string\n}\n\n// ============================================================================\n// Store Actions\n// ============================================================================\n\nexport interface NotebookStoreActions {\n // Block actions\n addBlock: (block: NotebookBlock) => void\n removeBlock: (id: string) => void\n moveBlock: (id: string, direction: 'up' | 'down') => void\n updateBlock: (id: string, updates: Partial<Omit<PortletBlock, 'id' | 'type'>>) => void\n\n // Chat actions\n addMessage: (message: ChatMessage) => void\n appendToLastAssistantMessage: (text: string) => void\n setLastAssistantError: (error: string) => void\n addToolCallToLastAssistant: (toolCall: ToolCallRecord) => void\n updateLastToolCall: (update: Partial<ToolCallRecord>) => void\n\n // Session/UI actions\n setIsStreaming: (streaming: boolean) => void\n setSessionId: (id: string | null) => void\n setInputValue: (value: string) => void\n\n // Persistence\n save: () => NotebookConfig\n load: (config: NotebookConfig) => void\n\n // Reset\n reset: () => void\n}\n\n/**\n * Combined store type\n */\nexport type NotebookStore = NotebookStoreState & NotebookStoreActions\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst createDefaultState = (): NotebookStoreState => ({\n blocks: [],\n messages: [],\n isStreaming: false,\n sessionId: null,\n inputValue: '',\n})\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\nfunction createStoreActions(\n set: (\n partial:\n | Partial<NotebookStore>\n | ((state: NotebookStore) => Partial<NotebookStore>)\n ) => void,\n get: () => NotebookStore\n): NotebookStoreActions {\n return {\n // Block actions\n addBlock: (block) =>\n set((state) => ({\n blocks: [...state.blocks, block],\n })),\n\n removeBlock: (id) =>\n set((state) => ({\n blocks: state.blocks.filter((b) => b.id !== id),\n })),\n\n moveBlock: (id, direction) =>\n set((state) => {\n const idx = state.blocks.findIndex((b) => b.id === id)\n if (idx === -1) return {}\n if (direction === 'up' && idx === 0) return {}\n if (direction === 'down' && idx === state.blocks.length - 1) return {}\n\n const newBlocks = [...state.blocks]\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n ;[newBlocks[idx], newBlocks[swapIdx]] = [newBlocks[swapIdx], newBlocks[idx]]\n return { blocks: newBlocks }\n }),\n\n updateBlock: (id, updates) =>\n set((state) => ({\n blocks: state.blocks.map((b) =>\n b.id === id && b.type === 'portlet' ? { ...b, ...updates } : b\n ),\n })),\n\n // Chat actions\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n\n appendToLastAssistantMessage: (text) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = {\n ...lastMsg,\n content: lastMsg.content + text,\n }\n }\n return { messages }\n }),\n\n setLastAssistantError: (error) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = { ...lastMsg, error }\n }\n return { messages }\n }),\n\n addToolCallToLastAssistant: (toolCall) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg && lastMsg.role === 'assistant') {\n messages[messages.length - 1] = {\n ...lastMsg,\n toolCalls: [...(lastMsg.toolCalls || []), toolCall],\n }\n }\n return { messages }\n }),\n\n updateLastToolCall: (update) =>\n set((state) => {\n const messages = [...state.messages]\n const lastMsg = messages[messages.length - 1]\n if (lastMsg?.role === 'assistant' && lastMsg.toolCalls?.length) {\n const toolCalls = [...lastMsg.toolCalls]\n // Find by ID if provided, otherwise fall back to last\n const idx = update.id\n ? toolCalls.findIndex((tc) => tc.id === update.id)\n : toolCalls.length - 1\n if (idx !== -1) {\n toolCalls[idx] = { ...toolCalls[idx], ...update }\n messages[messages.length - 1] = { ...lastMsg, toolCalls }\n }\n }\n return { messages }\n }),\n\n // Session/UI actions\n setIsStreaming: (streaming) => set({ isStreaming: streaming }),\n setSessionId: (id) => set({ sessionId: id }),\n setInputValue: (value) => set({ inputValue: value }),\n\n // Persistence\n save: () => {\n const state = get()\n return {\n blocks: state.blocks,\n messages: state.messages,\n }\n },\n\n load: (config) =>\n set({\n blocks: config.blocks || [],\n messages: config.messages || [],\n }),\n\n // Reset\n reset: () => set(createDefaultState()),\n }\n}\n\n/**\n * Create a new notebook store instance\n */\nexport function createNotebookStore() {\n const initialState = createDefaultState()\n\n return createStore<NotebookStore>()(\n devtools(\n subscribeWithSelector((set, get) => ({\n ...initialState,\n ...createStoreActions(set, get),\n })),\n { name: 'NotebookStore' }\n )\n )\n}\n\n// ============================================================================\n// React Context & Provider\n// ============================================================================\n\nconst NotebookStoreContext = createContext<StoreApi<NotebookStore> | null>(null)\n\nexport interface NotebookStoreProviderProps {\n children: ReactNode\n /** Initial config to load */\n initialConfig?: NotebookConfig\n}\n\n/**\n * Provider component that creates a store instance per AgenticNotebook\n */\nexport function NotebookStoreProvider({\n children,\n initialConfig,\n}: NotebookStoreProviderProps) {\n const storeRef = useRef<StoreApi<NotebookStore> | null>(null)\n\n if (!storeRef.current) {\n const store = createNotebookStore()\n if (initialConfig) {\n store.getState().load(initialConfig)\n }\n storeRef.current = store\n }\n\n return (\n <NotebookStoreContext.Provider value={storeRef.current}>\n {children}\n </NotebookStoreContext.Provider>\n )\n}\n\n/**\n * Hook to access the notebook store from context\n * @throws Error if used outside of provider\n */\nexport function useNotebookStore<T>(selector: (state: NotebookStore) => T): T {\n const store = useContext(NotebookStoreContext)\n if (!store) {\n throw new Error('useNotebookStore must be used within NotebookStoreProvider')\n }\n return useStore(store, selector)\n}\n\n// ============================================================================\n// Selectors\n// ============================================================================\n\nexport const selectBlocks = (state: NotebookStore) => state.blocks\nexport const selectMessages = (state: NotebookStore) => state.messages\nexport const selectIsStreaming = (state: NotebookStore) => state.isStreaming\nexport const selectSessionId = (state: NotebookStore) => state.sessionId\nexport const selectInputValue = (state: NotebookStore) => state.inputValue\n\nexport const selectChatState = (state: NotebookStore) => ({\n messages: state.messages,\n isStreaming: state.isStreaming,\n inputValue: state.inputValue,\n})\n\nexport const selectChatActions = (state: NotebookStore) => ({\n addMessage: state.addMessage,\n appendToLastAssistantMessage: state.appendToLastAssistantMessage,\n setLastAssistantError: state.setLastAssistantError,\n addToolCallToLastAssistant: state.addToolCallToLastAssistant,\n updateLastToolCall: state.updateLastToolCall,\n setIsStreaming: state.setIsStreaming,\n setInputValue: state.setInputValue,\n setSessionId: state.setSessionId,\n})\n\nexport const selectBlockActions = (state: NotebookStore) => ({\n addBlock: state.addBlock,\n removeBlock: state.removeBlock,\n moveBlock: state.moveBlock,\n updateBlock: state.updateBlock,\n})\n","/**\n * NotebookPortletBlock - Wraps AnalyticsPortlet for notebook display\n *\n * Uses the same header pattern as DashboardPortletCard for consistency:\n * - Title on the left with DebugModal inline\n * - Action buttons on the right (move, edit, delete)\n */\n\nimport React, { useState, useCallback } from 'react'\nimport type { CSSProperties } from 'react'\nimport type { PortletBlock } from '../../stores/notebookStore'\nimport type { ChartAxisConfig, ChartDisplayConfig, ChartType } from '../../types'\nimport type { ColorPalette } from '../../utils/colorPalettes'\nimport type { FlowChartData } from '../../types/flow'\nimport type { RetentionChartData } from '../../types/retention'\nimport { getIcon } from '../../icons/registry'\nimport AnalyticsPortlet from '../AnalyticsPortlet'\nimport DebugModal from '../DebugModal'\n\nconst ICON_STYLE: CSSProperties = { width: '16px', height: '16px', color: 'currentColor' }\n\ninterface DebugData {\n chartConfig: ChartAxisConfig\n displayConfig: ChartDisplayConfig\n queryObject: unknown\n data: unknown[] | FlowChartData | RetentionChartData\n chartType: ChartType\n cacheInfo?: { hit: true; cachedAt: string; ttlMs: number; ttlRemainingMs: number } | null\n drillState?: unknown\n}\n\ninterface NotebookPortletBlockProps {\n block: PortletBlock\n colorPalette?: ColorPalette\n onRemove: (id: string) => void\n onMoveUp: (id: string) => void\n onMoveDown: (id: string) => void\n onEdit: (block: PortletBlock) => void\n isFirst: boolean\n isLast: boolean\n}\n\nconst ChevronUpIcon = getIcon('chevronUp')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst EditIcon = getIcon('edit')\nconst DeleteIcon = getIcon('delete')\n\nconst NotebookPortletBlock = React.memo(function NotebookPortletBlock({\n block,\n colorPalette,\n onRemove,\n onMoveUp,\n onMoveDown,\n onEdit,\n isFirst,\n isLast,\n}: NotebookPortletBlockProps) {\n const [debugData, setDebugData] = useState<DebugData | null>(null)\n\n const handleDebugDataReady = useCallback((data: DebugData) => {\n setDebugData(data)\n }, [])\n\n return (\n <div className=\"dc:relative dc:mb-4 bg-dc-surface dc:border border-dc-border dc:rounded-lg dc:flex dc:flex-col\">\n {/* Header - same pattern as DashboardPortletCard */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-3 dc:py-1.5 dc:border-b border-dc-border dc:shrink-0 bg-dc-surface-secondary dc:rounded-t-lg\">\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:flex-1 dc:min-w-0\">\n <h3 className=\"dc:font-semibold dc:text-sm text-dc-text dc:truncate\">\n {block.title || 'Untitled'}\n </h3>\n {debugData && (\n <DebugModal\n chartConfig={debugData.chartConfig}\n displayConfig={debugData.displayConfig}\n queryObject={debugData.queryObject}\n data={debugData.data}\n chartType={debugData.chartType}\n cacheInfo={debugData.cacheInfo ?? undefined}\n />\n )}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-1 dc:shrink-0 dc:ml-4 dc:-mr-2\">\n {!isFirst && (\n <button\n onClick={() => onMoveUp(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move up\"\n >\n <ChevronUpIcon style={ICON_STYLE} />\n </button>\n )}\n {!isLast && (\n <button\n onClick={() => onMoveDown(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move down\"\n >\n <ChevronDownIcon style={ICON_STYLE} />\n </button>\n )}\n <button\n onClick={() => onEdit(block)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Edit visualization\"\n >\n <EditIcon style={ICON_STYLE} />\n </button>\n <button\n onClick={() => onRemove(block.id)}\n className=\"dc:p-1 dc:mr-0.5 dc:bg-transparent dc:border-none dc:rounded-sm dc:cursor-pointer dc:hover:bg-dc-danger-bg text-dc-danger dc:transition-colors\"\n title=\"Remove\"\n >\n <DeleteIcon style={ICON_STYLE} />\n </button>\n </div>\n </div>\n\n {/* Portlet body */}\n <div className=\"dc:flex-1 dc:min-h-0\">\n <AnalyticsPortlet\n query={block.query}\n chartType={block.chartType}\n chartConfig={block.chartConfig}\n displayConfig={block.displayConfig}\n colorPalette={colorPalette}\n height={400}\n eagerLoad={true}\n onDebugDataReady={handleDebugDataReady}\n />\n </div>\n </div>\n )\n})\n\nexport default NotebookPortletBlock\n","/**\n * NotebookMarkdownBlock - Renders a markdown text block in the notebook\n * Uses markdown-to-jsx for full GFM support including tables\n *\n * Header matches NotebookPortletBlock pattern for visual consistency.\n */\n\nimport React from 'react'\nimport type { CSSProperties } from 'react'\nimport Markdown from 'markdown-to-jsx'\nimport type { MarkdownBlock } from '../../stores/notebookStore'\nimport { getIcon } from '../../icons/registry'\n\nconst ICON_STYLE: CSSProperties = { width: '16px', height: '16px', color: 'currentColor' }\n\nconst DocumentTextIcon = getIcon('documentText')\nconst ChevronUpIcon = getIcon('chevronUp')\nconst ChevronDownIcon = getIcon('chevronDown')\nconst DeleteIcon = getIcon('delete')\n\ninterface NotebookMarkdownBlockProps {\n block: MarkdownBlock\n onRemove: (id: string) => void\n onMoveUp: (id: string) => void\n onMoveDown: (id: string) => void\n isFirst: boolean\n isLast: boolean\n}\n\n/** Scrollable table wrapper so wide tables don't overflow the block */\nfunction ScrollableTable({ children, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return (\n <div className=\"dc:overflow-x-auto dc:my-2\">\n <table {...props}>{children}</table>\n </div>\n )\n}\n\n/** markdown-to-jsx options with dc: themed overrides */\nconst markdownOptions = {\n overrides: {\n h1: { props: { className: 'dc:text-lg dc:font-bold text-dc-text dc:mb-2 dc:mt-3' } },\n h2: { props: { className: 'dc:text-base dc:font-semibold text-dc-text dc:mb-2 dc:mt-3' } },\n h3: { props: { className: 'dc:text-sm dc:font-semibold text-dc-text dc:mb-2 dc:mt-3' } },\n p: { props: { className: 'dc:text-sm dc:leading-relaxed text-dc-text dc:mb-2' } },\n strong: { props: { className: 'dc:font-semibold' } },\n a: { props: { className: 'text-dc-accent dc:hover:underline', target: '_blank', rel: 'noopener noreferrer' } },\n code: { props: { className: 'dc:px-1 dc:py-0.5 dc:rounded dc:text-xs bg-dc-surface-secondary text-dc-accent dc:font-mono' } },\n pre: { props: { className: 'dc:rounded-lg dc:p-3 dc:my-2 dc:overflow-x-auto dc:text-xs bg-dc-surface-secondary text-dc-text dc:font-mono' } },\n ul: { props: { className: 'dc:list-disc dc:ml-5 dc:mb-2 dc:text-sm text-dc-text dc:space-y-1' } },\n ol: { props: { className: 'dc:list-decimal dc:ml-5 dc:mb-2 dc:text-sm text-dc-text dc:space-y-1' } },\n li: { props: { className: 'dc:text-sm text-dc-text' } },\n hr: { props: { className: 'dc:my-3 border-dc-border' } },\n blockquote: { props: { className: 'dc:border-l-4 border-dc-accent dc:pl-3 dc:my-2 dc:italic text-dc-text-secondary dc:text-sm' } },\n table: { component: ScrollableTable, props: { className: 'dc:w-full dc:border-collapse dc:text-sm' } },\n thead: { props: { className: 'bg-dc-surface-secondary' } },\n th: { props: { className: 'dc:px-3 dc:py-2 dc:text-left dc:font-semibold dc:text-xs text-dc-text-secondary dc:uppercase dc:tracking-wider border-dc-border dc:border-b' } },\n td: { props: { className: 'dc:px-3 dc:py-2 dc:text-sm text-dc-text border-dc-border dc:border-b' } },\n tr: { props: { className: 'dc:hover:opacity-80' } },\n },\n}\n\nconst NotebookMarkdownBlock = React.memo(function NotebookMarkdownBlock({\n block,\n onRemove,\n onMoveUp,\n onMoveDown,\n isFirst,\n isLast,\n}: NotebookMarkdownBlockProps) {\n return (\n <div className=\"dc:relative dc:mb-4 bg-dc-surface dc:border border-dc-border dc:rounded-lg dc:flex dc:flex-col\">\n {/* Header - same pattern as NotebookPortletBlock / DashboardPortletCard */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-3 dc:py-1.5 dc:border-b border-dc-border dc:shrink-0 bg-dc-surface-secondary dc:rounded-t-lg\">\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:flex-1 dc:min-w-0\">\n <DocumentTextIcon style={ICON_STYLE} />\n <h3 className=\"dc:font-semibold dc:text-sm text-dc-text dc:truncate\">\n {block.title || 'Markdown'}\n </h3>\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-1 dc:shrink-0 dc:ml-4 dc:-mr-2\">\n {!isFirst && (\n <button\n onClick={() => onMoveUp(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move up\"\n >\n <ChevronUpIcon style={ICON_STYLE} />\n </button>\n )}\n {!isLast && (\n <button\n onClick={() => onMoveDown(block.id)}\n className=\"dc:p-1 dc:bg-transparent dc:border-none dc:rounded-sm text-dc-text-secondary dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Move down\"\n >\n <ChevronDownIcon style={ICON_STYLE} />\n </button>\n )}\n <button\n onClick={() => onRemove(block.id)}\n className=\"dc:p-1 dc:mr-0.5 dc:bg-transparent dc:border-none dc:rounded-sm dc:cursor-pointer dc:hover:bg-dc-danger-bg text-dc-danger dc:transition-colors\"\n title=\"Remove\"\n >\n <DeleteIcon style={ICON_STYLE} />\n </button>\n </div>\n </div>\n\n {/* Markdown content */}\n <div className=\"dc:p-4 dc:min-w-0 dc:overflow-hidden\">\n <Markdown options={markdownOptions}>\n {block.content}\n </Markdown>\n </div>\n </div>\n )\n})\n\nexport default NotebookMarkdownBlock\n","/**\n * NotebookCanvas - Left panel displaying notebook blocks\n */\n\nimport React, { useCallback, useRef, useEffect, useState } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useNotebookStore, selectBlocks, selectBlockActions } from '../../stores/notebookStore'\nimport type { PortletBlock } from '../../stores/notebookStore'\nimport type { PortletConfig } from '../../types'\nimport type { ColorPalette } from '../../utils/colorPalettes'\nimport { getColorPalette } from '../../utils/colorPalettes'\nimport { ensureAnalysisConfig } from '../../utils/configMigration'\nimport NotebookPortletBlock from './NotebookPortletBlock'\nimport NotebookMarkdownBlock from './NotebookMarkdownBlock'\nimport PortletAnalysisModal from '../PortletAnalysisModal'\n\nconst NotebookCanvas = React.memo(function NotebookCanvas({ colorPalette }: { colorPalette?: ColorPalette }) {\n const resolvedPalette = colorPalette ?? getColorPalette()\n const blocks = useNotebookStore(selectBlocks)\n const { removeBlock, moveBlock, updateBlock } = useNotebookStore(useShallow(selectBlockActions))\n const endRef = useRef<HTMLDivElement>(null)\n\n // Edit modal state\n const [editingBlock, setEditingBlock] = useState<PortletBlock | null>(null)\n\n // Auto-scroll only when NEW blocks are added (not on initial load)\n const prevCountRef = useRef(blocks.length)\n useEffect(() => {\n if (blocks.length > prevCountRef.current) {\n endRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n prevCountRef.current = blocks.length\n }, [blocks.length])\n\n const handleRemove = useCallback((id: string) => removeBlock(id), [removeBlock])\n const handleMoveUp = useCallback((id: string) => moveBlock(id, 'up'), [moveBlock])\n const handleMoveDown = useCallback((id: string) => moveBlock(id, 'down'), [moveBlock])\n const handleEdit = useCallback((block: PortletBlock) => setEditingBlock(block), [])\n\n const handleEditSave = useCallback((portletData: PortletConfig | Omit<PortletConfig, 'id' | 'x' | 'y'>) => {\n if (!editingBlock) return\n\n // Normalize to ensure analysisConfig exists\n const normalized = ensureAnalysisConfig(portletData as PortletConfig)\n const { analysisConfig } = normalized\n\n if (analysisConfig) {\n const chartModeConfig = analysisConfig.charts[analysisConfig.analysisType]\n updateBlock(editingBlock.id, {\n title: portletData.title,\n query: JSON.stringify(analysisConfig.query),\n chartType: chartModeConfig?.chartType || 'bar',\n chartConfig: chartModeConfig?.chartConfig,\n displayConfig: chartModeConfig?.displayConfig,\n })\n }\n\n setEditingBlock(null)\n }, [editingBlock, updateBlock])\n\n if (blocks.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center dc:max-w-sm dc:px-6\">\n <h3 className=\"dc:text-base dc:font-semibold text-dc-text dc:mb-2\">\n Your notebook is empty\n </h3>\n <p className=\"dc:text-sm text-dc-text-secondary\">\n Ask the AI assistant a question about your data.\n Charts and insights will appear here as the assistant analyzes your data.\n </p>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:h-full dc:overflow-y-auto dc:p-4\">\n {blocks.map((block, index) => {\n const isFirst = index === 0\n const isLast = index === blocks.length - 1\n\n if (block.type === 'portlet') {\n return (\n <NotebookPortletBlock\n key={block.id}\n block={block}\n colorPalette={resolvedPalette}\n onRemove={handleRemove}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n onEdit={handleEdit}\n isFirst={isFirst}\n isLast={isLast}\n />\n )\n }\n\n if (block.type === 'markdown') {\n return (\n <NotebookMarkdownBlock\n key={block.id}\n block={block}\n onRemove={handleRemove}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n isFirst={isFirst}\n isLast={isLast}\n />\n )\n }\n\n return null\n })}\n <div ref={endRef} />\n\n {/* Edit modal */}\n <PortletAnalysisModal\n isOpen={!!editingBlock}\n onClose={() => setEditingBlock(null)}\n onSave={handleEditSave}\n colorPalette={resolvedPalette}\n portlet={editingBlock ? {\n id: editingBlock.id,\n title: editingBlock.title,\n query: editingBlock.query,\n chartType: editingBlock.chartType,\n chartConfig: editingBlock.chartConfig,\n displayConfig: editingBlock.displayConfig,\n w: 5, h: 4, x: 0, y: 0,\n } : null}\n title=\"Edit Visualization\"\n submitText=\"Update\"\n />\n </div>\n )\n})\n\nexport default NotebookCanvas\n","/**\n * useAgentChat Hook\n * SSE streaming hook for the agentic notebook chat interface\n */\n\nimport { useRef, useCallback, useState } from 'react'\nimport { useCubeApi } from '../providers/CubeProvider'\nimport type { PortletBlock, MarkdownBlock } from '../stores/notebookStore'\n\n/** Clean up raw API errors into user-friendly messages */\nfunction formatUserFacingError(message: string): string {\n // Detect raw JSON error payloads (e.g. from Anthropic API)\n if (message.startsWith('{') || message.includes('\"type\":\"error\"')) {\n try {\n const parsed = JSON.parse(message.replace(/^Error:\\s*/, ''))\n const errorType = parsed.error?.type || parsed.type || ''\n const friendly: Record<string, string> = {\n overloaded_error: 'The AI service is temporarily busy. Please try again in a moment.',\n rate_limit_error: 'Too many requests. Please wait a moment and try again.',\n api_error: 'The AI service encountered an error. Please try again.',\n authentication_error: 'Authentication failed. Please check your configuration.',\n }\n return friendly[errorType] || 'The AI service encountered an error. Please try again.'\n } catch {\n return 'The AI service encountered an error. Please try again.'\n }\n }\n // HTTP status errors\n if (message.startsWith('Agent request failed:')) {\n const status = message.match(/\\d+/)?.[0]\n if (status === '429') return 'Too many requests. Please wait a moment and try again.'\n if (status === '503' || status === '529') return 'The AI service is temporarily busy. Please try again in a moment.'\n return 'The AI service is temporarily unavailable. Please try again.'\n }\n return message\n}\n\ninterface AgentSSEEvent {\n type: 'text_delta' | 'tool_use_start' | 'tool_use_result' | 'add_portlet' | 'add_markdown' | 'dashboard_saved' | 'turn_complete' | 'done' | 'error'\n data: any\n}\n\nexport interface UseAgentChatOptions {\n /** Override default agent endpoint (default: apiUrl + '/agent/chat') */\n agentEndpoint?: string\n /** Client-side API key for demo/try-site use */\n agentApiKey?: string\n /** Override LLM provider (anthropic | openai | google) */\n agentProvider?: string\n /** Override LLM model (e.g. 'gpt-4o', 'gemini-2.0-flash') */\n agentModel?: string\n /** Override provider endpoint URL (for OpenAI-compatible services) */\n agentProviderEndpoint?: string\n /** Called when agent adds a portlet to the notebook */\n onAddPortlet: (data: PortletBlock) => void\n /** Called when agent adds a markdown block to the notebook */\n onAddMarkdown: (data: MarkdownBlock) => void\n /** Called when the agent saves a dashboard configuration */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when streaming text arrives */\n onTextDelta: (text: string) => void\n /** Called when a tool call starts */\n onToolStart: (id: string, name: string, input?: unknown) => void\n /** Called when a tool call completes */\n onToolResult: (id: string, name: string, result?: unknown, isError?: boolean) => void\n /** Called when the agent completes with session ID and optional trace ID */\n onDone: (sessionId: string, traceId?: string) => void\n /** Called when a turn completes (between agentic turns) */\n onTurnComplete?: () => void\n /** Called on error */\n onError: (message: string) => void\n}\n\n/** Simplified message format for sending conversation history */\nexport interface AgentHistoryMessage {\n role: 'user' | 'assistant'\n content: string\n toolCalls?: Array<{\n id: string\n name: string\n input?: unknown\n result?: unknown\n status: 'running' | 'complete' | 'error'\n }>\n}\n\nexport interface UseAgentChatResult {\n /** Send a message to the agent, optionally with prior conversation history */\n sendMessage: (content: string, sessionId?: string | null, history?: AgentHistoryMessage[]) => Promise<void>\n /** Whether the agent is currently streaming */\n isStreaming: boolean\n /** Abort the current stream */\n abort: () => void\n}\n\n/**\n * Hook for streaming chat with the agentic notebook backend.\n * Uses fetch() with ReadableStream to consume SSE events.\n */\nexport function useAgentChat(options: UseAgentChatOptions): UseAgentChatResult {\n const { agentEndpoint, agentApiKey, agentProvider, agentModel, agentProviderEndpoint } = options\n\n const { cubeApi } = useCubeApi()\n const abortControllerRef = useRef<AbortController | null>(null)\n const [isStreaming, setIsStreaming] = useState(false)\n\n // Store callbacks in a ref so handleEvent always reads the latest\n // without causing sendMessage to be recreated on every render\n const callbacksRef = useRef(options)\n callbacksRef.current = options\n\n const sendMessage = useCallback(async (content: string, sessionId?: string | null, history?: AgentHistoryMessage[]) => {\n function handleEvent(event: AgentSSEEvent) {\n const cb = callbacksRef.current\n switch (event.type) {\n case 'text_delta':\n cb.onTextDelta(event.data)\n break\n case 'tool_use_start':\n cb.onToolStart(event.data.id, event.data.name, event.data.input)\n break\n case 'tool_use_result':\n cb.onToolResult(event.data.id, event.data.name, event.data.result, event.data.isError)\n break\n case 'add_portlet':\n cb.onAddPortlet({\n ...event.data,\n type: 'portlet',\n })\n break\n case 'add_markdown':\n cb.onAddMarkdown({\n ...event.data,\n type: 'markdown',\n })\n break\n case 'dashboard_saved':\n cb.onDashboardSaved?.(event.data)\n break\n case 'turn_complete':\n cb.onTurnComplete?.()\n break\n case 'done':\n cb.onDone(event.data.sessionId, event.data.traceId)\n break\n case 'error':\n cb.onError(event.data.message)\n break\n }\n }\n\n // Abort any existing stream\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n\n const controller = new AbortController()\n abortControllerRef.current = controller\n setIsStreaming(true)\n\n try {\n // Build endpoint URL from CubeClient's API URL\n const apiUrl = (cubeApi as any).apiUrl || '/cubejs-api/v1'\n const endpoint = agentEndpoint || `${apiUrl}/agent/chat`\n\n // Build headers matching CubeClient's auth pattern\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(cubeApi as any).headers,\n }\n\n // Add agent API key if provided\n if (agentApiKey) {\n headers['X-Agent-Api-Key'] = agentApiKey\n }\n if (agentProvider) {\n headers['X-Agent-Provider'] = agentProvider\n }\n if (agentModel) {\n headers['X-Agent-Model'] = agentModel\n }\n if (agentProviderEndpoint) {\n headers['X-Agent-Provider-Endpoint'] = agentProviderEndpoint\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n credentials: (cubeApi as any).credentials ?? 'include',\n body: JSON.stringify({\n message: content,\n ...(sessionId ? { sessionId } : {}),\n ...(history && history.length > 0 ? { history } : {}),\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error || `Agent request failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body received')\n }\n\n // Read SSE stream\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Process complete SSE events (delimited by double newline)\n const events = buffer.split('\\n\\n')\n buffer = events.pop() || '' // Keep incomplete last chunk\n\n for (const eventStr of events) {\n const lines = eventStr.trim().split('\\n')\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event: AgentSSEEvent = JSON.parse(line.slice(6))\n handleEvent(event)\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n }\n\n // Process any remaining buffer\n if (buffer.trim()) {\n const lines = buffer.trim().split('\\n')\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event: AgentSSEEvent = JSON.parse(line.slice(6))\n handleEvent(event)\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const raw = error instanceof Error ? error.message : 'Stream failed'\n callbacksRef.current.onError(formatUserFacingError(raw))\n }\n } finally {\n setIsStreaming(false)\n abortControllerRef.current = null\n }\n }, [cubeApi, agentEndpoint, agentApiKey, agentProvider, agentModel, agentProviderEndpoint])\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n abortControllerRef.current = null\n setIsStreaming(false)\n }\n }, [])\n\n return {\n sendMessage,\n isStreaming,\n abort,\n }\n}\n","/**\n * ChatMessage - Renders individual user and assistant messages\n */\n\nimport React, { useState } from 'react'\nimport type { ChatMessage as ChatMessageType, ToolCallRecord } from '../../stores/notebookStore'\nimport LoadingIndicator from '../LoadingIndicator'\n\n/** Simple inline markdown parser for bold, italic, and code in chat text */\nfunction renderInlineMarkdown(text: string): React.ReactNode[] {\n const nodes: React.ReactNode[] = []\n let remaining = text\n let key = 0\n\n while (remaining) {\n // Code inline `text`\n const codeMatch = remaining.match(/^(.*?)`([^`]+)`(.*)$/)\n if (codeMatch) {\n const [, before, code, after] = codeMatch\n if (before) nodes.push(<span key={key++}>{before}</span>)\n nodes.push(\n <code key={key++} className=\"dc:px-1 dc:py-0.5 dc:rounded dc:text-xs bg-dc-surface dc:font-mono\">\n {code}\n </code>\n )\n remaining = after\n continue\n }\n\n // Bold **text**\n const boldMatch = remaining.match(/^(.*?)\\*\\*([^*]+)\\*\\*(.*)$/)\n if (boldMatch) {\n const [, before, bold, after] = boldMatch\n if (before) nodes.push(<span key={key++}>{before}</span>)\n nodes.push(<strong key={key++} className=\"dc:font-semibold\">{bold}</strong>)\n remaining = after\n continue\n }\n\n // Plain text\n nodes.push(<span key={key}>{remaining}</span>)\n break\n }\n\n return nodes\n}\n\ninterface ChatMessageProps {\n message: ChatMessageType\n /** Custom loading indicator for tool call spinners */\n loadingComponent?: React.ReactNode\n}\n\n/** Tool call label mapping for user-friendly display */\nconst TOOL_LABELS: Record<string, string> = {\n discover_cubes: 'Discovering cubes',\n get_cube_metadata: 'Reading metadata',\n execute_query: 'Executing query',\n add_portlet: 'Adding visualization',\n add_markdown: 'Adding explanation',\n}\n\nfunction ToolCallIndicator({ toolCall, loadingComponent }: { toolCall: ToolCallRecord; loadingComponent?: React.ReactNode }) {\n const [expanded, setExpanded] = useState(false)\n const label = TOOL_LABELS[toolCall.name] || toolCall.name\n const isRunning = toolCall.status === 'running'\n\n return (\n <div className=\"dc:my-1 dc:text-xs\">\n <button\n onClick={() => setExpanded(!expanded)}\n className=\"dc:flex dc:items-center dc:gap-1.5 text-dc-text-secondary dc:hover:opacity-80 dc:transition-opacity\"\n >\n {isRunning ? (\n loadingComponent\n ? <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:h-3 dc:w-3\">{loadingComponent}</span>\n : <LoadingIndicator size=\"xs\" />\n ) : (\n <span className=\"dc:text-xs\">\n {toolCall.status === 'error' ? '\\u2717' : '\\u2713'}\n </span>\n )}\n <span>{label}{isRunning ? '...' : ''}</span>\n {!isRunning && (\n <span className=\"dc:text-[10px] dc:opacity-60\">\n {expanded ? '\\u25B2' : '\\u25BC'}\n </span>\n )}\n </button>\n {expanded && toolCall.result != null && (\n <pre className=\"dc:mt-1 dc:p-2 dc:rounded dc:text-[11px] dc:overflow-x-auto dc:max-h-32 dc:overflow-y-auto bg-dc-surface-secondary text-dc-text-secondary\">\n {typeof toolCall.result === 'string'\n ? toolCall.result\n : JSON.stringify(toolCall.result, null, 2)}\n </pre>\n )}\n </div>\n )\n}\n\nconst MSG_FADE_IN: React.CSSProperties = {\n animation: 'dc-msg-in 100ms ease-out',\n}\n\nconst ChatMessage = React.memo(function ChatMessage({ message, loadingComponent }: ChatMessageProps) {\n const isUser = message.role === 'user'\n const hasContent = !!message.content?.trim()\n const hasError = !!message.error\n const hasToolCalls = message.toolCalls && message.toolCalls.length > 0\n\n // Don't render empty assistant messages\n if (!isUser && !hasContent && !hasError && !hasToolCalls) return null\n\n return (\n <div\n className={`dc:flex dc:mb-3 ${isUser ? 'dc:justify-end' : 'dc:justify-start'}`}\n style={MSG_FADE_IN}\n >\n <div\n className={`dc:max-w-[85%] dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm ${\n isUser\n ? 'bg-dc-accent text-dc-accent-text dc:rounded-br-sm'\n : hasError && !hasContent\n ? 'bg-dc-warning-bg text-dc-text dc:rounded-bl-sm'\n : 'bg-dc-surface-secondary text-dc-text dc:rounded-bl-sm'\n }`}\n >\n {/* Message text */}\n {hasContent && (\n <div className=\"dc:whitespace-pre-wrap dc:break-words\">\n {isUser ? message.content : renderInlineMarkdown(message.content)}\n </div>\n )}\n\n {/* Error display */}\n {hasError && (\n <div className={`dc:flex dc:items-start dc:gap-2 ${hasContent ? 'dc:mt-2 dc:pt-2 dc:border-t dc:border-current dc:border-opacity-10' : ''}`}>\n <span className=\"dc:text-base dc:leading-none dc:mt-0.5 text-dc-warning dc:flex-shrink-0\">{'\\u26A0'}</span>\n <span className=\"text-dc-text-secondary\">{message.error}</span>\n </div>\n )}\n\n {/* Tool call indicators */}\n {hasToolCalls && (\n <div className={hasContent || hasError ? 'dc:mt-1 dc:border-t dc:border-current dc:border-opacity-10 dc:pt-1' : ''}>\n {message.toolCalls!.map((tc, i) => (\n <ToolCallIndicator key={tc.id || i} toolCall={tc} loadingComponent={loadingComponent} />\n ))}\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default ChatMessage\n","/**\n * ChatInput - Text input for sending messages to the agent\n */\n\nimport React, { useCallback, useRef, useEffect } from 'react'\n\ninterface ChatInputProps {\n value: string\n onChange: (value: string) => void\n onSend: () => void\n onStop?: () => void\n onContinue?: () => void\n isStreaming?: boolean\n showContinue?: boolean\n disabled?: boolean\n placeholder?: string\n}\n\nconst ChatInput = React.memo(function ChatInput({\n value,\n onChange,\n onSend,\n onStop,\n onContinue,\n isStreaming = false,\n showContinue = false,\n disabled = false,\n placeholder = 'Ask about your data...',\n}: ChatInputProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current\n if (textarea) {\n textarea.style.height = 'auto'\n textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`\n }\n }, [value])\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (!disabled && value.trim()) {\n onSend()\n }\n }\n },\n [disabled, value, onSend]\n )\n\n return (\n <div className=\"dc:flex dc:gap-2 dc:items-end dc:p-3 border-dc-border dc:border-t\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n className=\"dc:flex-1 dc:resize-none dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm bg-dc-surface-secondary text-dc-text border-dc-border dc:border dc:outline-none dc:focus:ring-1 focus:ring-dc-accent dc:disabled:opacity-50\"\n />\n {isStreaming ? (\n <button\n onClick={onStop}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors text-dc-error border-dc-border dc:border dc:hover:opacity-80 dc:shrink-0\"\n >\n Stop\n </button>\n ) : (\n <>\n {showContinue && !value.trim() && (\n <button\n onClick={() => {\n onContinue?.()\n textareaRef.current?.focus()\n }}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors border-dc-border dc:border text-dc-text-secondary dc:hover:opacity-80 dc:shrink-0\"\n >\n Continue\n </button>\n )}\n <button\n onClick={onSend}\n disabled={disabled || !value.trim()}\n className=\"dc:px-4 dc:py-2 dc:rounded-lg dc:text-sm dc:font-medium dc:transition-colors bg-dc-accent text-dc-accent-text dc:hover:opacity-90 dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:shrink-0\"\n >\n Send\n </button>\n </>\n )}\n </div>\n )\n})\n\nexport default ChatInput\n","/**\n * AgentChatPanel - Right panel containing chat messages and input\n */\n\nimport React, { useRef, useEffect, useCallback, useState } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useNotebookStore, selectChatState, selectChatActions } from '../../stores/notebookStore'\nimport { useAgentChat } from '../../hooks/useAgentChat'\nimport type { PortletBlock, MarkdownBlock, ChatMessage as ChatMessageType } from '../../stores/notebookStore'\nimport ChatMessage from './ChatMessage'\nimport ChatInput from './ChatInput'\nimport LoadingIndicator from '../LoadingIndicator'\nimport { getIcon } from '../../icons'\n\nconst ThumbUpIcon = getIcon('thumbUp')\nconst ThumbDownIcon = getIcon('thumbDown')\n\ninterface AgentChatPanelProps {\n agentEndpoint?: string\n agentApiKey?: string\n agentProvider?: string\n agentModel?: string\n agentProviderEndpoint?: string\n onClear?: () => void\n /** Called when the agent saves a dashboard. Presence enables the \"Save as Dashboard\" button. */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when user submits feedback (thumbs up/down) */\n onScore?: (data: { traceId: string; value: number; comment?: string }) => void\n /** Custom loading indicator for tool call spinners */\n loadingComponent?: React.ReactNode\n /** Initial prompt to auto-send on mount */\n initialPrompt?: string\n}\n\nconst AgentChatPanel = React.memo(function AgentChatPanel({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onClear,\n onDashboardSaved,\n onScore,\n loadingComponent,\n initialPrompt,\n}: AgentChatPanelProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null)\n const initialPromptSentRef = useRef(false)\n const [lastTraceId, setLastTraceId] = useState<string | null>(null)\n const [scoredTraceIds, setScoredTraceIds] = useState<Set<string>>(new Set())\n const [isThinking, setIsThinking] = useState(false)\n\n // Track whether the next content should start a new assistant message\n // (set after turn_complete, cleared when first content of new turn arrives)\n const needsNewMessageRef = useRef(false)\n\n // Store state\n const { messages, isStreaming, inputValue } = useNotebookStore(useShallow(selectChatState))\n const {\n addMessage,\n appendToLastAssistantMessage,\n setLastAssistantError,\n addToolCallToLastAssistant,\n updateLastToolCall,\n setIsStreaming,\n setInputValue,\n setSessionId,\n } = useNotebookStore(useShallow(selectChatActions))\n\n const sessionId = useNotebookStore((s) => s.sessionId)\n const addBlock = useNotebookStore((s) => s.addBlock)\n const reset = useNotebookStore((s) => s.reset)\n const portletBlockCount = useNotebookStore((s) => s.blocks.filter((b) => b.type === 'portlet').length)\n\n // Refs for values doSend reads at call-time (avoids recreating callbacks on every text delta)\n const messagesRef = useRef(messages)\n messagesRef.current = messages\n const isStreamingRef = useRef(isStreaming)\n isStreamingRef.current = isStreaming\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n // Lazily create a new assistant message when needed (between turns)\n const ensureNewMessage = useCallback(() => {\n if (needsNewMessageRef.current) {\n needsNewMessageRef.current = false\n addMessage({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: '',\n toolCalls: [],\n timestamp: Date.now(),\n })\n }\n }, [addMessage])\n\n // Auto-scroll only when NEW messages arrive or thinking starts (not on initial load)\n const prevMsgCountRef = useRef(messages.length)\n useEffect(() => {\n if (messages.length > prevMsgCountRef.current) {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n prevMsgCountRef.current = messages.length\n }, [messages])\n\n useEffect(() => {\n if (isThinking) {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })\n }\n }, [isThinking])\n\n // Agent chat hook\n const { sendMessage, abort } = useAgentChat({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onTextDelta: useCallback((text: string) => {\n setIsThinking(false)\n ensureNewMessage()\n appendToLastAssistantMessage(text)\n }, [ensureNewMessage, appendToLastAssistantMessage]),\n onToolStart: useCallback((id: string, name: string, input?: unknown) => {\n setIsThinking(false)\n ensureNewMessage()\n addToolCallToLastAssistant({ id, name, input, status: 'running' })\n }, [ensureNewMessage, addToolCallToLastAssistant]),\n onToolResult: useCallback((id: string, _name: string, result?: unknown, isError?: boolean) => {\n updateLastToolCall({ id, status: isError ? 'error' : 'complete', result })\n }, [updateLastToolCall]),\n onAddPortlet: useCallback((data: PortletBlock) => {\n addBlock(data)\n }, [addBlock]),\n onAddMarkdown: useCallback((data: MarkdownBlock) => {\n addBlock(data)\n }, [addBlock]),\n onDashboardSaved,\n onTurnComplete: useCallback(() => {\n // Don't create a new message yet — just flag that the next turn\n // should start a new bubble (created lazily by ensureNewMessage)\n needsNewMessageRef.current = true\n setIsThinking(true)\n }, []),\n onDone: useCallback((sid: string, traceId?: string) => {\n needsNewMessageRef.current = false\n setSessionId(sid)\n setIsStreaming(false)\n setIsThinking(false)\n if (traceId) setLastTraceId(traceId)\n }, [setSessionId, setIsStreaming]),\n onError: useCallback((message: string) => {\n setIsThinking(false)\n ensureNewMessage()\n setLastAssistantError(message)\n setIsStreaming(false)\n }, [ensureNewMessage, setLastAssistantError, setIsStreaming]),\n })\n\n // Send a message (used by both Send and Continue)\n // Reads messages/isStreaming/sessionId from refs to avoid recreating on every text delta\n const doSend = useCallback((content: string) => {\n if (!content || isStreamingRef.current) return\n\n needsNewMessageRef.current = false\n\n // Capture current messages as history BEFORE adding the new ones\n const history = messagesRef.current.map((m: ChatMessageType) => ({\n role: m.role,\n content: m.content,\n ...(m.toolCalls && m.toolCalls.length > 0 ? { toolCalls: m.toolCalls } : {}),\n }))\n\n // Add user message\n addMessage({\n id: `msg-${Date.now()}`,\n role: 'user',\n content,\n timestamp: Date.now(),\n })\n\n // Create empty assistant message for first turn's streaming\n addMessage({\n id: `msg-${Date.now() + 1}`,\n role: 'assistant',\n content: '',\n toolCalls: [],\n timestamp: Date.now(),\n })\n\n setInputValue('')\n setIsStreaming(true)\n setIsThinking(true)\n\n // Send to agent with conversation history for session continuity\n sendMessage(content, sessionIdRef.current, history)\n }, [addMessage, setInputValue, setIsStreaming, sendMessage])\n\n // Auto-send initial prompt on mount (doSend is stable so this won't re-trigger)\n // Reset ref on cleanup so React StrictMode's double-mount doesn't block the real mount\n useEffect(() => {\n if (initialPrompt && !initialPromptSentRef.current && messages.length === 0) {\n initialPromptSentRef.current = true\n // Small delay to ensure chat hook is fully initialized\n const timer = setTimeout(() => doSend(initialPrompt), 100)\n return () => {\n clearTimeout(timer)\n initialPromptSentRef.current = false\n }\n }\n }, [initialPrompt, messages.length, doSend])\n\n const inputValueRef = useRef(inputValue)\n inputValueRef.current = inputValue\n\n const handleSend = useCallback(() => {\n doSend(inputValueRef.current.trim())\n }, [doSend])\n\n const handleStop = useCallback(() => {\n abort()\n setIsStreaming(false)\n }, [abort, setIsStreaming])\n\n const handleContinue = useCallback(() => {\n // Just set placeholder text — user types their own follow-up and sends\n setInputValue('')\n }, [setInputValue])\n\n const handleClear = useCallback(() => {\n abort()\n setIsStreaming(false)\n setIsThinking(false)\n reset()\n setLastTraceId(null)\n setScoredTraceIds(new Set())\n onClear?.()\n }, [abort, setIsStreaming, reset, onClear])\n\n const handleSaveAsDashboard = useCallback(() => {\n doSend(\n 'Save the current notebook as a dashboard with a professional layout, section headers, and appropriate filters.'\n )\n }, [doSend])\n\n const handleScore = useCallback((value: number) => {\n if (!lastTraceId || !onScore) return\n onScore({ traceId: lastTraceId, value })\n setScoredTraceIds(prev => new Set(prev).add(lastTraceId))\n }, [lastTraceId, onScore])\n\n const showSaveAsDashboard = !!onDashboardSaved && !isStreaming && portletBlockCount > 0 && messages.length > 0\n const showFeedback = !!onScore && !isStreaming && lastTraceId && messages.length > 0 && !scoredTraceIds.has(lastTraceId)\n const lastScored = lastTraceId ? scoredTraceIds.has(lastTraceId) : false\n\n return (\n <div className=\"dc:flex dc:flex-col dc:h-full bg-dc-surface\">\n {/* Header */}\n <div className=\"dc:flex dc:items-center dc:justify-between dc:px-4 dc:py-3 border-dc-border dc:border-b\">\n <h3 className=\"dc:text-sm dc:font-semibold text-dc-text\">AI Assistant</h3>\n <div className=\"dc:flex dc:items-center dc:gap-1\">\n {showSaveAsDashboard && (\n <button\n onClick={handleSaveAsDashboard}\n className=\"dc:text-xs dc:px-2 dc:py-1 dc:rounded text-dc-accent dc:hover:opacity-80\"\n title=\"Save notebook as a dashboard\"\n >\n Save as Dashboard\n </button>\n )}\n {(messages.length > 0) && (\n <button\n onClick={handleClear}\n disabled={isStreaming}\n className=\"dc:text-xs dc:px-2 dc:py-1 dc:rounded text-dc-text-secondary dc:hover:opacity-80 dc:disabled:opacity-40\"\n title=\"Clear notebook and chat\"\n >\n Clear\n </button>\n )}\n </div>\n </div>\n\n {/* Messages */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:px-4 dc:py-3\">\n {messages.length === 0 ? (\n <EmptyState />\n ) : (\n messages.map((msg) => (\n <ChatMessage\n key={msg.id}\n message={msg}\n loadingComponent={loadingComponent}\n />\n ))\n )}\n {/* Thinking indicator (between turns or waiting for first response) */}\n {isThinking && <ThinkingBubble loadingComponent={loadingComponent} />}\n\n {/* Feedback (thumbs up/down) */}\n {(showFeedback || lastScored) && (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:gap-3 dc:py-4 dc:mt-2\">\n {lastScored ? (\n <span className=\"dc:text-sm text-dc-text-secondary\">Thanks for your feedback!</span>\n ) : (\n <>\n <span className=\"dc:text-sm text-dc-text-secondary\">Was this helpful?</span>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <button\n onClick={() => handleScore(1)}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-3 dc:py-1.5 dc:rounded-lg dc:text-sm dc:font-medium border-dc-border dc:border text-dc-success hover:bg-dc-success-bg dc:transition-colors bg-dc-surface dc:cursor-pointer\"\n >\n <ThumbUpIcon className=\"dc:w-4 dc:h-4\" />\n Yes\n </button>\n <button\n onClick={() => handleScore(0)}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-3 dc:py-1.5 dc:rounded-lg dc:text-sm dc:font-medium border-dc-border dc:border text-dc-error hover:bg-dc-danger-bg dc:transition-colors bg-dc-surface dc:cursor-pointer\"\n >\n <ThumbDownIcon className=\"dc:w-4 dc:h-4\" />\n No\n </button>\n </div>\n </>\n )}\n </div>\n )}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <ChatInput\n value={inputValue}\n onChange={setInputValue}\n onSend={handleSend}\n onStop={handleStop}\n onContinue={handleContinue}\n isStreaming={isStreaming}\n showContinue={!isStreaming && messages.length > 0}\n />\n </div>\n )\n})\n\nfunction ThinkingBubble({ loadingComponent }: { loadingComponent?: React.ReactNode }) {\n return (\n <div\n className=\"dc:flex dc:mb-3 dc:justify-start\"\n style={{ animation: 'dc-msg-in 100ms ease-out' }}\n >\n <div className=\"dc:rounded-lg dc:px-3 dc:py-2 dc:text-sm bg-dc-surface-secondary text-dc-text-secondary dc:rounded-bl-sm dc:flex dc:items-center dc:gap-2\">\n {loadingComponent\n ? <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:h-4 dc:w-4\">{loadingComponent}</span>\n : <LoadingIndicator size=\"xs\" />}\n <span>Thinking...</span>\n </div>\n </div>\n )\n}\n\nfunction EmptyState() {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center dc:max-w-xs\">\n <div className=\"dc:text-lg dc:font-semibold text-dc-text dc:mb-2\">\n Data Analysis Assistant\n </div>\n <p className=\"dc:text-sm text-dc-text-secondary dc:mb-4\">\n Ask me about your data and I'll create visualizations and insights.\n </p>\n <div className=\"dc:space-y-2 dc:text-xs text-dc-text-muted\">\n <p>\"Show me employee productivity trends\"</p>\n <p>\"What are the top departments by headcount?\"</p>\n <p>\"Compare revenue across product categories\"</p>\n </div>\n </div>\n </div>\n )\n}\n\nexport default AgentChatPanel\n","/**\n * AgenticNotebook - AI-powered data analysis notebook\n *\n * Top-level component combining a notebook canvas (left) with a chat panel (right).\n * The AI agent discovers available data, executes queries, creates visualizations,\n * and explains findings within a single conversational flow.\n *\n * Responsive behavior:\n * - Wide (>= 768px): Drag-resizable two-column layout\n * - Narrow (< 768px): Toggle between collapsed icon strip + expanded panel\n *\n * Requires:\n * - CubeProvider wrapping this component\n * - Server configured with `agent` option in HonoAdapterOptions\n * - @anthropic-ai/claude-agent-sdk installed on the server\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport {\n NotebookStoreProvider,\n useNotebookStore,\n type NotebookBlock,\n type NotebookConfig,\n} from '../../stores/notebookStore'\nimport NotebookCanvas from './NotebookCanvas'\nimport AgentChatPanel from './AgentChatPanel'\nimport { useNotebookLayout } from '../../hooks/useNotebookLayout'\nimport { getChartTypeIcon, getIcon } from '../../icons/registry'\nimport type { ColorPalette } from '../../types'\nimport type { ReactNode } from 'react'\n\nexport interface AgenticNotebookProps {\n /** Initial config to restore (saved notebooks) */\n config?: NotebookConfig\n /** Override default agent endpoint (default: apiUrl + '/agent/chat') */\n agentEndpoint?: string\n /** Client-side API key (for demo/try-site use) */\n agentApiKey?: string\n /** Override LLM provider (anthropic | openai | google) */\n agentProvider?: string\n /** Override LLM model (e.g. 'gpt-4o', 'gemini-2.0-flash') */\n agentModel?: string\n /** Override provider endpoint URL (for OpenAI-compatible services) */\n agentProviderEndpoint?: string\n /** Callback when notebook state changes (for persistence) */\n onSave?: (config: NotebookConfig) => void | Promise<void>\n /** Callback when dirty state changes */\n onDirtyStateChange?: (isDirty: boolean) => void\n /** Color palette for charts */\n colorPalette?: ColorPalette\n /** Called when the agent saves a dashboard. Presence enables the \"Save as Dashboard\" button. */\n onDashboardSaved?: (data: { title: string; description?: string; dashboardConfig: any }) => void\n /** Called when user submits feedback (thumbs up/down). Receives traceId from the last agent response. */\n onScore?: (data: { traceId: string; value: number; comment?: string }) => void\n /** Custom loading indicator for tool call spinners (defaults to LoadingIndicator) */\n loadingComponent?: ReactNode\n /** Additional CSS class name */\n className?: string\n /** Initial prompt to auto-send on mount */\n initialPrompt?: string\n}\n\n/**\n * Collapsed strip showing notebook block icons (shown in narrow mode when chat is expanded)\n */\nfunction CollapsedNotebookStrip({\n blocks,\n pulsingBlockId,\n nudge,\n onExpand,\n}: {\n blocks: NotebookBlock[]\n pulsingBlockId: string | null\n nudge: boolean\n onExpand: () => void\n}) {\n const BookOpenIcon = getIcon('bookOpen')\n const DocumentIcon = getIcon('documentText')\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n className=\"dc:h-full dc:flex-shrink-0 dc:flex dc:flex-col dc:items-center dc:pt-3 dc:gap-2 bg-dc-surface border-dc-border dc:border-r dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n style={\n nudge\n ? { animation: 'dc-strip-nudge 0.8s ease-in-out 2', width: 48 }\n : { width: 48 }\n }\n title=\"Expand notebook\"\n >\n <BookOpenIcon className=\"dc:w-5 dc:h-5 text-dc-text-muted\" />\n <div\n className=\"dc:flex dc:flex-col dc:items-center dc:gap-1.5 dc:flex-1 dc:overflow-y-auto dc:py-1\"\n style={{ scrollbarWidth: 'none' }}\n >\n {blocks.length === 0 ? (\n <span\n className=\"dc:text-[9px] text-dc-text-disabled dc:writing-vertical-lr dc:mt-2\"\n style={{ writingMode: 'vertical-lr' }}\n >\n No blocks\n </span>\n ) : (\n blocks.map((block) => {\n const isPulsing = block.id === pulsingBlockId\n let Icon: React.ComponentType<{ className?: string }>\n if (block.type === 'portlet') {\n Icon = getChartTypeIcon(block.chartType)\n } else {\n Icon = DocumentIcon\n }\n return (\n <div\n key={block.id}\n className=\"dc:w-6 dc:h-6 dc:flex dc:items-center dc:justify-center dc:rounded\"\n style={\n isPulsing\n ? { animation: 'dc-icon-pulse 0.6s ease-in-out 3' }\n : undefined\n }\n title={block.type === 'portlet' ? block.title : (block.title || 'Markdown')}\n >\n <Icon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </div>\n )\n })\n )}\n </div>\n </button>\n )\n}\n\n/**\n * Collapsed strip showing AI chat icon (shown in narrow mode when notebook is expanded)\n */\nfunction CollapsedChatStrip({ onExpand }: { onExpand: () => void }) {\n const SparklesIcon = getIcon('sparkles')\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n className=\"dc:w-12 dc:h-full dc:flex-shrink-0 dc:flex dc:flex-col dc:items-center dc:pt-3 dc:gap-2 bg-dc-surface border-dc-border dc:border-l dc:cursor-pointer dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Expand AI chat\"\n >\n <SparklesIcon className=\"dc:w-5 dc:h-5 text-dc-accent\" />\n <span\n className=\"dc:text-[10px] dc:font-medium text-dc-text-muted\"\n style={{ writingMode: 'vertical-lr' }}\n >\n AI Chat\n </span>\n </button>\n )\n}\n\n/**\n * Inner component that uses the notebook store (must be inside provider)\n */\nfunction AgenticNotebookInner({\n agentEndpoint,\n agentApiKey,\n agentProvider,\n agentModel,\n agentProviderEndpoint,\n onSave,\n onDirtyStateChange,\n onDashboardSaved,\n onScore,\n colorPalette,\n loadingComponent,\n className,\n initialPrompt,\n}: Omit<AgenticNotebookProps, 'config'>) {\n const [dividerPosition, setDividerPosition] = useState(60) // 60% left, 40% right\n const dividerContainerRef = useRef<HTMLDivElement | null>(null)\n const isDraggingRef = useRef(false)\n\n // Responsive layout\n const { containerRef: layoutRef, layoutMode } = useNotebookLayout()\n const [expandedPanel, setExpandedPanel] = useState<'chat' | 'notebook'>('chat')\n const [pulsingBlockId, setPulsingBlockId] = useState<string | null>(null)\n const [nudgeStrip, setNudgeStrip] = useState(false)\n const prevLayoutModeRef = useRef(layoutMode)\n\n const blocks = useNotebookStore((s) => s.blocks)\n const blockCount = blocks.length\n const messageCount = useNotebookStore((s) => s.messages.length)\n const isStreaming = useNotebookStore((s) => s.isStreaming)\n const save = useNotebookStore((s) => s.save)\n\n // Reset to chat when crossing from narrow → wide\n useEffect(() => {\n if (prevLayoutModeRef.current === 'narrow' && layoutMode === 'wide') {\n setExpandedPanel('chat')\n }\n prevLayoutModeRef.current = layoutMode\n }, [layoutMode])\n\n // Detect new blocks added while notebook is collapsed → pulse the icon\n const prevBlockCountRef = useRef(blockCount)\n useEffect(() => {\n if (\n layoutMode === 'narrow' &&\n expandedPanel === 'chat' &&\n blockCount > prevBlockCountRef.current\n ) {\n // Find the newest block (last in the array)\n const newestBlock = blocks[blocks.length - 1]\n if (newestBlock) {\n setPulsingBlockId(newestBlock.id)\n const timer = setTimeout(() => setPulsingBlockId(null), 2000)\n return () => clearTimeout(timer)\n }\n }\n prevBlockCountRef.current = blockCount\n }, [blockCount, blocks, layoutMode, expandedPanel])\n\n // Nudge the notebook strip when streaming ends while collapsed and there are blocks\n const wasStreamingRef = useRef(false)\n useEffect(() => {\n if (isStreaming) {\n wasStreamingRef.current = true\n } else if (\n wasStreamingRef.current &&\n layoutMode === 'narrow' &&\n expandedPanel === 'chat' &&\n blockCount > 0\n ) {\n wasStreamingRef.current = false\n setNudgeStrip(true)\n const timer = setTimeout(() => setNudgeStrip(false), 1700)\n return () => clearTimeout(timer)\n }\n }, [isStreaming, layoutMode, expandedPanel, blockCount])\n\n // Merge refs: layoutRef (RefCallback) + dividerContainerRef (for drag calculations)\n const mergedRef = useCallback(\n (node: HTMLDivElement | null) => {\n layoutRef(node)\n dividerContainerRef.current = node\n },\n [layoutRef],\n )\n\n // Track dirty state\n const initialRef = useRef({ blockCount, msgCount: messageCount })\n useEffect(() => {\n const isDirty =\n blockCount !== initialRef.current.blockCount ||\n messageCount !== initialRef.current.msgCount\n onDirtyStateChange?.(isDirty)\n }, [blockCount, messageCount, onDirtyStateChange])\n\n // Debounced save - fires 1s after blocks/messages count stabilizes\n // Waits until streaming completes to avoid saving partial content\n const saveTimeoutRef = useRef<ReturnType<typeof setTimeout>>()\n const pendingSaveRef = useRef(false)\n const onSaveRef = useRef(onSave)\n onSaveRef.current = onSave\n // Track whether we've ever had content (so we save empty state on Clear but not on initial mount)\n const hasHadContentRef = useRef(blockCount > 0 || messageCount > 0)\n useEffect(() => {\n if (blockCount > 0 || messageCount > 0) {\n hasHadContentRef.current = true\n }\n if (!onSaveRef.current || !hasHadContentRef.current) return\n\n if (isStreaming) {\n // Mark that a save is needed once streaming completes\n pendingSaveRef.current = true\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n return\n }\n\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n saveTimeoutRef.current = setTimeout(() => {\n pendingSaveRef.current = false\n const config = save()\n onSaveRef.current?.(config)\n }, 1000)\n\n return () => {\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n }\n }, [blockCount, messageCount, isStreaming, save])\n\n // Flush pending save when streaming ends\n useEffect(() => {\n if (!isStreaming && pendingSaveRef.current && onSaveRef.current && hasHadContentRef.current) {\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n saveTimeoutRef.current = setTimeout(() => {\n pendingSaveRef.current = false\n const config = save()\n onSaveRef.current?.(config)\n }, 1000)\n }\n }, [isStreaming, save])\n\n // Explicit clear handler — save immediately with empty state\n const handleClear = useCallback(() => {\n if (onSaveRef.current) {\n // Cancel any pending debounced save\n if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)\n onSaveRef.current({ blocks: [], messages: [] })\n }\n }, [])\n\n // Divider drag handlers\n const handleDividerMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault()\n isDraggingRef.current = true\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n if (!isDraggingRef.current || !dividerContainerRef.current) return\n const rect = dividerContainerRef.current.getBoundingClientRect()\n const newPos = ((moveEvent.clientX - rect.left) / rect.width) * 100\n setDividerPosition(Math.min(Math.max(newPos, 30), 80))\n }\n\n const handleMouseUp = () => {\n isDraggingRef.current = false\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }, [])\n\n const chatPanel = (\n <AgentChatPanel\n agentEndpoint={agentEndpoint}\n agentApiKey={agentApiKey}\n agentProvider={agentProvider}\n agentModel={agentModel}\n agentProviderEndpoint={agentProviderEndpoint}\n onClear={handleClear}\n onDashboardSaved={onDashboardSaved}\n onScore={onScore}\n loadingComponent={loadingComponent}\n initialPrompt={initialPrompt}\n />\n )\n\n // --- Narrow mode: collapsed strip + expanded panel ---\n if (layoutMode === 'narrow') {\n return (\n <div\n ref={mergedRef}\n className={`dc:flex dc:h-full dc:w-full dc:overflow-hidden bg-dc-surface-secondary ${className || ''}`}\n >\n {expandedPanel === 'chat' ? (\n <>\n <CollapsedNotebookStrip\n blocks={blocks}\n pulsingBlockId={pulsingBlockId}\n nudge={nudgeStrip}\n onExpand={() => setExpandedPanel('notebook')}\n />\n <div className=\"dc:h-full dc:overflow-hidden dc:flex-1\">\n {chatPanel}\n </div>\n </>\n ) : (\n <>\n <div className=\"dc:h-full dc:overflow-hidden dc:flex-1\">\n <NotebookCanvas colorPalette={colorPalette} />\n </div>\n <CollapsedChatStrip onExpand={() => setExpandedPanel('chat')} />\n </>\n )}\n </div>\n )\n }\n\n // --- Wide mode: existing drag-resizable two-column layout ---\n return (\n <div\n ref={mergedRef}\n className={`dc:flex dc:h-full dc:w-full dc:overflow-hidden bg-dc-surface-secondary ${className || ''}`}\n >\n {/* Left: Notebook Canvas */}\n <div\n className=\"dc:h-full dc:overflow-hidden\"\n style={{ width: `${dividerPosition}%` }}\n >\n <NotebookCanvas colorPalette={colorPalette} />\n </div>\n\n {/* Resizable Divider */}\n <div\n className=\"dc:w-1 dc:h-full dc:cursor-col-resize dc:flex-shrink-0 dc:transition-colors bg-dc-border dc:hover:bg-dc-accent\"\n onMouseDown={handleDividerMouseDown}\n />\n\n {/* Right: Chat Panel */}\n <div\n className=\"dc:h-full dc:overflow-hidden\"\n style={{ width: `${100 - dividerPosition}%` }}\n >\n {chatPanel}\n </div>\n </div>\n )\n}\n\n/**\n * AgenticNotebook - AI-powered data analysis notebook\n *\n * @example\n * ```tsx\n * <CubeProvider apiOptions={{ apiUrl: '/api/cubejs-api/v1' }} token={token}>\n * <AgenticNotebook\n * agentApiKey=\"sk-...\"\n * onSave={(config) => saveToDatabase(config)}\n * />\n * </CubeProvider>\n * ```\n */\nconst AgenticNotebook = React.memo(function AgenticNotebook({\n config,\n colorPalette,\n ...props\n}: AgenticNotebookProps) {\n return (\n <NotebookStoreProvider initialConfig={config}>\n <AgenticNotebookInner {...props} colorPalette={colorPalette} />\n </NotebookStoreProvider>\n )\n})\n\nexport default AgenticNotebook\n","// Placeholder component - will be implemented in Phase 4\nexport function AnalyticsPage() {\n return <div>Analytics Page - Coming in Phase 4</div>\n}","/**\n * Data Browser Zustand Store (Instance-based)\n *\n * Manages UI state for the DataBrowser component:\n * - Selected cube and visible columns\n * - Sorting, pagination, and filters\n * - Column picker and filter bar visibility\n *\n * Uses Zustand's createStore (factory) for instance isolation.\n */\n\nimport { createContext, useContext, useRef, type ReactNode } from 'react'\nimport { createStore, useStore, type StoreApi } from 'zustand'\nimport type { Filter } from '../types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DataBrowserStore {\n // Selected cube\n selectedCube: string | null\n\n // Visible columns (fully qualified: 'CubeName.fieldName')\n visibleColumns: string[]\n\n // Sorting\n sortColumn: string | null\n sortDirection: 'asc' | 'desc'\n\n // Pagination\n page: number\n pageSize: number\n\n // Filters\n filters: Filter[]\n\n // UI state\n showFilterBar: boolean\n showColumnPicker: boolean\n\n // Column widths (purely cosmetic — never affects queries)\n columnWidths: Record<string, number>\n\n // Actions\n selectCube: (cubeName: string, allDimensions: string[]) => void\n setVisibleColumns: (columns: string[]) => void\n toggleColumn: (column: string) => void\n setSort: (column: string) => void\n clearSort: () => void\n setPage: (page: number) => void\n setPageSize: (size: number) => void\n setFilters: (filters: Filter[]) => void\n toggleFilterBar: () => void\n setShowColumnPicker: (show: boolean) => void\n setColumnWidth: (column: string, width: number) => void\n setColumnWidths: (widths: Record<string, number>) => void\n}\n\n// ============================================================================\n// Store Factory\n// ============================================================================\n\ninterface DataBrowserStoreOptions {\n defaultPageSize?: number\n defaultCube?: string\n defaultColumns?: string[]\n}\n\nconst COLUMN_WIDTHS_STORAGE_KEY = 'dc-data-browser-column-widths'\n\nfunction loadColumnWidths(cubeName: string): Record<string, number> {\n try {\n const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY)\n if (!raw) return {}\n const all = JSON.parse(raw)\n return all[cubeName] ?? {}\n } catch {\n return {}\n }\n}\n\nfunction saveColumnWidths(cubeName: string, widths: Record<string, number>): void {\n try {\n const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY)\n const all = raw ? JSON.parse(raw) : {}\n all[cubeName] = widths\n localStorage.setItem(COLUMN_WIDTHS_STORAGE_KEY, JSON.stringify(all))\n } catch {\n // localStorage unavailable — silently ignore\n }\n}\n\nfunction createDataBrowserStore(options: DataBrowserStoreOptions = {}) {\n return createStore<DataBrowserStore>()((set, get) => ({\n // Initial state\n selectedCube: options.defaultCube ?? null,\n visibleColumns: options.defaultColumns ?? [],\n sortColumn: null,\n sortDirection: 'asc',\n page: 0,\n pageSize: options.defaultPageSize ?? 20,\n filters: [],\n showFilterBar: false,\n showColumnPicker: false,\n columnWidths: options.defaultCube ? loadColumnWidths(options.defaultCube) : {},\n\n // Actions\n selectCube: (cubeName, allDimensions) =>\n set({\n selectedCube: cubeName,\n visibleColumns: allDimensions,\n sortColumn: null,\n sortDirection: 'asc',\n page: 0,\n filters: [],\n showFilterBar: false,\n columnWidths: loadColumnWidths(cubeName),\n }),\n\n setVisibleColumns: (columns) =>\n set({ visibleColumns: columns, page: 0 }),\n\n toggleColumn: (column) =>\n set((state) => {\n const idx = state.visibleColumns.indexOf(column)\n const next =\n idx >= 0\n ? state.visibleColumns.filter((c) => c !== column)\n : [...state.visibleColumns, column]\n return {\n visibleColumns: next,\n page: 0,\n // Clear sort if the sorted column was removed\n sortColumn: idx >= 0 && state.sortColumn === column ? null : state.sortColumn,\n }\n }),\n\n setSort: (column) =>\n set((state) => {\n if (state.sortColumn === column) {\n // Toggle direction, or clear if already desc\n if (state.sortDirection === 'asc') {\n return { sortDirection: 'desc' as const, page: 0 }\n }\n return { sortColumn: null, sortDirection: 'asc' as const, page: 0 }\n }\n return { sortColumn: column, sortDirection: 'asc' as const, page: 0 }\n }),\n\n clearSort: () => set({ sortColumn: null, sortDirection: 'asc', page: 0 }),\n\n setPage: (page) => set({ page }),\n\n setPageSize: (size) => set({ pageSize: size, page: 0 }),\n\n setFilters: (filters) => set({ filters, page: 0 }),\n\n toggleFilterBar: () =>\n set((state) => ({ showFilterBar: !state.showFilterBar })),\n\n setShowColumnPicker: (show) => set({ showColumnPicker: show }),\n\n setColumnWidth: (column, width) =>\n set((state) => {\n const updated = { ...state.columnWidths, [column]: width }\n if (state.selectedCube) saveColumnWidths(state.selectedCube, updated)\n return { columnWidths: updated }\n }),\n\n setColumnWidths: (widths) => {\n const cube = get().selectedCube\n if (cube) saveColumnWidths(cube, widths)\n set({ columnWidths: widths })\n },\n }))\n}\n\n// ============================================================================\n// React Context + Provider\n// ============================================================================\n\nconst DataBrowserStoreContext = createContext<StoreApi<DataBrowserStore> | null>(null)\n\nexport interface DataBrowserStoreProviderProps {\n children: ReactNode\n defaultPageSize?: number\n defaultCube?: string\n defaultColumns?: string[]\n}\n\nexport function DataBrowserStoreProvider({\n children,\n defaultPageSize,\n defaultCube,\n defaultColumns,\n}: DataBrowserStoreProviderProps) {\n const storeRef = useRef<StoreApi<DataBrowserStore> | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createDataBrowserStore({\n defaultPageSize,\n defaultCube,\n defaultColumns,\n })\n }\n\n return (\n <DataBrowserStoreContext.Provider value={storeRef.current}>\n {children}\n </DataBrowserStoreContext.Provider>\n )\n}\n\nexport function useDataBrowserStore<T>(selector: (state: DataBrowserStore) => T): T {\n const store = useContext(DataBrowserStoreContext)\n if (!store) {\n throw new Error('useDataBrowserStore must be used within DataBrowserStoreProvider')\n }\n return useStore(store, selector)\n}\n","/**\n * useDataBrowser Master Hook\n *\n * Coordinates DataBrowser store state with query building and data fetching.\n * Builds ungrouped SemanticQueries from the store's selected cube, columns,\n * sort, pagination, and filter state.\n */\n\nimport { useMemo } from 'react'\nimport { useShallow } from 'zustand/react/shallow'\nimport { useDataBrowserStore } from '../stores/dataBrowserStore'\nimport { useCubeMeta } from '../providers/CubeProvider'\nimport { useCubeLoadQuery } from './queries/useCubeLoadQuery'\nimport type { CubeQuery } from '../types'\n\n/**\n * Determine whether a field is a dimension on a given cube from metadata\n */\nfunction isDimension(fieldName: string, meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string }> }> } | null): boolean {\n if (!meta) return true // default to dimension if no meta\n const [cubeName, field] = fieldName.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return true\n return cube.dimensions.some((d) => d.name === `${cubeName}.${field}`)\n}\n\n/**\n * Get field type from metadata\n */\nexport function getFieldType(\n fieldName: string,\n meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string; type: string }>; measures: Array<{ name: string; type: string }> }> } | null\n): string {\n if (!meta) return 'string'\n const [cubeName] = fieldName.split('.')\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return 'string'\n const dim = cube.dimensions.find((d) => d.name === fieldName)\n if (dim) return dim.type\n const meas = cube.measures.find((m) => m.name === fieldName)\n if (meas) return meas.type\n return 'string'\n}\n\n/**\n * Get all browsable columns for a cube (dimensions + ungrouped-compatible measures)\n */\nexport function getCubeColumns(\n cubeName: string,\n meta: { cubes: Array<{ name: string; dimensions: Array<{ name: string }>; measures: Array<{ name: string; type: string }> }> } | null\n): { dimensions: string[]; measures: string[] } {\n if (!meta) return { dimensions: [], measures: [] }\n const cube = meta.cubes.find((c) => c.name === cubeName)\n if (!cube) return { dimensions: [], measures: [] }\n\n const ungroupedCompatible = new Set(['sum', 'avg', 'min', 'max', 'number'])\n const dimensions = cube.dimensions.map((d) => d.name)\n const measures = cube.measures\n .filter((m) => ungroupedCompatible.has(m.type))\n .map((m) => m.name)\n\n return { dimensions, measures }\n}\n\nexport function useDataBrowser() {\n // Store state\n const selectedCube = useDataBrowserStore((s) => s.selectedCube)\n const visibleColumns = useDataBrowserStore((s) => s.visibleColumns)\n const sortColumn = useDataBrowserStore((s) => s.sortColumn)\n const sortDirection = useDataBrowserStore((s) => s.sortDirection)\n const page = useDataBrowserStore((s) => s.page)\n const pageSize = useDataBrowserStore((s) => s.pageSize)\n const filters = useDataBrowserStore((s) => s.filters)\n const showFilterBar = useDataBrowserStore((s) => s.showFilterBar)\n const showColumnPicker = useDataBrowserStore((s) => s.showColumnPicker)\n\n // Actions\n const actions = useDataBrowserStore(\n useShallow((s) => ({\n selectCube: s.selectCube,\n setVisibleColumns: s.setVisibleColumns,\n toggleColumn: s.toggleColumn,\n setSort: s.setSort,\n clearSort: s.clearSort,\n setPage: s.setPage,\n setPageSize: s.setPageSize,\n setFilters: s.setFilters,\n toggleFilterBar: s.toggleFilterBar,\n setShowColumnPicker: s.setShowColumnPicker,\n }))\n )\n\n // Metadata\n const { meta, getFieldLabel } = useCubeMeta()\n\n // Determine default sort: first primary key dimension, or first dimension\n const defaultSortColumn = useMemo(() => {\n if (!meta || !selectedCube) return null\n const cube = meta.cubes.find((c) => c.name === selectedCube)\n if (!cube) return null\n // Look for a primary key dimension first\n const pkDim = cube.dimensions.find((d: any) => d.primaryKey)\n if (pkDim) return pkDim.name\n // Fall back to first dimension\n if (cube.dimensions.length > 0) return cube.dimensions[0].name\n return null\n }, [meta, selectedCube])\n\n const effectiveSortColumn = sortColumn ?? defaultSortColumn\n const effectiveSortDirection = sortColumn ? sortDirection : 'asc'\n\n // Build query from store state\n const query = useMemo<CubeQuery | null>(() => {\n if (!selectedCube || visibleColumns.length === 0) return null\n\n const dimensions = visibleColumns.filter((col) => isDimension(col, meta))\n const measures = visibleColumns.filter((col) => !isDimension(col, meta))\n\n if (dimensions.length === 0) return null // ungrouped requires at least one dimension\n\n const q: CubeQuery = {\n dimensions,\n ungrouped: true,\n limit: pageSize,\n offset: page * pageSize,\n }\n\n if (measures.length > 0) q.measures = measures\n if (filters.length > 0) q.filters = filters\n if (effectiveSortColumn) q.order = { [effectiveSortColumn]: effectiveSortDirection }\n\n return q\n }, [selectedCube, visibleColumns, filters, effectiveSortColumn, effectiveSortDirection, page, pageSize, meta])\n\n // Fetch data — keepPreviousData ON so pagination/sort keeps showing\n // stale data while new page loads. We detect cube switches by checking\n // if the data keys match the current columns.\n const {\n rawData: rawDataFromQuery,\n isLoading,\n isFetching,\n isDebouncing,\n error,\n refetch,\n } = useCubeLoadQuery(query, {\n skip: !query,\n debounceMs: 400,\n keepPreviousData: true,\n staleTime: 60000, // 1 minute — prevent unnecessary refetches\n })\n\n // Detect stale data from a different cube by checking if data keys\n // match the current visible columns. This handles cube switches\n // (keys won't match) while preserving data during pagination/sort\n // (keys still match since it's the same cube).\n const rawData = (() => {\n if (!rawDataFromQuery || rawDataFromQuery.length === 0) return rawDataFromQuery\n const dataKeys = Object.keys(rawDataFromQuery[0] as Record<string, unknown>)\n const matches = visibleColumns.some(col => dataKeys.includes(col))\n return matches ? rawDataFromQuery : null\n })()\n\n // Loading when: TanStack is loading, or debouncing with no valid data\n const effectiveIsLoading = isLoading || (!rawData && (isDebouncing || isFetching))\n\n // Compute total page info\n const rowCount = rawData?.length ?? 0\n const hasNextPage = rowCount === pageSize // if we got a full page, there might be more\n const hasPrevPage = page > 0\n\n return {\n // State\n selectedCube,\n visibleColumns,\n sortColumn: effectiveSortColumn,\n sortDirection: effectiveSortDirection,\n page,\n pageSize,\n filters,\n showFilterBar,\n showColumnPicker,\n\n // Data\n rawData,\n isLoading: effectiveIsLoading,\n isFetching,\n error,\n query,\n rowCount,\n hasNextPage,\n hasPrevPage,\n\n // Metadata\n meta,\n getFieldLabel,\n\n // Actions\n ...actions,\n refetch,\n }\n}\n","/**\n * DataBrowserSidebar\n *\n * Left panel showing a searchable list of cubes.\n * Clicking a cube loads its dimensions into the table view.\n */\n\nimport { useState, useMemo } from 'react'\nimport { getIcon } from '../../icons'\n\nconst SearchIcon = getIcon('search')\nconst CubeIcon = getIcon('cube')\n\ninterface DataBrowserSidebarProps {\n cubes: Array<{ name: string; title: string }>\n selectedCube: string | null\n onSelectCube: (cubeName: string) => void\n}\n\nexport default function DataBrowserSidebar({\n cubes,\n selectedCube,\n onSelectCube,\n}: DataBrowserSidebarProps) {\n const [search, setSearch] = useState('')\n\n const filteredCubes = useMemo(() => {\n const sorted = [...cubes].sort((a, b) =>\n (a.title || a.name).localeCompare(b.title || b.name)\n )\n if (!search) return sorted\n const lower = search.toLowerCase()\n return sorted.filter(\n (c) =>\n c.name.toLowerCase().includes(lower) ||\n c.title.toLowerCase().includes(lower)\n )\n }, [cubes, search])\n\n return (\n <div className=\"dc:flex dc:flex-col dc:h-full dc:border-r border-dc-border bg-dc-surface dc:w-60 dc:shrink-0\">\n {/* Header */}\n <div className=\"dc:px-3 dc:py-3 dc:border-b border-dc-border\">\n <h2 className=\"dc:text-sm dc:font-semibold text-dc-text dc:mb-2\">Cubes</h2>\n {/* Search */}\n <div className=\"dc:relative\">\n <SearchIcon className=\"dc:absolute dc:left-2 dc:top-1/2 dc:-translate-y-1/2 dc:w-3.5 dc:h-3.5 text-dc-text-muted\" />\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search...\"\n className=\"dc:w-full dc:pl-7 dc:pr-2 dc:py-1.5 dc:text-xs dc:rounded border-dc-border dc:border bg-dc-surface text-dc-text dc:outline-none dc:focus:ring-1 focus:ring-dc-accent\"\n />\n </div>\n </div>\n\n {/* Cube list */}\n <div className=\"dc:flex-1 dc:overflow-y-auto dc:py-1\">\n {filteredCubes.map((cube) => (\n <button\n key={cube.name}\n onClick={() => onSelectCube(cube.name)}\n className={`dc:flex dc:items-center dc:gap-2 dc:w-full dc:px-3 dc:py-1.5 dc:text-left dc:text-sm dc:transition-colors ${\n selectedCube === cube.name\n ? 'bg-dc-accent-bg text-dc-accent dc:font-medium'\n : 'text-dc-text dc:hover:bg-dc-surface-hover'\n }`}\n >\n <CubeIcon className=\"dc:w-4 dc:h-4 dc:shrink-0 text-dc-text-muted\" />\n <span className=\"dc:truncate\">{cube.title || cube.name}</span>\n </button>\n ))}\n\n {filteredCubes.length === 0 && (\n <div className=\"dc:px-3 dc:py-4 dc:text-xs text-dc-text-muted dc:text-center\">\n No cubes found\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * DataBrowserToolbar\n *\n * Top toolbar with filter toggle, column picker, row count, and pagination.\n */\n\nimport { getIcon } from '../../icons'\n\nconst FilterIcon = getIcon('filter')\nconst ColumnsIcon = getIcon('settings')\nconst ChevronLeftIcon = getIcon('chevronLeft')\nconst ChevronRightIcon = getIcon('chevronRight')\nconst RefreshIcon = getIcon('refresh')\n\ninterface DataBrowserToolbarProps {\n // Filter state\n showFilterBar: boolean\n filterCount: number\n onToggleFilterBar: () => void\n\n // Column picker\n onToggleColumnPicker: () => void\n\n // Pagination\n page: number\n pageSize: number\n rowCount: number\n hasNextPage: boolean\n hasPrevPage: boolean\n onPageChange: (page: number) => void\n onPageSizeChange: (size: number) => void\n\n // Status\n isFetching: boolean\n onRefresh: () => void\n}\n\nexport default function DataBrowserToolbar({\n showFilterBar,\n filterCount,\n onToggleFilterBar,\n onToggleColumnPicker,\n page,\n pageSize,\n rowCount,\n hasNextPage,\n hasPrevPage,\n onPageChange,\n onPageSizeChange,\n isFetching,\n onRefresh,\n}: DataBrowserToolbarProps) {\n return (\n <div className=\"dc:flex dc:items-center dc:gap-2 dc:px-3 dc:py-2 dc:border-b border-dc-border bg-dc-surface-secondary\">\n {/* Filter toggle */}\n <button\n onClick={onToggleFilterBar}\n className={`dc:flex dc:items-center dc:gap-1.5 dc:px-2.5 dc:py-1.5 dc:text-xs dc:font-medium dc:rounded dc:border dc:transition-colors ${\n showFilterBar\n ? 'border-dc-accent bg-dc-accent-bg text-dc-accent'\n : 'border-dc-border bg-dc-surface text-dc-text dc:hover:bg-dc-surface-hover'\n }`}\n >\n <FilterIcon className=\"dc:w-3.5 dc:h-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"dc:inline-flex dc:items-center dc:justify-center dc:w-4 dc:h-4 dc:text-[10px] dc:font-bold dc:rounded-full bg-dc-accent text-dc-surface\">\n {filterCount}\n </span>\n )}\n </button>\n\n {/* Columns button */}\n <button\n onClick={onToggleColumnPicker}\n className=\"dc:flex dc:items-center dc:gap-1.5 dc:px-2.5 dc:py-1.5 dc:text-xs dc:font-medium dc:rounded dc:border border-dc-border bg-dc-surface text-dc-text dc:hover:bg-dc-surface-hover dc:transition-colors\"\n >\n <ColumnsIcon className=\"dc:w-3.5 dc:h-3.5\" />\n Columns\n </button>\n\n {/* Spacer */}\n <div className=\"dc:flex-1\" />\n\n {/* Row count */}\n <span className=\"dc:text-xs text-dc-text-muted\">\n {rowCount} rows\n </span>\n\n {/* Refresh */}\n <button\n onClick={onRefresh}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:transition-colors\"\n title=\"Refresh\"\n >\n <RefreshIcon className={`dc:w-3.5 dc:h-3.5 text-dc-text-muted ${isFetching ? 'dc:animate-spin' : ''}`} />\n </button>\n\n {/* Page size selector */}\n <select\n value={pageSize}\n onChange={(e) => onPageSizeChange(Number(e.target.value))}\n className=\"dc:text-xs dc:px-1.5 dc:py-1 dc:rounded dc:border border-dc-border bg-dc-surface text-dc-text dc:outline-none\"\n >\n <option value={20}>20</option>\n <option value={50}>50</option>\n <option value={100}>100</option>\n </select>\n\n {/* Pagination */}\n <div className=\"dc:flex dc:items-center dc:gap-1\">\n <button\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPrevPage}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:disabled:opacity-30 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n <ChevronLeftIcon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </button>\n <span className=\"dc:text-xs dc:font-medium text-dc-text dc:min-w-[2rem] dc:text-center\">\n {page + 1}\n </span>\n <button\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n className=\"dc:p-1 dc:rounded dc:hover:bg-dc-surface-hover dc:disabled:opacity-30 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n <ChevronRightIcon className=\"dc:w-4 dc:h-4 text-dc-text-muted\" />\n </button>\n </div>\n </div>\n )\n}\n","/**\n * DataBrowserTable\n *\n * Sortable data table with resizable columns, type badges, and click-to-sort headers.\n * Designed for browsing raw row-level data from ungrouped queries.\n *\n * Column widths are stored in the Zustand store (cosmetic-only slice)\n * and never affect query construction or data fetching.\n */\n\nimport React, { useCallback, useRef } from 'react'\nimport { getIcon } from '../../icons'\nimport { getFieldType } from '../../hooks/useDataBrowser'\nimport { useDataBrowserStore } from '../../stores/dataBrowserStore'\nimport LoadingIndicator from '../LoadingIndicator'\n\nconst SortAscIcon = getIcon('chevronUp')\nconst SortDescIcon = getIcon('chevronDown')\n\ninterface DataBrowserTableProps {\n data: unknown[] | null\n columns: string[]\n sortColumn: string | null\n sortDirection: 'asc' | 'desc'\n onSort: (column: string) => void\n getFieldLabel: (field: string) => string\n meta: any\n isLoading: boolean\n isFetching: boolean\n selectedCube: string | null\n loadingComponent?: React.ReactNode\n}\n\nfunction getTypeLabel(fieldName: string, meta: any): string {\n const type = getFieldType(fieldName, meta)\n const typeMap: Record<string, string> = {\n string: 'text',\n number: 'num',\n time: 'time',\n boolean: 'bool',\n sum: 'num',\n avg: 'num',\n min: 'num',\n max: 'num',\n }\n return typeMap[type] || type\n}\n\nfunction isNumericType(fieldName: string, meta: any): boolean {\n return getTypeLabel(fieldName, meta) === 'num'\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value == null) return ''\n if (typeof value === 'number') return value.toLocaleString()\n if (typeof value === 'boolean') return value ? 'true' : 'false'\n if (value instanceof Date) return value.toISOString()\n return String(value)\n}\n\nconst MIN_COL_WIDTH = 60\nconst DEFAULT_COL_WIDTH = 150\n\nexport default React.memo(function DataBrowserTable({\n data,\n columns,\n sortColumn,\n sortDirection,\n onSort,\n getFieldLabel,\n meta,\n isLoading,\n isFetching,\n selectedCube,\n loadingComponent,\n}: DataBrowserTableProps) {\n // Column widths from store (cosmetic only — never affects queries)\n const columnWidths = useDataBrowserStore((s) => s.columnWidths)\n const storeSetColumnWidth = useDataBrowserStore((s) => s.setColumnWidth)\n const storeSetColumnWidths = useDataBrowserStore((s) => s.setColumnWidths)\n\n const tableRef = useRef<HTMLTableElement>(null)\n // Suppress the next click on <th> after a resize drag\n const didResizeRef = useRef(false)\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent, column: string) => {\n e.preventDefault()\n e.stopPropagation()\n\n const startX = e.clientX\n didResizeRef.current = false\n\n // Snapshot all column widths from the DOM so other columns stay fixed\n const table = tableRef.current\n if (table) {\n const ths = table.querySelectorAll('thead th')\n const snapshot: Record<string, number> = {}\n ths.forEach((th, idx) => {\n const col = columns[idx]\n if (col) snapshot[col] = th.getBoundingClientRect().width\n })\n storeSetColumnWidths(snapshot)\n }\n\n const th = (e.target as HTMLElement).closest('th')\n const startWidth = th ? th.getBoundingClientRect().width : DEFAULT_COL_WIDTH\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const diff = moveEvent.clientX - startX\n if (Math.abs(diff) > 2) didResizeRef.current = true\n const newWidth = Math.max(MIN_COL_WIDTH, startWidth + diff)\n storeSetColumnWidth(column, newWidth)\n }\n\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n document.body.style.cursor = ''\n document.body.style.userSelect = ''\n // Keep didResizeRef true briefly so the click handler can check it\n requestAnimationFrame(() => { didResizeRef.current = false })\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n document.body.style.cursor = 'col-resize'\n document.body.style.userSelect = 'none'\n },\n [columns, storeSetColumnWidth, storeSetColumnWidths]\n )\n\n const handleHeaderClick = useCallback(\n (column: string) => {\n if (didResizeRef.current) return // suppress click after resize drag\n onSort(column)\n },\n [onSort]\n )\n\n // Compute table width when column widths are explicitly set\n const hasExplicitWidths = Object.keys(columnWidths).length > 0\n const tableWidth = hasExplicitWidths\n ? columns.reduce((sum, col) => sum + (columnWidths[col] ?? DEFAULT_COL_WIDTH), 0)\n : undefined\n\n // No cube selected\n if (!selectedCube) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-base dc:font-semibold dc:mb-1\">Select a cube</div>\n <div className=\"dc:text-sm text-dc-text-secondary\">\n Choose a cube from the sidebar to browse its data\n </div>\n </div>\n </div>\n )\n }\n\n // Loading: no data yet (initial load, cube switch, or fetching)\n if (!data) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:h-full dc:gap-3\">\n {loadingComponent ?? (\n <>\n <LoadingIndicator size=\"md\" />\n <div className=\"dc:text-sm text-dc-text-muted\">Loading data...</div>\n </>\n )}\n </div>\n )\n }\n\n // Empty result set (query completed but returned no rows)\n if (data.length === 0 && !isLoading && !isFetching) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:h-full\">\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No rows returned for this query</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:relative dc:flex-1 dc:overflow-auto\">\n {isFetching && (\n <div className=\"dc:absolute dc:inset-0 bg-dc-surface dc:opacity-40 dc:z-10 dc:pointer-events-none\" />\n )}\n\n <table ref={tableRef} className=\"dc:border-collapse\" style={{ tableLayout: 'fixed', width: tableWidth, minWidth: '100%' }}>\n <colgroup>\n {columns.map((column) => (\n <col key={column} style={{ width: columnWidths[column] ?? DEFAULT_COL_WIDTH }} />\n ))}\n </colgroup>\n <thead className=\"dc:sticky dc:top-0 dc:z-20\" style={{ backgroundColor: 'var(--dc-surface-secondary)' }}>\n <tr>\n {columns.map((column, colIdx) => {\n const isSorted = sortColumn === column\n const label = getFieldLabel(column)\n const typeLabel = getTypeLabel(column, meta)\n const isLast = colIdx === columns.length - 1\n const isNumeric = isNumericType(column, meta)\n\n return (\n <th\n key={column}\n onClick={() => handleHeaderClick(column)}\n className={`dc:relative dc:px-3 dc:py-2 dc:text-xs dc:font-normal dc:cursor-pointer dc:select-none dc:border-b border-dc-border dc:transition-colors${!isLast ? ' dc:border-r' : ''}${isNumeric ? ' dc:text-right' : ' dc:text-left'}`}\n style={{ color: 'var(--dc-text-muted)' }}\n >\n <div className={`dc:flex dc:items-center dc:gap-1.5 dc:overflow-hidden${isNumeric ? ' dc:justify-end' : ''}`}>\n <span className=\"dc:font-medium dc:truncate\" style={{ color: 'var(--dc-text)' }}>{label}</span>\n <span className=\"dc:text-[10px] dc:opacity-50 dc:shrink-0\">{typeLabel}</span>\n {isSorted && (\n sortDirection === 'asc'\n ? <SortAscIcon className=\"dc:w-3 dc:h-3 text-dc-accent dc:shrink-0\" />\n : <SortDescIcon className=\"dc:w-3 dc:h-3 text-dc-accent dc:shrink-0\" />\n )}\n </div>\n {/* Resize handle */}\n <div\n onMouseDown={(e) => handleResizeStart(e, column)}\n className=\"dc:absolute dc:top-0 dc:right-0 dc:w-1.5 dc:h-full dc:cursor-col-resize dc:hover:bg-dc-accent dc:opacity-0 dc:hover:opacity-100 dc:transition-opacity\"\n style={{ zIndex: 30 }}\n />\n </th>\n )\n })}\n </tr>\n </thead>\n <tbody>\n {(data as Record<string, unknown>[]).map((row, rowIdx) => (\n <tr\n key={rowIdx}\n className=\"dc:border-b border-dc-border\"\n style={{ transition: 'background-color 0.1s' }}\n onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = 'var(--dc-surface-hover, rgba(0,0,0,0.02))' }}\n onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = '' }}\n >\n {columns.map((column, colIdx) => {\n const isLast = colIdx === columns.length - 1\n const isNumeric = isNumericType(column, meta)\n return (\n <td\n key={column}\n className={`dc:px-3 dc:py-1.5 dc:text-sm dc:overflow-hidden dc:text-ellipsis dc:whitespace-nowrap${!isLast ? ' dc:border-r border-dc-border' : ''}${isNumeric ? ' dc:text-right dc:tabular-nums' : ''}`}\n style={{ color: 'var(--dc-text)' }}\n >\n {formatCellValue(row[column])}\n </td>\n )\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n})\n","/**\n * DataBrowser Component\n *\n * A Neon-style full-page data browser for exploring raw cube data.\n * Uses ungrouped queries to display row-level data with:\n * - Cube list sidebar (left)\n * - Sortable data table (right)\n * - Filter bar and column picker\n * - Server-side pagination\n *\n * Must be wrapped in a CubeProvider.\n */\n\nimport { useMemo, useCallback } from 'react'\nimport { DataBrowserStoreProvider } from '../../stores/dataBrowserStore'\nimport { useDataBrowser, getCubeColumns } from '../../hooks/useDataBrowser'\nimport DataBrowserSidebar from './DataBrowserSidebar'\nimport DataBrowserToolbar from './DataBrowserToolbar'\nimport DataBrowserTable from './DataBrowserTable'\nimport AnalysisFilterSection from '../AnalysisBuilder/AnalysisFilterSection'\nimport FieldSearchModal from '../AnalysisBuilder/FieldSearchModal'\nimport type { MetaResponse, MetaField } from '../../shared/types'\n\nexport interface DataBrowserProps {\n /** Additional CSS classes */\n className?: string\n /** Initially selected cube */\n defaultCube?: string\n /** Default page size (default: 20) */\n defaultPageSize?: number\n /** Max height for the component (default: '100vh') */\n maxHeight?: string\n /** Custom loading indicator (defaults to LoadingIndicator) */\n loadingComponent?: import('react').ReactNode\n}\n\n/**\n * Inner component (must be inside store provider)\n */\nfunction DataBrowserInner({ className = '', maxHeight = '100vh', loadingComponent }: Omit<DataBrowserProps, 'defaultCube' | 'defaultPageSize'>) {\n const {\n selectedCube,\n visibleColumns,\n sortColumn,\n sortDirection,\n page,\n pageSize,\n filters,\n showFilterBar,\n showColumnPicker,\n rawData,\n isLoading,\n isFetching,\n rowCount,\n hasNextPage,\n hasPrevPage,\n meta,\n getFieldLabel,\n selectCube,\n setSort,\n setPage,\n setPageSize,\n setFilters,\n toggleFilterBar,\n setShowColumnPicker,\n toggleColumn,\n refetch,\n } = useDataBrowser()\n\n // Build cube list from metadata\n const cubeList = useMemo(() => {\n if (!meta) return []\n return meta.cubes.map((c) => ({ name: c.name, title: c.title || c.name }))\n }, [meta])\n\n // Handle cube selection — auto-populate with all dimensions\n const handleSelectCube = useCallback(\n (cubeName: string) => {\n const { dimensions } = getCubeColumns(cubeName, meta)\n selectCube(cubeName, dimensions)\n },\n [meta, selectCube]\n )\n\n // Filter count\n const filterCount = useMemo(() => {\n function count(fs: typeof filters): number {\n return fs.reduce((n, f) => {\n if ('member' in f) return n + 1\n if ('type' in f && 'filters' in f) return n + count(f.filters)\n return n\n }, 0)\n }\n return count(filters)\n }, [filters])\n\n // Schema for filter section and field search modal\n // Cast to MetaResponse since the components handle optional description gracefully\n const schema = useMemo<MetaResponse | null>(() => {\n if (!meta) return null\n if (selectedCube) {\n const cube = meta.cubes.find((c) => c.name === selectedCube)\n return cube ? { cubes: [cube] } as unknown as MetaResponse : null\n }\n return meta as unknown as MetaResponse\n }, [meta, selectedCube])\n\n // Handle column toggle from FieldSearchModal\n const handleColumnSelect = useCallback(\n (field: MetaField, _fieldType: string, _cubeName: string, keepOpen?: boolean) => {\n void keepOpen\n toggleColumn(field.name)\n },\n [toggleColumn]\n )\n\n return (\n <div\n className={`dc:flex dc:border border-dc-border dc:rounded-lg dc:overflow-hidden bg-dc-surface ${className}`}\n style={{ height: maxHeight }}\n >\n {/* Sidebar */}\n <DataBrowserSidebar\n cubes={cubeList}\n selectedCube={selectedCube}\n onSelectCube={handleSelectCube}\n />\n\n {/* Main content */}\n <div className=\"dc:flex dc:flex-col dc:flex-1 dc:min-w-0\">\n {/* Toolbar */}\n {selectedCube && (\n <DataBrowserToolbar\n showFilterBar={showFilterBar}\n filterCount={filterCount}\n onToggleFilterBar={toggleFilterBar}\n onToggleColumnPicker={() => setShowColumnPicker(!showColumnPicker)}\n page={page}\n pageSize={pageSize}\n rowCount={rowCount}\n hasNextPage={hasNextPage}\n hasPrevPage={hasPrevPage}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n isFetching={isFetching}\n onRefresh={() => refetch()}\n />\n )}\n\n {/* Filter bar (collapsible) */}\n {selectedCube && showFilterBar && (\n <div className=\"dc:px-3 dc:py-2 dc:border-b border-dc-border bg-dc-surface\">\n <AnalysisFilterSection\n filters={filters}\n schema={schema}\n onFiltersChange={setFilters}\n />\n </div>\n )}\n\n {/* Data table */}\n <DataBrowserTable\n data={rawData}\n columns={visibleColumns}\n sortColumn={sortColumn}\n sortDirection={sortDirection}\n onSort={setSort}\n getFieldLabel={getFieldLabel}\n meta={meta}\n isLoading={isLoading}\n isFetching={isFetching}\n selectedCube={selectedCube}\n loadingComponent={loadingComponent}\n />\n </div>\n\n {/* Column picker modal */}\n {showColumnPicker && schema && (\n <FieldSearchModal\n isOpen={showColumnPicker}\n onClose={() => setShowColumnPicker(false)}\n onSelect={handleColumnSelect}\n mode=\"breakdown\"\n schema={schema}\n selectedFields={visibleColumns}\n />\n )}\n </div>\n )\n}\n\n/**\n * DataBrowser — standalone data browsing component\n */\nexport default function DataBrowser({\n className,\n defaultCube,\n defaultPageSize = 20,\n maxHeight,\n loadingComponent,\n}: DataBrowserProps) {\n return (\n <DataBrowserStoreProvider defaultPageSize={defaultPageSize} defaultCube={defaultCube}>\n <DataBrowserInner className={className} maxHeight={maxHeight} loadingComponent={loadingComponent} />\n </DataBrowserStoreProvider>\n )\n}\n","/**\n * DashboardThumbnailPlaceholder\n *\n * A placeholder component shown when a dashboard thumbnail doesn't exist\n * but the thumbnail feature is enabled. Displays a simple grid icon\n * with \"No preview\" text.\n */\n\nimport { getIcon } from '../icons'\n\nconst GridIcon = getIcon('segment')\n\nexport interface DashboardThumbnailPlaceholderProps {\n /** Additional CSS classes */\n className?: string\n}\n\nexport function DashboardThumbnailPlaceholder({\n className = ''\n}: DashboardThumbnailPlaceholderProps) {\n return (\n <div\n className={`dc:flex dc:items-center dc:justify-center bg-dc-bg-secondary ${className}`}\n >\n <div className=\"dc:text-center\">\n <GridIcon\n className=\"dc:w-8 dc:h-8 dc:mx-auto dc:mb-2 text-dc-text-muted dc:opacity-50\"\n />\n <span className=\"dc:text-xs text-dc-text-muted\">No preview</span>\n </div>\n </div>\n )\n}\n\nexport default DashboardThumbnailPlaceholder\n"],"mappings":"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"}