@finos/legend-cube-builder 0.0.0-stage → 0.0.2

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 (301) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +5 -2
  3. package/lib/__lib__/LegendCubeCommand.d.ts +26 -0
  4. package/lib/__lib__/LegendCubeCommand.d.ts.map +1 -0
  5. package/lib/__lib__/LegendCubeCommand.js +40 -0
  6. package/lib/__lib__/LegendCubeCommand.js.map +1 -0
  7. package/lib/__lib__/LegendCubeHelpText.d.ts +19 -0
  8. package/lib/__lib__/LegendCubeHelpText.d.ts.map +1 -0
  9. package/lib/__lib__/LegendCubeHelpText.js +27 -0
  10. package/lib/__lib__/LegendCubeHelpText.js.map +1 -0
  11. package/lib/__lib__/LegendCubeLabels.d.ts +68 -0
  12. package/lib/__lib__/LegendCubeLabels.d.ts.map +1 -0
  13. package/lib/__lib__/LegendCubeLabels.js +109 -0
  14. package/lib/__lib__/LegendCubeLabels.js.map +1 -0
  15. package/lib/__lib__/LegendCubeTesting.d.ts +33 -0
  16. package/lib/__lib__/LegendCubeTesting.d.ts.map +1 -0
  17. package/lib/__lib__/LegendCubeTesting.js +34 -0
  18. package/lib/__lib__/LegendCubeTesting.js.map +1 -0
  19. package/lib/__test-utils__/CubeCanvasTestUtils.d.ts +24 -0
  20. package/lib/__test-utils__/CubeCanvasTestUtils.d.ts.map +1 -0
  21. package/lib/__test-utils__/CubeCanvasTestUtils.js +37 -0
  22. package/lib/__test-utils__/CubeCanvasTestUtils.js.map +1 -0
  23. package/lib/__test-utils__/CubeEngineTestSupport.d.ts +41 -0
  24. package/lib/__test-utils__/CubeEngineTestSupport.d.ts.map +1 -0
  25. package/lib/__test-utils__/CubeEngineTestSupport.js +76 -0
  26. package/lib/__test-utils__/CubeEngineTestSupport.js.map +1 -0
  27. package/lib/__test-utils__/CubeNorthwindTestQueries.d.ts +31 -0
  28. package/lib/__test-utils__/CubeNorthwindTestQueries.d.ts.map +1 -0
  29. package/lib/__test-utils__/CubeNorthwindTestQueries.js +102 -0
  30. package/lib/__test-utils__/CubeNorthwindTestQueries.js.map +1 -0
  31. package/lib/__test-utils__/CubePageTestUtils.d.ts +33 -0
  32. package/lib/__test-utils__/CubePageTestUtils.d.ts.map +1 -0
  33. package/lib/__test-utils__/CubePageTestUtils.js +68 -0
  34. package/lib/__test-utils__/CubePageTestUtils.js.map +1 -0
  35. package/lib/__test-utils__/CubeTestApplication.d.ts +30 -0
  36. package/lib/__test-utils__/CubeTestApplication.d.ts.map +1 -0
  37. package/lib/__test-utils__/CubeTestApplication.js +57 -0
  38. package/lib/__test-utils__/CubeTestApplication.js.map +1 -0
  39. package/lib/__test-utils__/FakeCubeEngine.d.ts +41 -0
  40. package/lib/__test-utils__/FakeCubeEngine.d.ts.map +1 -0
  41. package/lib/__test-utils__/FakeCubeEngine.js +85 -0
  42. package/lib/__test-utils__/FakeCubeEngine.js.map +1 -0
  43. package/lib/components/CubeButton.d.ts +20 -0
  44. package/lib/components/CubeButton.d.ts.map +1 -0
  45. package/lib/components/CubeButton.js +24 -0
  46. package/lib/components/CubeButton.js.map +1 -0
  47. package/lib/components/CubeEditor.d.ts +31 -0
  48. package/lib/components/CubeEditor.d.ts.map +1 -0
  49. package/lib/components/CubeEditor.js +90 -0
  50. package/lib/components/CubeEditor.js.map +1 -0
  51. package/lib/components/CubeNodeIcon.d.ts +23 -0
  52. package/lib/components/CubeNodeIcon.d.ts.map +1 -0
  53. package/lib/components/CubeNodeIcon.js +32 -0
  54. package/lib/components/CubeNodeIcon.js.map +1 -0
  55. package/lib/components/canvas/CubeCanvas.d.ts +37 -0
  56. package/lib/components/canvas/CubeCanvas.d.ts.map +1 -0
  57. package/lib/components/canvas/CubeCanvas.js +135 -0
  58. package/lib/components/canvas/CubeCanvas.js.map +1 -0
  59. package/lib/components/canvas/CubeCanvasContext.d.ts +19 -0
  60. package/lib/components/canvas/CubeCanvasContext.d.ts.map +1 -0
  61. package/lib/components/canvas/CubeCanvasContext.js +22 -0
  62. package/lib/components/canvas/CubeCanvasContext.js.map +1 -0
  63. package/lib/components/canvas/CubeCanvasContextMenu.d.ts +28 -0
  64. package/lib/components/canvas/CubeCanvasContextMenu.d.ts.map +1 -0
  65. package/lib/components/canvas/CubeCanvasContextMenu.js +35 -0
  66. package/lib/components/canvas/CubeCanvasContextMenu.js.map +1 -0
  67. package/lib/components/canvas/CubeCanvasDnd.d.ts +43 -0
  68. package/lib/components/canvas/CubeCanvasDnd.d.ts.map +1 -0
  69. package/lib/components/canvas/CubeCanvasDnd.js +51 -0
  70. package/lib/components/canvas/CubeCanvasDnd.js.map +1 -0
  71. package/lib/components/canvas/CubeCanvasEdge.d.ts +24 -0
  72. package/lib/components/canvas/CubeCanvasEdge.d.ts.map +1 -0
  73. package/lib/components/canvas/CubeCanvasEdge.js +33 -0
  74. package/lib/components/canvas/CubeCanvasEdge.js.map +1 -0
  75. package/lib/components/canvas/CubeCanvasElements.d.ts +64 -0
  76. package/lib/components/canvas/CubeCanvasElements.d.ts.map +1 -0
  77. package/lib/components/canvas/CubeCanvasElements.js +96 -0
  78. package/lib/components/canvas/CubeCanvasElements.js.map +1 -0
  79. package/lib/components/canvas/CubeCanvasLayout.d.ts +32 -0
  80. package/lib/components/canvas/CubeCanvasLayout.d.ts.map +1 -0
  81. package/lib/components/canvas/CubeCanvasLayout.js +63 -0
  82. package/lib/components/canvas/CubeCanvasLayout.js.map +1 -0
  83. package/lib/components/canvas/CubeCanvasNode.d.ts +29 -0
  84. package/lib/components/canvas/CubeCanvasNode.d.ts.map +1 -0
  85. package/lib/components/canvas/CubeCanvasNode.js +72 -0
  86. package/lib/components/canvas/CubeCanvasNode.js.map +1 -0
  87. package/lib/components/editors/CubeColumnPicker.d.ts +40 -0
  88. package/lib/components/editors/CubeColumnPicker.d.ts.map +1 -0
  89. package/lib/components/editors/CubeColumnPicker.js +51 -0
  90. package/lib/components/editors/CubeColumnPicker.js.map +1 -0
  91. package/lib/components/editors/CubeFilterEditor.d.ts +26 -0
  92. package/lib/components/editors/CubeFilterEditor.d.ts.map +1 -0
  93. package/lib/components/editors/CubeFilterEditor.js +90 -0
  94. package/lib/components/editors/CubeFilterEditor.js.map +1 -0
  95. package/lib/components/editors/CubeJoinEditor.d.ts +26 -0
  96. package/lib/components/editors/CubeJoinEditor.d.ts.map +1 -0
  97. package/lib/components/editors/CubeJoinEditor.js +76 -0
  98. package/lib/components/editors/CubeJoinEditor.js.map +1 -0
  99. package/lib/components/editors/CubeNodeEditorPanel.d.ts +29 -0
  100. package/lib/components/editors/CubeNodeEditorPanel.d.ts.map +1 -0
  101. package/lib/components/editors/CubeNodeEditorPanel.js +71 -0
  102. package/lib/components/editors/CubeNodeEditorPanel.js.map +1 -0
  103. package/lib/components/editors/CubeNodeEditorRegistry.d.ts +44 -0
  104. package/lib/components/editors/CubeNodeEditorRegistry.d.ts.map +1 -0
  105. package/lib/components/editors/CubeNodeEditorRegistry.js +30 -0
  106. package/lib/components/editors/CubeNodeEditorRegistry.js.map +1 -0
  107. package/lib/components/editors/CubeSourceEditor.d.ts +25 -0
  108. package/lib/components/editors/CubeSourceEditor.d.ts.map +1 -0
  109. package/lib/components/editors/CubeSourceEditor.js +42 -0
  110. package/lib/components/editors/CubeSourceEditor.js.map +1 -0
  111. package/lib/components/editors/CubeValueEditor.d.ts +40 -0
  112. package/lib/components/editors/CubeValueEditor.d.ts.map +1 -0
  113. package/lib/components/editors/CubeValueEditor.js +177 -0
  114. package/lib/components/editors/CubeValueEditor.js.map +1 -0
  115. package/lib/components/grid/CubeGridRegion.d.ts +23 -0
  116. package/lib/components/grid/CubeGridRegion.d.ts.map +1 -0
  117. package/lib/components/grid/CubeGridRegion.js +94 -0
  118. package/lib/components/grid/CubeGridRegion.js.map +1 -0
  119. package/lib/components/grid/CubeGridValues.d.ts +25 -0
  120. package/lib/components/grid/CubeGridValues.d.ts.map +1 -0
  121. package/lib/components/grid/CubeGridValues.js +95 -0
  122. package/lib/components/grid/CubeGridValues.js.map +1 -0
  123. package/lib/components/grid/CubeResultGrid.d.ts +26 -0
  124. package/lib/components/grid/CubeResultGrid.d.ts.map +1 -0
  125. package/lib/components/grid/CubeResultGrid.js +50 -0
  126. package/lib/components/grid/CubeResultGrid.js.map +1 -0
  127. package/lib/components/palette/CubePalette.d.ts +29 -0
  128. package/lib/components/palette/CubePalette.d.ts.map +1 -0
  129. package/lib/components/palette/CubePalette.js +73 -0
  130. package/lib/components/palette/CubePalette.js.map +1 -0
  131. package/lib/components/show-pure/CubeShowPureDialog.d.ts +23 -0
  132. package/lib/components/show-pure/CubeShowPureDialog.d.ts.map +1 -0
  133. package/lib/components/show-pure/CubeShowPureDialog.js +37 -0
  134. package/lib/components/show-pure/CubeShowPureDialog.js.map +1 -0
  135. package/lib/components/source-picker/CubeSourcePicker.d.ts +22 -0
  136. package/lib/components/source-picker/CubeSourcePicker.d.ts.map +1 -0
  137. package/lib/components/source-picker/CubeSourcePicker.js +89 -0
  138. package/lib/components/source-picker/CubeSourcePicker.js.map +1 -0
  139. package/lib/components/spec-transfer/CubeSpecTransferDialog.d.ts +26 -0
  140. package/lib/components/spec-transfer/CubeSpecTransferDialog.d.ts.map +1 -0
  141. package/lib/components/spec-transfer/CubeSpecTransferDialog.js +45 -0
  142. package/lib/components/spec-transfer/CubeSpecTransferDialog.js.map +1 -0
  143. package/lib/graph-manager/CubeEngine.d.ts +115 -0
  144. package/lib/graph-manager/CubeEngine.d.ts.map +1 -0
  145. package/lib/graph-manager/CubeEngine.js +61 -0
  146. package/lib/graph-manager/CubeEngine.js.map +1 -0
  147. package/lib/graph-manager/CubeModelOutlineHelper.d.ts +25 -0
  148. package/lib/graph-manager/CubeModelOutlineHelper.d.ts.map +1 -0
  149. package/lib/graph-manager/CubeModelOutlineHelper.js +24 -0
  150. package/lib/graph-manager/CubeModelOutlineHelper.js.map +1 -0
  151. package/lib/graph-manager/protocol/pure/CubeEngineBuilder.d.ts +26 -0
  152. package/lib/graph-manager/protocol/pure/CubeEngineBuilder.d.ts.map +1 -0
  153. package/lib/graph-manager/protocol/pure/CubeEngineBuilder.js +22 -0
  154. package/lib/graph-manager/protocol/pure/CubeEngineBuilder.js.map +1 -0
  155. package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.d.ts +27 -0
  156. package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.d.ts.map +1 -0
  157. package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.js +76 -0
  158. package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.js.map +1 -0
  159. package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.d.ts +27 -0
  160. package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.d.ts.map +1 -0
  161. package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.js +82 -0
  162. package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.js.map +1 -0
  163. package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.d.ts +32 -0
  164. package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.d.ts.map +1 -0
  165. package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.js +195 -0
  166. package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.js.map +1 -0
  167. package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.d.ts +20 -0
  168. package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.d.ts.map +1 -0
  169. package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.js +121 -0
  170. package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.js.map +1 -0
  171. package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.d.ts +24 -0
  172. package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.d.ts.map +1 -0
  173. package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.js +43 -0
  174. package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.js.map +1 -0
  175. package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.d.ts +45 -0
  176. package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.d.ts.map +1 -0
  177. package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.js +171 -0
  178. package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.js.map +1 -0
  179. package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.d.ts +22 -0
  180. package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.d.ts.map +1 -0
  181. package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.js +79 -0
  182. package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.js.map +1 -0
  183. package/lib/index.css +17 -0
  184. package/lib/index.css.map +1 -0
  185. package/lib/index.d.ts +25 -0
  186. package/lib/index.d.ts.map +1 -0
  187. package/lib/index.js +24 -0
  188. package/lib/index.js.map +1 -0
  189. package/lib/stores/CubeEditorState.d.ts +206 -0
  190. package/lib/stores/CubeEditorState.d.ts.map +1 -0
  191. package/lib/stores/CubeEditorState.js +551 -0
  192. package/lib/stores/CubeEditorState.js.map +1 -0
  193. package/lib/stores/CubeExecutionState.d.ts +67 -0
  194. package/lib/stores/CubeExecutionState.d.ts.map +1 -0
  195. package/lib/stores/CubeExecutionState.js +196 -0
  196. package/lib/stores/CubeExecutionState.js.map +1 -0
  197. package/lib/stores/CubeHost.d.ts +31 -0
  198. package/lib/stores/CubeHost.d.ts.map +1 -0
  199. package/lib/stores/CubeHost.js +17 -0
  200. package/lib/stores/CubeHost.js.map +1 -0
  201. package/lib/stores/CubeNodeEditorState.d.ts +85 -0
  202. package/lib/stores/CubeNodeEditorState.d.ts.map +1 -0
  203. package/lib/stores/CubeNodeEditorState.js +207 -0
  204. package/lib/stores/CubeNodeEditorState.js.map +1 -0
  205. package/lib/stores/CubeShowPureState.d.ts +38 -0
  206. package/lib/stores/CubeShowPureState.d.ts.map +1 -0
  207. package/lib/stores/CubeShowPureState.js +83 -0
  208. package/lib/stores/CubeShowPureState.js.map +1 -0
  209. package/lib/stores/CubeSourcePickerState.d.ts +98 -0
  210. package/lib/stores/CubeSourcePickerState.d.ts.map +1 -0
  211. package/lib/stores/CubeSourcePickerState.js +334 -0
  212. package/lib/stores/CubeSourcePickerState.js.map +1 -0
  213. package/lib/stores/CubeSpecTransferState.d.ts +60 -0
  214. package/lib/stores/CubeSpecTransferState.d.ts.map +1 -0
  215. package/lib/stores/CubeSpecTransferState.js +167 -0
  216. package/lib/stores/CubeSpecTransferState.js.map +1 -0
  217. package/lib/stores/LocalModelCatalog.d.ts +37 -0
  218. package/lib/stores/LocalModelCatalog.d.ts.map +1 -0
  219. package/lib/stores/LocalModelCatalog.js +49 -0
  220. package/lib/stores/LocalModelCatalog.js.map +1 -0
  221. package/lib/stores/editors/CubeFilterDraft.d.ts +61 -0
  222. package/lib/stores/editors/CubeFilterDraft.d.ts.map +1 -0
  223. package/lib/stores/editors/CubeFilterDraft.js +186 -0
  224. package/lib/stores/editors/CubeFilterDraft.js.map +1 -0
  225. package/lib/stores/editors/CubeJoinDraft.d.ts +63 -0
  226. package/lib/stores/editors/CubeJoinDraft.d.ts.map +1 -0
  227. package/lib/stores/editors/CubeJoinDraft.js +136 -0
  228. package/lib/stores/editors/CubeJoinDraft.js.map +1 -0
  229. package/lib/stores/editors/CubeNodeDraft.d.ts +38 -0
  230. package/lib/stores/editors/CubeNodeDraft.d.ts.map +1 -0
  231. package/lib/stores/editors/CubeNodeDraft.js +35 -0
  232. package/lib/stores/editors/CubeNodeDraft.js.map +1 -0
  233. package/lib/stores/editors/CubeNodeDraftRegistry.d.ts +29 -0
  234. package/lib/stores/editors/CubeNodeDraftRegistry.d.ts.map +1 -0
  235. package/lib/stores/editors/CubeNodeDraftRegistry.js +33 -0
  236. package/lib/stores/editors/CubeNodeDraftRegistry.js.map +1 -0
  237. package/lib/stores/fixtures/CubeNorthwindModel.d.ts +23 -0
  238. package/lib/stores/fixtures/CubeNorthwindModel.d.ts.map +1 -0
  239. package/lib/stores/fixtures/CubeNorthwindModel.js +338 -0
  240. package/lib/stores/fixtures/CubeNorthwindModel.js.map +1 -0
  241. package/package.json +81 -3
  242. package/src/__lib__/LegendCubeCommand.ts +44 -0
  243. package/src/__lib__/LegendCubeHelpText.ts +38 -0
  244. package/src/__lib__/LegendCubeLabels.ts +141 -0
  245. package/src/__lib__/LegendCubeTesting.ts +33 -0
  246. package/src/__test-utils__/CubeCanvasTestUtils.ts +53 -0
  247. package/src/__test-utils__/CubeEngineTestSupport.ts +137 -0
  248. package/src/__test-utils__/CubeNorthwindTestQueries.ts +165 -0
  249. package/src/__test-utils__/CubePageTestUtils.tsx +96 -0
  250. package/src/__test-utils__/CubeTestApplication.ts +82 -0
  251. package/src/__test-utils__/FakeCubeEngine.ts +139 -0
  252. package/src/components/CubeButton.tsx +35 -0
  253. package/src/components/CubeEditor.tsx +239 -0
  254. package/src/components/CubeNodeIcon.tsx +47 -0
  255. package/src/components/canvas/CubeCanvas.tsx +260 -0
  256. package/src/components/canvas/CubeCanvasContext.ts +31 -0
  257. package/src/components/canvas/CubeCanvasContextMenu.tsx +89 -0
  258. package/src/components/canvas/CubeCanvasDnd.ts +82 -0
  259. package/src/components/canvas/CubeCanvasEdge.tsx +57 -0
  260. package/src/components/canvas/CubeCanvasElements.ts +150 -0
  261. package/src/components/canvas/CubeCanvasLayout.ts +88 -0
  262. package/src/components/canvas/CubeCanvasNode.tsx +141 -0
  263. package/src/components/editors/CubeColumnPicker.tsx +114 -0
  264. package/src/components/editors/CubeFilterEditor.tsx +309 -0
  265. package/src/components/editors/CubeJoinEditor.tsx +224 -0
  266. package/src/components/editors/CubeNodeEditorPanel.tsx +204 -0
  267. package/src/components/editors/CubeNodeEditorRegistry.ts +61 -0
  268. package/src/components/editors/CubeSourceEditor.tsx +116 -0
  269. package/src/components/editors/CubeValueEditor.tsx +332 -0
  270. package/src/components/grid/CubeGridRegion.tsx +274 -0
  271. package/src/components/grid/CubeGridValues.ts +125 -0
  272. package/src/components/grid/CubeResultGrid.tsx +84 -0
  273. package/src/components/palette/CubePalette.tsx +177 -0
  274. package/src/components/show-pure/CubeShowPureDialog.tsx +101 -0
  275. package/src/components/source-picker/CubeSourcePicker.tsx +304 -0
  276. package/src/components/spec-transfer/CubeSpecTransferDialog.tsx +157 -0
  277. package/src/graph-manager/CubeEngine.ts +155 -0
  278. package/src/graph-manager/CubeModelOutlineHelper.ts +32 -0
  279. package/src/graph-manager/protocol/pure/CubeEngineBuilder.ts +34 -0
  280. package/src/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.ts +109 -0
  281. package/src/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.ts +115 -0
  282. package/src/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.ts +257 -0
  283. package/src/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.ts +157 -0
  284. package/src/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.ts +58 -0
  285. package/src/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.ts +278 -0
  286. package/src/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.ts +124 -0
  287. package/src/index.ts +41 -0
  288. package/src/stores/CubeEditorState.ts +702 -0
  289. package/src/stores/CubeExecutionState.ts +255 -0
  290. package/src/stores/CubeHost.ts +32 -0
  291. package/src/stores/CubeNodeEditorState.ts +255 -0
  292. package/src/stores/CubeShowPureState.ts +96 -0
  293. package/src/stores/CubeSourcePickerState.ts +426 -0
  294. package/src/stores/CubeSpecTransferState.ts +198 -0
  295. package/src/stores/LocalModelCatalog.ts +70 -0
  296. package/src/stores/editors/CubeFilterDraft.ts +241 -0
  297. package/src/stores/editors/CubeJoinDraft.ts +197 -0
  298. package/src/stores/editors/CubeNodeDraft.ts +46 -0
  299. package/src/stores/editors/CubeNodeDraftRegistry.ts +49 -0
  300. package/src/stores/fixtures/CubeNorthwindModel.ts +355 -0
  301. package/tsconfig.json +118 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import type { CubeEditorState } from '../../stores/CubeEditorState.js';
