@quillsql/react 2.12.35 → 2.12.37

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 (475) hide show
  1. package/dist/cjs/Chart.d.ts +2 -1
  2. package/dist/cjs/Chart.d.ts.map +1 -1
  3. package/dist/cjs/Chart.js +3 -3
  4. package/dist/cjs/ChartBuilder.d.ts.map +1 -1
  5. package/dist/cjs/ChartBuilder.js +3 -3
  6. package/dist/cjs/Dashboard.d.ts.map +1 -1
  7. package/dist/cjs/Dashboard.js +2 -2
  8. package/dist/cjs/ReportBuilder.d.ts.map +1 -1
  9. package/dist/cjs/ReportBuilder.js +13 -0
  10. package/dist/cjs/SQLEditor.js +2 -1
  11. package/dist/cjs/components/Chart/BarList.d.ts +1 -0
  12. package/dist/cjs/components/Chart/BarList.d.ts.map +1 -1
  13. package/dist/cjs/components/Chart/BarList.js +3 -3
  14. package/dist/cjs/components/Chart/ChartError.js +1 -1
  15. package/dist/cjs/utils/dashboard.js +1 -1
  16. package/dist/cjs/utils/dataFetcher.d.ts.map +1 -1
  17. package/dist/cjs/utils/dataFetcher.js +7 -1
  18. package/dist/cjs/utils/dataProcessing.d.ts +1 -0
  19. package/dist/cjs/utils/dataProcessing.d.ts.map +1 -1
  20. package/dist/cjs/utils/dataProcessing.js +20 -1
  21. package/dist/cjs/utils/queryConstructor.d.ts +1 -1
  22. package/dist/cjs/utils/queryConstructor.d.ts.map +1 -1
  23. package/dist/cjs/utils/queryConstructor.js +8 -5
  24. package/dist/cjs/utils/report.d.ts.map +1 -1
  25. package/dist/cjs/utils/report.js +17 -5
  26. package/dist/cjs/utils/tableProcessing.d.ts.map +1 -1
  27. package/dist/cjs/utils/tableProcessing.js +7 -0
  28. package/package.json +1 -1
  29. package/dist/esm/Chart.d.ts +0 -203
  30. package/dist/esm/Chart.d.ts.map +0 -1
  31. package/dist/esm/Chart.js +0 -431
  32. package/dist/esm/ChartBuilder.d.ts +0 -339
  33. package/dist/esm/ChartBuilder.d.ts.map +0 -1
  34. package/dist/esm/ChartBuilder.js +0 -1312
  35. package/dist/esm/ChartEditor.d.ts +0 -209
  36. package/dist/esm/ChartEditor.d.ts.map +0 -1
  37. package/dist/esm/ChartEditor.js +0 -182
  38. package/dist/esm/Context.d.ts +0 -14
  39. package/dist/esm/Context.d.ts.map +0 -1
  40. package/dist/esm/Context.js +0 -269
  41. package/dist/esm/Dashboard.d.ts +0 -279
  42. package/dist/esm/Dashboard.d.ts.map +0 -1
  43. package/dist/esm/Dashboard.js +0 -660
  44. package/dist/esm/DateRangePicker/Calendar.d.ts +0 -17
  45. package/dist/esm/DateRangePicker/Calendar.d.ts.map +0 -1
  46. package/dist/esm/DateRangePicker/Calendar.js +0 -164
  47. package/dist/esm/DateRangePicker/DateRangePicker.d.ts +0 -39
  48. package/dist/esm/DateRangePicker/DateRangePicker.d.ts.map +0 -1
  49. package/dist/esm/DateRangePicker/DateRangePicker.js +0 -95
  50. package/dist/esm/DateRangePicker/DateRangePickerButton.d.ts +0 -22
  51. package/dist/esm/DateRangePicker/DateRangePickerButton.d.ts.map +0 -1
  52. package/dist/esm/DateRangePicker/DateRangePickerButton.js +0 -134
  53. package/dist/esm/DateRangePicker/QuillDateRangePicker.d.ts +0 -25
  54. package/dist/esm/DateRangePicker/QuillDateRangePicker.d.ts.map +0 -1
  55. package/dist/esm/DateRangePicker/QuillDateRangePicker.js +0 -260
  56. package/dist/esm/DateRangePicker/dateRangePickerUtils.d.ts +0 -80
  57. package/dist/esm/DateRangePicker/dateRangePickerUtils.d.ts.map +0 -1
  58. package/dist/esm/DateRangePicker/dateRangePickerUtils.js +0 -521
  59. package/dist/esm/DateRangePicker/index.d.ts +0 -3
  60. package/dist/esm/DateRangePicker/index.d.ts.map +0 -1
  61. package/dist/esm/DateRangePicker/index.js +0 -2
  62. package/dist/esm/QuillProvider.d.ts +0 -163
  63. package/dist/esm/QuillProvider.d.ts.map +0 -1
  64. package/dist/esm/QuillProvider.js +0 -104
  65. package/dist/esm/ReportBuilder.d.ts +0 -318
  66. package/dist/esm/ReportBuilder.d.ts.map +0 -1
  67. package/dist/esm/ReportBuilder.js +0 -3266
  68. package/dist/esm/SQLEditor.d.ts +0 -272
  69. package/dist/esm/SQLEditor.d.ts.map +0 -1
  70. package/dist/esm/SQLEditor.js +0 -509
  71. package/dist/esm/Table.d.ts +0 -167
  72. package/dist/esm/Table.d.ts.map +0 -1
  73. package/dist/esm/Table.js +0 -215
  74. package/dist/esm/TableChart.d.ts +0 -15
  75. package/dist/esm/TableChart.d.ts.map +0 -1
  76. package/dist/esm/TableChart.js +0 -95
  77. package/dist/esm/assets/ArrowDownHeadIcon.d.ts +0 -5
  78. package/dist/esm/assets/ArrowDownHeadIcon.d.ts.map +0 -1
  79. package/dist/esm/assets/ArrowDownHeadIcon.js +0 -3
  80. package/dist/esm/assets/ArrowDownIcon.d.ts +0 -5
  81. package/dist/esm/assets/ArrowDownIcon.d.ts.map +0 -1
  82. package/dist/esm/assets/ArrowDownIcon.js +0 -3
  83. package/dist/esm/assets/ArrowDownRightIcon.d.ts +0 -5
  84. package/dist/esm/assets/ArrowDownRightIcon.d.ts.map +0 -1
  85. package/dist/esm/assets/ArrowDownRightIcon.js +0 -3
  86. package/dist/esm/assets/ArrowLeftHeadIcon.d.ts +0 -5
  87. package/dist/esm/assets/ArrowLeftHeadIcon.d.ts.map +0 -1
  88. package/dist/esm/assets/ArrowLeftHeadIcon.js +0 -3
  89. package/dist/esm/assets/ArrowRightHeadIcon.d.ts +0 -5
  90. package/dist/esm/assets/ArrowRightHeadIcon.d.ts.map +0 -1
  91. package/dist/esm/assets/ArrowRightHeadIcon.js +0 -3
  92. package/dist/esm/assets/ArrowRightIcon.d.ts +0 -5
  93. package/dist/esm/assets/ArrowRightIcon.d.ts.map +0 -1
  94. package/dist/esm/assets/ArrowRightIcon.js +0 -3
  95. package/dist/esm/assets/ArrowUpHeadIcon.d.ts +0 -5
  96. package/dist/esm/assets/ArrowUpHeadIcon.d.ts.map +0 -1
  97. package/dist/esm/assets/ArrowUpHeadIcon.js +0 -3
  98. package/dist/esm/assets/ArrowUpIcon.d.ts +0 -5
  99. package/dist/esm/assets/ArrowUpIcon.d.ts.map +0 -1
  100. package/dist/esm/assets/ArrowUpIcon.js +0 -3
  101. package/dist/esm/assets/ArrowUpRightIcon.d.ts +0 -5
  102. package/dist/esm/assets/ArrowUpRightIcon.d.ts.map +0 -1
  103. package/dist/esm/assets/ArrowUpRightIcon.js +0 -3
  104. package/dist/esm/assets/CalendarIcon.d.ts +0 -5
  105. package/dist/esm/assets/CalendarIcon.d.ts.map +0 -1
  106. package/dist/esm/assets/CalendarIcon.js +0 -3
  107. package/dist/esm/assets/CalendarNormalIcon.d.ts +0 -5
  108. package/dist/esm/assets/CalendarNormalIcon.d.ts.map +0 -1
  109. package/dist/esm/assets/CalendarNormalIcon.js +0 -3
  110. package/dist/esm/assets/DoubleArrowLeftHeadIcon.d.ts +0 -5
  111. package/dist/esm/assets/DoubleArrowLeftHeadIcon.d.ts.map +0 -1
  112. package/dist/esm/assets/DoubleArrowLeftHeadIcon.js +0 -3
  113. package/dist/esm/assets/DoubleArrowRightHeadIcon.d.ts +0 -5
  114. package/dist/esm/assets/DoubleArrowRightHeadIcon.d.ts.map +0 -1
  115. package/dist/esm/assets/DoubleArrowRightHeadIcon.js +0 -3
  116. package/dist/esm/assets/ExclamationFilledIcon.d.ts +0 -5
  117. package/dist/esm/assets/ExclamationFilledIcon.d.ts.map +0 -1
  118. package/dist/esm/assets/ExclamationFilledIcon.js +0 -3
  119. package/dist/esm/assets/FilterIcon.d.ts +0 -5
  120. package/dist/esm/assets/FilterIcon.d.ts.map +0 -1
  121. package/dist/esm/assets/FilterIcon.js +0 -3
  122. package/dist/esm/assets/LoadingSpinner.d.ts +0 -5
  123. package/dist/esm/assets/LoadingSpinner.d.ts.map +0 -1
  124. package/dist/esm/assets/LoadingSpinner.js +0 -3
  125. package/dist/esm/assets/RefreshIcon.d.ts +0 -5
  126. package/dist/esm/assets/RefreshIcon.d.ts.map +0 -1
  127. package/dist/esm/assets/RefreshIcon.js +0 -3
  128. package/dist/esm/assets/SearchIcon.d.ts +0 -5
  129. package/dist/esm/assets/SearchIcon.d.ts.map +0 -1
  130. package/dist/esm/assets/SearchIcon.js +0 -3
  131. package/dist/esm/assets/UpLeftArrowsIcon.d.ts +0 -5
  132. package/dist/esm/assets/UpLeftArrowsIcon.d.ts.map +0 -1
  133. package/dist/esm/assets/UpLeftArrowsIcon.js +0 -3
  134. package/dist/esm/assets/XCircleIcon.d.ts +0 -5
  135. package/dist/esm/assets/XCircleIcon.d.ts.map +0 -1
  136. package/dist/esm/assets/XCircleIcon.js +0 -3
  137. package/dist/esm/assets/XIcon.d.ts +0 -5
  138. package/dist/esm/assets/XIcon.d.ts.map +0 -1
  139. package/dist/esm/assets/XIcon.js +0 -3
  140. package/dist/esm/assets/index.d.ts +0 -22
  141. package/dist/esm/assets/index.d.ts.map +0 -1
  142. package/dist/esm/assets/index.js +0 -21
  143. package/dist/esm/components/Banner/index.d.ts +0 -3
  144. package/dist/esm/components/Banner/index.d.ts.map +0 -1
  145. package/dist/esm/components/Banner/index.js +0 -24
  146. package/dist/esm/components/BigModal/BigModal.d.ts +0 -15
  147. package/dist/esm/components/BigModal/BigModal.d.ts.map +0 -1
  148. package/dist/esm/components/BigModal/BigModal.js +0 -56
  149. package/dist/esm/components/Chart/BarChart.d.ts +0 -23
  150. package/dist/esm/components/Chart/BarChart.d.ts.map +0 -1
  151. package/dist/esm/components/Chart/BarChart.js +0 -110
  152. package/dist/esm/components/Chart/BarList.d.ts +0 -26
  153. package/dist/esm/components/Chart/BarList.d.ts.map +0 -1
  154. package/dist/esm/components/Chart/BarList.js +0 -148
  155. package/dist/esm/components/Chart/ChartError.d.ts +0 -10
  156. package/dist/esm/components/Chart/ChartError.d.ts.map +0 -1
  157. package/dist/esm/components/Chart/ChartError.js +0 -65
  158. package/dist/esm/components/Chart/ChartSkeleton.d.ts +0 -8
  159. package/dist/esm/components/Chart/ChartSkeleton.d.ts.map +0 -1
  160. package/dist/esm/components/Chart/ChartSkeleton.js +0 -19
  161. package/dist/esm/components/Chart/ChartTooltip.d.ts +0 -31
  162. package/dist/esm/components/Chart/ChartTooltip.d.ts.map +0 -1
  163. package/dist/esm/components/Chart/ChartTooltip.js +0 -234
  164. package/dist/esm/components/Chart/ChartTooltipFrame.d.ts +0 -6
  165. package/dist/esm/components/Chart/ChartTooltipFrame.d.ts.map +0 -1
  166. package/dist/esm/components/Chart/ChartTooltipFrame.js +0 -14
  167. package/dist/esm/components/Chart/ChartTooltipGroup.d.ts +0 -11
  168. package/dist/esm/components/Chart/ChartTooltipGroup.d.ts.map +0 -1
  169. package/dist/esm/components/Chart/ChartTooltipGroup.js +0 -23
  170. package/dist/esm/components/Chart/ChartTooltipRow.d.ts +0 -8
  171. package/dist/esm/components/Chart/ChartTooltipRow.d.ts.map +0 -1
  172. package/dist/esm/components/Chart/ChartTooltipRow.js +0 -41
  173. package/dist/esm/components/Chart/LineChart.d.ts +0 -29
  174. package/dist/esm/components/Chart/LineChart.d.ts.map +0 -1
  175. package/dist/esm/components/Chart/LineChart.js +0 -163
  176. package/dist/esm/components/Chart/PieChart.d.ts +0 -62
  177. package/dist/esm/components/Chart/PieChart.d.ts.map +0 -1
  178. package/dist/esm/components/Chart/PieChart.js +0 -195
  179. package/dist/esm/components/Dashboard/ChartComponent.d.ts +0 -4
  180. package/dist/esm/components/Dashboard/ChartComponent.d.ts.map +0 -1
  181. package/dist/esm/components/Dashboard/ChartComponent.js +0 -60
  182. package/dist/esm/components/Dashboard/DashboardFilter.d.ts +0 -38
  183. package/dist/esm/components/Dashboard/DashboardFilter.d.ts.map +0 -1
  184. package/dist/esm/components/Dashboard/DashboardFilter.js +0 -89
  185. package/dist/esm/components/Dashboard/DashboardSection.d.ts +0 -7
  186. package/dist/esm/components/Dashboard/DashboardSection.d.ts.map +0 -1
  187. package/dist/esm/components/Dashboard/DashboardSection.js +0 -22
  188. package/dist/esm/components/Dashboard/DashboardSectionContainer.d.ts +0 -3
  189. package/dist/esm/components/Dashboard/DashboardSectionContainer.d.ts.map +0 -1
  190. package/dist/esm/components/Dashboard/DashboardSectionContainer.js +0 -10
  191. package/dist/esm/components/Dashboard/DataLoader.d.ts +0 -44
  192. package/dist/esm/components/Dashboard/DataLoader.d.ts.map +0 -1
  193. package/dist/esm/components/Dashboard/DataLoader.js +0 -190
  194. package/dist/esm/components/Dashboard/MetricComponent.d.ts +0 -4
  195. package/dist/esm/components/Dashboard/MetricComponent.d.ts.map +0 -1
  196. package/dist/esm/components/Dashboard/MetricComponent.js +0 -133
  197. package/dist/esm/components/Dashboard/TableComponent.d.ts +0 -15
  198. package/dist/esm/components/Dashboard/TableComponent.d.ts.map +0 -1
  199. package/dist/esm/components/Dashboard/TableComponent.js +0 -62
  200. package/dist/esm/components/Dropdown/Dropdown.d.ts +0 -14
  201. package/dist/esm/components/Dropdown/Dropdown.d.ts.map +0 -1
  202. package/dist/esm/components/Dropdown/Dropdown.js +0 -69
  203. package/dist/esm/components/Dropdown/DropdownItem.d.ts +0 -11
  204. package/dist/esm/components/Dropdown/DropdownItem.d.ts.map +0 -1
  205. package/dist/esm/components/Dropdown/DropdownItem.js +0 -37
  206. package/dist/esm/components/Dropdown/index.d.ts +0 -3
  207. package/dist/esm/components/Dropdown/index.d.ts.map +0 -1
  208. package/dist/esm/components/Dropdown/index.js +0 -2
  209. package/dist/esm/components/Modal/Modal.d.ts +0 -15
  210. package/dist/esm/components/Modal/Modal.d.ts.map +0 -1
  211. package/dist/esm/components/Modal/Modal.js +0 -64
  212. package/dist/esm/components/Modal/index.d.ts +0 -2
  213. package/dist/esm/components/Modal/index.d.ts.map +0 -1
  214. package/dist/esm/components/Modal/index.js +0 -1
  215. package/dist/esm/components/QuillCard.d.ts +0 -9
  216. package/dist/esm/components/QuillCard.d.ts.map +0 -1
  217. package/dist/esm/components/QuillCard.js +0 -56
  218. package/dist/esm/components/QuillMultiSelect.d.ts +0 -11
  219. package/dist/esm/components/QuillMultiSelect.d.ts.map +0 -1
  220. package/dist/esm/components/QuillMultiSelect.js +0 -193
  221. package/dist/esm/components/QuillMultiSelectWithCombo.d.ts +0 -11
  222. package/dist/esm/components/QuillMultiSelectWithCombo.d.ts.map +0 -1
  223. package/dist/esm/components/QuillMultiSelectWithCombo.js +0 -215
  224. package/dist/esm/components/QuillSelect.d.ts +0 -6
  225. package/dist/esm/components/QuillSelect.d.ts.map +0 -1
  226. package/dist/esm/components/QuillSelect.js +0 -136
  227. package/dist/esm/components/QuillSelectWithCombo.d.ts +0 -6
  228. package/dist/esm/components/QuillSelectWithCombo.d.ts.map +0 -1
  229. package/dist/esm/components/QuillSelectWithCombo.js +0 -163
  230. package/dist/esm/components/QuillTable.d.ts +0 -31
  231. package/dist/esm/components/QuillTable.d.ts.map +0 -1
  232. package/dist/esm/components/QuillTable.js +0 -261
  233. package/dist/esm/components/ReportBuilder/AddColumnModal.d.ts +0 -34
  234. package/dist/esm/components/ReportBuilder/AddColumnModal.d.ts.map +0 -1
  235. package/dist/esm/components/ReportBuilder/AddColumnModal.js +0 -145
  236. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts +0 -26
  237. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts.map +0 -1
  238. package/dist/esm/components/ReportBuilder/AddLimitPopover.js +0 -36
  239. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts +0 -23
  240. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts.map +0 -1
  241. package/dist/esm/components/ReportBuilder/AddSortPopover.js +0 -73
  242. package/dist/esm/components/ReportBuilder/FilterModal.d.ts +0 -30
  243. package/dist/esm/components/ReportBuilder/FilterModal.d.ts.map +0 -1
  244. package/dist/esm/components/ReportBuilder/FilterModal.js +0 -576
  245. package/dist/esm/components/ReportBuilder/ast.d.ts +0 -523
  246. package/dist/esm/components/ReportBuilder/ast.d.ts.map +0 -1
  247. package/dist/esm/components/ReportBuilder/ast.js +0 -230
  248. package/dist/esm/components/ReportBuilder/bigDateMap.d.ts +0 -7
  249. package/dist/esm/components/ReportBuilder/bigDateMap.d.ts.map +0 -1
  250. package/dist/esm/components/ReportBuilder/bigDateMap.js +0 -687
  251. package/dist/esm/components/ReportBuilder/constants.d.ts +0 -117
  252. package/dist/esm/components/ReportBuilder/constants.d.ts.map +0 -1
  253. package/dist/esm/components/ReportBuilder/constants.js +0 -161
  254. package/dist/esm/components/ReportBuilder/convert.d.ts +0 -65
  255. package/dist/esm/components/ReportBuilder/convert.d.ts.map +0 -1
  256. package/dist/esm/components/ReportBuilder/convert.js +0 -717
  257. package/dist/esm/components/ReportBuilder/operators.d.ts +0 -462
  258. package/dist/esm/components/ReportBuilder/operators.d.ts.map +0 -1
  259. package/dist/esm/components/ReportBuilder/operators.js +0 -581
  260. package/dist/esm/components/ReportBuilder/pivot.d.ts +0 -16
  261. package/dist/esm/components/ReportBuilder/pivot.d.ts.map +0 -1
  262. package/dist/esm/components/ReportBuilder/pivot.js +0 -1
  263. package/dist/esm/components/ReportBuilder/postgres.d.ts +0 -150
  264. package/dist/esm/components/ReportBuilder/postgres.d.ts.map +0 -1
  265. package/dist/esm/components/ReportBuilder/postgres.js +0 -355
  266. package/dist/esm/components/ReportBuilder/schema.d.ts +0 -23
  267. package/dist/esm/components/ReportBuilder/schema.d.ts.map +0 -1
  268. package/dist/esm/components/ReportBuilder/schema.js +0 -1
  269. package/dist/esm/components/ReportBuilder/ui.d.ts +0 -119
  270. package/dist/esm/components/ReportBuilder/ui.d.ts.map +0 -1
  271. package/dist/esm/components/ReportBuilder/ui.js +0 -382
  272. package/dist/esm/components/ReportBuilder/util.d.ts +0 -76
  273. package/dist/esm/components/ReportBuilder/util.d.ts.map +0 -1
  274. package/dist/esm/components/ReportBuilder/util.js +0 -729
  275. package/dist/esm/components/UiComponents.d.ts +0 -221
  276. package/dist/esm/components/UiComponents.d.ts.map +0 -1
  277. package/dist/esm/components/UiComponents.js +0 -571
  278. package/dist/esm/components/selectUtils.d.ts +0 -9
  279. package/dist/esm/components/selectUtils.d.ts.map +0 -1
  280. package/dist/esm/components/selectUtils.js +0 -17
  281. package/dist/esm/contexts/BaseColorContext.d.ts +0 -4
  282. package/dist/esm/contexts/BaseColorContext.d.ts.map +0 -1
  283. package/dist/esm/contexts/BaseColorContext.js +0 -3
  284. package/dist/esm/contexts/HoveredValueContext.d.ts +0 -8
  285. package/dist/esm/contexts/HoveredValueContext.d.ts.map +0 -1
  286. package/dist/esm/contexts/HoveredValueContext.js +0 -5
  287. package/dist/esm/contexts/RootStylesContext.d.ts +0 -4
  288. package/dist/esm/contexts/RootStylesContext.d.ts.map +0 -1
  289. package/dist/esm/contexts/RootStylesContext.js +0 -3
  290. package/dist/esm/contexts/SelectedValueContext.d.ts +0 -8
  291. package/dist/esm/contexts/SelectedValueContext.d.ts.map +0 -1
  292. package/dist/esm/contexts/SelectedValueContext.js +0 -6
  293. package/dist/esm/contexts/index.d.ts +0 -5
  294. package/dist/esm/contexts/index.d.ts.map +0 -1
  295. package/dist/esm/contexts/index.js +0 -4
  296. package/dist/esm/hooks/index.d.ts +0 -6
  297. package/dist/esm/hooks/index.d.ts.map +0 -1
  298. package/dist/esm/hooks/index.js +0 -5
  299. package/dist/esm/hooks/useAstToFilterTree.d.ts +0 -11
  300. package/dist/esm/hooks/useAstToFilterTree.d.ts.map +0 -1
  301. package/dist/esm/hooks/useAstToFilterTree.js +0 -24
  302. package/dist/esm/hooks/useDashboard.d.ts +0 -7
  303. package/dist/esm/hooks/useDashboard.d.ts.map +0 -1
  304. package/dist/esm/hooks/useDashboard.js +0 -69
  305. package/dist/esm/hooks/useExport.d.ts +0 -6
  306. package/dist/esm/hooks/useExport.d.ts.map +0 -1
  307. package/dist/esm/hooks/useExport.js +0 -125
  308. package/dist/esm/hooks/useFormat.d.ts +0 -5
  309. package/dist/esm/hooks/useFormat.d.ts.map +0 -1
  310. package/dist/esm/hooks/useFormat.js +0 -25
  311. package/dist/esm/hooks/useInternalState.d.ts +0 -4
  312. package/dist/esm/hooks/useInternalState.d.ts.map +0 -1
  313. package/dist/esm/hooks/useInternalState.js +0 -14
  314. package/dist/esm/hooks/useOnClickOutside.d.ts +0 -3
  315. package/dist/esm/hooks/useOnClickOutside.d.ts.map +0 -1
  316. package/dist/esm/hooks/useOnClickOutside.js +0 -18
  317. package/dist/esm/hooks/useOnWindowResize.d.ts +0 -5
  318. package/dist/esm/hooks/useOnWindowResize.d.ts.map +0 -1
  319. package/dist/esm/hooks/useOnWindowResize.js +0 -14
  320. package/dist/esm/hooks/useQuill.d.ts +0 -37
  321. package/dist/esm/hooks/useQuill.d.ts.map +0 -1
  322. package/dist/esm/hooks/useQuill.js +0 -182
  323. package/dist/esm/hooks/useSelectOnKeyDown.d.ts +0 -3
  324. package/dist/esm/hooks/useSelectOnKeyDown.d.ts.map +0 -1
  325. package/dist/esm/hooks/useSelectOnKeyDown.js +0 -63
  326. package/dist/esm/hooks/useTheme.d.ts +0 -7
  327. package/dist/esm/hooks/useTheme.d.ts.map +0 -1
  328. package/dist/esm/hooks/useTheme.js +0 -10
  329. package/dist/esm/index.d.ts +0 -29
  330. package/dist/esm/index.d.ts.map +0 -1
  331. package/dist/esm/index.js +0 -16
  332. package/dist/esm/internals/ReportBuilder/PivotForm.d.ts +0 -28
  333. package/dist/esm/internals/ReportBuilder/PivotForm.d.ts.map +0 -1
  334. package/dist/esm/internals/ReportBuilder/PivotForm.js +0 -62
  335. package/dist/esm/internals/ReportBuilder/PivotList.d.ts +0 -39
  336. package/dist/esm/internals/ReportBuilder/PivotList.d.ts.map +0 -1
  337. package/dist/esm/internals/ReportBuilder/PivotList.js +0 -89
  338. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +0 -146
  339. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +0 -1
  340. package/dist/esm/internals/ReportBuilder/PivotModal.js +0 -1210
  341. package/dist/esm/lib/font.d.ts +0 -14
  342. package/dist/esm/lib/font.d.ts.map +0 -1
  343. package/dist/esm/lib/font.js +0 -13
  344. package/dist/esm/lib/index.d.ts +0 -4
  345. package/dist/esm/lib/index.d.ts.map +0 -1
  346. package/dist/esm/lib/index.js +0 -3
  347. package/dist/esm/lib/inputTypes.d.ts +0 -21
  348. package/dist/esm/lib/inputTypes.d.ts.map +0 -1
  349. package/dist/esm/lib/inputTypes.js +0 -55
  350. package/dist/esm/lib/utils.d.ts +0 -10
  351. package/dist/esm/lib/utils.d.ts.map +0 -1
  352. package/dist/esm/lib/utils.js +0 -35
  353. package/dist/esm/models/Columns.d.ts +0 -12
  354. package/dist/esm/models/Columns.d.ts.map +0 -1
  355. package/dist/esm/models/Columns.js +0 -1
  356. package/dist/esm/models/Filter.d.ts +0 -118
  357. package/dist/esm/models/Filter.d.ts.map +0 -1
  358. package/dist/esm/models/Filter.js +0 -98
  359. package/dist/esm/models/Pagination.d.ts +0 -10
  360. package/dist/esm/models/Pagination.d.ts.map +0 -1
  361. package/dist/esm/models/Pagination.js +0 -1
  362. package/dist/esm/models/Pivots.d.ts +0 -2
  363. package/dist/esm/models/Pivots.d.ts.map +0 -1
  364. package/dist/esm/models/Pivots.js +0 -1
  365. package/dist/esm/models/Report.d.ts +0 -103
  366. package/dist/esm/models/Report.d.ts.map +0 -1
  367. package/dist/esm/models/Report.js +0 -1
  368. package/dist/esm/models/Tables.d.ts +0 -8
  369. package/dist/esm/models/Tables.d.ts.map +0 -1
  370. package/dist/esm/models/Tables.js +0 -1
  371. package/dist/esm/utils/aggregate.d.ts +0 -4
  372. package/dist/esm/utils/aggregate.d.ts.map +0 -1
  373. package/dist/esm/utils/aggregate.js +0 -422
  374. package/dist/esm/utils/astFilterProcessing.d.ts +0 -36
  375. package/dist/esm/utils/astFilterProcessing.d.ts.map +0 -1
  376. package/dist/esm/utils/astFilterProcessing.js +0 -8084
  377. package/dist/esm/utils/astProcessing.d.ts +0 -26
  378. package/dist/esm/utils/astProcessing.d.ts.map +0 -1
  379. package/dist/esm/utils/astProcessing.js +0 -254
  380. package/dist/esm/utils/axisFormatter.d.ts +0 -20
  381. package/dist/esm/utils/axisFormatter.d.ts.map +0 -1
  382. package/dist/esm/utils/axisFormatter.js +0 -179
  383. package/dist/esm/utils/color.d.ts +0 -44
  384. package/dist/esm/utils/color.d.ts.map +0 -1
  385. package/dist/esm/utils/color.js +0 -425
  386. package/dist/esm/utils/columnProcessing.d.ts +0 -13
  387. package/dist/esm/utils/columnProcessing.d.ts.map +0 -1
  388. package/dist/esm/utils/columnProcessing.js +0 -260
  389. package/dist/esm/utils/constants.d.ts +0 -2
  390. package/dist/esm/utils/constants.d.ts.map +0 -1
  391. package/dist/esm/utils/constants.js +0 -1
  392. package/dist/esm/utils/crypto.d.ts +0 -2
  393. package/dist/esm/utils/crypto.d.ts.map +0 -1
  394. package/dist/esm/utils/crypto.js +0 -10
  395. package/dist/esm/utils/csv.d.ts +0 -6
  396. package/dist/esm/utils/csv.d.ts.map +0 -1
  397. package/dist/esm/utils/csv.js +0 -78
  398. package/dist/esm/utils/dashboard.d.ts +0 -13
  399. package/dist/esm/utils/dashboard.d.ts.map +0 -1
  400. package/dist/esm/utils/dashboard.js +0 -171
  401. package/dist/esm/utils/dataFetcher.d.ts +0 -3
  402. package/dist/esm/utils/dataFetcher.d.ts.map +0 -1
  403. package/dist/esm/utils/dataFetcher.js +0 -199
  404. package/dist/esm/utils/dataProcessing.d.ts +0 -10
  405. package/dist/esm/utils/dataProcessing.d.ts.map +0 -1
  406. package/dist/esm/utils/dataProcessing.js +0 -144
  407. package/dist/esm/utils/dates.d.ts +0 -20
  408. package/dist/esm/utils/dates.d.ts.map +0 -1
  409. package/dist/esm/utils/dates.js +0 -95
  410. package/dist/esm/utils/error.d.ts +0 -5
  411. package/dist/esm/utils/error.d.ts.map +0 -1
  412. package/dist/esm/utils/error.js +0 -8
  413. package/dist/esm/utils/errorProcessing.d.ts +0 -2
  414. package/dist/esm/utils/errorProcessing.d.ts.map +0 -1
  415. package/dist/esm/utils/errorProcessing.js +0 -5
  416. package/dist/esm/utils/filterConstants.d.ts +0 -34
  417. package/dist/esm/utils/filterConstants.d.ts.map +0 -1
  418. package/dist/esm/utils/filterConstants.js +0 -33
  419. package/dist/esm/utils/filterProcessing.d.ts +0 -10
  420. package/dist/esm/utils/filterProcessing.d.ts.map +0 -1
  421. package/dist/esm/utils/filterProcessing.js +0 -232
  422. package/dist/esm/utils/getDomain.d.ts +0 -8
  423. package/dist/esm/utils/getDomain.d.ts.map +0 -1
  424. package/dist/esm/utils/getDomain.js +0 -52
  425. package/dist/esm/utils/logging.d.ts +0 -2
  426. package/dist/esm/utils/logging.d.ts.map +0 -1
  427. package/dist/esm/utils/logging.js +0 -7
  428. package/dist/esm/utils/merge.d.ts +0 -2
  429. package/dist/esm/utils/merge.d.ts.map +0 -1
  430. package/dist/esm/utils/merge.js +0 -18
  431. package/dist/esm/utils/monacoConfig.d.ts +0 -21
  432. package/dist/esm/utils/monacoConfig.d.ts.map +0 -1
  433. package/dist/esm/utils/monacoConfig.js +0 -319
  434. package/dist/esm/utils/paginationProcessing.d.ts +0 -5
  435. package/dist/esm/utils/paginationProcessing.d.ts.map +0 -1
  436. package/dist/esm/utils/paginationProcessing.js +0 -25
  437. package/dist/esm/utils/parserBigQuery.d.ts +0 -6
  438. package/dist/esm/utils/parserBigQuery.d.ts.map +0 -1
  439. package/dist/esm/utils/parserBigQuery.js +0 -52
  440. package/dist/esm/utils/parserPostgres.d.ts +0 -3
  441. package/dist/esm/utils/parserPostgres.d.ts.map +0 -1
  442. package/dist/esm/utils/parserPostgres.js +0 -37
  443. package/dist/esm/utils/pivotConstructor.d.ts +0 -7
  444. package/dist/esm/utils/pivotConstructor.d.ts.map +0 -1
  445. package/dist/esm/utils/pivotConstructor.js +0 -151
  446. package/dist/esm/utils/pivotProcessing.d.ts +0 -17
  447. package/dist/esm/utils/pivotProcessing.d.ts.map +0 -1
  448. package/dist/esm/utils/pivotProcessing.js +0 -132
  449. package/dist/esm/utils/queryConstructor.d.ts +0 -7
  450. package/dist/esm/utils/queryConstructor.d.ts.map +0 -1
  451. package/dist/esm/utils/queryConstructor.js +0 -223
  452. package/dist/esm/utils/report.d.ts +0 -10
  453. package/dist/esm/utils/report.d.ts.map +0 -1
  454. package/dist/esm/utils/report.js +0 -174
  455. package/dist/esm/utils/schema.d.ts +0 -6
  456. package/dist/esm/utils/schema.d.ts.map +0 -1
  457. package/dist/esm/utils/schema.js +0 -153
  458. package/dist/esm/utils/styles.d.ts +0 -17
  459. package/dist/esm/utils/styles.d.ts.map +0 -1
  460. package/dist/esm/utils/styles.js +0 -16
  461. package/dist/esm/utils/tableProcessing.d.ts +0 -45
  462. package/dist/esm/utils/tableProcessing.d.ts.map +0 -1
  463. package/dist/esm/utils/tableProcessing.js +0 -293
  464. package/dist/esm/utils/textProcessing.d.ts +0 -6
  465. package/dist/esm/utils/textProcessing.d.ts.map +0 -1
  466. package/dist/esm/utils/textProcessing.js +0 -49
  467. package/dist/esm/utils/validation.d.ts +0 -9
  468. package/dist/esm/utils/validation.d.ts.map +0 -1
  469. package/dist/esm/utils/validation.js +0 -20
  470. package/dist/esm/utils/valueFormatter.d.ts +0 -29
  471. package/dist/esm/utils/valueFormatter.d.ts.map +0 -1
  472. package/dist/esm/utils/valueFormatter.js +0 -342
  473. package/dist/esm/utils/width.d.ts +0 -12
  474. package/dist/esm/utils/width.d.ts.map +0 -1
  475. package/dist/esm/utils/width.js +0 -21
