@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,239 @@
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
+ getCollapsiblePanelGroupProps,
19
+ PanelLoadingIndicator,
20
+ ResizablePanel,
21
+ ResizablePanelGroup,
22
+ ResizablePanelSplitter,
23
+ } from '@finos/legend-art';
24
+ import { useCommands } from '@finos/legend-application';
25
+ import type { CubeDocument } from '@finos/legend-cube';
26
+ import { flowResult } from 'mobx';
27
+ import { observer } from 'mobx-react-lite';
28
+ import { useEffect, useState } from 'react';
29
+ import { UNDO_SHORTCUT_LABEL } from '../__lib__/LegendCubeCommand.js';
30
+ import {
31
+ CUBE_PENDING_LABEL,
32
+ formatDisabledReasons,
33
+ READ_ONLY_CUBE_TITLE,
34
+ UNSAVED_CUBE_NAME,
35
+ } from '../__lib__/LegendCubeLabels.js';
36
+ import { LEGEND_CUBE_TEST_ID } from '../__lib__/LegendCubeTesting.js';
37
+ import { CubeEditorState } from '../stores/CubeEditorState.js';
38
+ import type { CubeHost } from '../stores/CubeHost.js';
39
+ import { CubeButton } from './CubeButton.js';
40
+ import { CubeCanvas } from './canvas/CubeCanvas.js';
41
+ import { CubeNodeEditorPanel } from './editors/CubeNodeEditorPanel.js';
42
+ import { CubeGridRegion } from './grid/CubeGridRegion.js';
43
+ import { CubePalette } from './palette/CubePalette.js';
44
+ import { CubeShowPureDialog } from './show-pure/CubeShowPureDialog.js';
45
+ import { CubeSourcePicker } from './source-picker/CubeSourcePicker.js';
46
+ import { CubeSpecTransferDialog } from './spec-transfer/CubeSpecTransferDialog.js';
47
+
48
+ /** The graph never takes more of the window's height than this, so the results stay in view (spec §17.3) */
49
+ const MAX_GRAPH_SHARE_OF_WINDOW = 0.6;
50
+
51
+ /** How wide the node editor opens, in pixels */
52
+ const NODE_EDITOR_WIDTH = 400;
53
+
54
+ /** The tallest the graph region may be, following the window's height */
55
+ const useMaxGraphHeight = (): number => {
56
+ const [windowHeight, setWindowHeight] = useState(() => window.innerHeight);
57
+ useEffect(() => {
58
+ const onResize = (): void => setWindowHeight(window.innerHeight);
59
+ window.addEventListener('resize', onResize);
60
+ return () => window.removeEventListener('resize', onResize);
61
+ }, []);
62
+ return Math.round(windowHeight * MAX_GRAPH_SHARE_OF_WINDOW);
63
+ };
64
+
65
+ /**
66
+ * The graph region's header, above the graph and the results: the cube's
67
+ * name, its actions, its pending and read-only notes, and its dialogs. It
68
+ * stays when the graph is hidden; its buttons wrap when the page is narrow.
69
+ */
70
+ const CubeGraphHeader = observer((props: { editorState: CubeEditorState }) => {
71
+ const { editorState } = props;
72
+ const { readOnly } = editorState;
73
+ const { showGraph } = editorState.document.meta.presentation;
74
+ return (
75
+ <div
76
+ className="flex shrink-0 flex-col bg-[var(--color-bg-panel)]"
77
+ data-testid={LEGEND_CUBE_TEST_ID.GRAPH_REGION}
78
+ >
79
+ <div className="flex min-h-8 shrink-0 flex-wrap items-center gap-2 border-b border-[var(--color-border-default)] bg-[var(--color-bg-panel-header)] px-2 py-1">
80
+ <span className="min-w-24 flex-1 truncate text-lg font-medium">
81
+ {editorState.document.name ?? UNSAVED_CUBE_NAME}
82
+ </span>
83
+ {editorState.isResolvingSources && (
84
+ <span className="shrink-0 text-base text-[var(--color-text-secondary)]">
85
+ {CUBE_PENDING_LABEL.RESOLVING_SOURCE}
86
+ </span>
87
+ )}
88
+ <CubeButton
89
+ title={readOnly ? READ_ONLY_CUBE_TITLE : undefined}
90
+ disabled={readOnly}
91
+ onClick={() => editorState.sourcePicker.open()}
92
+ >
93
+ Add table
94
+ </CubeButton>
95
+ <CubeButton
96
+ title={
97
+ readOnly
98
+ ? READ_ONLY_CUBE_TITLE
99
+ : `Undo the last change (${UNDO_SHORTCUT_LABEL})`
100
+ }
101
+ disabled={!editorState.canUndo}
102
+ onClick={() => editorState.undo()}
103
+ >
104
+ Undo
105
+ </CubeButton>
106
+ <CubeButton
107
+ title={
108
+ editorState.execution.canExecute
109
+ ? 'Show the Pure query that Execute runs'
110
+ : formatDisabledReasons(editorState.execution.disabledReasons)
111
+ }
112
+ disabled={!editorState.execution.canExecute}
113
+ onClick={() => {
114
+ flowResult(editorState.showPure.open()).catch(
115
+ editorState.host.applicationStore.alertUnhandledError,
116
+ );
117
+ }}
118
+ >
119
+ Show Pure
120
+ </CubeButton>
121
+ <CubeButton
122
+ title={
123
+ readOnly
124
+ ? READ_ONLY_CUBE_TITLE
125
+ : "Show the cube's spec, to copy or download"
126
+ }
127
+ disabled={readOnly}
128
+ onClick={() => editorState.specTransfer.openExport()}
129
+ >
130
+ Export (dev)
131
+ </CubeButton>
132
+ <CubeButton
133
+ title="Open a cube from its spec, in place of this one"
134
+ onClick={() => editorState.specTransfer.openImport()}
135
+ >
136
+ Import (dev)
137
+ </CubeButton>
138
+ <CubeButton
139
+ title={
140
+ showGraph
141
+ ? 'Hide the graph, leaving more room for the results'
142
+ : 'Show the graph'
143
+ }
144
+ onClick={() => editorState.setShowGraph(!showGraph)}
145
+ >
146
+ {showGraph ? 'Hide graph' : 'Show graph'}
147
+ </CubeButton>
148
+ </div>
149
+ <PanelLoadingIndicator isLoading={editorState.isResolvingSources} />
150
+ {readOnly && (
151
+ <div
152
+ className="shrink-0 border-b border-[var(--color-border-default)] bg-[var(--color-status-warn-bg)] px-2 py-1 text-base text-[var(--color-status-warn)]"
153
+ role="status"
154
+ >
155
+ {READ_ONLY_CUBE_TITLE}. You can view and run it.
156
+ </div>
157
+ )}
158
+ {editorState.nodeEditor.notice && (
159
+ <div
160
+ className="flex shrink-0 items-center gap-2 border-b border-[var(--color-border-default)] bg-[var(--color-status-warn-bg)] px-2 py-1 text-base text-[var(--color-status-warn)]"
161
+ role="status"
162
+ data-testid={LEGEND_CUBE_TEST_ID.EDITOR_NOTICE}
163
+ >
164
+ <span className="min-w-0 flex-1">
165
+ {editorState.nodeEditor.notice}
166
+ </span>
167
+ <CubeButton onClick={() => editorState.nodeEditor.dismissNotice()}>
168
+ Dismiss
169
+ </CubeButton>
170
+ </div>
171
+ )}
172
+ <CubeSourcePicker editorState={editorState} />
173
+ <CubeSpecTransferDialog editorState={editorState} />
174
+ <CubeShowPureDialog editorState={editorState} />
175
+ </div>
176
+ );
177
+ });
178
+
179
+ /**
180
+ * The Legend Cube page: the query above, its results below, both always
181
+ * shown (PLAN §7.1); hiding the graph leaves its header. The host gives it
182
+ * the engine, the models and the application store; the page's state lives
183
+ * as long as the page.
184
+ */
185
+ export const CubeEditor = observer(
186
+ (props: {
187
+ host: CubeHost;
188
+ /** The cube to open; an empty one by default */
189
+ initialDocument?: CubeDocument | undefined;
190
+ }) => {
191
+ const [editorState] = useState(
192
+ () => new CubeEditorState(props.host, props.initialDocument),
193
+ );
194
+ useEffect(() => () => editorState.dispose(), [editorState]);
195
+ useCommands(editorState);
196
+ const maxGraphHeight = useMaxGraphHeight();
197
+ const isEditorOpen = editorState.nodeEditor.nodeId !== undefined;
198
+ const editorPanel = getCollapsiblePanelGroupProps(!isEditorOpen, {
199
+ size: NODE_EDITOR_WIDTH,
200
+ });
201
+ const { showGraph } = editorState.document.meta.presentation;
202
+ // hiding the graph collapses its panel: the header and the results stay
203
+ // where they are, so the grid keeps its state
204
+ const graphPanel = getCollapsiblePanelGroupProps(!showGraph);
205
+
206
+ return (
207
+ <div
208
+ className="legend-cube flex bg-[var(--color-bg-app)] text-[var(--color-text-primary)]"
209
+ data-testid={LEGEND_CUBE_TEST_ID.EDITOR}
210
+ >
211
+ <CubePalette editorState={editorState} />
212
+ <ResizablePanelGroup orientation="vertical">
213
+ <ResizablePanel {...editorPanel.remainingPanel} minSize={320}>
214
+ <div className="flex h-full min-w-0 flex-1 flex-col">
215
+ <CubeGraphHeader editorState={editorState} />
216
+ <ResizablePanelGroup orientation="horizontal">
217
+ <ResizablePanel
218
+ {...graphPanel.collapsiblePanel}
219
+ minSize={showGraph ? 96 : 0}
220
+ maxSize={maxGraphHeight}
221
+ >
222
+ {showGraph && <CubeCanvas editorState={editorState} />}
223
+ </ResizablePanel>
224
+ <ResizablePanelSplitter className={showGraph ? '' : 'hidden'} />
225
+ <ResizablePanel {...graphPanel.remainingPanel} minSize={96}>
226
+ <CubeGridRegion editorState={editorState} />
227
+ </ResizablePanel>
228
+ </ResizablePanelGroup>
229
+ </div>
230
+ </ResizablePanel>
231
+ <ResizablePanelSplitter className={isEditorOpen ? '' : 'hidden'} />
232
+ <ResizablePanel {...editorPanel.collapsiblePanel} direction={-1}>
233
+ <CubeNodeEditorPanel editorState={editorState} />
234
+ </ResizablePanel>
235
+ </ResizablePanelGroup>
236
+ </div>
237
+ );
238
+ },
239
+ );
@@ -0,0 +1,47 @@
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
+ ArrowsJoinIcon,
19
+ clsx,
20
+ FilterIcon,
21
+ QuestionSquareIcon,
22
+ TableIcon,
23
+ } from '@finos/legend-art';
24
+
25
+ /** The icon of each icon name a node definition gives (`NodeDefinition.icon`) */
26
+ const NODE_ICONS: Readonly<
27
+ Record<string, React.FC<{ className?: string; title?: string }>>
28
+ > = {
29
+ table: TableIcon,
30
+ filter: FilterIcon,
31
+ join: ArrowsJoinIcon,
32
+ };
33
+
34
+ /** Whether a node definition's icon name maps to an icon, rather than the question mark */
35
+ export const hasCubeNodeIcon = (name: string): boolean =>
36
+ Object.hasOwn(NODE_ICONS, name);
37
+
38
+ /** A node type's icon; an unknown name, or an Unknown node, gets a question mark */
39
+ export const CubeNodeIcon: React.FC<{
40
+ icon: string | undefined;
41
+ className?: string;
42
+ }> = (props) => {
43
+ const { icon, className } = props;
44
+ const Icon =
45
+ (icon === undefined ? undefined : NODE_ICONS[icon]) ?? QuestionSquareIcon;
46
+ return <Icon className={clsx(className)} />;
47
+ };
@@ -0,0 +1,260 @@
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 { ContextMenu } from '@finos/legend-art';
18
+ import type { Query } from '@finos/legend-cube';
19
+ import { noop } from '@finos/legend-shared';
20
+ import {
21
+ Background,
22
+ type Connection as FlowConnection,
23
+ Controls,
24
+ type Edge,
25
+ MiniMap,
26
+ ReactFlow,
27
+ ReactFlowProvider,
28
+ useNodesInitialized,
29
+ useReactFlow,
30
+ useStore,
31
+ } from '@xyflow/react';
32
+ // imported here, not in the builder's stylesheet, so it loads with the Cube
33
+ // page's chunk: Query's reactflow 11 lineage viewer uses the same class names
34
+ import '@xyflow/react/dist/style.css';
35
+ import { observer } from 'mobx-react-lite';
36
+ import { useEffect, useMemo, useRef } from 'react';
37
+ import { useDrop } from 'react-dnd';
38
+ import { LEGEND_CUBE_TEST_ID } from '../../__lib__/LegendCubeTesting.js';
39
+ import type { CubeEditorState } from '../../stores/CubeEditorState.js';
40
+ import {
41
+ buildCubeCanvasEdges,
42
+ buildCubeCanvasNodes,
43
+ CUBE_CANVAS_EDGE_TYPE,
44
+ CUBE_CANVAS_NODE_TYPE,
45
+ CUBE_OUTPUT_HANDLE_ID,
46
+ type CubeCanvasFlowEdge,
47
+ type CubeCanvasFlowNode,
48
+ } from './CubeCanvasElements.js';
49
+ import { CubeCanvasContext } from './CubeCanvasContext.js';
50
+ import { CubeCanvasContextMenu } from './CubeCanvasContextMenu.js';
51
+ import {
52
+ CUBE_DND_TYPE,
53
+ type CubePaletteDragItem,
54
+ dropOnCubeCanvas,
55
+ } from './CubeCanvasDnd.js';
56
+ import { CubeCanvasEdge } from './CubeCanvasEdge.js';
57
+ import { layoutCubeQuery } from './CubeCanvasLayout.js';
58
+ import { CubeCanvasNode } from './CubeCanvasNode.js';
59
+
60
+ // React Flow re-renders every node when these change identity
61
+ const NODE_TYPES = { [CUBE_CANVAS_NODE_TYPE]: CubeCanvasNode };
62
+ const EDGE_TYPES = { [CUBE_CANVAS_EDGE_TYPE]: CubeCanvasEdge };
63
+ const PRO_OPTIONS = { hideAttribution: true };
64
+ /** Small, so it covers little of a short canvas */
65
+ const MINI_MAP_STYLE = { width: 120, height: 80 };
66
+ const FIT_VIEW_OPTIONS = { padding: 0.2, maxZoom: 1 };
67
+
68
+ /**
69
+ * Whether dragging from one handle to another may connect the two nodes: out
70
+ * of a node's output, into a free input port that the query lets it feed
71
+ */
72
+ export const isCubeCanvasConnectionValid = (
73
+ query: Query,
74
+ connection: FlowConnection | Edge,
75
+ ): boolean =>
76
+ connection.sourceHandle === CUBE_OUTPUT_HANDLE_ID &&
77
+ typeof connection.targetHandle === 'string' &&
78
+ query.canConnect(
79
+ connection.source,
80
+ connection.target,
81
+ connection.targetHandle,
82
+ );
83
+
84
+ const CubeCanvasFlow = observer((props: { editorState: CubeEditorState }) => {
85
+ const { editorState } = props;
86
+ const { query } = editorState.document;
87
+ const { readOnly } = editorState;
88
+ const { fitView } = useReactFlow();
89
+ const positions = useMemo(() => layoutCubeQuery(query), [query]);
90
+ const nodes = useMemo(
91
+ () => buildCubeCanvasNodes(query, positions),
92
+ [query, positions],
93
+ );
94
+ const edges = useMemo(() => buildCubeCanvasEdges(query), [query]);
95
+ // the view fits the graph again whenever the layout moves a node, or the
96
+ // canvas gets wider or narrower (e.g. the node editor opens beside it),
97
+ // once React Flow has measured every node: it fits only measured ones
98
+ const layoutSignature = useMemo(
99
+ () => JSON.stringify([...positions]),
100
+ [positions],
101
+ );
102
+ const nodesInitialized = useNodesInitialized();
103
+ const canvasWidth = useStore((state) => state.width);
104
+ useEffect(() => {
105
+ if (!nodesInitialized) {
106
+ return undefined;
107
+ }
108
+ const timer = window.setTimeout(() => {
109
+ fitView(FIT_VIEW_OPTIONS).catch(noop());
110
+ }, 0);
111
+ return () => window.clearTimeout(timer);
112
+ }, [layoutSignature, canvasWidth, nodesInitialized, fitView]);
113
+
114
+ return (
115
+ <ReactFlow<CubeCanvasFlowNode, CubeCanvasFlowEdge>
116
+ nodes={nodes}
117
+ edges={edges}
118
+ nodeTypes={NODE_TYPES}
119
+ edgeTypes={EDGE_TYPES}
120
+ // the layout places the nodes; nothing is selected or deleted in React Flow
121
+ nodesDraggable={false}
122
+ nodesConnectable={!readOnly}
123
+ elementsSelectable={false}
124
+ deleteKeyCode={null}
125
+ selectionKeyCode={null}
126
+ multiSelectionKeyCode={null}
127
+ onNodeClick={(event, flowNode) => {
128
+ // a click on a handle starts or ends a connection, not a node click
129
+ if (
130
+ event.target instanceof Element &&
131
+ event.target.closest('.react-flow__handle')
132
+ ) {
133
+ return;
134
+ }
135
+ if (event.ctrlKey || event.metaKey) {
136
+ editorState.select(flowNode.id);
137
+ } else {
138
+ editorState.nodeEditor.open(flowNode.id);
139
+ }
140
+ }}
141
+ // React Flow's own keyboard help speaks of selecting, moving and
142
+ // deleting nodes, which Cube doesn't do; Enter and Space open a node's
143
+ // editor instead, and Ctrl or Cmd with them select it
144
+ disableKeyboardA11y={true}
145
+ edgesFocusable={false}
146
+ onKeyDown={(event) => {
147
+ const target = event.target;
148
+ const nodeId =
149
+ target instanceof HTMLElement &&
150
+ target.classList.contains('react-flow__node')
151
+ ? target.dataset.id
152
+ : undefined;
153
+ if (
154
+ nodeId === undefined ||
155
+ (event.key !== 'Enter' && event.key !== ' ')
156
+ ) {
157
+ return;
158
+ }
159
+ event.preventDefault();
160
+ if (event.ctrlKey || event.metaKey) {
161
+ editorState.select(nodeId);
162
+ } else {
163
+ editorState.nodeEditor.open(nodeId);
164
+ }
165
+ }}
166
+ isValidConnection={(connection) =>
167
+ !readOnly && isCubeCanvasConnectionValid(query, connection)
168
+ }
169
+ onConnect={(connection) => {
170
+ if (connection.targetHandle) {
171
+ editorState.connect(
172
+ connection.source,
173
+ connection.target,
174
+ connection.targetHandle,
175
+ );
176
+ }
177
+ }}
178
+ colorMode={
179
+ editorState.host.applicationStore.layoutService
180
+ .TEMPORARY__isLightColorThemeEnabled
181
+ ? 'light'
182
+ : 'dark'
183
+ }
184
+ proOptions={PRO_OPTIONS}
185
+ fitView={true}
186
+ fitViewOptions={FIT_VIEW_OPTIONS}
187
+ minZoom={0.2}
188
+ maxZoom={1.5}
189
+ >
190
+ <Background />
191
+ <Controls showInteractive={false} />
192
+ <MiniMap pannable={true} zoomable={true} style={MINI_MAP_STYLE} />
193
+ </ReactFlow>
194
+ );
195
+ });
196
+
197
+ /**
198
+ * The query as a graph, laid out left to right (spec §17.3). Click a node to
199
+ * edit it, Ctrl or Cmd-click it to run the query up to it, drag from a node's
200
+ * output to another node's input to connect them. A palette item dropped
201
+ * around the nodes is added unconnected. Right-click it, or a node, for the
202
+ * context menu.
203
+ */
204
+ export const CubeCanvas = observer(
205
+ (props: { editorState: CubeEditorState }) => {
206
+ const { editorState } = props;
207
+ const ref = useRef<HTMLDivElement>(null);
208
+ const [, dropConnector] = useDrop<CubePaletteDragItem>(
209
+ () => ({
210
+ accept: [CUBE_DND_TYPE.PALETTE_ITEM],
211
+ canDrop: () => !editorState.readOnly,
212
+ // a node under the pointer, whether it took the drop or refused it,
213
+ // keeps it from the canvas
214
+ drop: (item, monitor) =>
215
+ dropOnCubeCanvas(
216
+ editorState,
217
+ item,
218
+ monitor.didDrop() || !monitor.isOver({ shallow: true }),
219
+ ),
220
+ }),
221
+ [editorState],
222
+ );
223
+ dropConnector(ref);
224
+ return (
225
+ <div
226
+ ref={ref}
227
+ className="relative h-full w-full"
228
+ data-testid={LEGEND_CUBE_TEST_ID.CANVAS}
229
+ >
230
+ <ContextMenu
231
+ className="h-full w-full"
232
+ content={<CubeCanvasContextMenu editorState={editorState} />}
233
+ menuProps={{ elevation: 7 }}
234
+ >
235
+ {editorState.document.query.isEmpty ? (
236
+ <div className="flex h-full items-center justify-center p-4 text-base text-[var(--color-text-secondary)]">
237
+ <span>
238
+ No tables yet:{' '}
239
+ <button
240
+ className="text-[var(--color-accent)] underline disabled:text-[var(--color-text-disabled)] disabled:no-underline"
241
+ disabled={editorState.readOnly}
242
+ onClick={() => editorState.sourcePicker.open()}
243
+ >
244
+ add a table
245
+ </button>{' '}
246
+ to start.
247
+ </span>
248
+ </div>
249
+ ) : (
250
+ <CubeCanvasContext.Provider value={editorState}>
251
+ <ReactFlowProvider>
252
+ <CubeCanvasFlow editorState={editorState} />
253
+ </ReactFlowProvider>
254
+ </CubeCanvasContext.Provider>
255
+ )}
256
+ </ContextMenu>
257
+ </div>
258
+ );
259
+ },
260
+ );
@@ -0,0 +1,31 @@
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 { guaranteeNonNullable } from '@finos/legend-shared';
18
+ import { createContext, useContext } from 'react';
19
+ import type { CubeEditorState } from '../../stores/CubeEditorState.js';
20
+
21
+ // React Flow renders the canvas's nodes itself, so they reach the page's
22
+ // state through a context rather than props
23
+ export const CubeCanvasContext = createContext<CubeEditorState | undefined>(
24
+ undefined,
25
+ );
26
+
27
+ export const useCubeCanvasEditorState = (): CubeEditorState =>
28
+ guaranteeNonNullable(
29
+ useContext(CubeCanvasContext),
30
+ `A canvas node must be rendered inside the Cube canvas`,
31
+ );
@@ -0,0 +1,89 @@
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
+ MenuContent,
19
+ MenuContentDivider,
20
+ MenuContentItem,
21
+ MenuContentItemIcon,
22
+ MenuContentItemLabel,
23
+ } from '@finos/legend-art';
24
+ import type { AnyNodeDefinition } from '@finos/legend-cube';
25
+ import { observer } from 'mobx-react-lite';
26
+ import { forwardRef } from 'react';
27
+ import type { CubeEditorState } from '../../stores/CubeEditorState.js';
28
+ import { CubeNodeIcon } from '../CubeNodeIcon.js';
29
+
30
+ /**
31
+ * The canvas's context menu (spec §17.4): the palette, then what can be done
32
+ * to the node it was opened on. On a node, a palette item is added after it;
33
+ * around the nodes, on its own. Every item shows, disabled when it can't be
34
+ * done, so Swap Inputs can be found. The node comes through props: a menu
35
+ * opened around the nodes has none.
36
+ */
37
+ export const CubeCanvasContextMenu = observer(
38
+ forwardRef<
39
+ HTMLDivElement,
40
+ { editorState: CubeEditorState; nodeId?: string | undefined }
41
+ >(function CubeCanvasContextMenu(props, ref) {
42
+ const { editorState, nodeId } = props;
43
+ const { query } = editorState.document;
44
+ const { registry } = editorState;
45
+ const paletteItem = (definition: AnyNodeDefinition): React.ReactNode => (
46
+ <MenuContentItem
47
+ key={definition.type}
48
+ disabled={!editorState.canAddNode(definition.type, nodeId)}
49
+ onClick={() => editorState.addNode(definition.type, nodeId)}
50
+ >
51
+ <MenuContentItemIcon>
52
+ <CubeNodeIcon icon={definition.icon} />
53
+ </MenuContentItemIcon>
54
+ <MenuContentItemLabel>
55
+ {definition.label}
56
+ {definition.beta ? ' (BETA)' : ''}
57
+ </MenuContentItemLabel>
58
+ </MenuContentItem>
59
+ );
60
+ return (
61
+ <MenuContent ref={ref}>
62
+ {registry.sources.map(paletteItem)}
63
+ <MenuContentDivider />
64
+ {registry.transforms.map(paletteItem)}
65
+ <MenuContentDivider />
66
+ <MenuContentItem
67
+ title="Execute runs the query up to this node"
68
+ disabled={nodeId === undefined || !query.canSelect(nodeId)}
69
+ onClick={() => nodeId !== undefined && editorState.select(nodeId)}
70
+ >
71
+ Select
72
+ </MenuContentItem>
73
+ <MenuContentItem
74
+ disabled={nodeId === undefined || !editorState.canRemoveNode(nodeId)}
75
+ onClick={() => nodeId !== undefined && editorState.removeNode(nodeId)}
76
+ >
77
+ Remove
78
+ </MenuContentItem>
79
+ <MenuContentItem
80
+ title="Swap the node's two inputs, e.g. a Join's Left and Right"
81
+ disabled={nodeId === undefined || !editorState.canSwapInputs(nodeId)}
82
+ onClick={() => nodeId !== undefined && editorState.swapInputs(nodeId)}
83
+ >
84
+ Swap Inputs
85
+ </MenuContentItem>
86
+ </MenuContent>
87
+ );
88
+ }),
89
+ );