18
+
19
+ // Drag and drop on the canvas (spec §17.3): palette items and nodes are
20
+ // dragged; nodes and the canvas take drops. The app's HTML5 backend provider
21
+ // wraps every Legend application, so Cube mounts none of its own.
22
+
23
+ export enum CUBE_DND_TYPE {
24
+ PALETTE_ITEM = 'legend-cube.palette-item',
25
+ NODE = 'legend-cube.node',
26
+ }
27
+
28
+ /** A palette item carries the type of node it adds */
29
+ export interface CubePaletteDragItem {
30
+ readonly nodeType: string;
31
+ }
32
+
33
+ /** A node carries only its id */
34
+ export interface CubeNodeDragItem {
35
+ readonly nodeId: string;
36
+ }
37
+
38
+ export type CubeDragItem = CubePaletteDragItem | CubeNodeDragItem;
39
+
40
+ const isNodeDragItem = (item: CubeDragItem): item is CubeNodeDragItem =>
41
+ 'nodeId' in item;
42
+
43
+ /**
44
+ * Whether dropping the item on the node does anything, which also decides
45
+ * whether the node lights up under it: a palette item is spliced in after
46
+ * the node, another node connects to it or else moves after it
47
+ */
48
+ export const canDropOnCubeNode = (
49
+ editorState: CubeEditorState,
50
+ item: CubeDragItem,
51
+ targetId: string,
52
+ ): boolean =>
53
+ isNodeDragItem(item)
54
+ ? editorState.canDropNode(item.nodeId, targetId)
55
+ : editorState.canAddNode(item.nodeType, targetId);
56
+
57
+ export const dropOnCubeNode = (
58
+ editorState: CubeEditorState,
59
+ item: CubeDragItem,
60
+ targetId: string,
61
+ ): void => {
62
+ if (isNodeDragItem(item)) {
63
+ editorState.dropNode(item.nodeId, targetId);
64
+ } else {
65
+ editorState.addNode(item.nodeType, targetId);
66
+ }
67
+ };
68
+
69
+ /**
70
+ * A palette item dropped on the canvas around the nodes: a transform is
71
+ * added unconnected, a source opens the picker. A drop on a node is the
72
+ * node's, taken or refused, never the canvas's.
73
+ */
74
+ export const dropOnCubeCanvas = (
75
+ editorState: CubeEditorState,
76
+ item: CubeDragItem,
77
+ isOverNode: boolean,
78
+ ): void => {
79
+ if (!isOverNode && !isNodeDragItem(item)) {
80
+ editorState.addNode(item.nodeType);
81
+ }
82
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ BaseEdge,
19
+ EdgeLabelRenderer,
20
+ type EdgeProps,
21
+ getBezierPath,
22
+ } from '@xyflow/react';
23
+ import { LEGEND_CUBE_TEST_ID } from '../../__lib__/LegendCubeTesting.js';
24
+ import type { CubeCanvasFlowEdge } from './CubeCanvasElements.js';
25
+
26
+ /** The gap between an input's label and the node it feeds */
27
+ const LABEL_GAP = 6;
28
+
29
+ /**
30
+ * A connection, with its port's label (Left or Right on a Join) shown as text
31
+ * beside the input it feeds, not in a tooltip (spec §17.3). The label is HTML:
32
+ * React Flow's own edge label measures SVG text, which jsdom can't.
33
+ */
34
+ export const CubeCanvasEdge: React.FC<EdgeProps<CubeCanvasFlowEdge>> = (
35
+ props,
36
+ ) => {
37
+ const { id, targetX, targetY, markerEnd, data } = props;
38
+ const [path] = getBezierPath(props);
39
+ return (
40
+ <>
41
+ <BaseEdge id={id} path={path} markerEnd={markerEnd} />
42
+ {data?.label && (
43
+ <EdgeLabelRenderer>
44
+ <div
45
+ className="absolute rounded bg-[var(--color-bg-panel)] px-1 text-sm text-[var(--color-text-secondary)]"
46
+ style={{
47
+ transform: `translate(-100%, -100%) translate(${targetX - LABEL_GAP}px, ${targetY - 2}px)`,
48
+ }}
49
+ data-testid={LEGEND_CUBE_TEST_ID.CANVAS_EDGE_LABEL}
50
+ >
51
+ {data.label}
52
+ </div>
53
+ </EdgeLabelRenderer>
54
+ )}
55
+ </>
56
+ );
57
+ };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ isIncompleteError,
19
+ isSchemasError,
20
+ type Query,
21
+ type QueryNode,
22
+ } from '@finos/legend-cube';
23
+ import { type Edge, MarkerType, type Node, Position } from '@xyflow/react';
24
+ import type { CubeEditorState } from '../../stores/CubeEditorState.js';
25
+ import {
26
+ CUBE_CANVAS_NODE_HEIGHT,
27
+ CUBE_CANVAS_NODE_WIDTH,
28
+ type CubeCanvasPosition,
29
+ } from './CubeCanvasLayout.js';
30
+
31
+ // The query as React Flow draws it: one node per query node, one edge per
32
+ // connection. Rebuilt from the query on every change; React Flow keeps no
33
+ // state of its own that matters (PLAN §7.2)
34
+
35
+ export const CUBE_CANVAS_NODE_TYPE = 'cube';
36
+ export const CUBE_CANVAS_EDGE_TYPE = 'cube';
37
+ /** The one output of every node; its inputs are named by its ports */
38
+ export const CUBE_OUTPUT_HANDLE_ID = 'output';
39
+
40
+ /** Shown when a node has no validity entry at all, which inference never leaves out */
41
+ export const MISSING_VALIDITY_TOOLTIP =
42
+ 'This node depends on some invalid inputs.';
43
+
44
+ export type CubeCanvasNodeData = { readonly node: QueryNode };
45
+ export type CubeCanvasEdgeData = { readonly label: string | undefined };
46
+ export type CubeCanvasFlowNode = Node<CubeCanvasNodeData, 'cube'>;
47
+ export type CubeCanvasFlowEdge = Edge<CubeCanvasEdgeData, 'cube'>;
48
+ type CubeCanvasHandle = NonNullable<Node['handles']>[number];
49
+
50
+ /** How far down the node's left side each input handle sits: evenly spaced, in port order */
51
+ export const getInputHandleOffset = (index: number, count: number): number =>
52
+ (CUBE_CANVAS_NODE_HEIGHT * (index + 1)) / (count + 1);
53
+
54
+ /**
55
+ * Where the node's handles are, so edges are drawn without measuring the DOM:
56
+ * its inputs down its left side in port order (a Join's Left above its
57
+ * Right), its output in the middle of its right side. New objects each time:
58
+ * React Flow writes into them.
59
+ */
60
+ export const getCubeCanvasHandles = (node: QueryNode): CubeCanvasHandle[] => [
61
+ ...node.ports.map((port, index) => ({
62
+ id: port,
63
+ type: 'target' as const,
64
+ position: Position.Left,
65
+ x: 0,
66
+ y: getInputHandleOffset(index, node.ports.length),
67
+ })),
68
+ {
69
+ id: CUBE_OUTPUT_HANDLE_ID,
70
+ type: 'source' as const,
71
+ position: Position.Right,
72
+ x: CUBE_CANVAS_NODE_WIDTH,
73
+ y: CUBE_CANVAS_NODE_HEIGHT / 2,
74
+ },
75
+ ];
76
+
77
+ export const buildCubeCanvasNodes = (
78
+ query: Query,
79
+ positions: ReadonlyMap<string, CubeCanvasPosition>,
80
+ ): CubeCanvasFlowNode[] =>
81
+ query.nodes.map((node) => ({
82
+ id: node.id,
83
+ type: CUBE_CANVAS_NODE_TYPE,
84
+ position: { ...(positions.get(node.id) ?? { x: 0, y: 0 }) },
85
+ width: CUBE_CANVAS_NODE_WIDTH,
86
+ height: CUBE_CANVAS_NODE_HEIGHT,
87
+ handles: getCubeCanvasHandles(node),
88
+ data: { node },
89
+ }));
90
+
91
+ /** Each connection, labelled with its port's label when the target has one, e.g. Left and Right on a Join */
92
+ export const buildCubeCanvasEdges = (query: Query): CubeCanvasFlowEdge[] =>
93
+ query.connections.map((connection) => {
94
+ const target = query.getNode(connection.target);
95
+ const label = target?.portLabels[target.ports.indexOf(connection.port)];
96
+ return {
97
+ id: connection.toString(),
98
+ type: CUBE_CANVAS_EDGE_TYPE,
99
+ source: connection.source,
100
+ target: connection.target,
101
+ sourceHandle: CUBE_OUTPUT_HANDLE_ID,
102
+ targetHandle: connection.port,
103
+ markerEnd: { type: MarkerType.ArrowClosed },
104
+ data: { label },
105
+ };
106
+ });
107
+
108
+ /** How a node looks on the canvas (spec §17.3): each state is its own class modifier */
109
+ export interface CubeCanvasNodeStatus {
110
+ /** Execute runs the query up to this node */
111
+ readonly isCapture: boolean;
112
+ /** It has errors of its own, the query rules' included; not the engine's */
113
+ readonly isInvalid: boolean;
114
+ /** An input is missing, or an input is invalid */
115
+ readonly isIncomplete: boolean;
116
+ /** The engine is typing its table */
117
+ readonly isResolving: boolean;
118
+ /** The last run failed on it */
119
+ readonly hasEngineError: boolean;
120
+ /** Its errors, then its warnings, its description and its id, one a line */
121
+ readonly tooltip: string;
122
+ }
123
+
124
+ export const getCubeCanvasNodeStatus = (
125
+ editorState: CubeEditorState,
126
+ node: QueryNode,
127
+ ): CubeCanvasNodeStatus => {
128
+ const ownErrors = editorState.analysis.validity.get(node.id);
129
+ // the tooltip adds the engine's error; the states keep it apart
130
+ const errors = editorState.getNodeErrors(node.id);
131
+ const warnings = editorState.warnings.get(node.key) ?? [];
132
+ return {
133
+ isCapture: editorState.document.query.selected === node.id,
134
+ isInvalid: (ownErrors ?? []).some(
135
+ (error) => !isIncompleteError(error) && !isSchemasError(error),
136
+ ),
137
+ isIncomplete: (ownErrors ?? []).some(
138
+ (error) => isIncompleteError(error) || isSchemasError(error),
139
+ ),
140
+ isResolving: editorState.isPendingSource(node),
141
+ hasEngineError: editorState.hostIssues.has(node.id),
142
+ tooltip: [
143
+ ...(ownErrors ? [] : [MISSING_VALIDITY_TOOLTIP]),
144
+ ...errors,
145
+ ...warnings,
146
+ node.describe(),
147
+ node.id,
148
+ ].join('\n'),
149
+ };
150
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import dagre from '@dagrejs/dagre';
18
+ import type { Connection, Query } from '@finos/legend-cube';
19
+
20
+ /** Every node is drawn this size, so edges need no DOM measurement (PLAN §7.2) */
21
+ export const CUBE_CANVAS_NODE_WIDTH = 200;
22
+ export const CUBE_CANVAS_NODE_HEIGHT = 72;
23
+
24
+ const RANK_SEPARATION = 80;
25
+ const NODE_SEPARATION = 32;
26
+
27
+ /** A node's top-left corner on the canvas */
28
+ export interface CubeCanvasPosition {
29
+ readonly x: number;
30
+ readonly y: number;
31
+ }
32
+
33
+ // by code unit, so the order never depends on the locale
34
+ const compareText = (a: string, b: string): number =>
35
+ a < b ? -1 : a > b ? 1 : 0;
36
+
37
+ const compareConnections = (a: Connection, b: Connection): number =>
38
+ compareText(a.port, b.port) ||
39
+ compareText(a.source, b.source) ||
40
+ compareText(a.target, b.target);
41
+
42
+ /**
43
+ * Where each node goes, laid out left to right (spec §17.3): a pure function
44
+ * of the query, recomputed on every change, so undo, import and every edit
45
+ * need no layout state. Nodes go in sorted by id and connections by port,
46
+ * source and target, so an edit that only reorders them moves nothing.
47
+ */
48
+ export const layoutCubeQuery = (
49
+ query: Query,
50
+ ): Map<string, CubeCanvasPosition> => {
51
+ const graph = new dagre.graphlib.Graph<{
52
+ width: number;
53
+ height: number;
54
+ }>({ multigraph: true });
55
+ graph.setGraph({
56
+ rankdir: 'LR',
57
+ ranksep: RANK_SEPARATION,
58
+ nodesep: NODE_SEPARATION,
59
+ });
60
+ graph.setDefaultEdgeLabel(() => ({}));
61
+ [...query.nodes]
62
+ .sort((a, b) => compareText(a.id, b.id))
63
+ .forEach((node) =>
64
+ graph.setNode(node.id, {
65
+ width: CUBE_CANVAS_NODE_WIDTH,
66
+ height: CUBE_CANVAS_NODE_HEIGHT,
67
+ }),
68
+ );
69
+ [...query.connections]
70
+ .sort(compareConnections)
71
+ .forEach((connection) =>
72
+ graph.setEdge(connection.source, connection.target, {}, connection.port),
73
+ );
74
+ dagre.layout(graph);
75
+ return new Map(
76
+ query.nodes.map((node) => {
77
+ // dagre gives each node's centre
78
+ const { x, y } = graph.node(node.id);
79
+ return [
80
+ node.id,
81
+ {
82
+ x: x - CUBE_CANVAS_NODE_WIDTH / 2,
83
+ y: y - CUBE_CANVAS_NODE_HEIGHT / 2,
84
+ },
85
+ ];
86
+ }),
87
+ );
88
+ };
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { clsx, ContextMenu } from '@finos/legend-art';
18
+ import { Handle, type NodeProps, Position } from '@xyflow/react';
19
+ import { observer } from 'mobx-react-lite';
20
+ import { useRef } from 'react';
21
+ import { useDrag, useDrop } from 'react-dnd';
22
+ import { LEGEND_CUBE_TEST_ID } from '../../__lib__/LegendCubeTesting.js';
23
+ import { CubeNodeIcon } from '../CubeNodeIcon.js';
24
+ import {
25
+ CUBE_OUTPUT_HANDLE_ID,
26
+ type CubeCanvasFlowNode,
27
+ getCubeCanvasNodeStatus,
28
+ getInputHandleOffset,
29
+ } from './CubeCanvasElements.js';
30
+ import { useCubeCanvasEditorState } from './CubeCanvasContext.js';
31
+ import { CubeCanvasContextMenu } from './CubeCanvasContextMenu.js';
32
+ import {
33
+ canDropOnCubeNode,
34
+ CUBE_DND_TYPE,
35
+ type CubeDragItem,
36
+ type CubeNodeDragItem,
37
+ dropOnCubeNode,
38
+ } from './CubeCanvasDnd.js';
39
+
40
+ /**
41
+ * A node on the canvas: its type's icon and its description, never its id,
42
+ * which is in the tooltip (spec §17.3). Its look tells its state at a glance.
43
+ * It can be dragged onto another node, and takes palette items and other
44
+ * nodes, lighting up only for a drop that would do something. Its handles
45
+ * sit beside its draggable body, not in it, so dragging from a handle
46
+ * connects rather than drags the node.
47
+ */
48
+ export const CubeCanvasNode = observer(
49
+ (props: NodeProps<CubeCanvasFlowNode>) => {
50
+ const { node } = props.data;
51
+ const editorState = useCubeCanvasEditorState();
52
+ const status = getCubeCanvasNodeStatus(editorState, node);
53
+ const connectable = !editorState.readOnly && node.acceptsNewInputs;
54
+ const ref = useRef<HTMLDivElement>(null);
55
+ const [, dragConnector] = useDrag<CubeNodeDragItem>(
56
+ () => ({
57
+ type: CUBE_DND_TYPE.NODE,
58
+ item: { nodeId: node.id },
59
+ canDrag: () => !editorState.readOnly,
60
+ }),
61
+ [editorState, node.id],
62
+ );
63
+ const [{ isDropTarget }, dropConnector] = useDrop<
64
+ CubeDragItem,
65
+ void,
66
+ { isDropTarget: boolean }
67
+ >(
68
+ () => ({
69
+ accept: [CUBE_DND_TYPE.NODE, CUBE_DND_TYPE.PALETTE_ITEM],
70
+ canDrop: (item) => canDropOnCubeNode(editorState, item, node.id),
71
+ drop: (item) => dropOnCubeNode(editorState, item, node.id),
72
+ collect: (monitor) => ({
73
+ isDropTarget: monitor.isOver({ shallow: true }) && monitor.canDrop(),
74
+ }),
75
+ }),
76
+ [editorState, node.id],
77
+ );
78
+ dragConnector(dropConnector(ref));
79
+ return (
80
+ <ContextMenu
81
+ className="h-full w-full"
82
+ content={
83
+ <CubeCanvasContextMenu editorState={editorState} nodeId={node.id} />
84
+ }
85
+ menuProps={{ elevation: 7 }}
86
+ >
87
+ {node.ports.map((port, index) => (
88
+ <Handle
89
+ key={port}
90
+ id={port}
91
+ type="target"
92
+ position={Position.Left}
93
+ isConnectable={connectable}
94
+ style={{ top: getInputHandleOffset(index, node.ports.length) }}
95
+ />
96
+ ))}
97
+ <div
98
+ ref={ref}
99
+ className={clsx(
100
+ // React Flow must leave the mouse to the HTML drag: 'nodrag' keeps
101
+ // it from moving the node, 'nopan' from panning the canvas
102
+ 'legend-cube__node nodrag nopan flex h-full w-full items-center gap-2 rounded border bg-[var(--color-bg-panel)] px-2 text-base text-[var(--color-text-primary)]',
103
+ status.isInvalid
104
+ ? 'border-[var(--color-status-error)]'
105
+ : status.isIncomplete
106
+ ? 'border-dashed border-[var(--color-status-warn)]'
107
+ : 'border-[var(--color-border-default)]',
108
+ {
109
+ 'legend-cube__node--selected ring-2 ring-[var(--color-accent)]':
110
+ status.isCapture,
111
+ 'legend-cube__node--invalid': status.isInvalid,
112
+ 'legend-cube__node--incomplete': status.isIncomplete,
113
+ 'legend-cube__node--resolving animate-pulse': status.isResolving,
114
+ 'legend-cube__node--engine-error bg-[var(--color-status-error-bg)]':
115
+ status.hasEngineError,
116
+ 'legend-cube__node--drop-target outline-dashed outline-2 outline-[var(--color-accent)]':
117
+ isDropTarget,
118
+ },
119
+ )}
120
+ title={status.tooltip}
121
+ aria-current={status.isCapture}
122
+ data-testid={LEGEND_CUBE_TEST_ID.CANVAS_NODE}
123
+ >
124
+ <CubeNodeIcon
125
+ icon={editorState.registry.get(node.type)?.icon}
126
+ className="shrink-0 text-lg text-[var(--color-text-secondary)]"
127
+ />
128
+ <span className="line-clamp-2 min-w-0 break-words leading-tight">
129
+ {node.describe()}
130
+ </span>
131
+ </div>
132
+ <Handle
133
+ id={CUBE_OUTPUT_HANDLE_ID}
134
+ type="source"
135
+ position={Position.Right}
136
+ isConnectable={!editorState.readOnly}
137
+ />
138
+ </ContextMenu>
139
+ );
140
+ },
141
+ );
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ CalendarIcon,
19
+ clsx,
20
+ HashtagIcon,
21
+ ListIcon,
22
+ QuestionIcon,
23
+ StringTypeIcon,
24
+ ToggleIcon,
25
+ } from '@finos/legend-art';
26
+ import { type CubeType, type Schema, TypeFamily } from '@finos/legend-cube';
27
+ import { getColumnTypeLabel } from '../../__lib__/LegendCubeLabels.js';
28
+
29
+ const FAMILY_ICONS: Readonly<
30
+ Partial<Record<TypeFamily, React.FC<{ className?: string }>>>
31
+ > = {
32
+ [TypeFamily.STRING]: StringTypeIcon,
33
+ [TypeFamily.BOOLEAN]: ToggleIcon,
34
+ [TypeFamily.INTEGER]: HashtagIcon,
35
+ [TypeFamily.FLOAT]: HashtagIcon,
36
+ [TypeFamily.DECIMAL]: HashtagIcon,
37
+ [TypeFamily.NUMBER]: HashtagIcon,
38
+ [TypeFamily.STRICT_DATE]: CalendarIcon,
39
+ [TypeFamily.DATETIME]: CalendarIcon,
40
+ [TypeFamily.DATE]: CalendarIcon,
41
+ [TypeFamily.ENUM]: ListIcon,
42
+ };
43
+
44
+ /** The icon of a column type's family: text, number, date, ...; a question mark for the rest */
45
+ export const CubeColumnTypeIcon: React.FC<{
46
+ type: CubeType;
47
+ className?: string;
48
+ }> = (props) => {
49
+ const Icon = FAMILY_ICONS[props.type.family] ?? QuestionIcon;
50
+ return <Icon className={clsx('shrink-0', props.className)} />;
51
+ };
52
+
53
+ /**
54
+ * Picks a column of an input schema, in schema order (spec §17.5: only the
55
+ * columns of the actual input). Each option names its type, e.g.
56
+ * `CUSTOMER_ID: Varchar(5)?`; the picked column's type shows beside, with
57
+ * its family's icon and its full type in the tooltip. A column the input
58
+ * doesn't have stays shown, so the problem can be seen and fixed.
59
+ */
60
+ export const CubeColumnPicker: React.FC<{
61
+ /** What the column is for, e.g. `Left join column 1`: the picker's accessible name */
62
+ label: string;
63
+ schema: Schema;
64
+ /** The picked column's name, `''` or `undefined` for none */
65
+ value: string | undefined;
66
+ onChange: (columnName: string) => void;
67
+ disabled?: boolean | undefined;
68
+ /** Marks the pick as wrong, e.g. a type that doesn't match */
69
+ invalid?: boolean | undefined;
70
+ }> = (props) => {
71
+ const { label, schema, value, onChange, disabled, invalid } = props;
72
+ const picked = value ? schema.lookup(value) : undefined;
73
+ return (
74
+ <div className="flex min-w-0 items-center gap-1">
75
+ <select
76
+ aria-label={label}
77
+ aria-invalid={Boolean(invalid) || (Boolean(value) && !picked)}
78
+ className={clsx(
79
+ 'h-6 min-w-0 flex-1 rounded-sm border bg-[var(--color-bg-input)] px-1 text-base',
80
+ invalid || (value && !picked)
81
+ ? 'border-[var(--color-status-error)]'
82
+ : 'border-[var(--color-border-default)]',
83
+ )}
84
+ value={value ?? ''}
85
+ disabled={disabled}
86
+ onChange={(event) => onChange(event.target.value)}
87
+ >
88
+ {!picked && (
89
+ <option value={value ?? ''} disabled={true}>
90
+ {value ? `${value} (not in the input)` : 'Pick a column'}
91
+ </option>
92
+ )}
93
+ {schema.columns.map((column) => (
94
+ <option
95
+ key={column.name}
96
+ value={column.name}
97
+ title={column.type.fullName}
98
+ >
99
+ {`${column.name}: ${getColumnTypeLabel(column)}`}
100
+ </option>
101
+ ))}
102
+ </select>
103
+ {picked && (
104
+ <span
105
+ className="flex shrink-0 items-center gap-1 text-sm text-[var(--color-text-secondary)]"
106
+ title={picked.type.fullName}
107
+ >
108
+ <CubeColumnTypeIcon type={picked.type} />
109
+ {getColumnTypeLabel(picked)}
110
+ </span>
111
+ )}
112
+ </div>
113
+ );
114
+ };