@@ -1,3266 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useContext, useEffect, useRef, useState, } from 'react';
3
- import { DEFAULT_TAB_OPTIONS, MemoizedButton, MemoizedCheckbox, MemoizedDeleteButton, MemoizedHeader, MemoizedLabel, MemoizedSecondaryButton, MemoizedText, MemoizedPopover, QuillTabs, MemoizedModal, QuillChartBuilderInputRowContainer, QuillChartBuilderInputColumnContainer, MemoizedSubHeader, QuillErrorMessageComponent, QuillPivotRowContainer, QuillPivotColumnContainer, QuillColumnSearchEmptyState, QuillChartBuilderFormContainer, QuillLoadingComponent, QuillTableSQLEditorComponent, } from './components/UiComponents';
4
- import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core';
5
- import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable, } from '@dnd-kit/sortable';
6
- import { CSS as DND_CSS } from '@dnd-kit/utilities';
7
- import { ClientContext, CustomFieldContext, SchemaContext, ThemeContext, } from './Context';
8
- import { extractColumnish, getTableAliases, getTableNames, isBoolColumnType, isDateishColumnType, isNumericColumnType, isTextColumnType, } from './components/ReportBuilder/ast';
9
- import { ChartBuilderWithModal, createInitialFormData } from './ChartBuilder';
10
- import { QuillTextInput } from './components/UiComponents';
11
- import { QuillSidebar, CustomContainer, QuillSelectColumn, QuillDraggableColumn, QuillSidebarHeading, QuillFilterPopover, QuillSortPopover, QuillLimitPopover, FilterPopoverWrapper, } from './components/ReportBuilder/ui';
12
- import { generateCurrentPeriodPostgres, generateEqualsPostgres, generateLastNPeriodsPostgres, generatePreviousPeriodPostgres, } from './components/ReportBuilder/postgres';
13
- import { convertBigQuery, convertGroupBy, convertRemoveSimpleParentheses, convertStringComparison, convertWildcardColumns, convertUnaryToBinary, } from './components/ReportBuilder/convert';
14
- import { deepCopy, formatDateComparisonNode, getDateFilterInfo, isColumnComparison, isDateTruncEquals, isInTheLastInterval, isNodeEmptyCollection, isTheCurrentInterval, isThePreviousInterval, showNodeAsRow, removeNonSelectedTableReferences, isEquals, } from './components/ReportBuilder/util';
15
- import { getDefaultOperatorSubtrees, OPERATOR_GROUPS, } from './components/ReportBuilder/operators';
16
- import { hashCode } from './utils/crypto';
17
- import { defaultAST, defaultBoolComparison, defaultColumn, defaultEntry, defaultNumericComparison, defaultTable, defaultVariant, } from './components/ReportBuilder/constants';
18
- import AddColumnModal from './components/ReportBuilder/AddColumnModal';
19
- import { AddSortPopover, SortSentence, } from './components/ReportBuilder/AddSortPopover';
20
- import { PivotModal, generatePivotTable, } from './internals/ReportBuilder/PivotModal';
21
- import { snakeAndCamelCaseToTitleCase } from './utils/textProcessing';
22
- import { AddLimitPopover, LimitSentence, } from './components/ReportBuilder/AddLimitPopover';
23
- import { updateFirstChildWidth } from './utils/width';
24
- import { QuillSelectComponent } from './components/QuillSelect';
25
- import { QuillCard } from './components/QuillCard';
26
- import { getData } from './utils/dataFetcher';
27
- import { DATE_FORMAT_TYPES, quillFormat } from './utils/valueFormatter';
28
- import { getPossiblePivotFieldOptions, pivotToSql, } from './utils/pivotProcessing';
29
- import { getUniqueValuesByColumns, getDateRangeByColumns, getCountsByColumns, fetchTableByQuery, } from './utils/tableProcessing';
30
- import { useQuill } from './hooks/useQuill';
31
- import { getDataFromCloud } from './utils/dataFetcher';
32
- import { convertColumnInfoToColumnInternal, convertPostgresColumn, } from './utils/columnProcessing';
33
- import { getSelectFromAST, processApostrophe, processStarColumn, } from './utils/astProcessing';
34
- import PivotForm from './internals/ReportBuilder/PivotForm';
35
- import { getSchemaInfoWithCustomFields } from './utils/schema';
36
- import { getDateBucketFromRange } from './utils/dates';
37
- import FilterModal from './components/ReportBuilder/FilterModal';
38
- import { filterToAst, filterTreeToAst, } from './utils/astFilterProcessing';
39
- import useAstToFilterTree from './hooks/useAstToFilterTree';
40
- import { filterSentence } from './utils/filterProcessing';
41
- import { QuillMultiSelectComponentWithCombo } from './components/QuillMultiSelectWithCombo';
42
- import { shouldFetchMore, DEFAULT_PAGINATION, shouldSortInMemory, } from './utils/paginationProcessing';
43
- import { EMPTY_REPORT, formatRowsFromReport } from './utils/report';
44
- export const QUILL_SERVER = (typeof process !== 'undefined' && process?.env?.QUILL_SERVER_HOST) ||
45
- 'https://quill-344421.uc.r.appspot.com';
46
- /**
47
- * Quill Report Builder
48
- *
49
- * Allows non-technical users to build SQL queries using either UI or AI and
50
- * then edit them on the fly. Once users have constructed a query they like,
51
- * they can click a button and add that report to their dashboard or export it
52
- * as a CSV.
53
- *
54
- * @example
55
- * ```js
56
- * // Usage without custom components
57
- * <ReportBuilder />
58
- * ```
59
- *
60
- * @example
61
- * ```js
62
- * // You can also pass your own components
63
- * <ReportBuilder
64
- * initialTableName="transactions"
65
- * TableComponent={MyTable}
66
- * SelectComponent={MySelect}
67
- * ButtonComponent={MyButton}
68
- * PopoverComponent={MyPopover}
69
- * TextInputComponent={MyTextInput}
70
- * containerStyle={{ backgroundColor: 'white', padding: '10px' }}
71
- * />
72
- * ```
73
- *
74
- * ### Report Builder API
75
- * @see https://docs.quillsql.com/components/report-builder
76
- */
77
- export default function ReportBuilder({ initialTableName = '', onSubmitEditReport = () => void null, onSubmitCreateReport = () => void null, destinationDashboard = undefined, organizationName = '', ButtonComponent = MemoizedButton, SecondaryButtonComponent = MemoizedSecondaryButton, DeleteButtonComponent = MemoizedDeleteButton, ModalComponent = MemoizedModal, TextInputComponent = QuillTextInput, SelectComponent = QuillSelectComponent, MultiSelectComponent = QuillMultiSelectComponentWithCombo, TableComponent = QuillTableSQLEditorComponent, PopoverComponent = MemoizedPopover, TabsComponent = QuillTabs, CheckboxComponent = MemoizedCheckbox, SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectColumnComponent = QuillSelectColumn, DraggableColumnComponent = QuillDraggableColumn, SidebarHeadingComponent = QuillSidebarHeading, FilterPopoverComponent = QuillFilterPopover, SortPopoverComponent = QuillSortPopover, LimitPopoverComponent = QuillLimitPopover, CardComponent = QuillCard, LabelComponent = MemoizedLabel, HeaderComponent = MemoizedHeader, SubHeaderComponent = MemoizedSubHeader, TextComponent = MemoizedText, ErrorMessageComponent = QuillErrorMessageComponent, ChartBuilderInputRowContainer = QuillChartBuilderInputRowContainer, ChartBuilderInputColumnContainer = QuillChartBuilderInputColumnContainer, PivotRowContainer = QuillPivotRowContainer, PivotColumnContainer = QuillPivotColumnContainer, LoadingComponent = QuillLoadingComponent, ColumnSearchEmptyState = QuillColumnSearchEmptyState, ChartBuilderFormContainer = QuillChartBuilderFormContainer, ChartBuilderModalComponent = MemoizedModal, isAdminEnabled = false, isAIEnabled = true, showChartBuilderTableFormatOptions = true, containerStyle, className, pivotRecommendationsEnabled = true, reportId, hideCopySQL = true, isChartBuilderHorizontalView = true, onClickChartElement, }) {
78
- const { data: report } = useQuill(reportId || '');
79
- const [aiPrompt, setAiPrompt] = useState('');
80
- const [errorMessage, setErrorMessage] = useState('');
81
- const [baseAst, setBaseAst] = useState(null);
82
- const [formData, setFormData] = useState(null);
83
- const [orderedColumnNames, setOrderedColumnNames] = useState([]);
84
- const [selectedColumns, setSelectedColumns] = useState([]);
85
- const [selectedOrderedColumns, setSelectedOrderedColumns] = useState([]);
86
- const [schema, setSchema] = useContext(SchemaContext);
87
- const [activeQuery, setActiveQuery] = useState('');
88
- const [activeEditItem, setActiveEditItem] = useState(null);
89
- const [activePath, setActivePath] = useState(null);
90
- const [openPopover, setOpenPopover] = useState(null);
91
- const [loading, setLoading] = useState(!!initialTableName);
92
- const [loadingSchema, setLoadingSchema] = useState(false);
93
- const [isChartBuilderOpen, setIsChartBuilderOpen] = useState(false);
94
- const [isPending, setIsPending] = useState(false);
95
- const [isCopying, setIsCopying] = useState(false);
96
- const [dataDisplayed, setDataDisplayed] = useState(false);
97
- const [rows, setRows] = useState([]);
98
- const [formattedRows, setFormattedRows] = useState([]);
99
- const [columns, setColumns] = useState([]);
100
- const [tempReport, setTempReport] = useState(EMPTY_REPORT);
101
- const [topLevelBinaryOperator, setTopLevelBinaryOperator] = useState('AND');
102
- const [uniqueValues, setUniqueValues] = useState({});
103
- const [pivot, setPivot] = useState(null);
104
- const [pivotData, setPivotData] = useState(null);
105
- const [createdPivots, setCreatedPivots] = useState([]);
106
- const [recommendedPivots, setRecommendedPivots] = useState([]);
107
- const [pivotPopUpTitle, setPivotPopUpTitle] = useState('Add pivot');
108
- const [showPivotPopover, setShowPivotPopover] = useState(false);
109
- const [isEditingPivot, setIsEditingPivot] = useState(false);
110
- const [initialChartLoad, setInitialChartLoad] = useState(false);
111
- const [askedAQuestion, setAskedAQuestion] = useState(false);
112
- const [selectedPivotIndex, setSelectedPivotIndex] = useState(-1);
113
- const [initialLoad, setInitialLoad] = useState(!!initialTableName || !!reportId);
114
- const [currentTable, setCurrentTable] = useState(initialTableName || '');
115
- const parentRef = useRef(null);
116
- const askAIContainerRef = useRef(null);
117
- const askAILoadingContainerRef = useRef(null);
118
- const [askAIInputWidth, setAskAIInputWidth] = useState(-1);
119
- const [askAILoadingContainerWidth, setAskAILoadingContainerWidth] = useState(-1);
120
- const [theme] = useContext(ThemeContext);
121
- const [pivotRowField, setPivotRowField] = useState(undefined);
122
- const [pivotColumnField, setPivotColumnField] = useState(undefined);
123
- const [pivotValueField, setPivotValueField] = useState(undefined);
124
- const [pivotAggregation, setPivotAggregation] = useState(undefined);
125
- const [dateRanges, setDateRanges] = useState(null);
126
- const [client] = useContext(ClientContext);
127
- // JANK: This is temp and stupid
128
- const [overrideRecommendations, setOverrideRecommendations] = useState(true);
129
- const [customFields, setCustomFields] = useContext(CustomFieldContext);
130
- const [fieldValuesMap, setFieldValuesMap] = useState({}); // Mapping of unique values per field, used in string filter 'in' and 'not in'
131
- const filterTree = useAstToFilterTree(formData, client); // Stores the state of filters
132
- useEffect(() => {
133
- if (!client) {
134
- return;
135
- }
136
- if (client.publicKey === '663416663aa9bc716e59a89d') {
137
- setOverrideRecommendations(false);
138
- }
139
- if (!loadingSchema) {
140
- fetchSchema();
141
- }
142
- }, [client]);
143
- useEffect(() => {
144
- updateFirstChildWidth(askAIContainerRef, setAskAIInputWidth, { gap: 12 });
145
- updateFirstChildWidth(askAILoadingContainerRef, setAskAILoadingContainerWidth, { gap: 12 });
146
- }, [dataDisplayed]);
147
- // Whenever unique values changes, update the fieldValuesMap, used in FilterModals
148
- useEffect(() => {
149
- const tables = getTableNames(baseAst);
150
- const table = tables.length === 1 ? tables[0] : initialTableName;
151
- const newFieldValues = {};
152
- if (uniqueValues[table]) {
153
- for (const field of Object.keys(uniqueValues[table])) {
154
- newFieldValues[field] = [];
155
- for (const value of Object.keys(uniqueValues[table][field])) {
156
- newFieldValues[field]?.push(value);
157
- }
158
- }
159
- }
160
- setFieldValuesMap(newFieldValues);
161
- }, [uniqueValues]);
162
- useEffect(() => {
163
- // Since the TextInput component takes a required numeric width parameter,
164
- // we dynamically calculate the width of this component here.
165
- function handleResize() {
166
- updateFirstChildWidth(askAIContainerRef, setAskAIInputWidth, { gap: 12 });
167
- updateFirstChildWidth(askAILoadingContainerRef, setAskAILoadingContainerWidth, { gap: 12 });
168
- }
169
- handleResize();
170
- window.addEventListener('resize', handleResize);
171
- return () => {
172
- window.removeEventListener('resize', handleResize);
173
- };
174
- }, []);
175
- const updatePivot = async (changeField, fieldKey) => {
176
- const newPivot = pivot;
177
- setTableLoading(true);
178
- // @ts-ignore
179
- newPivot[fieldKey] = changeField;
180
- if (fieldKey === 'rowField') {
181
- // check to see if the new rowField value is a date field
182
- const column = columns.find((c) => c.field === changeField);
183
- if (column?.jsType === 'date') {
184
- newPivot.rowFieldType = 'date';
185
- newPivot.sort = 'true';
186
- newPivot.sortField = changeField;
187
- newPivot.sortFieldType = column.format;
188
- newPivot.sortDirection = 'ASC';
189
- }
190
- else {
191
- newPivot.rowFieldType = 'string';
192
- newPivot.sort = undefined;
193
- }
194
- }
195
- let dateBucket = undefined;
196
- const tempDateRange = dateRanges && dateRanges[newPivot.rowField];
197
- if (tempDateRange) {
198
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
199
- }
200
- let distinctValuesForQuery = {};
201
- if (pivot.columnField) {
202
- distinctValuesForQuery = await getUniqueValuesByColumns([
203
- {
204
- field: pivot.columnField,
205
- label: pivot.columnField,
206
- format: 'string',
207
- },
208
- ], activeQuery, [], client, customFields);
209
- }
210
- const pivotedData = await generatePivotTable(pivot, rows, undefined, false, -1, undefined, dateBucket, tempReport, client, distinctValuesForQuery);
211
- setPivotData(pivotedData || []);
212
- const formattedRows = formatRows(pivotedData.rows, columns, true, newPivot.aggregationType);
213
- setPivot(newPivot);
214
- setFormattedRows(formattedRows);
215
- setTableLoading(false);
216
- };
217
- const enforceOrderOnColumns = (columnNames) => {
218
- if (pivot) {
219
- const rowName = pivot.rowField;
220
- const sortFn = (a, b) => a === rowName ? -1 : b === rowName ? 1 : 0;
221
- const columnsInPivot = getColumnsInPivotExpanded();
222
- return columnNames
223
- .sort(sortFn)
224
- .filter((c) => columnsInPivot.includes(c));
225
- }
226
- // make the columnNames match the order of the selectedOrderedColumns
227
- return columnNames.sort((a, b) => selectedOrderedColumns.indexOf(a) - selectedOrderedColumns.indexOf(b));
228
- // return columnNames;
229
- };
230
- const clearAllState = () => {
231
- // We're trying to not block the main thread while resetting all the state.
232
- // This shouldn't be an issue since the dispatches shouldn't block, but
233
- // this seems to work for now. ¯\_(ツ)_/¯
234
- setTimeout(() => {
235
- setAskedAQuestion(false);
236
- setAiPrompt('');
237
- setBaseAst(null);
238
- setFormData(null);
239
- setSelectedColumns([]);
240
- setActiveQuery('');
241
- setActiveEditItem(null);
242
- setActivePath(null);
243
- setOpenPopover(null);
244
- setLoading(false);
245
- setIsPending(false);
246
- setDataDisplayed(false);
247
- setRows([]);
248
- setColumns([]);
249
- setTopLevelBinaryOperator('AND');
250
- setErrorMessage('');
251
- setFormattedRows([]);
252
- // setUniqueValues({});
253
- setPivot(null);
254
- setPivotData(null);
255
- setRecommendedPivots([]);
256
- }, 0);
257
- };
258
- useEffect(() => {
259
- if (!client) {
260
- return;
261
- }
262
- if (!initialLoad && client.publicKey) {
263
- clearAllState();
264
- }
265
- }, [client]);
266
- useEffect(() => {
267
- if (activePath !== null) {
268
- // update the modal with the new subtree
269
- setActiveEditItem(getByKey(formData, activePath));
270
- }
271
- }, [formData]);
272
- const formatRows = (rows, columns, pivot, aggregationType) => {
273
- const copiedRows = deepCopy(rows);
274
- if (pivot) {
275
- const formattedRows = copiedRows.map((row) => {
276
- const formattedRow = row;
277
- Object.keys(row).forEach((key) => {
278
- const column = columns.find((c) => c.field === key);
279
- let format = 'string';
280
- if (!column) {
281
- format =
282
- aggregationType === 'count'
283
- ? 'whole_number'
284
- : 'two_decimal_places';
285
- }
286
- else {
287
- format = DATE_FORMAT_TYPES.includes(column.format)
288
- ? 'MMM_yyyy'
289
- : 'string';
290
- }
291
- const formattedValue = quillFormat({
292
- value: row[key],
293
- format,
294
- });
295
- formattedRow[key] = formattedValue;
296
- });
297
- return formattedRow;
298
- });
299
- return formattedRows;
300
- }
301
- else {
302
- const formattedRows = copiedRows.map((row) => {
303
- return columns.reduce((formattedRow, column) => {
304
- // Apply the format function to each field in the row
305
- const formattedValue = quillFormat({
306
- value: row[column.field],
307
- format: column.format,
308
- });
309
- formattedRow[column.field] = formattedValue;
310
- return formattedRow;
311
- }, {});
312
- });
313
- return formattedRows;
314
- }
315
- };
316
- const getByKey = (formData, path) => {
317
- if (!path)
318
- return deepCopy(formData);
319
- // Function to immutably update or delete nodes based on their path
320
- const paths = path.split('.');
321
- let current = deepCopy(formData);
322
- for (let i = 0; i < paths.length; i++) {
323
- if (current[paths[i]]) {
324
- current = current[paths[i]];
325
- }
326
- }
327
- return current;
328
- };
329
- const copySQLToClipboard = () => {
330
- let query = activeQuery;
331
- if (pivot) {
332
- query = pivotToSql(pivot, activeQuery, columns);
333
- }
334
- setIsCopying(true);
335
- navigator.clipboard.writeText(query);
336
- setTimeout(() => setIsCopying(false), 800);
337
- };
338
- const clearCheckboxes = () => {
339
- const checkboxes = uniqueValues;
340
- const newValues = {};
341
- for (const table of Object.keys(checkboxes)) {
342
- newValues[table] = {};
343
- for (const column of Object.keys(checkboxes[table])) {
344
- newValues[table][column] = {};
345
- for (const variant of Object.keys(checkboxes[table][column])) {
346
- newValues[table][column][variant] = false;
347
- }
348
- }
349
- }
350
- setUniqueValues(newValues);
351
- };
352
- const fetchSqlQuery = async (ast, formData, fetchData = true) => {
353
- if (fetchData) {
354
- setLoading(true);
355
- }
356
- setErrorMessage('');
357
- try {
358
- const where = formData ? formData : ast?.where || null;
359
- const response = await fetch(`${QUILL_SERVER}/sqlify`, {
360
- method: 'POST',
361
- headers: {
362
- 'Content-Type': 'application/json',
363
- },
364
- body: JSON.stringify({
365
- ast: { ...ast, where },
366
- publicKey: client.publicKey,
367
- useNewNodeSql: true, // new flag
368
- }),
369
- });
370
- const data = await response.json();
371
- setActiveQuery(data.query);
372
- if (fetchData) {
373
- fetchUponChange(ast, formData);
374
- }
375
- return data.query;
376
- }
377
- catch (error) {
378
- setLoading(false);
379
- console.error(error);
380
- }
381
- };
382
- const getUniqueStringValues = async (columns, tableName) => {
383
- const convertedStringColumns = columns
384
- .filter((column) => {
385
- return isTextColumnType(column.fieldType);
386
- })
387
- .map((column) => convertColumnInfoToColumnInternal(column));
388
- const stringNames = convertedStringColumns.map((column) => column.field);
389
- const smallStringColumns = await getCountsByColumns(convertedStringColumns, `Select ${stringNames.join(', ')} from ${tableName}`, client, customFields);
390
- const smallStringNames = smallStringColumns.map((column) => column.field);
391
- const newUniqueValues = await getUniqueValuesByColumns(smallStringColumns, `Select ${smallStringNames.join(', ')} from ${tableName}`, [], client, customFields);
392
- const joinedUniqueValues = deepCopy(uniqueValues);
393
- joinedUniqueValues[tableName] = newUniqueValues;
394
- return joinedUniqueValues;
395
- };
396
- const getDateRanges = async (columns, tableName) => {
397
- const dateColumns = columns.filter((column) => {
398
- return column.fieldType === 'date';
399
- });
400
- if (dateColumns.length === 0) {
401
- return {};
402
- }
403
- const dateColumnNames = dateColumns.map((column) => {
404
- //@ts-ignore
405
- return column.field || column.name;
406
- });
407
- const dateRanges = await getDateRangeByColumns(dateColumns, `Select ${dateColumnNames.join(', ')} from ${tableName}`, client, customFields);
408
- return dateRanges;
409
- };
410
- // It's just like getColumnsInPivot but we expand the columnField
411
- // if there is one to include all the variants just like it would
412
- // show up in the table. (eg. category -> ...[Fuel, Food, Other])
413
- const getColumnsInPivotExpanded = () => {
414
- if (!pivot)
415
- return [];
416
- const tables = getTableNames(baseAst);
417
- if (tables.length !== 1)
418
- return [];
419
- const result = [];
420
- const table = tables[0];
421
- const { valueField, rowField, columnField } = pivot;
422
- if (columnField &&
423
- uniqueValues[table] &&
424
- uniqueValues[table][columnField]) {
425
- result.push(...Object.keys(uniqueValues[table][columnField]));
426
- }
427
- result.push(valueField, rowField);
428
- return result.filter(Boolean);
429
- };
430
- const loadTable = async (tables) => {
431
- if (!tables)
432
- return;
433
- setLoading(true);
434
- const tableInfo = tables.find((tableInfo) => tableInfo.name === initialTableName);
435
- if (tableInfo) {
436
- const newUniqueValues = await getUniqueStringValues(tableInfo.columns, initialTableName);
437
- if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
438
- setUniqueValues(newUniqueValues);
439
- }
440
- const dateRangesTemp = await getDateRanges(tableInfo.columns, initialTableName);
441
- setDateRanges(dateRangesTemp);
442
- }
443
- const columnsForTable = tables
444
- .find((t) => t.name === initialTableName)
445
- ?.columns.map((c) => c.name)
446
- .sort((a, b) => {
447
- const aIsId = a.endsWith('.id') ||
448
- a.endsWith('_id') ||
449
- a.endsWith('Id') ||
450
- a === 'id';
451
- const bIsId = b.endsWith('.id') ||
452
- b.endsWith('_id') ||
453
- b.endsWith('Id') ||
454
- b === 'id';
455
- if (aIsId && !bIsId)
456
- return 1;
457
- if (bIsId && !aIsId)
458
- return -1;
459
- return 0;
460
- });
461
- await handleAsk(`get ${columnsForTable} from ${initialTableName}`);
462
- setInitialLoad(false);
463
- };
464
- const fetchSchema = async () => {
465
- try {
466
- setLoadingSchema(true);
467
- const { schemaData, customFieldsByTable } = await getSchemaInfoWithCustomFields(client, 'rb');
468
- setCustomFields(customFieldsByTable);
469
- setSchema(schemaData ?? []);
470
- setOrderedColumnNames((schemaData ?? []).flatMap((table) => table.columns
471
- .map((c) => `${table.name}.${c.name}`)
472
- .sort((a, b) => {
473
- const aIsId = a.endsWith('.id') ||
474
- a.endsWith('_id') ||
475
- a.endsWith('Id') ||
476
- a === 'id';
477
- const bIsId = b.endsWith('.id') ||
478
- b.endsWith('_id') ||
479
- b.endsWith('Id') ||
480
- b === 'id';
481
- if (aIsId && !bIsId)
482
- return 1;
483
- if (bIsId && !aIsId)
484
- return -1;
485
- return 0;
486
- })));
487
- if (initialTableName) {
488
- await loadTable(schemaData);
489
- }
490
- setLoadingSchema(false);
491
- setInitialLoad(false);
492
- return schemaData;
493
- }
494
- catch (error) {
495
- console.error(error);
496
- }
497
- };
498
- useEffect(() => {
499
- const loadChart = async () => {
500
- setInitialChartLoad(true);
501
- // @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
502
- if (!report || report.referencedTables.length !== 1) {
503
- setInitialChartLoad(false);
504
- return;
505
- }
506
- try {
507
- // @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
508
- const tableName = report.referencedTables[0];
509
- if (!tableName) {
510
- return;
511
- }
512
- const resp = await getDataFromCloud(client, `astify`, {
513
- // @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
514
- query: report.queryString,
515
- useNewNodeSql: true,
516
- });
517
- if (resp.success === false) {
518
- setErrorMessage(resp.message);
519
- return;
520
- }
521
- const ast = getSelectFromAST(resp.ast);
522
- let convertedAst = processStarColumn(ast, report.columns);
523
- processApostrophe(convertedAst, ['type', 'value']);
524
- convertedAst = convertBigQuery(convertedAst);
525
- const schemaInfo = schema.length !== 0 ? schema : await fetchSchema();
526
- let newAst;
527
- let groupByPivot = {};
528
- ({ ast: newAst, pivot: groupByPivot } = convertGroupBy(convertedAst,
529
- // @ts-ignore
530
- report.pivot, schemaInfo));
531
- if (convertedAst.where) {
532
- setFormData(deepCopy(convertedAst.where));
533
- }
534
- // @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
535
- setActiveQuery(report.queryString);
536
- newAst = groupByPivot ? newAst : convertedAst;
537
- const initialRows = await fetchUponChange(newAst, undefined);
538
- if (initialRows.error) {
539
- setBaseAst(null);
540
- setErrorMessage(initialRows.message);
541
- setInitialChartLoad(false);
542
- return;
543
- }
544
- setBaseAst(newAst);
545
- const tableInfo = schemaInfo.find((table) => table.name === tableName);
546
- let newUniqueValues = undefined;
547
- let dateRangesTemp = undefined;
548
- if (tableName) {
549
- newUniqueValues = await getUniqueStringValues(tableInfo.columns, tableName);
550
- setUniqueValues(newUniqueValues);
551
- dateRangesTemp = await getDateRanges(tableInfo.columns, tableName);
552
- setDateRanges(dateRangesTemp);
553
- }
554
- if (groupByPivot) {
555
- // @ts-ignore
556
- setPivotRowField(groupByPivot.rowField);
557
- // @ts-ignore
558
- setPivotAggregation(groupByPivot.aggregationType);
559
- // @ts-ignore
560
- setPivotColumnField(groupByPivot.columnField);
561
- // @ts-ignore
562
- setPivotValueField(groupByPivot.valueField);
563
- setPivot(groupByPivot);
564
- let dateBucket = undefined;
565
- const tempDateRange = dateRangesTemp &&
566
- groupByPivot.rowField &&
567
- dateRangesTemp[groupByPivot.rowField];
568
- if (tempDateRange) {
569
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
570
- }
571
- const pivotedData = await generatePivotTable(
572
- // @ts-ignore
573
- groupByPivot, initialRows, tempDateRange, false, -1, undefined, dateBucket, report, client, newUniqueValues[tableName]);
574
- setPivotData(pivotedData || []);
575
- const formattedRows = formatRows(pivotedData.rows, report.columns, true,
576
- // @ts-ignore
577
- groupByPivot.aggregationType);
578
- setFormattedRows(formattedRows);
579
- }
580
- else {
581
- const formattedRows = formatRows(report.rows, report.columns);
582
- setFormattedRows(formattedRows);
583
- }
584
- setCurrentTable(tableName);
585
- }
586
- catch (error) {
587
- console.error(error);
588
- setErrorMessage('Error loading report');
589
- }
590
- // This handles a flashing issue
591
- setTimeout(() => {
592
- setInitialChartLoad(false);
593
- }, 500);
594
- };
595
- // @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
596
- if (report && report.referencedTables.length === 1) {
597
- loadChart();
598
- }
599
- }, [report]);
600
- useEffect(() => {
601
- if (schema.length === 0) {
602
- fetchSchema();
603
- }
604
- }, [schema, initialTableName, reportId]);
605
- const updateFormData = (updates, { isDeletion = false, isInsertion = false, isReplaceSubtree = false, isAddVariant = false, isDeleteVariant = false, topLevelBinOp = 'OR', isCondition = undefined, }) => {
606
- // Function to immutably update or delete nodes based on their path
607
- // TODO: fix the following horible code
608
- updates.forEach(({ path, value }) => {
609
- const globalPath = [
610
- activePath ?? isDeletion ? path : '',
611
- isDeletion || isReplaceSubtree ? '' : path,
612
- ]
613
- .filter(Boolean)
614
- .join('.');
615
- const paths = globalPath.split('.').filter((p) => p);
616
- if (paths.length === 0 && !isInsertion && !isReplaceSubtree) {
617
- setFormData(null);
618
- const newAst = deepCopy({
619
- ...defaultAST,
620
- ...baseAst,
621
- ...(!baseAst?.columns && {
622
- columns: getAllPossibleColumns().map((c) => {
623
- const newColumn = deepCopy(defaultColumn);
624
- newColumn.expr.column = c.name;
625
- return newColumn;
626
- }),
627
- }),
628
- ...(!baseAst?.from && {
629
- from: [{ ...defaultTable, table: initialTableName }],
630
- }),
631
- where: null,
632
- });
633
- setBaseAst(newAst);
634
- fetchSqlQuery(newAst, null);
635
- return;
636
- }
637
- if (!formData && isInsertion) {
638
- const newAst = deepCopy({
639
- ...defaultAST,
640
- ...baseAst,
641
- ...(!baseAst?.columns && {
642
- columns: getAllPossibleColumns().map((c) => {
643
- const newColumn = deepCopy(defaultColumn);
644
- newColumn.expr.column = c.name;
645
- return newColumn;
646
- }),
647
- }),
648
- ...(!baseAst?.from && {
649
- from: [{ ...defaultTable, table: initialTableName }],
650
- }),
651
- where: value,
652
- });
653
- setFormData(value);
654
- setBaseAst(newAst);
655
- fetchSqlQuery(newAst, value);
656
- return;
657
- }
658
- let newState = deepCopy(formData);
659
- let current = newState;
660
- let parent = null;
661
- let parentKey = null;
662
- for (let i = 0; i < paths.length - 1; i++) {
663
- if (current[paths[i]]) {
664
- parent = current;
665
- parentKey = paths[i];
666
- current = current[paths[i]];
667
- }
668
- }
669
- const lastKey = paths[paths.length - 1];
670
- if (isDeletion) {
671
- if (lastKey === 'left' || lastKey === 'right') {
672
- if (parent) {
673
- if (lastKey === 'right') {
674
- parent[parentKey] = parent[parentKey].left;
675
- }
676
- else {
677
- parent[parentKey] = parent[parentKey].right;
678
- }
679
- }
680
- else {
681
- delete current[lastKey];
682
- if (newState?.left && !newState?.right) {
683
- newState = newState.left;
684
- }
685
- else if (newState?.right && !newState?.left) {
686
- newState = newState.right;
687
- }
688
- }
689
- }
690
- }
691
- else if (isInsertion) {
692
- newState = {
693
- type: 'binary_expr',
694
- operator: topLevelBinOp,
695
- isCondition: isCondition,
696
- left: newState,
697
- right: value,
698
- };
699
- }
700
- else if (isAddVariant) {
701
- const newVariant = deepCopy(defaultVariant);
702
- if (value) {
703
- newVariant.args.value[0].value = value;
704
- // if there is already a single default value there,
705
- // let's remove it so when we push we replace.
706
- if (current[lastKey].length === 1 &&
707
- current[lastKey][0].args.value[0].value === '') {
708
- current[lastKey].pop();
709
- }
710
- }
711
- current[lastKey].push(newVariant);
712
- }
713
- else if (isDeleteVariant) {
714
- if (value) {
715
- const argList = current[lastKey];
716
- argList.splice(argList.findIndex((arg) => arg.args.value[0].value === name), 1);
717
- }
718
- else {
719
- current[lastKey].pop();
720
- }
721
- }
722
- else if (isReplaceSubtree) {
723
- if (lastKey) {
724
- current[lastKey] = value;
725
- }
726
- else {
727
- newState = value;
728
- }
729
- }
730
- else {
731
- if (typeof current[lastKey] === 'object' && current[lastKey] !== null) {
732
- current[lastKey].value = value;
733
- }
734
- else {
735
- current[lastKey] = value;
736
- }
737
- }
738
- setFormData(newState);
739
- const newAst = {
740
- ...defaultAST,
741
- ...baseAst,
742
- ...(!baseAst?.columns && {
743
- columns: getAllPossibleColumns().map((c) => {
744
- const newColumn = deepCopy(defaultColumn);
745
- newColumn.expr.column = c.name;
746
- return newColumn;
747
- }),
748
- }),
749
- ...(!baseAst?.from && {
750
- from: [{ ...defaultTable, table: initialTableName }],
751
- }),
752
- where: { ...newState },
753
- };
754
- setBaseAst(newAst);
755
- fetchSqlQuery(newAst, newState);
756
- });
757
- };
758
- // TODO: Merge this function with the updateFormData function
759
- const updateActiveItem = (updates, { isDeletion = false, isInsertion = false, isReplaceSubtree = false, isAddVariant = false, isDeleteVariant = false, column = undefined, }) => {
760
- let newState = deepCopy(activeEditItem);
761
- updates.forEach(({ path, value }) => {
762
- let current = newState;
763
- const globalPath = path;
764
- const paths = globalPath.split('.').filter((p) => p);
765
- if (paths.length === 0 && !isInsertion && !isReplaceSubtree) {
766
- setActiveEditItem(null);
767
- return;
768
- }
769
- const isOperatorChange = paths[paths.length - 1] === 'operator';
770
- let parent = null;
771
- let parentKey = null;
772
- for (let i = 0; i < paths.length - 1; i++) {
773
- let currentPath = paths[i];
774
- let index;
775
- if (paths[i].includes('||')) {
776
- const splitPath = paths[i].split('||');
777
- currentPath = splitPath[0];
778
- index = splitPath[1];
779
- }
780
- if (current[currentPath]) {
781
- parent = current;
782
- parentKey = currentPath;
783
- current = current[currentPath];
784
- }
785
- if (index) {
786
- current = current[parseInt(index)];
787
- }
788
- }
789
- const lastKey = paths[paths.length - 1];
790
- if (isDeletion) {
791
- if (lastKey === 'left' || lastKey === 'right') {
792
- if (parent) {
793
- if (lastKey === 'right') {
794
- parent[parentKey] = parent[parentKey].left;
795
- }
796
- else {
797
- parent[parentKey] = parent[parentKey].right;
798
- }
799
- }
800
- else {
801
- delete current[lastKey];
802
- if (newState?.left && !newState?.right) {
803
- newState = newState.left;
804
- }
805
- else if (newState?.right && !newState?.left) {
806
- newState = newState.right;
807
- }
808
- }
809
- }
810
- }
811
- else if (isInsertion) {
812
- const columns = getAllPossibleColumns();
813
- const defaultColumn = columns[0].name;
814
- // TODO: I think this is a bug, take a closer look here
815
- newState = {
816
- type: 'binary_expr',
817
- operator: 'AND',
818
- left: newState,
819
- right: {
820
- ...defaultEntry,
821
- left: {
822
- ...defaultEntry.left,
823
- column: defaultColumn,
824
- },
825
- },
826
- };
827
- }
828
- else if (isAddVariant) {
829
- const newVariant = deepCopy(defaultVariant);
830
- if (value) {
831
- newVariant.args.value[0].value = value;
832
- // if there is already a single default value there,
833
- // let's remove it so when we push we replace.
834
- if (current[lastKey].length === 1 &&
835
- current[lastKey][0].args.value[0].value === '') {
836
- current[lastKey].pop();
837
- }
838
- }
839
- current[lastKey].push(newVariant);
840
- }
841
- else if (isDeleteVariant) {
842
- if (value) {
843
- const argList = current[lastKey];
844
- argList.splice(argList.findIndex((arg) => arg.args.value[0].value === value), 1);
845
- }
846
- else {
847
- current[lastKey].pop();
848
- }
849
- // add back in a phantom element to prevent app from crashing
850
- // when the user removes all variants and hits save.
851
- if (current[lastKey].length === 0) {
852
- const newVariant = deepCopy(defaultVariant);
853
- newVariant.args.value[0].value = '';
854
- current[lastKey].push(newVariant);
855
- }
856
- }
857
- else if (isReplaceSubtree) {
858
- if (lastKey) {
859
- current[lastKey] = value;
860
- }
861
- else {
862
- newState = value;
863
- }
864
- }
865
- else if (isOperatorChange) {
866
- const newOp = value;
867
- const oldOp = current[lastKey];
868
- if (OPERATOR_GROUPS[oldOp] === OPERATOR_GROUPS[newOp]) {
869
- current[lastKey] = value;
870
- }
871
- else {
872
- const group = OPERATOR_GROUPS[newOp];
873
- const subtree = getDefaultOperatorSubtrees(group, newOp, column, '', client.databaseType);
874
- if (parentKey) {
875
- parent[parentKey] = deepCopy(subtree);
876
- }
877
- else {
878
- newState = deepCopy(subtree);
879
- }
880
- }
881
- }
882
- else {
883
- if (typeof current[lastKey] === 'object' && current[lastKey] !== null) {
884
- current[lastKey].value = value;
885
- }
886
- else {
887
- current[lastKey] = value;
888
- }
889
- }
890
- });
891
- // Function to immutably update or delete nodes based on their path
892
- setActiveEditItem(newState);
893
- };
894
- const handleChange = (updates) => {
895
- const callback = isPending ? updateActiveItem : updateFormData;
896
- callback(updates, {});
897
- };
898
- const handleChangeText = (updates) => {
899
- const callback = isPending ? updateActiveItem : updateFormData;
900
- callback(updates, {});
901
- };
902
- // Function to handle operator changes
903
- const handleOperatorChange = (value, node, keyPrefix, column = null) => {
904
- if (!keyPrefix) {
905
- setTopLevelBinaryOperator(value);
906
- }
907
- if (isPending) {
908
- updateActiveItem([{ path: keyPrefix + 'operator', value }], { column });
909
- }
910
- else {
911
- updateFormData([{ path: keyPrefix + 'operator', value }], { column });
912
- }
913
- };
914
- // Function to replace an entire subtree with a given value.
915
- const handleReplaceSubtree = (keyPrefix, newValue, pending = isPending) => {
916
- const callback = pending ? updateActiveItem : updateFormData;
917
- callback([{ path: keyPrefix, value: newValue }], {
918
- isReplaceSubtree: true,
919
- });
920
- };
921
- // Function to handle the insertion of expressions
922
- const handleInsertion = (value, op = 'OR', isCondition = undefined) => {
923
- updateFormData([{ path: '', value }], {
924
- isInsertion: true,
925
- topLevelBinOp: op,
926
- isCondition,
927
- });
928
- };
929
- // Function to handle the insertion of expr_list variants
930
- const handleInsertVariant = (key, name = null) => {
931
- // note: if name, treat that as the name of the value to insert
932
- const callback = isPending ? updateActiveItem : updateFormData;
933
- callback([{ path: key, value: name }], { isAddVariant: true });
934
- };
935
- // Function to handle the insertion of expr_list variants
936
- const handleDeleteVariant = (key, name = null) => {
937
- // note: if name, treat that as the name of the valeu to delete
938
- const callback = isPending ? updateActiveItem : updateFormData;
939
- callback([{ path: key, value: name }], { isDeleteVariant: true });
940
- };
941
- const getColumnValueForColumnComparison = (node) => node.left.value ??
942
- node.left.column ??
943
- node.left.args?.value[0]?.value ??
944
- node.left.args?.value[0]?.column ??
945
- undefined;
946
- /**
947
- * Searches for the column by name and returns the field type.
948
- *
949
- * Searches the known schema and returns the fieldType of the first column
950
- * it can find with the given name. Will first search through the current
951
- * list of fields in the current query if any, then will default to searching
952
- * through the whole schema.
953
- *
954
- * If more than one column exist with the given name, it will return the first
955
- * one that it finds. This might not be the one that you intended.
956
- *
957
- * TODO: pass an optional table param to limit the search to a given table.
958
- *
959
- * @param columnName the name to search for.
960
- * @returns the fieldType string or undefined if not found.
961
- */
962
- const getColumnTypeByName = (columnName) => {
963
- const column = columns.find((col) => col.field === columnName);
964
- return column?.fieldType;
965
- };
966
- const emptyPivotColumns = () => {
967
- if (pivot && pivot.rowField && pivot.columnField && pivot.valueField) {
968
- return [
969
- { label: snakeAndCamelCaseToTitleCase(pivot.rowField) },
970
- { label: snakeAndCamelCaseToTitleCase(pivot.columnField) },
971
- ];
972
- }
973
- else if (pivot && pivot.rowField && pivot.valueField) {
974
- return [
975
- { label: snakeAndCamelCaseToTitleCase(pivot.rowField) },
976
- { label: snakeAndCamelCaseToTitleCase(pivot.valueField) },
977
- ];
978
- }
979
- else {
980
- return [{ label: snakeAndCamelCaseToTitleCase(pivot.valueField) }];
981
- }
982
- };
983
- const [previousPage, setPreviousPage] = useState(0);
984
- const [currentProcessing, setCurrentProcessing] = useState({
985
- page: DEFAULT_PAGINATION,
986
- });
987
- const [numberOfRows, setNumberOfRows] = useState(0);
988
- const [tableLoading, setTableLoading] = useState(false);
989
- const onPageChange = (page) => {
990
- if (currentProcessing.page &&
991
- shouldFetchMore(DEFAULT_PAGINATION, page, previousPage)) {
992
- const newPagination = { ...currentProcessing.page, page };
993
- const updatedProcessing = { ...currentProcessing, page: newPagination };
994
- setCurrentProcessing(updatedProcessing);
995
- handleRunQuery(updatedProcessing);
996
- }
997
- if (page > previousPage) {
998
- setPreviousPage(page);
999
- }
1000
- };
1001
- const onSortChange = (sort) => {
1002
- if (shouldSortInMemory(DEFAULT_PAGINATION, numberOfRows, !!pivot)) {
1003
- return;
1004
- }
1005
- const updatedProcessing = { page: DEFAULT_PAGINATION, sort };
1006
- handleRunQuery(updatedProcessing, true);
1007
- setCurrentProcessing(updatedProcessing);
1008
- setPreviousPage(0);
1009
- };
1010
- const handleRunQuery = async (processing, resetRows = false) => {
1011
- try {
1012
- setErrorMessage('');
1013
- setTableLoading(true);
1014
- const tableInfo = await fetchTableByQuery(activeQuery, client, processing, customFields);
1015
- if (tableInfo.error) {
1016
- throw new Error(tableInfo.error);
1017
- }
1018
- else if (tableInfo.rows.length === 0) {
1019
- throw new Error('No data found');
1020
- }
1021
- if (tableInfo.rowCount) {
1022
- setNumberOfRows(tableInfo.rowCount);
1023
- }
1024
- setCurrentProcessing(processing);
1025
- let tempRows = [...rows, ...tableInfo.rows];
1026
- if (resetRows) {
1027
- tempRows = tableInfo.rows;
1028
- }
1029
- setRows(tempRows);
1030
- setFormattedRows(formatRowsFromReport({ rows: tempRows, columns: tableInfo.columns }));
1031
- setColumns(tableInfo.columns);
1032
- setTableLoading(false);
1033
- }
1034
- catch (e) {
1035
- setTableLoading(false);
1036
- setErrorMessage('Failed to run SQL query: ' + e.message);
1037
- setRows([]);
1038
- setColumns([]);
1039
- return;
1040
- }
1041
- };
1042
- /**
1043
- * Render form fields based on the type of the node
1044
- * @param node the AST or subtree to render recursively
1045
- * @param keyPrefix a stringified version of the path from the root
1046
- *
1047
- * Note: The keyPrefix should be separated by '.' characters and each item
1048
- * should be a valid index into the node (eg. 'left.right.value' is a valid
1049
- * keyPrefix but 'left.args[0].value' is not -- should be 'left.args.0.value')
1050
- */
1051
- const renderNode = (node, keyPrefix = '') => {
1052
- const dateComparisonPartialMatch = formatDateComparisonNode(node);
1053
- switch (node.type) {
1054
- case 'binary_expr':
1055
- if (dateComparisonPartialMatch ||
1056
- (isDateTruncEquals(node) && client.databaseType !== 'BigQuery')) {
1057
- const { dateColumn, dateFilterType, intervalCount, intervalType, intervalPaths, } = getDateFilterInfo(node);
1058
- const isPlural = intervalCount !== 1 && dateFilterType !== 'in the current'
1059
- ? 's'
1060
- : '';
1061
- // Pull off the string literal date for "equals" comparisons
1062
- const rawDateStringEquals = node.right?.value ??
1063
- node.right?.args?.value[1]?.column ??
1064
- node.right?.args?.value[1]?.value;
1065
- const rawDateStringEqualsPath = (node.right?.value && 'node.right.value') ??
1066
- (node.right?.args?.value[1]?.column &&
1067
- 'node.right.args.value.1.column') ??
1068
- (node.right?.args?.value[1]?.value &&
1069
- 'node.right.args.value.1.value');
1070
- return (_jsxs("div", { style: { display: 'flex', gap: 20 }, children: [_jsx(SelectComponent, { value: dateColumn, onChange: (event) => {
1071
- const columnType = getColumnTypeByName(event.target.value);
1072
- if (isDateishColumnType(columnType)) {
1073
- // handleChange(value, keyPrefix + dateColumnPath, "text");
1074
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1075
- }
1076
- else if (isNumericColumnType(columnType)) {
1077
- const newSubtree = deepCopy(defaultNumericComparison);
1078
- newSubtree.left.column = event.target.value;
1079
- handleReplaceSubtree(keyPrefix, newSubtree);
1080
- }
1081
- else if (isBoolColumnType(columnType)) {
1082
- const newSubtree = deepCopy(defaultBoolComparison);
1083
- newSubtree.left.column = event.target.value;
1084
- handleReplaceSubtree(keyPrefix, newSubtree);
1085
- }
1086
- else {
1087
- const newSubtree = deepCopy(defaultEntry);
1088
- newSubtree.left.args.value[0].column = event.target.value;
1089
- handleReplaceSubtree(keyPrefix, newSubtree);
1090
- }
1091
- }, options: getAllPossibleColumns().map((column) => ({
1092
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1093
- value: column.name,
1094
- })), width: 200 }), _jsx(SelectComponent, { value: dateFilterType, onChange: (event) => {
1095
- if (event.target.value === dateFilterType)
1096
- return null;
1097
- let newSubtree = {};
1098
- // TODO: implement one for each database type (eg. pg, snowflake, etc.)
1099
- if (event.target.value === 'in the last') {
1100
- newSubtree = generateLastNPeriodsPostgres({
1101
- dateField: dateColumn,
1102
- intervalPeriod: `${intervalCount ?? 1} ${intervalType}`,
1103
- });
1104
- }
1105
- else if (event.target.value === 'in the previous') {
1106
- newSubtree = generatePreviousPeriodPostgres({
1107
- dateField: dateColumn,
1108
- intervalPeriod: `${intervalCount ?? 1} ${intervalType}`,
1109
- currentPeriod: intervalType,
1110
- });
1111
- }
1112
- else if (event.target.value === 'in the current') {
1113
- newSubtree = generateCurrentPeriodPostgres({
1114
- dateField: dateColumn,
1115
- currentPeriod: intervalType,
1116
- });
1117
- }
1118
- else if (event.target.value === 'equals') {
1119
- newSubtree = generateEqualsPostgres({
1120
- dateField: dateColumn,
1121
- currentPeriod: intervalType,
1122
- timestamp: '2024-01-01',
1123
- });
1124
- }
1125
- // replace the entire subtree for this filter
1126
- handleReplaceSubtree(keyPrefix, newSubtree);
1127
- }, options: [
1128
- { label: 'in the last', value: 'in the last' },
1129
- { label: 'in the previous', value: 'in the previous' },
1130
- { label: 'in the current', value: 'in the current' },
1131
- { label: 'equals', value: 'equals' },
1132
- ], width: 200 }), !['in the current', 'equals'].includes(dateFilterType) && (_jsx(TextInputComponent, { id: "date_filter_interval_count", value: intervalCount?.toString() ?? '', width: 70, onChange: (e) => {
1133
- if (Number.isNaN(parseFloat(e.target.value || '0'))) {
1134
- alert('Please input a number.');
1135
- return;
1136
- }
1137
- const isPluralNow = parseFloat(e.target.value || '0') !== 1 ? 's' : '';
1138
- intervalPaths.forEach((intervalPath) => handleChangeText([
1139
- {
1140
- value: `${e.target.value || 0} ${intervalType}${isPluralNow}`,
1141
- path: keyPrefix + intervalPath,
1142
- },
1143
- ]));
1144
- } })), _jsx(SelectComponent, { value: intervalType, onChange: (event) => {
1145
- if (intervalPaths.length === 1 &&
1146
- dateFilterType !== 'in the previous') {
1147
- handleChangeText([
1148
- {
1149
- value: intervalCount !== null
1150
- ? `${intervalCount} ${event.target.value}${isPlural}`
1151
- : event.target.value,
1152
- path: keyPrefix + intervalPaths[0],
1153
- },
1154
- ]);
1155
- return;
1156
- }
1157
- let newSubtree;
1158
- if (dateFilterType === 'in the previous') {
1159
- newSubtree = generatePreviousPeriodPostgres({
1160
- dateField: dateColumn,
1161
- intervalPeriod: `${intervalCount ?? 1} ${event.target.value}`,
1162
- currentPeriod: event.target.value,
1163
- });
1164
- }
1165
- else if (dateFilterType === 'equals') {
1166
- newSubtree = generateEqualsPostgres({
1167
- dateField: dateColumn,
1168
- currentPeriod: event.target.value,
1169
- timestamp: rawDateStringEquals,
1170
- });
1171
- }
1172
- else {
1173
- newSubtree = generateCurrentPeriodPostgres({
1174
- dateField: dateColumn,
1175
- currentPeriod: event.target.value,
1176
- });
1177
- }
1178
- handleReplaceSubtree(keyPrefix, newSubtree);
1179
- }, options: dateFilterType === 'in the previous' ||
1180
- dateFilterType === 'in the last'
1181
- ? [
1182
- { label: `year${isPlural}`, value: 'year' },
1183
- { label: `month${isPlural}`, value: 'month' },
1184
- { label: `week${isPlural}`, value: 'week' },
1185
- { label: `day${isPlural}`, value: 'day' },
1186
- { label: `hour${isPlural}`, value: 'hour' },
1187
- ]
1188
- : [
1189
- { label: `year${isPlural}`, value: 'year' },
1190
- { label: `quarter${isPlural}`, value: 'quarter' },
1191
- { label: `month${isPlural}`, value: 'month' },
1192
- { label: `week${isPlural}`, value: 'week' },
1193
- { label: `day${isPlural}`, value: 'day' },
1194
- { label: `hour${isPlural}`, value: 'hour' },
1195
- ], width: 200 }), dateFilterType === 'equals' && (_jsx(TextInputComponent, { id: "date_filter_equals_raw_date", value: rawDateStringEquals, width: 120, onChange: (e) => {
1196
- handleChangeText([
1197
- {
1198
- value: e.target.value,
1199
- path: keyPrefix + rawDateStringEqualsPath,
1200
- },
1201
- ]);
1202
- } }))] }));
1203
- }
1204
- else if (isInTheLastInterval(node, client.databaseType)) {
1205
- const { dateColumn } = getDateFilterInfo(node);
1206
- const options = getAllPossibleColumns().map((column) => ({
1207
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1208
- value: column.name,
1209
- }));
1210
- const plural = node.right.args.value[1].expr.value !== 1 ? 's' : '';
1211
- return (_jsxs("div", { style: {
1212
- display: 'flex',
1213
- flexDirection: 'row',
1214
- alignItems: 'center',
1215
- gap: 20,
1216
- }, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
1217
- const columnType = getColumnTypeByName(event.target.value);
1218
- if (isDateishColumnType(columnType)) {
1219
- // handleChange(value, keyPrefix + dateColumnPath, "text");
1220
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1221
- }
1222
- else if (isNumericColumnType(columnType)) {
1223
- const newSubtree = deepCopy(defaultNumericComparison);
1224
- newSubtree.left.column = event.target.value;
1225
- handleReplaceSubtree(keyPrefix, newSubtree);
1226
- }
1227
- else if (isBoolColumnType(columnType)) {
1228
- const newSubtree = deepCopy(defaultBoolComparison);
1229
- newSubtree.left.column = event.target.value;
1230
- handleReplaceSubtree(keyPrefix, newSubtree);
1231
- }
1232
- else {
1233
- const newSubtree = deepCopy(defaultEntry);
1234
- newSubtree.left.args.value[0].column = event.target.value;
1235
- handleReplaceSubtree(keyPrefix, newSubtree);
1236
- }
1237
- }, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_LAST', onChange: (event) => {
1238
- handleOperatorChange(event.target.value, node, keyPrefix, dateColumn);
1239
- }, options: [
1240
- { label: 'in the last', value: 'IN_THE_LAST' },
1241
- { label: 'in the previous', value: 'IN_THE_PREVIOUS' },
1242
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1243
- { label: 'equals', value: 'EQUALS' },
1244
- { label: 'is not null', value: 'IS NOT' },
1245
- { label: 'is null', value: 'IS' },
1246
- ], width: 200 }), _jsx(TextInputComponent, { id: 'date_window_interval_count', value: node.right.args.value[1].expr.value, width: 120, onChange: (e) => {
1247
- handleChange([
1248
- {
1249
- value: e.target.value,
1250
- path: keyPrefix + 'right.args.value||1.expr.value',
1251
- },
1252
- ]);
1253
- } }), _jsx("div", { children: _jsx(SelectComponent, { value: node.right.args.value[1].unit, onChange: (event) => handleChange([
1254
- {
1255
- value: event.target.value,
1256
- path: keyPrefix + 'right.args.value||1.unit',
1257
- },
1258
- ]), options: [
1259
- { label: `year${plural}`, value: '* 365 DAY' },
1260
- { label: `month${plural}`, value: '* 30 DAY' },
1261
- { label: `week${plural}`, value: '* 7 DAY' },
1262
- { label: `day${plural}`, value: 'DAY' },
1263
- ], width: 200 }) })] }));
1264
- }
1265
- else if (isTheCurrentInterval(node, client.databaseType)) {
1266
- const options = getAllPossibleColumns().map((column) => ({
1267
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1268
- value: column.name,
1269
- }));
1270
- return (_jsxs("div", { style: {
1271
- display: 'flex',
1272
- flexDirection: 'row',
1273
- alignItems: 'center',
1274
- gap: 20,
1275
- }, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
1276
- const columnType = getColumnTypeByName(event.target.value);
1277
- if (isDateishColumnType(columnType)) {
1278
- // handleChange(value, keyPrefix + dateColumnPath, "text");
1279
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1280
- }
1281
- else if (isNumericColumnType(columnType)) {
1282
- const newSubtree = deepCopy(defaultNumericComparison);
1283
- newSubtree.left.column = event.target.value;
1284
- handleReplaceSubtree(keyPrefix, newSubtree);
1285
- }
1286
- else if (isBoolColumnType(columnType)) {
1287
- const newSubtree = deepCopy(defaultBoolComparison);
1288
- newSubtree.left.column = event.target.value;
1289
- handleReplaceSubtree(keyPrefix, newSubtree);
1290
- }
1291
- else {
1292
- const newSubtree = deepCopy(defaultEntry);
1293
- newSubtree.left.args.value[0].column = event.target.value;
1294
- handleReplaceSubtree(keyPrefix, newSubtree);
1295
- }
1296
- }, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_CURRENT', onChange: (event) => {
1297
- handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
1298
- }, options: [
1299
- { label: 'in the last', value: 'IN_THE_LAST' },
1300
- { label: 'in the previous', value: 'IN_THE_PREVIOUS' },
1301
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1302
- { label: 'equals', value: 'EQUALS' },
1303
- { label: 'is not null', value: 'IS NOT' },
1304
- { label: 'is null', value: 'IS' },
1305
- // { label: 'equals', value: 'equals' },
1306
- ], width: 200 }), _jsx(SelectComponent, { value: node.left.args.value[1].column, onChange: (event) => {
1307
- handleChange([
1308
- {
1309
- value: event.target.value,
1310
- path: 'right.args.value||1.column',
1311
- },
1312
- {
1313
- value: event.target.value,
1314
- path: 'left.args.value||1.column',
1315
- },
1316
- ]);
1317
- }, options: [
1318
- { label: `year`, value: 'YEAR' },
1319
- { label: `quarter`, value: 'QUARTER' },
1320
- { label: `month`, value: 'MONTH' },
1321
- { label: `week`, value: 'WEEK' },
1322
- ], width: 200 })] }));
1323
- }
1324
- else if (isThePreviousInterval(node)) {
1325
- const options = getAllPossibleColumns().map((column) => ({
1326
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1327
- value: column.name,
1328
- }));
1329
- return (_jsxs("div", { style: {
1330
- display: 'flex',
1331
- flexDirection: 'row',
1332
- alignItems: 'center',
1333
- gap: 20,
1334
- }, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
1335
- const columnType = getColumnTypeByName(event.target.value);
1336
- if (isDateishColumnType(columnType)) {
1337
- // handleChange(value, keyPrefix + dateColumnPath, "text");
1338
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1339
- }
1340
- else if (isNumericColumnType(columnType)) {
1341
- const newSubtree = deepCopy(defaultNumericComparison);
1342
- newSubtree.left.column = event.target.value;
1343
- handleReplaceSubtree(keyPrefix, newSubtree);
1344
- }
1345
- else if (isBoolColumnType(columnType)) {
1346
- const newSubtree = deepCopy(defaultBoolComparison);
1347
- newSubtree.left.column = event.target.value;
1348
- handleReplaceSubtree(keyPrefix, newSubtree);
1349
- }
1350
- else {
1351
- const newSubtree = deepCopy(defaultEntry);
1352
- newSubtree.left.args.value[0].column = event.target.value;
1353
- handleReplaceSubtree(keyPrefix, newSubtree);
1354
- }
1355
- }, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_PREVIOUS', onChange: (event) => {
1356
- handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
1357
- }, options: [
1358
- { label: 'in the last', value: 'IN_THE_LAST' },
1359
- { label: 'in the previous', value: 'IN_THE_PREVIOUS' },
1360
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1361
- { label: 'equals', value: 'EQUALS' },
1362
- { label: 'is not null', value: 'IS NOT' },
1363
- { label: 'is null', value: 'IS' },
1364
- // { label: 'equals', value: 'equals' },
1365
- ], width: 200 }), _jsx(SelectComponent, { value: node.left.args.value[1].column, onChange: (event) => {
1366
- const dayConversion = {
1367
- YEAR: 365,
1368
- QUARTER: 90,
1369
- MONTH: 30,
1370
- WEEK: 7,
1371
- };
1372
- handleChange([
1373
- {
1374
- value: event.target.value,
1375
- path: 'left.args.value||1.column',
1376
- },
1377
- {
1378
- value: event.target.value,
1379
- path: 'right.args.value||1.column',
1380
- },
1381
- {
1382
- value: dayConversion[event.target.value] || 30,
1383
- path: 'right.args.value||0.args.value||1.expr.value',
1384
- },
1385
- ]);
1386
- }, options: [
1387
- { label: `year`, value: 'YEAR' },
1388
- { label: `quarter`, value: 'QUARTER' },
1389
- { label: `month`, value: 'MONTH' },
1390
- { label: `week`, value: 'WEEK' },
1391
- ], width: 200 })] }));
1392
- }
1393
- else if (isEquals(node, client.databaseType)) {
1394
- const options = getAllPossibleColumns().map((column) => ({
1395
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1396
- value: column.name,
1397
- }));
1398
- return (_jsxs("div", { style: {
1399
- display: 'flex',
1400
- flexDirection: 'row',
1401
- alignItems: 'center',
1402
- gap: 20,
1403
- }, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
1404
- const columnType = getColumnTypeByName(event.target.value);
1405
- if (isDateishColumnType(columnType)) {
1406
- // handleChange(value, keyPrefix + dateColumnPath, "text");
1407
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1408
- }
1409
- else if (isNumericColumnType(columnType)) {
1410
- const newSubtree = deepCopy(defaultNumericComparison);
1411
- newSubtree.left.column = event.target.value;
1412
- handleReplaceSubtree(keyPrefix, newSubtree);
1413
- }
1414
- else if (isBoolColumnType(columnType)) {
1415
- const newSubtree = deepCopy(defaultBoolComparison);
1416
- newSubtree.left.column = event.target.value;
1417
- handleReplaceSubtree(keyPrefix, newSubtree);
1418
- }
1419
- else {
1420
- const newSubtree = deepCopy(defaultEntry);
1421
- newSubtree.left.args.value[0].column = event.target.value;
1422
- handleReplaceSubtree(keyPrefix, newSubtree);
1423
- }
1424
- }, options: options, width: 200 }), _jsx(SelectComponent, { value: 'EQUALS', onChange: (event) => {
1425
- handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
1426
- }, options: [
1427
- { label: 'in the last', value: 'IN_THE_LAST' },
1428
- { label: 'in the previous', value: 'IN_THE_PREVIOUS' },
1429
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1430
- { label: 'equals', value: 'EQUALS' },
1431
- { label: 'is not null', value: 'IS NOT' },
1432
- { label: 'is null', value: 'IS' },
1433
- // { label: 'equals', value: 'equals' },
1434
- ], width: 200 }), _jsx(SelectComponent, { value: node.right.args.value[1].column, onChange: (event) => {
1435
- handleChange([
1436
- {
1437
- value: event.target.value,
1438
- path: 'right.args.value||1.column',
1439
- },
1440
- {
1441
- value: event.target.value,
1442
- path: 'left.args.value||1.column',
1443
- },
1444
- ]);
1445
- }, options: [
1446
- { label: `year`, value: 'YEAR' },
1447
- { label: `quarter`, value: 'QUARTER' },
1448
- { label: `month`, value: 'MONTH' },
1449
- { label: `week`, value: 'WEEK' },
1450
- ], width: 200 }), _jsx(TextInputComponent, { id: 'quoted_string', value: node.right.args.value[0].value, width: 120, onChange: (e) => handleChange([
1451
- {
1452
- value: e.target.value,
1453
- path: 'right.args.value||0.value',
1454
- },
1455
- ]) })] }));
1456
- }
1457
- else if (isColumnComparison(node)) {
1458
- const options = getAllPossibleColumns().map((column) => ({
1459
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1460
- value: column.name,
1461
- }));
1462
- // grab the value of the left child of the column comparison
1463
- // operator (ie. the column name)
1464
- const leftChildValue = getColumnValueForColumnComparison(node);
1465
- const tables = getTableNames(baseAst);
1466
- const table = tables.length === 1 ? tables[0] : initialTableName;
1467
- const column = schema
1468
- .find((tableInfo) => tableInfo.name === table)
1469
- ?.columns.find((col) => col.name === leftChildValue);
1470
- const columnType = column?.fieldType;
1471
- const operatorOptions = [
1472
- ...(isNumericColumnType(columnType)
1473
- ? [
1474
- { label: 'equal to', value: '=' },
1475
- { label: 'not equal to', value: '!=' },
1476
- { label: 'greater than', value: '>' },
1477
- { label: 'less than', value: '<' },
1478
- { label: 'greater than or equal to', value: '>=' },
1479
- { label: 'less than or equal to', value: '<=' },
1480
- { label: 'is not null', value: 'IS NOT' },
1481
- { label: 'is null', value: 'IS' },
1482
- ]
1483
- : []),
1484
- ...(isTextColumnType(columnType)
1485
- ? [
1486
- { label: 'is exactly', value: 'LIKE' },
1487
- { label: 'is not exactly', value: 'NOT LIKE' },
1488
- { label: 'is', value: 'IN' },
1489
- { label: 'is not', value: 'NOT IN' },
1490
- { label: 'is not null', value: 'IS NOT' },
1491
- { label: 'is null', value: 'IS' },
1492
- ]
1493
- : []),
1494
- ...(isDateishColumnType(columnType)
1495
- ? [
1496
- { label: 'in the last', value: 'IN_THE_LAST' },
1497
- {
1498
- label: 'in the previous',
1499
- value: 'IN_THE_PREVIOUS',
1500
- },
1501
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1502
- { label: 'equals', value: 'equals' },
1503
- ]
1504
- : []),
1505
- ];
1506
- return (_jsxs("div", { style: {
1507
- display: 'flex',
1508
- gap: 12,
1509
- flexDirection: 'column',
1510
- width: '100%',
1511
- padding: '6px 0px',
1512
- }, children: [_jsxs("div", { style: {
1513
- display: 'flex',
1514
- gap: 20,
1515
- flexDirection: showNodeAsRow(node, formData)
1516
- ? 'row'
1517
- : 'column',
1518
- width: '100%',
1519
- }, children: [_jsx(SelectComponent, { value: leftChildValue, onChange: (event) => {
1520
- const columnType = getColumnTypeByName(event.target.value);
1521
- if (isDateishColumnType(columnType)) {
1522
- handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
1523
- }
1524
- else if (isNumericColumnType(columnType)) {
1525
- const newSubtree = deepCopy(defaultNumericComparison);
1526
- newSubtree.left.column = event.target.value;
1527
- handleReplaceSubtree(keyPrefix, newSubtree);
1528
- }
1529
- else if (isBoolColumnType(columnType)) {
1530
- const newSubtree = deepCopy(defaultBoolComparison);
1531
- newSubtree.left.column = event.target.value;
1532
- handleReplaceSubtree(keyPrefix, newSubtree);
1533
- }
1534
- else {
1535
- const newSubtree = deepCopy(defaultEntry);
1536
- newSubtree.left.args.value[0].column = event.target.value;
1537
- handleReplaceSubtree(keyPrefix, newSubtree);
1538
- }
1539
- }, options: options, width: 200 }), operatorOptions.length > 0 && (_jsx(SelectComponent, { value: node.operator, onChange: (event) => {
1540
- handleOperatorChange(event.target.value, node, keyPrefix, leftChildValue);
1541
- }, options: operatorOptions, width: 200 })), node.right &&
1542
- node.right.type !== 'expr_list' &&
1543
- renderNode(node.right, keyPrefix + 'right.')] }, keyPrefix), node.right && node.right.type === 'expr_list' && (_jsx("div", { style: {
1544
- display: 'grid',
1545
- gridTemplateColumns: 'repeat(2, 1fr)',
1546
- gap: 12,
1547
- }, children: uniqueValues[table] &&
1548
- Object.keys(uniqueValues[table][leftChildValue] ?? {}).map((key) => (_jsx(CheckboxComponent, { label: key, isChecked: uniqueValues[table][leftChildValue][key], onChange: (event) => {
1549
- const newValues = deepCopy(uniqueValues);
1550
- newValues[table][leftChildValue][key] =
1551
- event.target.checked;
1552
- setUniqueValues(newValues);
1553
- if (event.target.checked) {
1554
- handleInsertVariant(keyPrefix + 'right.' + 'value', key);
1555
- }
1556
- else {
1557
- handleDeleteVariant(keyPrefix + 'right.' + 'value', key);
1558
- }
1559
- } }))) }, keyPrefix + 'right.'))] }));
1560
- }
1561
- else {
1562
- const columnName = node.left.column;
1563
- const column = schema
1564
- .find((tableInfo) => tableInfo.name === currentTable)
1565
- ?.columns.find((col) => col.name === columnName);
1566
- const columnType = column?.fieldType;
1567
- return (_jsxs("div", { style: {
1568
- display: 'flex',
1569
- gap: 12,
1570
- justifyContent: 'space-between',
1571
- flexDirection: showNodeAsRow(node, formData) ? 'row' : 'column',
1572
- width: '100%',
1573
- }, children: [node.left && renderNode(node.left, keyPrefix + 'left.'), _jsx(SelectComponent, { value: node.operator, onChange: (event) => {
1574
- handleOperatorChange(event.target.value, node, keyPrefix);
1575
- }, options: [
1576
- // { label: `and`, value: "AND" },
1577
- // { label: `or`, value: "OR" },
1578
- ...(isNumericColumnType(columnType)
1579
- ? [
1580
- { label: 'equal to', value: '=' },
1581
- { label: 'not equal to', value: '!=' },
1582
- { label: 'greater than', value: '>' },
1583
- { label: 'less than', value: '<' },
1584
- { label: 'greater than or equal to', value: '>=' },
1585
- { label: 'less than or equal to', value: '<=' },
1586
- { label: 'is not null', value: 'IS NOT' },
1587
- { label: 'is null', value: 'IS' },
1588
- ]
1589
- : []),
1590
- ...(isTextColumnType(columnType)
1591
- ? [
1592
- { label: 'is exactly', value: 'LIKE' },
1593
- { label: 'is not exactly', value: 'NOT LIKE' },
1594
- { label: 'is', value: 'IN' },
1595
- { label: 'is not', value: 'NOT IN' },
1596
- { label: 'is not null', value: 'IS NOT' },
1597
- { label: 'is null', value: 'IS' },
1598
- ]
1599
- : []),
1600
- ...(isDateishColumnType(columnType)
1601
- ? [
1602
- { label: 'in the last', value: 'IN_THE_LAST' },
1603
- { label: 'in the previous', value: 'IN_THE_PREVIOUS' },
1604
- { label: 'in the current', value: 'IN_THE_CURRENT' },
1605
- { label: 'equals', value: 'EQUALS' },
1606
- { label: 'is not null', value: 'IS NOT' },
1607
- { label: 'is null', value: 'IS' },
1608
- ]
1609
- : []),
1610
- // { label: `minus`, value: "-" },
1611
- // { label: `plus`, value: "+" },
1612
- ], width: 200 }), node.right && renderNode(node.right, keyPrefix + 'right.')] }, keyPrefix));
1613
- }
1614
- case 'column_ref': {
1615
- const options = getAllPossibleColumns().map((column) => ({
1616
- label: snakeAndCamelCaseToTitleCase(column.displayName),
1617
- value: column.name,
1618
- }));
1619
- return (_jsx(SelectComponent, { value: node.column ?? options[0]?.value, onChange: (event) => {
1620
- handleChange([
1621
- { value: event.target.value, path: keyPrefix + 'column' },
1622
- ]);
1623
- }, options: options, width: 200 }));
1624
- }
1625
- case 'expr_list': {
1626
- const len = node.value.length;
1627
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: 12 }, children: [node.value.map((elem, index) => {
1628
- if (elem.value) {
1629
- return (_jsx(TextInputComponent, { id: `expr_list_${index}`, width: 200, value: elem.value, onChange: (e) => handleChange([
1630
- {
1631
- value: e.target.value,
1632
- path: keyPrefix + `value.${index}.`,
1633
- },
1634
- ]) }, `input_${index}`));
1635
- }
1636
- return renderNode(elem, keyPrefix + `value.${index}.`);
1637
- }), len > 1 && (_jsx(SecondaryButtonComponent, { label: '-', onClick: () => handleDeleteVariant(keyPrefix + 'value') })), _jsx(SecondaryButtonComponent, { onClick: () => handleInsertVariant(keyPrefix + 'value'), label: '+' })] }, keyPrefix));
1638
- }
1639
- case 'double_quote_string':
1640
- case 'single_quote_string':
1641
- return (_jsx(TextInputComponent, { id: 'quoted_string', value: node.value.replaceAll('%', ''), width: 120, onChange: (e) => handleChange([
1642
- {
1643
- value: e.target.value,
1644
- path: keyPrefix + 'value',
1645
- },
1646
- ]) }));
1647
- case 'null':
1648
- return _jsx("div", {});
1649
- case 'number':
1650
- return (_jsx(TextInputComponent, { id: "quill_number_input", value: node.value, width: 120, onChange: (e) => {
1651
- handleChange([
1652
- {
1653
- value: e.target.value,
1654
- path: keyPrefix + 'value',
1655
- },
1656
- ]);
1657
- } }));
1658
- case 'bool':
1659
- return (_jsx(SelectComponent, { value: node.value.toString(), onChange: (event) => {
1660
- let formatted = true;
1661
- if (event.target.value === 'false') {
1662
- formatted = false;
1663
- }
1664
- handleChange([
1665
- {
1666
- value: formatted,
1667
- path: keyPrefix + 'value',
1668
- },
1669
- ]);
1670
- }, options: [
1671
- { label: 'is true', value: 'true' },
1672
- { label: 'is false', value: 'false' },
1673
- ], width: 200 }));
1674
- case 'function':
1675
- if (!node.args) {
1676
- return _jsx("label", {});
1677
- }
1678
- else if (node.args.type === 'expr_list' &&
1679
- node.args.value.length === 1) {
1680
- return (_jsx("div", { style: { display: 'flex', flexDirection: 'row' }, children: node.args.value[0] &&
1681
- renderNode(node.args.value[0], keyPrefix + 'args.value.0.') }));
1682
- }
1683
- else if (node.args.type === 'expr_list' &&
1684
- node.args.value.length === 2) {
1685
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: 20 }, children: [node.args.value[0] &&
1686
- renderNode(node.args.value[0], keyPrefix + 'args.value.0.'), node.args.value[1] &&
1687
- renderNode(node.args.value[1], keyPrefix + 'args.value.1.')] }));
1688
- }
1689
- return node.name;
1690
- case 'interval':
1691
- return (_jsx("div", { style: { display: 'flex', flexDirection: 'row', gap: 20 }, children: renderNode(node.expr, keyPrefix + 'expr.') }));
1692
- default:
1693
- return null;
1694
- }
1695
- };
1696
- const isValidPivot = (fields) => {
1697
- let validPivot = true;
1698
- if (pivot.rowField &&
1699
- !fields.find((field) => field.name === pivot.rowField)) {
1700
- validPivot = false;
1701
- }
1702
- if (pivot.valueField &&
1703
- !fields.find((field) => field.name === pivot.valueField)) {
1704
- validPivot = false;
1705
- }
1706
- if (pivot.columnField &&
1707
- !fields.find((field) => field.name === pivot.columnField)) {
1708
- validPivot = false;
1709
- }
1710
- return validPivot;
1711
- };
1712
- /**
1713
- * @param filterTree
1714
- * Returns a list of filters to be displayed
1715
- * Replaces the functionality of renderNodes in the context of filters
1716
- */
1717
- const renderFilters = (filterTree) => {
1718
- let tree = filterTree;
1719
- let filterStack = [];
1720
- /**
1721
- * Function that takes in a FilterTree and flattens it into an array using in order traversal
1722
- */
1723
- function traverseTree(node) {
1724
- if (!node) {
1725
- return;
1726
- }
1727
- if (node.leaf) {
1728
- filterStack.push(node);
1729
- }
1730
- else {
1731
- traverseTree(node.leftNode);
1732
- filterStack.push(node);
1733
- traverseTree(node.rightNode);
1734
- }
1735
- }
1736
- /**
1737
- * Given an array of Filters (presumed to be in in-order state), generate
1738
- * the corresponding Filter tree. Essentially the reverse of what traverseTree does
1739
- */
1740
- function filterStackToFilterTree(stack) {
1741
- function buildTree(i) {
1742
- const newNode = {
1743
- leaf: false,
1744
- operator: null,
1745
- leftNode: null,
1746
- rightNode: null,
1747
- };
1748
- if (i >= stack.length) {
1749
- return null;
1750
- }
1751
- else if (stack[i].leaf) {
1752
- if (i < stack.length - 1) {
1753
- // more nodes later
1754
- newNode.operator = stack[i + 1].operator;
1755
- newNode.leftNode = {
1756
- leaf: true,
1757
- leftNode: null,
1758
- rightNode: null,
1759
- operator: null,
1760
- value: stack[i].value,
1761
- };
1762
- newNode.rightNode = buildTree(i + 2);
1763
- }
1764
- else {
1765
- newNode.leaf = true;
1766
- newNode.value = stack[i].value;
1767
- }
1768
- }
1769
- return newNode;
1770
- }
1771
- return buildTree(0);
1772
- }
1773
- traverseTree(tree);
1774
- // Remove null (invalid) filters from filter stack
1775
- filterStack = filterStack.filter((filter) => {
1776
- return ((!filter.leaf &&
1777
- filter.rightNode &&
1778
- (!filter.rightNode.leaf || filter.rightNode.value)) ||
1779
- (filter.leaf && filter.value));
1780
- });
1781
- // Render filterStack
1782
- return (_jsx("div", { style: {
1783
- display: 'flex',
1784
- flexDirection: 'column',
1785
- }, children: filterStack.map((item, index) => {
1786
- if (!item.leaf &&
1787
- (item.operator === 'and' || item.operator === 'or')) {
1788
- return (_jsx("div", { style: {
1789
- width: 'fit-content',
1790
- marginBottom: '8px',
1791
- marginTop: '8px',
1792
- }, children: _jsx(TabsComponent, { value: item.operator.toUpperCase(), options: DEFAULT_TAB_OPTIONS, onChange: () => {
1793
- if (item.operator === 'and') {
1794
- item.operator = 'or';
1795
- }
1796
- else {
1797
- item.operator = 'and';
1798
- }
1799
- let newFormData = null;
1800
- if (tree) {
1801
- newFormData = filterTreeToAst(tree, client.databaseType.toLowerCase());
1802
- }
1803
- const newAst = deepCopy({
1804
- ...defaultAST,
1805
- ...baseAst,
1806
- ...(!baseAst?.columns && {
1807
- columns: getAllPossibleColumns().map((c) => {
1808
- const newColumn = deepCopy(defaultColumn);
1809
- newColumn.expr.column = c.name;
1810
- return newColumn;
1811
- }),
1812
- }),
1813
- ...(!baseAst?.from && {
1814
- from: [{ ...defaultTable, table: initialTableName }],
1815
- }),
1816
- where: newFormData,
1817
- });
1818
- setBaseAst(newAst);
1819
- setFormData(newFormData);
1820
- fetchSqlQuery(newAst, newFormData);
1821
- } }) }, index));
1822
- }
1823
- else {
1824
- return (_jsx(FilterPopoverWrapper, { schema: schema.find((s) => s.name === currentTable || s.displayName === currentTable) ?? schema[0], filter: item.value, filterLabel: item.value ? filterSentence(item.value) : '', index: index, FilterTagComponent: FilterPopoverComponent, FilterModal: FilterModal, fieldValuesMap: fieldValuesMap, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, MultiSelectComponent: MultiSelectComponent, handleFilterSave: (filter) => {
1825
- item.value = filter;
1826
- let newFormData = null;
1827
- if (tree) {
1828
- newFormData = filterTreeToAst(tree, client.databaseType.toLowerCase());
1829
- }
1830
- const newAst = deepCopy({
1831
- ...defaultAST,
1832
- ...baseAst,
1833
- ...(!baseAst?.columns && {
1834
- columns: getAllPossibleColumns().map((c) => {
1835
- const newColumn = deepCopy(defaultColumn);
1836
- newColumn.expr.column = c.name;
1837
- return newColumn;
1838
- }),
1839
- }),
1840
- ...(!baseAst?.from && {
1841
- from: [{ ...defaultTable, table: initialTableName }],
1842
- }),
1843
- where: newFormData,
1844
- });
1845
- setBaseAst(newAst);
1846
- setFormData(newFormData);
1847
- fetchSqlQuery(newAst, newFormData);
1848
- }, handleFilterDelete: (i) => {
1849
- if (i > 0) {
1850
- filterStack.splice(i - 1, 2);
1851
- }
1852
- else {
1853
- if (filterStack.length > 1) {
1854
- filterStack.splice(i, 2);
1855
- }
1856
- else {
1857
- filterStack.splice(i, 1);
1858
- }
1859
- }
1860
- tree = filterStackToFilterTree(filterStack);
1861
- let newFormData = null;
1862
- if (tree) {
1863
- newFormData = filterTreeToAst(tree, client.databaseType.toLowerCase());
1864
- }
1865
- const newAst = deepCopy({
1866
- ...defaultAST,
1867
- ...baseAst,
1868
- ...(!baseAst?.columns && {
1869
- columns: getAllPossibleColumns().map((c) => {
1870
- const newColumn = deepCopy(defaultColumn);
1871
- newColumn.expr.column = c.name;
1872
- return newColumn;
1873
- }),
1874
- }),
1875
- ...(!baseAst?.from && {
1876
- from: [{ ...defaultTable, table: initialTableName }],
1877
- }),
1878
- where: newFormData,
1879
- });
1880
- setBaseAst(newAst);
1881
- setFormData(newFormData);
1882
- fetchSqlQuery(newAst, newFormData);
1883
- } }, 'filter' + index));
1884
- }
1885
- }) }));
1886
- };
1887
- const getAllPossibleColumns = () => {
1888
- if (!baseAst || !baseAst.from) {
1889
- return schema.flatMap((table) => table.columns.map((c) => ({
1890
- ...c,
1891
- table: table.displayName,
1892
- })));
1893
- }
1894
- // TODO: support infinitely nested FROM table lookups.
1895
- // This currently only supports top-level table names in the FROM section
1896
- // of queries (eg. FROM "table_name", not "FROM (SELECT * FROM other) AS table_name")
1897
- const tableNamesInQuery = baseAst.from.map((tbl) => tbl.table);
1898
- return schema
1899
- .filter((t) => tableNamesInQuery.includes(t.displayName))
1900
- .flatMap((table) => table.columns
1901
- .map((c) => ({
1902
- ...c,
1903
- table: table.displayName,
1904
- }))
1905
- .sort((a, b) => {
1906
- const aIsId = a.name.toLowerCase() === 'id' ||
1907
- a.name.toLowerCase().endsWith('_id') ||
1908
- a.name.endsWith('Id');
1909
- const bIsId = b.name.toLowerCase() === 'id' ||
1910
- b.name.toLowerCase().endsWith('_id') ||
1911
- b.name.endsWith('Id');
1912
- if (aIsId && !bIsId)
1913
- return 1;
1914
- if (bIsId && !aIsId)
1915
- return -1;
1916
- return 0;
1917
- }));
1918
- };
1919
- /**
1920
- * Return whether all columns have been selected (used to hide select all
1921
- * and show clear button).
1922
- */
1923
- const isSelectedAllColumns = () => {
1924
- if (selectedColumns.length < 1)
1925
- return false;
1926
- const allColumns = orderedColumnNames.filter((row) => {
1927
- const [table] = row.split('.');
1928
- const selectedTable = selectedColumns[0].split('.')[0];
1929
- return selectedTable === table;
1930
- });
1931
- return selectedColumns.length === allColumns.length;
1932
- };
1933
- const nameToColumn = (name) => ({
1934
- type: 'expr',
1935
- expr: {
1936
- type: 'column_ref',
1937
- table: null,
1938
- column: name,
1939
- },
1940
- as: null,
1941
- });
1942
- const AddConditionPopover = ({ onSave }) => {
1943
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx("h1", { style: {
1944
- fontWeight: '600',
1945
- fontSize: 18,
1946
- margin: 0,
1947
- textAlign: 'left',
1948
- }, children: "Add condition" }), _jsx(TabsComponent, { value: topLevelBinaryOperator, options: DEFAULT_TAB_OPTIONS, onChange: (event) => setTopLevelBinaryOperator(event.target.value) }), activeEditItem && renderNode(activeEditItem), _jsx("div", { style: {
1949
- display: 'flex',
1950
- flexDirection: 'row',
1951
- gap: 8,
1952
- justifyContent: 'end',
1953
- }, children: _jsx(ButtonComponent, { onClick: onSave, label: 'Add condition' }) })] }));
1954
- };
1955
- const fetchUponChange = async (baseAst, newFormData) => {
1956
- // if newFormData is null still use it
1957
- const curFormData = newFormData !== undefined ? newFormData : formData;
1958
- let rows;
1959
- if ((curFormData || baseAst) && !loading) {
1960
- try {
1961
- setLoading(true);
1962
- const hostedBody = {
1963
- metadata: {
1964
- clientId: client.publicKey,
1965
- ast: { ...baseAst, where: curFormData },
1966
- publicKey: client.publicKey,
1967
- orgId: client.customerId,
1968
- task: 'patterns',
1969
- getCustomFields: false,
1970
- customFields,
1971
- additionalProcessing: { page: { currentPage: 0, rowsPerPage: 20 } },
1972
- useUpdatedDataGathering: true,
1973
- useNewNodeSql: true, // new flag
1974
- },
1975
- };
1976
- const tables = getTableNames(baseAst);
1977
- const table = tables.length >= 1 ? tables[0] : initialTableName;
1978
- let newUniqueValues = uniqueValues;
1979
- let dateRangesTemp = dateRanges;
1980
- let curReport = tempReport;
1981
- if ((newUniqueValues && Object.keys(newUniqueValues).length === 0) ||
1982
- table !== currentTable) {
1983
- const tableInfo = schema.find((tableInfo) => tableInfo.name === table);
1984
- if (tableInfo) {
1985
- newUniqueValues = await getUniqueStringValues(tableInfo.columns, table);
1986
- if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
1987
- setUniqueValues(newUniqueValues);
1988
- }
1989
- dateRangesTemp = await getDateRanges(tableInfo.columns, table);
1990
- setDateRanges(dateRangesTemp || {});
1991
- }
1992
- setCurrentTable(table);
1993
- }
1994
- const cloudBody = {};
1995
- const data2 = await getData(client, 'dashquery', 'same-origin', hostedBody, cloudBody);
1996
- if (data2.success === false) {
1997
- throw new Error(data2.errorMessage);
1998
- }
1999
- rows = data2.rows;
2000
- if (data2.rowCount) {
2001
- setNumberOfRows(data2.rowCount);
2002
- }
2003
- if (data2.rows && data2.rows.length) {
2004
- if (pivot) {
2005
- // check if any of the pivot fields aren't in the data2.fields array
2006
- if (!isValidPivot(data2.fields)) {
2007
- const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
2008
- setPivot(null);
2009
- setPivotData(null);
2010
- setRows(data2.rows);
2011
- setColumns(processedFields);
2012
- if (data2.rowCount) {
2013
- const processedFormData = report
2014
- ? report
2015
- : createInitialFormData(processedFields);
2016
- setNumberOfRows(data2.rowCount);
2017
- curReport = {
2018
- ...formData,
2019
- ...processedFormData,
2020
- itemQuery: data2.itemQuery,
2021
- rowCount: data2.rowCount,
2022
- filtersApplied: [],
2023
- rows: data2.rows,
2024
- columns: processedFields,
2025
- };
2026
- setTempReport(curReport);
2027
- }
2028
- const formattedRows = formatRows(data2.rows, processedFields, false);
2029
- setFormattedRows(formattedRows);
2030
- return;
2031
- }
2032
- curReport = {
2033
- ...formData,
2034
- itemQuery: data2.itemQuery,
2035
- rowCount: data2.rowCount,
2036
- filtersApplied: [],
2037
- rows: data2.rows,
2038
- };
2039
- // Do all of this to make sure we have the right unique columns when applying a pivot
2040
- let dateBucket = undefined;
2041
- const tempDateRange = dateRangesTemp &&
2042
- pivot.rowField &&
2043
- dateRangesTemp[pivot.rowField];
2044
- if (tempDateRange) {
2045
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
2046
- }
2047
- let distinctValuesForQuery = {};
2048
- if (pivot.columnField) {
2049
- const sqlQuery = await fetchSqlQuery({ ...baseAst, where: curFormData }, null, false);
2050
- distinctValuesForQuery = await getUniqueValuesByColumns([
2051
- {
2052
- field: pivot.columnField,
2053
- label: pivot.columnField,
2054
- format: 'string',
2055
- },
2056
- ], sqlQuery, [], client, customFields);
2057
- }
2058
- const pivotedData = await generatePivotTable(
2059
- // @ts-ignore
2060
- pivot, data2.rows, undefined, false, -1, undefined, dateBucket, curReport, client, distinctValuesForQuery ? distinctValuesForQuery : undefined);
2061
- console.info(`%c[Pivot]: ${JSON.stringify(pivot)}`, 'color: dimgray');
2062
- const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
2063
- setPivotData(pivotedData);
2064
- setRows(data2.rows);
2065
- setColumns(processedFields);
2066
- if (data2.rowCount) {
2067
- const processedFormData = report
2068
- ? report
2069
- : createInitialFormData(processedFields);
2070
- setNumberOfRows(data2.rowCount);
2071
- setTempReport({
2072
- ...formData,
2073
- ...processedFormData,
2074
- itemQuery: data2.itemQuery,
2075
- rowCount: data2.rowCount,
2076
- filtersApplied: [],
2077
- rows: data2.rows,
2078
- columns: processedFields,
2079
- });
2080
- }
2081
- const formattedRows = formatRows(pivotedData.rows, processedFields, true, pivot.aggregationType);
2082
- setSelectedColumns(processedFields.map((column) => {
2083
- return `${table}.${column.field}`;
2084
- }));
2085
- setFormattedRows(formattedRows);
2086
- }
2087
- else {
2088
- const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
2089
- setRows(data2.rows);
2090
- setColumns(processedFields);
2091
- if (data2.rowCount) {
2092
- const processedFormData = report
2093
- ? report
2094
- : createInitialFormData(processedFields);
2095
- setNumberOfRows(data2.rowCount);
2096
- setTempReport({
2097
- ...formData,
2098
- ...processedFormData,
2099
- itemQuery: data2.itemQuery,
2100
- rowCount: data2.rowCount,
2101
- filtersApplied: [],
2102
- rows: data2.rows,
2103
- columns: processedFields,
2104
- });
2105
- }
2106
- setSelectedColumns(processedFields.map((column) => {
2107
- return `${table}.${column.field}`;
2108
- }));
2109
- const formattedRows = formatRows(data2.rows, processedFields, false);
2110
- setFormattedRows(formattedRows);
2111
- if (data2.errorMessage) {
2112
- setErrorMessage(`Error: ${data2.errorMessage}`);
2113
- }
2114
- }
2115
- }
2116
- else {
2117
- setRows([]);
2118
- setColumns([]);
2119
- setFormattedRows([]);
2120
- setPivotData(null);
2121
- }
2122
- setLoading(false);
2123
- setDataDisplayed(true);
2124
- return rows;
2125
- }
2126
- catch (e) {
2127
- setErrorMessage(e.message);
2128
- setLoading(false);
2129
- setDataDisplayed(true);
2130
- setRows([]);
2131
- setColumns([]);
2132
- setFormattedRows([]);
2133
- setPivotData(null);
2134
- return { error: true, message: e.message };
2135
- }
2136
- }
2137
- };
2138
- // Returns whether a where-clause contains a nested subquery.
2139
- const isSubquery = (node) => {
2140
- if (!node)
2141
- return false;
2142
- if (node.ast)
2143
- return true;
2144
- if (node.left && isSubquery(node.left))
2145
- return true;
2146
- if (node.right && isSubquery(node.right))
2147
- return true;
2148
- if (node.value && Array.isArray(node.value)) {
2149
- for (const value of node.value) {
2150
- if (isSubquery(value))
2151
- return true;
2152
- }
2153
- }
2154
- return false;
2155
- };
2156
- const handleAsk = async (overridePrompt = '') => {
2157
- if (!aiPrompt && !overridePrompt) {
2158
- return;
2159
- }
2160
- try {
2161
- setLoading(true);
2162
- setAskedAQuestion(true);
2163
- setErrorMessage('');
2164
- let res, data, ast;
2165
- let numRetries = 0;
2166
- const MAX_RETRIES = 3;
2167
- // refetch the request if it comes back and we know it's invalid.
2168
- // TODO: remove this to allow joins later down the road
2169
- let isTableJoin = !ast || !ast.from || ast.from.length !== 1;
2170
- while (isTableJoin || isSubquery(ast?.where)) {
2171
- if (numRetries === MAX_RETRIES)
2172
- break;
2173
- if (!activeQuery || (ast && (isTableJoin || isSubquery(ast?.where)))) {
2174
- res = await fetch(`${QUILL_SERVER}/magic`, {
2175
- method: 'POST',
2176
- headers: { 'Content-Type': 'application/json' },
2177
- body: JSON.stringify({
2178
- initialQuestion: aiPrompt || overridePrompt,
2179
- publicKey: client.publicKey,
2180
- useNewNodeSql: true, // new flag
2181
- }),
2182
- });
2183
- }
2184
- else {
2185
- res = await fetch(`${QUILL_SERVER}/magic/edit`, {
2186
- method: 'POST',
2187
- headers: { 'Content-Type': 'application/json' },
2188
- body: JSON.stringify({
2189
- sqlQuery: activeQuery,
2190
- initialQuestion: aiPrompt,
2191
- publicKey: client.publicKey,
2192
- useNewNodeSql: true, // new flag
2193
- }),
2194
- });
2195
- }
2196
- data = await res.json();
2197
- ast = data?.ast?.length ? data?.ast[0] : data?.ast;
2198
- // TODO: Debug invalid table joins in handleAsk
2199
- isTableJoin =
2200
- ast?.type !== 'bigquery' &&
2201
- (!ast || !ast.from || ast.from.length !== 1);
2202
- numRetries += 1;
2203
- }
2204
- if (numRetries === MAX_RETRIES) {
2205
- console.error('[Error]: Max retries exceeded.');
2206
- console.info(`%c[Prompt]: ${aiPrompt}`, 'color: dimgray');
2207
- setErrorMessage("Error: Couldn't process your request, please re-word your prompt.");
2208
- return;
2209
- }
2210
- let currentSchema = schema;
2211
- if (currentSchema && currentSchema.length === 0) {
2212
- currentSchema = await fetchSchema();
2213
- }
2214
- let newAst, groupByPivot;
2215
- if (ast) {
2216
- // Unwrap the ast object, supporting many possible types
2217
- ast = ast.length ? ast[0] : ast;
2218
- newAst = convertBigQuery(ast);
2219
- newAst = convertWildcardColumns(newAst, currentSchema); // must go before groupby
2220
- ({ ast: newAst, pivot: groupByPivot } = convertGroupBy(newAst, pivot, currentSchema));
2221
- newAst = convertStringComparison(newAst, client.databaseType);
2222
- newAst = convertRemoveSimpleParentheses(newAst);
2223
- const table = getTableNames(newAst)[0] ?? initialTableName;
2224
- const tableAlias = getTableAliases(newAst)[0] ?? initialTableName;
2225
- newAst = convertUnaryToBinary(newAst);
2226
- newAst = removeNonSelectedTableReferences(newAst, tableAlias ?? table, getAllPossibleColumns().map((col) => col.name));
2227
- const procesedColumns = deepCopy(newAst).columns?.map((column) => {
2228
- if (column.expr.type === 'column_ref') {
2229
- const columnName = extractColumnish(column.expr);
2230
- return `${table}.${columnName}`;
2231
- }
2232
- else if (column.as) {
2233
- return `${table}.${column.as}`;
2234
- }
2235
- return `${table}.${column.expr.value}`;
2236
- });
2237
- setSelectedColumns(procesedColumns);
2238
- if (groupByPivot) {
2239
- setBaseAst(deepCopy({ ...newAst, orderby: null, limit: null }));
2240
- newAst = deepCopy({ ...newAst, orderby: null, limit: null });
2241
- }
2242
- else {
2243
- setBaseAst(deepCopy({ ...newAst }));
2244
- }
2245
- setFormData(deepCopy(newAst.where));
2246
- setTopLevelBinaryOperator(
2247
- // @ts-ignore
2248
- newAst?.where ? newAst?.where?.operator : 'AND');
2249
- }
2250
- ast = newAst; // so we fetch data for newAst later.
2251
- fetchSqlQuery(ast, undefined, false);
2252
- const table = getTableNames(newAst)[0] ?? initialTableName;
2253
- const hostedBody = {
2254
- metadata: {
2255
- clientId: client.publicKey,
2256
- ast,
2257
- publicKey: client.publicKey,
2258
- orgId: client.customerId,
2259
- task: 'patterns',
2260
- additionalProcessing: { page: { currentPage: 0, rowsPerPage: 20 } },
2261
- useUpdatedDataGathering: true,
2262
- pivot: groupByPivot,
2263
- useNewNodeSql: true, // new flag
2264
- },
2265
- };
2266
- let currentUniqueValues = uniqueValues;
2267
- let dateRangesTemp = dateRanges;
2268
- if ((currentUniqueValues &&
2269
- currentUniqueValues[table] &&
2270
- Object.keys(currentUniqueValues[table]).length === 0) ||
2271
- table !== currentTable) {
2272
- const tableInfo = currentSchema.find((tableInfo) => tableInfo.name === table);
2273
- if (tableInfo) {
2274
- const newUniqueValues = await getUniqueStringValues(tableInfo.columns, table);
2275
- currentUniqueValues = newUniqueValues;
2276
- if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
2277
- setUniqueValues(newUniqueValues);
2278
- }
2279
- dateRangesTemp = await getDateRanges(tableInfo.columns, table);
2280
- setDateRanges(dateRangesTemp);
2281
- }
2282
- setCurrentTable(table);
2283
- }
2284
- const cloudBody = {};
2285
- const data2 = await getData(client, 'patterns', 'same-origin', hostedBody, cloudBody);
2286
- if (!data2 || data2.status === 'error') {
2287
- throw new Error('Error querying data from patterns');
2288
- }
2289
- if (data2.rows && data2.rows.length) {
2290
- const processedFields = data2.fields
2291
- .map((elem) => convertPostgresColumn(elem))
2292
- .map((elem) => {
2293
- const tableInfo = currentSchema.find((t) => t.name === table);
2294
- const columnInfo = tableInfo?.columns.find((column) => column.name === elem.field);
2295
- return columnInfo
2296
- ? convertColumnInfoToColumnInternal(columnInfo)
2297
- : null;
2298
- })
2299
- .filter((elem) => elem);
2300
- let possiblePivot = true;
2301
- const possibleColumns = getPossiblePivotFieldOptions(processedFields, currentUniqueValues[table]);
2302
- if (groupByPivot &&
2303
- ((groupByPivot.columnField &&
2304
- !possibleColumns.columnFields.includes(groupByPivot?.columnField)) ||
2305
- (groupByPivot.rowField &&
2306
- !possibleColumns.rowFields.includes(groupByPivot?.rowField)) ||
2307
- (groupByPivot.valueField &&
2308
- !possibleColumns.valueFields.includes(groupByPivot?.valueField || '')))) {
2309
- possiblePivot = false;
2310
- let errorMessageEnding = '';
2311
- if (groupByPivot.columnField &&
2312
- !possibleColumns.columnFields.includes(groupByPivot?.columnField || '')) {
2313
- if (currentUniqueValues[table]?.[groupByPivot?.columnField || '']) {
2314
- errorMessageEnding = `The column ${groupByPivot?.columnField} has more than 24 unique values to pivot on.`;
2315
- }
2316
- else {
2317
- errorMessageEnding = `The column ${groupByPivot?.columnField} is not a proper column field.`;
2318
- }
2319
- }
2320
- else if (groupByPivot.rowField &&
2321
- !possibleColumns.rowFields.includes(groupByPivot?.rowField || '')) {
2322
- if (currentUniqueValues[table]?.[groupByPivot?.rowField || '']) {
2323
- errorMessageEnding = `The column ${groupByPivot?.rowField} has more than 36 unique values to pivot on.`;
2324
- }
2325
- else {
2326
- errorMessageEnding = `The column ${groupByPivot?.rowField} is not a proper row field.`;
2327
- }
2328
- }
2329
- else if (groupByPivot.valueField &&
2330
- !possibleColumns.valueFields.includes(groupByPivot?.valueField || '')) {
2331
- errorMessageEnding = `The column ${groupByPivot?.valueField} is not a proper value field.`;
2332
- }
2333
- setErrorMessage(`The requested pivot is not supported. ${errorMessageEnding}`);
2334
- }
2335
- if (groupByPivot && possiblePivot) {
2336
- let curReport = report ? report : undefined;
2337
- if (data2.rowCount) {
2338
- const processedFormData = report
2339
- ? report
2340
- : createInitialFormData(processedFields);
2341
- setNumberOfRows(data2.rowCount);
2342
- curReport = {
2343
- ...formData,
2344
- ...processedFormData,
2345
- itemQuery: data2.itemQuery,
2346
- rowCount: data2.rowCount,
2347
- filtersApplied: [],
2348
- rows: data2.rows,
2349
- columns: processedFields,
2350
- };
2351
- setTempReport(curReport || null);
2352
- }
2353
- let dateBucket = undefined;
2354
- const tempDateRange = dateRangesTemp &&
2355
- groupByPivot.rowField &&
2356
- dateRangesTemp[groupByPivot.rowField];
2357
- if (tempDateRange) {
2358
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
2359
- }
2360
- const pivotedData = await generatePivotTable(
2361
- // @ts-ignore
2362
- groupByPivot, data2.rows, undefined, false, -1, undefined, dateBucket, curReport, client, groupByPivot.columnField
2363
- ? currentUniqueValues[groupByPivot.columnField]
2364
- : undefined);
2365
- console.info(`%c[Pivot]: ${JSON.stringify(groupByPivot)}`, 'color: dimgray');
2366
- setPivotData(pivotedData);
2367
- setPivot(groupByPivot);
2368
- setRows(data2.rows);
2369
- setPivotRowField(groupByPivot?.rowField);
2370
- setPivotColumnField(groupByPivot?.columnField);
2371
- setPivotValueField(groupByPivot?.valueField);
2372
- setPivotAggregation(groupByPivot?.aggregationType);
2373
- setColumns(processedFields);
2374
- const formattedRows = formatRows(pivotedData.rows, processedFields, true, groupByPivot.aggregationType);
2375
- setFormattedRows(formattedRows);
2376
- }
2377
- else {
2378
- const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
2379
- setRows(data2.rows);
2380
- setColumns(processedFields);
2381
- if (data2.rowCount) {
2382
- setNumberOfRows(data2.rowCount);
2383
- setTempReport({
2384
- ...formData,
2385
- itemQuery: data2.itemQuery,
2386
- rowCount: data2.rowCount,
2387
- filtersApplied: [],
2388
- rows: data2.rows,
2389
- columns: processedFields,
2390
- });
2391
- }
2392
- const formattedRows = formatRows(data2.rows, processedFields, false);
2393
- setFormattedRows(formattedRows);
2394
- }
2395
- return data2.rows;
2396
- }
2397
- else {
2398
- setPivotData([]);
2399
- setRows([]);
2400
- setColumns([]);
2401
- setFormattedRows([]);
2402
- }
2403
- if (data2.query) {
2404
- setActiveQuery(data2.query);
2405
- }
2406
- else {
2407
- setActiveQuery('');
2408
- }
2409
- if (data2.errorMessage) {
2410
- setErrorMessage(`Error: Couldn't process your request, please re-word your prompt.`);
2411
- }
2412
- }
2413
- catch (e) {
2414
- console.error(e);
2415
- setErrorMessage(`Error: Couldn't process your request, please re-word your prompt.`);
2416
- }
2417
- finally {
2418
- setLoading(false);
2419
- setDataDisplayed(true);
2420
- }
2421
- };
2422
- const handleDeleteColumn = (name) => {
2423
- if (!baseAst || !baseAst.columns.length || selectedColumns.length === 1) {
2424
- clearAllState();
2425
- return;
2426
- }
2427
- setSelectedColumns((selectedColumns) => selectedColumns.filter((column) => !column.endsWith(name)));
2428
- const columns = baseAst.columns.filter((col) => {
2429
- if (col.expr.type === 'column_ref') {
2430
- return (col.expr.column !== name &&
2431
- (!col.expr.column.expr || col.expr.column.expr.value !== name));
2432
- }
2433
- else if (col.as) {
2434
- return col.as !== name;
2435
- }
2436
- return col.expr.value !== name;
2437
- });
2438
- if (columns.length === 0) {
2439
- clearAllState();
2440
- return;
2441
- }
2442
- const newAst = deepCopy({ ...baseAst, columns });
2443
- setBaseAst(newAst);
2444
- fetchSqlQuery(newAst);
2445
- };
2446
- const DraggableItem = ({ id, label, onDelete }) => {
2447
- const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: id });
2448
- const style = {
2449
- transform: DND_CSS.Transform.toString(transform),
2450
- transition,
2451
- };
2452
- return (_jsx("div", { style: { ...style }, ref: setNodeRef, children: _jsx(DraggableColumnComponent, { label: snakeAndCamelCaseToTitleCase(label), onDelete: onDelete, DragHandle: (props) => (_jsx("div", { style: {
2453
- cursor: 'grab',
2454
- }, ...attributes, ...listeners, children: _jsx(props.dragIcon, {}) })) }) }));
2455
- };
2456
- function DraggableColumns() {
2457
- const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
2458
- coordinateGetter: sortableKeyboardCoordinates,
2459
- }));
2460
- // When a drag event ends, switch the item order.
2461
- function handleDragEnd(event) {
2462
- const { active, over } = event;
2463
- if (!active || !over)
2464
- return;
2465
- if (active.id !== over.id) {
2466
- const oldIndex = orderedColumnNames.findIndex((c) => c.endsWith(`${currentTable}.${active.id}`));
2467
- const newIndex = orderedColumnNames.findIndex((c) => c.endsWith(`${currentTable}.${over.id}`));
2468
- const newOrder = arrayMove(orderedColumnNames, oldIndex, newIndex);
2469
- setOrderedColumnNames(newOrder);
2470
- const orderedSelectedColumns = [];
2471
- for (const value of newOrder) {
2472
- const column = value.split('.')[1];
2473
- if (selectedColumns.includes(value)) {
2474
- orderedSelectedColumns.push(column);
2475
- }
2476
- }
2477
- setSelectedOrderedColumns(orderedSelectedColumns);
2478
- // If there is already an AST saved in state, only update the columns
2479
- // otherwise fill in the defaultAST shape and also update columns.
2480
- const fallbackAST = {
2481
- ...defaultAST,
2482
- from: [{ ...defaultTable }],
2483
- columns: orderedSelectedColumns.map((name) => nameToColumn(name)),
2484
- };
2485
- const newBaseAst = {
2486
- ...baseAst,
2487
- columns: baseAst?.columns.length
2488
- ? orderedSelectedColumns.map((name) => nameToColumn(name))
2489
- : baseAst?.columns,
2490
- };
2491
- const newAst = baseAst ? newBaseAst : fallbackAST;
2492
- setBaseAst(newAst);
2493
- fetchSqlQuery(newAst, undefined, false);
2494
- }
2495
- }
2496
- const columnNamesInAst = baseAst?.columns
2497
- .map((col) => {
2498
- if (col.expr.type === 'column_ref' && col.expr.column) {
2499
- if (typeof col.expr.column === 'string') {
2500
- return col.expr.column;
2501
- }
2502
- else {
2503
- return col.expr.column.expr.value;
2504
- }
2505
- }
2506
- else if (col.as) {
2507
- if (typeof col.as === 'string') {
2508
- return col.as;
2509
- }
2510
- else {
2511
- return col.as.expr?.value;
2512
- }
2513
- }
2514
- else if (col.expr && col.expr.type === 'aggr_func') {
2515
- if (col.expr.args) {
2516
- return `${col.expr.name.toLowerCase()}(${col.expr.args.expr.value})`;
2517
- }
2518
- return col.expr.name;
2519
- }
2520
- return col.expr.value;
2521
- })
2522
- .filter(
2523
- // remove duplicate entries
2524
- (value, index, self) => value && self.indexOf(value) === index) ?? [];
2525
- return (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: columnNamesInAst, strategy: verticalListSortingStrategy, children: _jsxs("div", { style: {
2526
- display: 'flex',
2527
- flexDirection: 'column',
2528
- gap: 8,
2529
- }, children: [columnNamesInAst.map((name) => (_jsx(DraggableItem, { id: name, label: name, onDelete: () => handleDeleteColumn(name) }, name))), columnNamesInAst?.length > 0 && _jsx("div", { style: { height: 6 } })] }) }) }));
2530
- }
2531
- if (loading || initialChartLoad) {
2532
- return (_jsxs("div", { style: {
2533
- display: 'flex',
2534
- flexDirection: 'row',
2535
- height: '100%',
2536
- ...containerStyle,
2537
- }, className: className, ref: parentRef, children: [_jsxs(SidebarComponent, { children: [_jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Columns" }), _jsx(DraggableColumns, {}), _jsx(SecondaryButtonComponent, { onClick: () => {
2538
- if (!openPopover) {
2539
- setOpenPopover('AddColumnModal');
2540
- }
2541
- }, label: 'Select columns' }), _jsx(ModalComponent, { isOpen: openPopover === 'AddColumnModal', setIsOpen: (isOpen) => {
2542
- if (!isOpen) {
2543
- // delay onClose callback so onClick no-ops
2544
- setTimeout(() => {
2545
- setIsPending(false);
2546
- setActiveEditItem(null);
2547
- setActivePath(null);
2548
- setOpenPopover(null);
2549
- }, 100);
2550
- }
2551
- }, title: "Select columns", children: _jsx(AddColumnModal, { onSave: () => {
2552
- setActiveEditItem(null);
2553
- setActivePath(null);
2554
- setOpenPopover(null);
2555
- }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: (ast) => {
2556
- setBaseAst(ast);
2557
- fetchSqlQuery(ast);
2558
- }, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, setPivot: setPivot, TextInput: TextInputComponent, SelectColumn: SelectColumnComponent, SecondaryButton: SecondaryButtonComponent, Button: ButtonComponent, ColumnSearchEmptyState: ColumnSearchEmptyState, LoadingComponent: LoadingComponent }) })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Filters" }), formData && (_jsx("div", { style: {
2559
- display: 'flex',
2560
- flexDirection: 'column',
2561
- gap: 8,
2562
- marginBottom: 12,
2563
- }, children: filterTree && renderFilters(filterTree) })), _jsxs("div", { style: {
2564
- display: 'flex',
2565
- flexDirection: 'column',
2566
- alignItems: 'flex-start',
2567
- }, children: [_jsx(SecondaryButtonComponent, { onClick: () => {
2568
- if (!selectedColumns ||
2569
- selectedColumns.length === 0 ||
2570
- loading) {
2571
- return;
2572
- }
2573
- if (!openPopover) {
2574
- const value = orderedColumnNames[0];
2575
- const column = value.split('.')[1];
2576
- const columnType = getColumnTypeByName(column);
2577
- if (isNumericColumnType(columnType)) {
2578
- const newSubtree = deepCopy(defaultNumericComparison);
2579
- newSubtree.left.column = column;
2580
- setActiveEditItem(newSubtree);
2581
- }
2582
- else {
2583
- const newSubtree = deepCopy(defaultEntry);
2584
- newSubtree.left.args.value[0].column = column;
2585
- setActiveEditItem(newSubtree);
2586
- }
2587
- setOpenPopover('AddFilterPopover');
2588
- setActivePath('');
2589
- setIsPending(true);
2590
- }
2591
- }, label: 'Add filter' }), _jsx("div", { style: {
2592
- position: 'relative',
2593
- ...(openPopover === 'AddFilterPopover' && { top: 12 }),
2594
- }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddFilterPopover', setIsOpen: (isOpen) => {
2595
- if (!isOpen) {
2596
- setIsPending(false);
2597
- setActivePath(null);
2598
- setOpenPopover(null);
2599
- setTimeout(() => {
2600
- clearCheckboxes();
2601
- setActiveEditItem(null);
2602
- }, 300);
2603
- }
2604
- }, popoverTitle: 'Add filter', popoverChildren: _jsx(FilterModal, { schema: schema.find((s) => s.name === currentTable ||
2605
- s.displayName === currentTable) ?? schema[0], fieldValuesMap: uniqueValues[getTableNames(baseAst).length === 1
2606
- ? getTableNames(baseAst)[0]
2607
- : initialTableName], onSubmitFilter: (filter) => {
2608
- setOpenPopover(null);
2609
- setIsPending(false);
2610
- const item = filterToAst(filter, client.databaseType.toLowerCase());
2611
- handleInsertion(item, 'AND', false);
2612
- }, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, SecondaryButtonComponent: SecondaryButtonComponent, MultiSelectComponent: MultiSelectComponent }) }) }), baseAst?.where &&
2613
- false && ( // temp removed the AddConditionPopover
2614
- _jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { onClick: () => {
2615
- if (!openPopover) {
2616
- setActiveEditItem(deepCopy(defaultEntry));
2617
- setOpenPopover('AddConditionPopover');
2618
- setActivePath('');
2619
- setIsPending(true);
2620
- }
2621
- }, label: "Add condition" }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddConditionPopover', setIsOpen: (isOpen) => {
2622
- if (!isOpen) {
2623
- setIsPending(false);
2624
- setTimeout(() => {
2625
- clearCheckboxes();
2626
- setActiveEditItem(null);
2627
- }, 300);
2628
- setActivePath(null);
2629
- setOpenPopover(null);
2630
- }
2631
- }, popoverTitle: "Add condition", popoverChildren: _jsx(AddConditionPopover, { onSave: () => {
2632
- if (isNodeEmptyCollection(activeEditItem)) {
2633
- setIsPending(false);
2634
- setTimeout(() => {
2635
- setActiveEditItem(null);
2636
- clearCheckboxes();
2637
- }, 300);
2638
- setActivePath(null);
2639
- setOpenPopover(null);
2640
- }
2641
- else {
2642
- setIsPending(false);
2643
- handleInsertion(activeEditItem, topLevelBinaryOperator, true);
2644
- setTimeout(() => {
2645
- setActiveEditItem(null);
2646
- clearCheckboxes();
2647
- }, 300);
2648
- setActivePath(null);
2649
- setOpenPopover(null);
2650
- }
2651
- } }) })] }))] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, setPivotValueField: setPivotValueField, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, CardComponent: CardComponent, SelectComponent: SelectComponent, ButtonComponent: ButtonComponent, PopoverComponent: PopoverComponent, TextComponent: TextComponent, ErrorMessageComponent: ErrorMessageComponent, PivotRowContainer: PivotRowContainer, PivotColumnContainer: PivotColumnContainer, LoadingComponent: LoadingComponent, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEditingPivot, setShowUpdatePivot: setIsEditingPivot, parentRef: parentRef, data: rows, columns: columns, triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
2652
- setPivot(null);
2653
- setPivotData(null);
2654
- const formattedRows = formatRows(rows, columns, false);
2655
- setFormattedRows(formattedRows);
2656
- },
2657
- // TODOs
2658
- selectPivot: () => {
2659
- return;
2660
- }, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: LabelComponent, HeaderComponent: HeaderComponent, dateRange: undefined, pivotCountRequest: 4, SecondaryButtonComponent: SecondaryButtonComponent, query: activeQuery, initialUniqueValues: uniqueValues[currentTable], disabled: !loading && (!baseAst || !dataDisplayed), pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, report: tempReport ?? report }), pivot && (_jsx(PivotForm, { columns: columns, uniqueValues: uniqueValues[currentTable], setPivotRowField: (value) => {
2661
- setPivotRowField(value);
2662
- }, setPivotColumnField: setPivotColumnField, setPivotValueField: setPivotValueField, setPivotAggregation: setPivotAggregation, pivotRowField: pivotRowField, pivotColumnField: pivotColumnField, pivotValueField: pivotValueField, pivotAggregation: pivotAggregation, onDelete: () => {
2663
- setPivot(null);
2664
- setPivotData([]);
2665
- const formattedRows = formatRows(rows, columns, false);
2666
- setFormattedRows(formattedRows);
2667
- }, SecondaryButtonComponent: SecondaryButtonComponent, SelectComponent: SelectComponent, PivotColumnContainer: PivotColumnContainer }))] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Sort" }), pivot && pivot.sort && (_jsx("div", { style: {
2668
- display: 'flex',
2669
- flexDirection: 'column',
2670
- gap: 8,
2671
- marginBottom: 12,
2672
- }, children: _jsx(SortSentence, { sortData: {
2673
- type: pivot.sortDirection,
2674
- expr: { type: 'column_ref', column: pivot.sortField },
2675
- }, columns: selectedColumns, setIsPending: setIsPending, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: () => {
2676
- setPivot({ ...pivot, sort: false });
2677
- setBaseAst(deepCopy(baseAst));
2678
- if (!pivot) {
2679
- fetchSqlQuery(baseAst);
2680
- }
2681
- }, onSave: (column, direction) => {
2682
- const sortFieldType = column === (pivot.valueField || 'count')
2683
- ? 'number'
2684
- : pivot.rowFieldType;
2685
- setPivot({
2686
- ...pivot,
2687
- sort: true,
2688
- sortDirection: direction,
2689
- sortField: column,
2690
- sortFieldType: sortFieldType,
2691
- });
2692
- setOpenPopover(null);
2693
- setBaseAst(deepCopy(baseAst));
2694
- if (!pivot) {
2695
- fetchSqlQuery(baseAst);
2696
- }
2697
- }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && (_jsx("div", { style: {
2698
- display: 'flex',
2699
- flexDirection: 'column',
2700
- gap: 8,
2701
- marginBottom: 12,
2702
- }, children: baseAst.orderby.map((sortData, id) => (_jsx(SortSentence, { sortData: sortData, columns: selectedColumns, onSave: (column, direction) => {
2703
- setIsPending(false);
2704
- setActiveEditItem(null);
2705
- setOpenPopover(null);
2706
- if (column === '')
2707
- return;
2708
- const newAst = { ...baseAst };
2709
- newAst.orderby[id] = {
2710
- expr: {
2711
- type: 'column_ref',
2712
- table: null,
2713
- column: column,
2714
- },
2715
- type: direction,
2716
- };
2717
- // look through the columns
2718
- setActivePath(null);
2719
- setOpenPopover(null);
2720
- setBaseAst(deepCopy(newAst));
2721
- if (!pivot) {
2722
- fetchSqlQuery(newAst);
2723
- }
2724
- }, setIsPending: setIsPending, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: () => {
2725
- const newAst = { ...baseAst };
2726
- newAst.orderby.splice(id, 1);
2727
- setBaseAst(deepCopy(newAst));
2728
- if (!pivot) {
2729
- fetchSqlQuery(newAst);
2730
- }
2731
- }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }, `sort-sentence-${id}`))) })), _jsx(SecondaryButtonComponent, { onClick: () => {
2732
- if (!selectedColumns ||
2733
- selectedColumns.length === 0 ||
2734
- loading) {
2735
- return;
2736
- }
2737
- if (!openPopover) {
2738
- setOpenPopover('AddSortPopover');
2739
- }
2740
- }, label: "Add sort" }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddSortPopover', setIsOpen: (isOpen) => {
2741
- if (!isOpen) {
2742
- setIsPending(false);
2743
- setActiveEditItem(null);
2744
- setActivePath(null);
2745
- setOpenPopover(null);
2746
- }
2747
- }, popoverTitle: "Sort by", popoverChildren: _jsx(AddSortPopover, { columns: selectedColumns, Select: SelectComponent, Button: ButtonComponent, onSave: () => { } }) })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Limit" }), baseAst && baseAst.limit && baseAst.limit.value?.length > 0 ? (_jsx("div", { style: {
2748
- display: 'flex',
2749
- flexDirection: 'column',
2750
- gap: 8,
2751
- marginBottom: 12,
2752
- }, children: _jsx(LimitSentence, { limit: baseAst.limit, setOpenPopover: setOpenPopover, LimitPopover: LimitPopoverComponent, EditPopover: AddLimitPopover, handleDelete: () => {
2753
- const newAst = { ...baseAst };
2754
- newAst.limit = null;
2755
- setBaseAst(deepCopy(newAst));
2756
- fetchSqlQuery(newAst);
2757
- }, onSave: (limit) => {
2758
- const newAst = { ...baseAst };
2759
- newAst.limit = {
2760
- seperator: '',
2761
- value: [
2762
- {
2763
- type: 'number',
2764
- value: limit,
2765
- },
2766
- ],
2767
- };
2768
- setOpenPopover(null);
2769
- setBaseAst(deepCopy(newAst));
2770
- fetchSqlQuery(newAst);
2771
- }, TextInput: TextInputComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }) })) : (_jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { onClick: () => {
2772
- if (!selectedColumns ||
2773
- selectedColumns.length === 0 ||
2774
- loading) {
2775
- return;
2776
- }
2777
- if (!openPopover) {
2778
- setOpenPopover('AddLimitPopover');
2779
- }
2780
- }, label: 'Add limit' }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddLimitPopover', setIsOpen: (isOpen) => {
2781
- if (!isOpen) {
2782
- setIsPending(false);
2783
- setActiveEditItem(null);
2784
- setActivePath(null);
2785
- setOpenPopover(null);
2786
- }
2787
- }, popoverTitle: "Add limit", popoverChildren: _jsx(AddLimitPopover, { TextInput: TextInputComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, onSave: () => { } }) })] }))] })] }), _jsxs(ContainerComponent, { children: [isAIEnabled && (_jsx("form", { ref: askAILoadingContainerRef, onSubmit: (event) => {
2788
- event.preventDefault();
2789
- }, style: {
2790
- display: 'flex',
2791
- flexDirection: 'row',
2792
- gap: 12,
2793
- visibility: askAIInputWidth === -1 && askAILoadingContainerWidth === -1
2794
- ? 'hidden'
2795
- : 'visible',
2796
- }, children: _jsxs(_Fragment, { children: [_jsx(TextInputComponent, { id: "ask_ai_loading_bar", placeholder: askedAQuestion
2797
- ? 'Ask a follow-up question...'
2798
- : 'Ask a question...', width: askAIInputWidth !== -1
2799
- ? askAIInputWidth
2800
- : askAILoadingContainerWidth, value: aiPrompt, onChange: () => { } }), _jsx(ButtonComponent, { onClick: () => { }, label: "Ask AI" }), ((baseAst && dataDisplayed) ||
2801
- initialLoad ||
2802
- initialChartLoad) && (_jsx(SecondaryButtonComponent, { onClick: () => { }, label: "New report" }))] }) })), _jsxs(_Fragment, { children: [_jsx(TableComponent, { isLoading: true, rows: [], columns: [] }), baseAst && dataDisplayed && !initialChartLoad && (_jsxs("div", { style: {
2803
- display: 'flex',
2804
- flexDirection: 'row',
2805
- gap: '12px',
2806
- }, children: [_jsx("div", { style: { width: '100%' } }), !hideCopySQL && (_jsx(SecondaryButtonComponent, { onClick: () => copySQLToClipboard(), label: isCopying ? '✅ Copied' : 'Copy SQL' })), _jsx(ButtonComponent, { label: report ? 'Save changes' : 'Add to dashboard', onClick: () => { } })] }))] })] }), _jsx("style", { children: `body{margin:0;}` })] }));
2807
- }
2808
- return (_jsxs("div", { style: { backgroundColor: theme.backgroundColor, ...containerStyle }, className: className, children: [(!isChartBuilderHorizontalView ||
2809
- (isChartBuilderHorizontalView && !isChartBuilderOpen)) && (_jsxs("div", { ref: parentRef, style: {
2810
- display: 'flex',
2811
- flexDirection: 'row',
2812
- height: '100%',
2813
- overflowY: 'auto',
2814
- boxSizing: 'border-box',
2815
- ...containerStyle,
2816
- }, className: className, children: [_jsxs(SidebarComponent, { children: [_jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Columns" }), _jsx(DraggableColumns, {}), _jsx(SecondaryButtonComponent, { onClick: () => {
2817
- if (!orderedColumnNames) {
2818
- return;
2819
- }
2820
- if (!openPopover) {
2821
- setOpenPopover('AddColumnModal');
2822
- }
2823
- }, label: "Select columns" }), _jsx(ModalComponent, { isOpen: openPopover === 'AddColumnModal', setIsOpen: (isOpen) => {
2824
- if (!isOpen) {
2825
- // delay onClose callback so onClick no-ops
2826
- setTimeout(() => {
2827
- setIsPending(false);
2828
- setActiveEditItem(null);
2829
- setActivePath(null);
2830
- setOpenPopover(null);
2831
- }, 100);
2832
- }
2833
- }, title: "Select columns", children: _jsx(AddColumnModal, { onSave: () => {
2834
- setActiveEditItem(null);
2835
- setActivePath(null);
2836
- setOpenPopover(null);
2837
- }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: (ast) => {
2838
- setBaseAst(ast);
2839
- fetchSqlQuery(ast);
2840
- }, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, schemaLoading: loadingSchema, setPivot: setPivot, TextInput: TextInputComponent, SelectColumn: SelectColumnComponent, SecondaryButton: SecondaryButtonComponent, Button: ButtonComponent, ColumnSearchEmptyState: ColumnSearchEmptyState, LoadingComponent: LoadingComponent }) })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Filters" }), formData && (_jsx("div", { style: {
2841
- display: 'flex',
2842
- flexDirection: 'column',
2843
- gap: 8,
2844
- marginBottom: 12,
2845
- }, children: filterTree && renderFilters(filterTree) })), _jsxs("div", { style: {
2846
- display: 'flex',
2847
- flexDirection: 'column',
2848
- alignItems: 'flex-start',
2849
- }, children: [_jsx(SecondaryButtonComponent, { disabled: !baseAst || !dataDisplayed, onClick: () => {
2850
- if (!selectedColumns ||
2851
- selectedColumns.length === 0 ||
2852
- loading) {
2853
- return;
2854
- }
2855
- if (!openPopover) {
2856
- const value = orderedColumnNames[0];
2857
- const column = value.split('.')[1];
2858
- const columnType = getColumnTypeByName(column);
2859
- if (isNumericColumnType(columnType)) {
2860
- const newSubtree = deepCopy(defaultNumericComparison);
2861
- newSubtree.left.column = column;
2862
- setActiveEditItem(newSubtree);
2863
- }
2864
- else {
2865
- const newSubtree = deepCopy(defaultEntry);
2866
- newSubtree.left.args.value[0].column = column;
2867
- setActiveEditItem(newSubtree);
2868
- }
2869
- setOpenPopover('AddFilterPopover');
2870
- setActivePath('');
2871
- setIsPending(true);
2872
- }
2873
- }, label: 'Add filter' }), _jsx("div", { style: {
2874
- position: 'relative',
2875
- ...(openPopover === 'AddFilterPopover' && { top: 12 }),
2876
- }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddFilterPopover', setIsOpen: (isOpen) => {
2877
- if (!isOpen) {
2878
- // delay onClose callback so onClick no-ops
2879
- setOpenPopover(null);
2880
- setTimeout(() => {
2881
- setIsPending(false);
2882
- setActivePath(null);
2883
- clearCheckboxes();
2884
- setActiveEditItem(null);
2885
- }, 300);
2886
- }
2887
- }, popoverTitle: "Add filter", popoverChildren: _jsx(FilterModal, { schema: schema.find((s) => s.name === currentTable ||
2888
- s.displayName === currentTable) ?? schema[0], fieldValuesMap: fieldValuesMap, onSubmitFilter: (filter) => {
2889
- setOpenPopover(null);
2890
- setIsPending(false);
2891
- const item = filterToAst(filter, client.databaseType.toLowerCase());
2892
- handleInsertion(item, 'AND', false);
2893
- }, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, MultiSelectComponent: MultiSelectComponent }) }) }), baseAst?.where &&
2894
- false && ( // temp removed the AddConditionPopover
2895
- _jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { onClick: () => {
2896
- if (!openPopover) {
2897
- setActiveEditItem(deepCopy(defaultEntry));
2898
- setOpenPopover('AddConditionPopover');
2899
- setActivePath('');
2900
- setIsPending(true);
2901
- }
2902
- }, label: 'Add condition' }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddConditionPopover', setIsOpen: (isOpen) => {
2903
- if (!isOpen) {
2904
- // delay onClose callback so onClick no-ops
2905
- setTimeout(() => {
2906
- setIsPending(false);
2907
- setActiveEditItem(null);
2908
- setActivePath(null);
2909
- setOpenPopover(null);
2910
- clearCheckboxes();
2911
- }, 200);
2912
- }
2913
- }, popoverChildren: _jsx(AddConditionPopover, { onSave: () => {
2914
- if (isNodeEmptyCollection(activeEditItem)) {
2915
- setIsPending(false);
2916
- setTimeout(() => {
2917
- setActiveEditItem(null);
2918
- }, 300);
2919
- setActivePath(null);
2920
- setOpenPopover(null);
2921
- clearCheckboxes();
2922
- }
2923
- else {
2924
- setIsPending(false);
2925
- handleInsertion(activeEditItem, topLevelBinaryOperator, true);
2926
- setTimeout(() => {
2927
- setActiveEditItem(null);
2928
- }, 300);
2929
- setActivePath(null);
2930
- setOpenPopover(null);
2931
- clearCheckboxes();
2932
- }
2933
- } }) })] }))] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, setPivotValueField: setPivotValueField, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, SelectComponent: SelectComponent, ButtonComponent: ButtonComponent, CardComponent: CardComponent, SecondaryButtonComponent: SecondaryButtonComponent, PopoverComponent: PopoverComponent, TextComponent: TextComponent, ErrorMessageComponent: ErrorMessageComponent, PivotRowContainer: PivotRowContainer, PivotColumnContainer: PivotColumnContainer, LoadingComponent: LoadingComponent, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEditingPivot, setShowUpdatePivot: setIsEditingPivot, parentRef: parentRef, data: rows, columns: columns, triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
2934
- setPivot(null);
2935
- setPivotData(null);
2936
- const formattedRows = formatRows(rows, columns, false);
2937
- setFormattedRows(formattedRows);
2938
- }, selectPivot: async (pivot, uniqueValues, dateRange, pivotTable) => {
2939
- if (!pivot)
2940
- return;
2941
- const newAst = { ...baseAst };
2942
- newAst.orderby = null;
2943
- if (pivot.rowFieldType === 'date') {
2944
- pivot['sort'] = true;
2945
- pivot['sortDirection'] = 'ASC';
2946
- }
2947
- setBaseAst(newAst); // trigger refetch
2948
- let dateBucket = undefined;
2949
- if (dateRange) {
2950
- dateBucket = getDateBucketFromRange(dateRange);
2951
- }
2952
- if (!pivotTable) {
2953
- pivotTable = await generatePivotTable(pivot, rows, undefined, false, -1, undefined, dateBucket, tempReport, client, uniqueValues);
2954
- }
2955
- setPivotData(pivotTable || []);
2956
- setPivot(pivot);
2957
- const formattedRows = formatRows(pivotTable.rows, columns, true, pivot.aggregationType);
2958
- setFormattedRows(formattedRows);
2959
- setErrorMessage('');
2960
- }, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: LabelComponent, HeaderComponent: HeaderComponent, dateRange: undefined, pivotCountRequest: 4, query: activeQuery, initialUniqueValues: uniqueValues[currentTable], disabled: !baseAst || !dataDisplayed, pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, report: tempReport }), pivot && (_jsx(PivotForm, { columns: columns, uniqueValues: uniqueValues[currentTable], setPivotRowField: (value) => {
2961
- setPivotRowField(value);
2962
- updatePivot(value, 'rowField');
2963
- }, setPivotColumnField: (value) => {
2964
- setPivotColumnField(value);
2965
- updatePivot(value, 'columnField');
2966
- }, setPivotValueField: (value) => {
2967
- setPivotValueField(value);
2968
- updatePivot(value, 'valueField');
2969
- }, setPivotAggregation: (value) => {
2970
- setPivotAggregation(value);
2971
- updatePivot(value, 'aggregationType');
2972
- }, onDelete: () => {
2973
- setPivot(null);
2974
- setPivotData([]);
2975
- const formattedRows = formatRows(rows, columns, false);
2976
- setFormattedRows(formattedRows);
2977
- }, pivotRowField: pivotRowField, pivotColumnField: pivotColumnField, pivotValueField: pivotValueField, pivotAggregation: pivotAggregation, SecondaryButtonComponent: SecondaryButtonComponent, SelectComponent: SelectComponent, PivotColumnContainer: PivotColumnContainer }))] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Sort" }), pivot && pivot.sort && (_jsx("div", { style: {
2978
- display: 'flex',
2979
- flexDirection: 'column',
2980
- gap: 8,
2981
- marginBottom: 12,
2982
- }, children: _jsx(SortSentence, { sortData: {
2983
- type: pivot.sortDirection,
2984
- expr: { type: 'column_ref', column: pivot.sortField },
2985
- }, columns: pivot
2986
- ? pivot.columnField
2987
- ? [`.${pivot.rowField}`]
2988
- : [
2989
- `.${pivot.rowField}`,
2990
- `.${pivot.valueField || 'count'}`,
2991
- ]
2992
- : selectedColumns, setIsPending: setIsPending, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: async () => {
2993
- if (pivot) {
2994
- const tempPivot = { ...pivot, sort: false };
2995
- let dateBucket = undefined;
2996
- const tempDateRange = dateRanges &&
2997
- pivot.rowField &&
2998
- dateRanges[pivot.rowField];
2999
- if (tempDateRange) {
3000
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
3001
- }
3002
- setPivot(tempPivot);
3003
- const pivotedData = await generatePivotTable(tempPivot, rows, undefined, false, -1, undefined, dateBucket, tempReport, client, uniqueValues[currentTable]);
3004
- setPivotData(pivotedData || []);
3005
- const formattedRows = formatRows(pivotedData.rows, columns, true, pivot.aggregationType);
3006
- setFormattedRows(formattedRows);
3007
- setErrorMessage('');
3008
- return;
3009
- }
3010
- setBaseAst(deepCopy(baseAst));
3011
- fetchSqlQuery(deepCopy(baseAst));
3012
- }, onSave: async (column, direction) => {
3013
- if (pivot) {
3014
- const sortFieldType = column === (pivot.valueField || 'count')
3015
- ? 'number'
3016
- : pivot.rowFieldType;
3017
- const tempPivot = {
3018
- ...pivot,
3019
- sort: true,
3020
- sortDirection: direction,
3021
- sortField: column,
3022
- sortFieldType: sortFieldType,
3023
- };
3024
- setPivot(tempPivot);
3025
- let dateBucket = undefined;
3026
- const tempDateRange = dateRanges &&
3027
- pivot.rowField &&
3028
- dateRanges[pivot.rowField];
3029
- if (tempDateRange) {
3030
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
3031
- }
3032
- const pivotedData = await generatePivotTable(tempPivot, rows, undefined, false, -1, undefined, dateBucket, tempReport, client, uniqueValues[currentTable]);
3033
- setPivotData(pivotedData || []);
3034
- const formattedRows = formatRows(pivotedData.rows, columns, true, pivot.aggregationType);
3035
- setFormattedRows(formattedRows);
3036
- setErrorMessage('');
3037
- return;
3038
- }
3039
- setOpenPopover(null);
3040
- setBaseAst(deepCopy(baseAst));
3041
- fetchSqlQuery(deepCopy(baseAst));
3042
- }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && (_jsx("div", { style: {
3043
- display: 'flex',
3044
- flexDirection: 'column',
3045
- gap: 8,
3046
- marginBottom: 12,
3047
- }, children: baseAst.orderby.map((sortData, id) => (_jsx(SortSentence, { sortData: sortData, columns: selectedColumns, setIsPending: setIsPending, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: () => {
3048
- if (pivot) {
3049
- setPivot({ ...pivot, sort: false });
3050
- return;
3051
- }
3052
- const newAst = { ...baseAst };
3053
- newAst.orderby.splice(id, 1);
3054
- setBaseAst(deepCopy(newAst));
3055
- fetchSqlQuery(deepCopy(newAst));
3056
- }, onSave: (column, direction) => {
3057
- if (pivot) {
3058
- const sortFieldType = column === (pivot.valueField || 'count')
3059
- ? 'number'
3060
- : pivot.rowFieldType;
3061
- setPivot({
3062
- ...pivot,
3063
- sort: true,
3064
- sortDirection: direction,
3065
- sortField: column,
3066
- sortFieldType: sortFieldType,
3067
- });
3068
- return;
3069
- }
3070
- setIsPending(false);
3071
- setActiveEditItem(null);
3072
- setOpenPopover(null);
3073
- if (column === '')
3074
- return;
3075
- const newAst = { ...baseAst };
3076
- newAst.orderby[id] = {
3077
- expr: {
3078
- type: 'column_ref',
3079
- table: null,
3080
- column: column,
3081
- },
3082
- type: direction,
3083
- };
3084
- // look through the columns
3085
- setActivePath(null);
3086
- setOpenPopover(null);
3087
- setBaseAst(deepCopy(newAst));
3088
- fetchSqlQuery(deepCopy(newAst));
3089
- }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }, `sort-sentence-${id}`))) })), _jsx(SecondaryButtonComponent, { disabled: !baseAst || !dataDisplayed, onClick: () => {
3090
- if (!selectedColumns || selectedColumns.length === 0) {
3091
- return;
3092
- }
3093
- if (!openPopover) {
3094
- setOpenPopover('AddSortPopover');
3095
- }
3096
- }, label: 'Add sort' }), _jsx("div", { style: {
3097
- position: 'relative',
3098
- ...(openPopover === 'AddSortPopover' && { top: 12 }),
3099
- }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddSortPopover', setIsOpen: (isOpen) => {
3100
- if (!isOpen) {
3101
- setIsPending(false);
3102
- setActiveEditItem(null);
3103
- setActivePath(null);
3104
- setOpenPopover(null);
3105
- }
3106
- }, popoverTitle: "Sort by", popoverChildren: _jsx(AddSortPopover, { columns: pivot
3107
- ? pivot.columnField
3108
- ? [`.${pivot.rowField}`]
3109
- : [
3110
- `.${pivot.rowField}`,
3111
- `.${pivot.valueField || 'count'}`,
3112
- ]
3113
- : selectedColumns, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, onSave: async (column, direction) => {
3114
- if (column === '')
3115
- return;
3116
- if (pivot) {
3117
- const sortFieldType = column === (pivot.valueField || 'count')
3118
- ? 'number'
3119
- : pivot.rowFieldType;
3120
- const tempPivot = {
3121
- ...pivot,
3122
- sort: true,
3123
- sortDirection: direction,
3124
- sortField: column,
3125
- sortFieldType: sortFieldType,
3126
- };
3127
- setPivot(tempPivot);
3128
- let dateBucket = undefined;
3129
- const tempDateRange = dateRanges &&
3130
- pivot.rowField &&
3131
- dateRanges[pivot.rowField];
3132
- if (tempDateRange) {
3133
- dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
3134
- }
3135
- const pivotedData = await generatePivotTable(tempPivot, rows, undefined, false, -1, undefined, dateBucket, tempReport, client, uniqueValues[currentTable]);
3136
- setErrorMessage('');
3137
- setPivotData(pivotedData || []);
3138
- const formattedRows = formatRows(pivotedData.rows, columns, true, pivot.aggregationType);
3139
- setFormattedRows(formattedRows);
3140
- setActivePath(null);
3141
- setOpenPopover(null);
3142
- setBaseAst(deepCopy(baseAst));
3143
- return;
3144
- }
3145
- const newAst = { ...baseAst };
3146
- if (!newAst.orderby)
3147
- newAst.orderby = [];
3148
- newAst.orderby.push({
3149
- expr: { type: 'column_ref', column },
3150
- type: direction,
3151
- });
3152
- // look through the columns
3153
- setActivePath(null);
3154
- setOpenPopover(null);
3155
- setBaseAst(deepCopy(newAst));
3156
- fetchSqlQuery(deepCopy(newAst));
3157
- } }) }) })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Limit" }), baseAst && baseAst.limit && baseAst.limit.value?.length > 0 ? (_jsx("div", { style: {
3158
- display: 'flex',
3159
- flexDirection: 'column',
3160
- gap: 8,
3161
- marginBottom: 12,
3162
- }, children: _jsx(LimitSentence, { limit: baseAst.limit, setOpenPopover: setOpenPopover, LimitPopover: LimitPopoverComponent, EditPopover: AddLimitPopover, handleDelete: () => {
3163
- const newAst = { ...baseAst };
3164
- newAst.limit = null;
3165
- setBaseAst(deepCopy(newAst));
3166
- fetchSqlQuery(deepCopy(newAst));
3167
- }, onSave: (limit) => {
3168
- const newAst = { ...baseAst };
3169
- newAst.limit = {
3170
- seperator: '',
3171
- value: [
3172
- {
3173
- type: 'number',
3174
- value: limit,
3175
- },
3176
- ],
3177
- };
3178
- setOpenPopover(null);
3179
- setBaseAst(deepCopy(newAst));
3180
- fetchSqlQuery(deepCopy(newAst));
3181
- }, TextInput: TextInputComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent }) })) : (_jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { disabled: !baseAst || !dataDisplayed, onClick: () => {
3182
- if (!selectedColumns || selectedColumns.length === 0) {
3183
- return;
3184
- }
3185
- if (!baseAst) {
3186
- return;
3187
- }
3188
- if (!openPopover) {
3189
- setOpenPopover('AddLimitPopover');
3190
- }
3191
- }, label: 'Add limit' }), _jsx("div", { style: {
3192
- position: 'relative',
3193
- ...(openPopover === 'AddLimitPopover' && { top: 12 }),
3194
- }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddLimitPopover', setIsOpen: (isOpen) => {
3195
- if (!isOpen) {
3196
- setIsPending(false);
3197
- setActiveEditItem(null);
3198
- setActivePath(null);
3199
- setOpenPopover(null);
3200
- }
3201
- }, popoverTitle: "Add limit", popoverChildren: _jsx(AddLimitPopover, { TextInput: TextInputComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, onSave: (limit) => {
3202
- const newAst = { ...baseAst };
3203
- newAst.limit = {
3204
- seperator: '',
3205
- value: [
3206
- {
3207
- type: 'number',
3208
- value: Number(limit),
3209
- },
3210
- ],
3211
- };
3212
- setOpenPopover(null);
3213
- setBaseAst(deepCopy(newAst));
3214
- fetchSqlQuery(deepCopy(newAst));
3215
- } }) }) })] }))] })] }), _jsxs(ContainerComponent, { children: [isAIEnabled && (_jsx("form", { ref: askAIContainerRef, onSubmit: (event) => {
3216
- event.preventDefault();
3217
- }, style: {
3218
- display: 'flex',
3219
- flexDirection: 'row',
3220
- gap: 12,
3221
- visibility: askAIInputWidth === -1 && askAILoadingContainerWidth === -1
3222
- ? 'hidden'
3223
- : 'visible',
3224
- }, children: _jsxs(_Fragment, { children: [_jsx(TextInputComponent, { id: "ask_ai_input_bar", value: aiPrompt, width: askAIInputWidth !== -1
3225
- ? askAIInputWidth
3226
- : askAILoadingContainerWidth, onChange: (e) => setAiPrompt(e.target.value), placeholder: askedAQuestion
3227
- ? 'Ask a follow-up question...'
3228
- : 'Ask a question...' }), _jsx(ButtonComponent, { onClick: handleAsk, label: 'Ask AI' }), ((baseAst && dataDisplayed) || initialLoad) && (_jsx(SecondaryButtonComponent, { label: 'New report', onClick: clearAllState }))] }) })), baseAst && (_jsx(TableComponent, { isLoading: tableLoading ||
3229
- (loading && errorMessage.length === 0) ||
3230
- initialChartLoad, rows: formattedRows, rowCount: pivot ? undefined : numberOfRows, columns: pivot
3231
- ? pivotData?.columns || emptyPivotColumns()
3232
- : enforceOrderOnColumns(Object.keys(rows[0] ?? {})).map((c) => {
3233
- return {
3234
- label: snakeAndCamelCaseToTitleCase(c),
3235
- field: c,
3236
- };
3237
- }), onPageChange: onPageChange, onSortChange: onSortChange })), _jsxs("div", { style: {
3238
- display: 'flex',
3239
- flexDirection: 'row',
3240
- gap: '12px',
3241
- width: '100%',
3242
- }, children: [errorMessage ? (_jsxs("div", { style: {
3243
- display: 'flex',
3244
- flexDirection: 'row',
3245
- overflow: 'hidden',
3246
- width: '100%',
3247
- gap: 12,
3248
- alignItems: 'center',
3249
- }, children: [_jsx(ErrorMessageComponent, { errorMessage: errorMessage }), _jsx(SecondaryButtonComponent, { onClick: handleAsk, label: 'Retry' })] })) : (_jsx("div", { style: { width: '100%' } })), baseAst && dataDisplayed && !initialChartLoad && (_jsxs(_Fragment, { children: [!hideCopySQL && (_jsx(SecondaryButtonComponent, { label: isCopying ? '✅ Copied' : 'Copy SQL', onClick: () => copySQLToClipboard() })), _jsx(ButtonComponent, { onClick: () => {
3250
- setIsChartBuilderOpen(true);
3251
- }, disabled: !!errorMessage, label: report ? 'Save changes' : 'Add to dashboard' })] }))] })] }), _jsx("style", { children: `body{margin:0;}` })] })), (!isChartBuilderHorizontalView || isChartBuilderOpen) && (_jsx(ChartBuilderWithModal, { report: report
3252
- ? {
3253
- ...report,
3254
- ...tempReport,
3255
- pivot: pivot,
3256
- yAxisFields: report.pivot && !pivot ? [] : report.yAxisFields,
3257
- columns: report.columns.filter((col) => {
3258
- return columns.find((c) => {
3259
- return col.field === c.field;
3260
- });
3261
- }),
3262
- queryString: activeQuery,
3263
- rows: rows,
3264
- }
3265
- : tempReport, rows: rows, columns: columns, pivot: pivot, query: activeQuery, showTableFormatOptions: showChartBuilderTableFormatOptions, showDateFieldOptions: isAdminEnabled, showAccessControlOptions: isAdminEnabled, title: report ? 'Save changes' : 'Add to dashboard', isHorizontalView: true, isOpen: isChartBuilderOpen, setIsOpen: setIsChartBuilderOpen, onAddToDashboardComplete: report ? onSubmitEditReport : onSubmitCreateReport, destinationDashboard: destinationDashboard, organizationName: organizationName, pivotData: pivotData, initialUniqueValues: uniqueValues[currentTable], pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, HeaderComponent: HeaderComponent, SubHeaderComponent: SubHeaderComponent, LabelComponent: LabelComponent, TextComponent: TextComponent, CardComponent: CardComponent, ModalComponent: ChartBuilderModalComponent, PopoverComponent: PopoverComponent, TableComponent: TableComponent, DeleteButtonComponent: DeleteButtonComponent, LoadingComponent: LoadingComponent, ChartBuilderInputRowContainer: ChartBuilderInputRowContainer, ChartBuilderInputColumnContainer: ChartBuilderInputColumnContainer, FormContainer: ChartBuilderFormContainer, hideDateRangeFilter: true, buttonLabel: report ? 'Save changes' : 'Add to dashboard', onClickChartElement: onClickChartElement, rowCount: numberOfRows, onPageChange: onPageChange, onSortChange: onSortChange, isLoading: tableLoading }))] }));
3266
- }