@finos/legend-cube-builder 0.0.0-stage → 0.0.3
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.
- package/LICENSE +201 -0
- package/README.md +64 -2
- package/docs/adding-an-operation.md +92 -0
- package/docs/hosting.md +79 -0
- package/docs/testing.md +83 -0
- package/lib/__lib__/LegendCubeCommand.d.ts +26 -0
- package/lib/__lib__/LegendCubeCommand.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeCommand.js +40 -0
- package/lib/__lib__/LegendCubeCommand.js.map +1 -0
- package/lib/__lib__/LegendCubeHelpText.d.ts +19 -0
- package/lib/__lib__/LegendCubeHelpText.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeHelpText.js +35 -0
- package/lib/__lib__/LegendCubeHelpText.js.map +1 -0
- package/lib/__lib__/LegendCubeLabels.d.ts +87 -0
- package/lib/__lib__/LegendCubeLabels.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeLabels.js +128 -0
- package/lib/__lib__/LegendCubeLabels.js.map +1 -0
- package/lib/__lib__/LegendCubeTesting.d.ts +33 -0
- package/lib/__lib__/LegendCubeTesting.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeTesting.js +34 -0
- package/lib/__lib__/LegendCubeTesting.js.map +1 -0
- package/lib/__test-utils__/CubeCanvasTestUtils.d.ts +24 -0
- package/lib/__test-utils__/CubeCanvasTestUtils.d.ts.map +1 -0
- package/lib/__test-utils__/CubeCanvasTestUtils.js +37 -0
- package/lib/__test-utils__/CubeCanvasTestUtils.js.map +1 -0
- package/lib/__test-utils__/CubeEngineTestSupport.d.ts +47 -0
- package/lib/__test-utils__/CubeEngineTestSupport.d.ts.map +1 -0
- package/lib/__test-utils__/CubeEngineTestSupport.js +106 -0
- package/lib/__test-utils__/CubeEngineTestSupport.js.map +1 -0
- package/lib/__test-utils__/CubeNorthwindTestQueries.d.ts +31 -0
- package/lib/__test-utils__/CubeNorthwindTestQueries.d.ts.map +1 -0
- package/lib/__test-utils__/CubeNorthwindTestQueries.js +102 -0
- package/lib/__test-utils__/CubeNorthwindTestQueries.js.map +1 -0
- package/lib/__test-utils__/CubeOperationsTestUtils.d.ts +42 -0
- package/lib/__test-utils__/CubeOperationsTestUtils.d.ts.map +1 -0
- package/lib/__test-utils__/CubeOperationsTestUtils.js +92 -0
- package/lib/__test-utils__/CubeOperationsTestUtils.js.map +1 -0
- package/lib/__test-utils__/CubePageTestUtils.d.ts +33 -0
- package/lib/__test-utils__/CubePageTestUtils.d.ts.map +1 -0
- package/lib/__test-utils__/CubePageTestUtils.js +68 -0
- package/lib/__test-utils__/CubePageTestUtils.js.map +1 -0
- package/lib/__test-utils__/CubeTestApplication.d.ts +30 -0
- package/lib/__test-utils__/CubeTestApplication.d.ts.map +1 -0
- package/lib/__test-utils__/CubeTestApplication.js +57 -0
- package/lib/__test-utils__/CubeTestApplication.js.map +1 -0
- package/lib/__test-utils__/FakeCubeEngine.d.ts +41 -0
- package/lib/__test-utils__/FakeCubeEngine.d.ts.map +1 -0
- package/lib/__test-utils__/FakeCubeEngine.js +91 -0
- package/lib/__test-utils__/FakeCubeEngine.js.map +1 -0
- package/lib/components/CubeButton.d.ts +20 -0
- package/lib/components/CubeButton.d.ts.map +1 -0
- package/lib/components/CubeButton.js +24 -0
- package/lib/components/CubeButton.js.map +1 -0
- package/lib/components/CubeEditor.d.ts +31 -0
- package/lib/components/CubeEditor.d.ts.map +1 -0
- package/lib/components/CubeEditor.js +90 -0
- package/lib/components/CubeEditor.js.map +1 -0
- package/lib/components/CubeNodeIcon.d.ts +23 -0
- package/lib/components/CubeNodeIcon.d.ts.map +1 -0
- package/lib/components/CubeNodeIcon.js +42 -0
- package/lib/components/CubeNodeIcon.js.map +1 -0
- package/lib/components/canvas/CubeCanvas.d.ts +37 -0
- package/lib/components/canvas/CubeCanvas.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvas.js +137 -0
- package/lib/components/canvas/CubeCanvas.js.map +1 -0
- package/lib/components/canvas/CubeCanvasContext.d.ts +19 -0
- package/lib/components/canvas/CubeCanvasContext.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasContext.js +22 -0
- package/lib/components/canvas/CubeCanvasContext.js.map +1 -0
- package/lib/components/canvas/CubeCanvasContextMenu.d.ts +28 -0
- package/lib/components/canvas/CubeCanvasContextMenu.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasContextMenu.js +35 -0
- package/lib/components/canvas/CubeCanvasContextMenu.js.map +1 -0
- package/lib/components/canvas/CubeCanvasDnd.d.ts +43 -0
- package/lib/components/canvas/CubeCanvasDnd.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasDnd.js +51 -0
- package/lib/components/canvas/CubeCanvasDnd.js.map +1 -0
- package/lib/components/canvas/CubeCanvasEdge.d.ts +24 -0
- package/lib/components/canvas/CubeCanvasEdge.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasEdge.js +33 -0
- package/lib/components/canvas/CubeCanvasEdge.js.map +1 -0
- package/lib/components/canvas/CubeCanvasElements.d.ts +66 -0
- package/lib/components/canvas/CubeCanvasElements.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasElements.js +97 -0
- package/lib/components/canvas/CubeCanvasElements.js.map +1 -0
- package/lib/components/canvas/CubeCanvasLayout.d.ts +32 -0
- package/lib/components/canvas/CubeCanvasLayout.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasLayout.js +63 -0
- package/lib/components/canvas/CubeCanvasLayout.js.map +1 -0
- package/lib/components/canvas/CubeCanvasNode.d.ts +29 -0
- package/lib/components/canvas/CubeCanvasNode.d.ts.map +1 -0
- package/lib/components/canvas/CubeCanvasNode.js +75 -0
- package/lib/components/canvas/CubeCanvasNode.js.map +1 -0
- package/lib/components/editors/CubeColumnPicker.d.ts +47 -0
- package/lib/components/editors/CubeColumnPicker.d.ts.map +1 -0
- package/lib/components/editors/CubeColumnPicker.js +56 -0
- package/lib/components/editors/CubeColumnPicker.js.map +1 -0
- package/lib/components/editors/CubeDistinctEditor.d.ts +23 -0
- package/lib/components/editors/CubeDistinctEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeDistinctEditor.js +24 -0
- package/lib/components/editors/CubeDistinctEditor.js.map +1 -0
- package/lib/components/editors/CubeFilterEditor.d.ts +26 -0
- package/lib/components/editors/CubeFilterEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeFilterEditor.js +90 -0
- package/lib/components/editors/CubeFilterEditor.js.map +1 -0
- package/lib/components/editors/CubeIntegerField.d.ts +29 -0
- package/lib/components/editors/CubeIntegerField.d.ts.map +1 -0
- package/lib/components/editors/CubeIntegerField.js +30 -0
- package/lib/components/editors/CubeIntegerField.js.map +1 -0
- package/lib/components/editors/CubeJoinEditor.d.ts +26 -0
- package/lib/components/editors/CubeJoinEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeJoinEditor.js +84 -0
- package/lib/components/editors/CubeJoinEditor.js.map +1 -0
- package/lib/components/editors/CubeNodeEditorPanel.d.ts +29 -0
- package/lib/components/editors/CubeNodeEditorPanel.d.ts.map +1 -0
- package/lib/components/editors/CubeNodeEditorPanel.js +72 -0
- package/lib/components/editors/CubeNodeEditorPanel.js.map +1 -0
- package/lib/components/editors/CubeNodeEditorRegistry.d.ts +44 -0
- package/lib/components/editors/CubeNodeEditorRegistry.d.ts.map +1 -0
- package/lib/components/editors/CubeNodeEditorRegistry.js +43 -0
- package/lib/components/editors/CubeNodeEditorRegistry.js.map +1 -0
- package/lib/components/editors/CubeRenameEditor.d.ts +26 -0
- package/lib/components/editors/CubeRenameEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeRenameEditor.js +58 -0
- package/lib/components/editors/CubeRenameEditor.js.map +1 -0
- package/lib/components/editors/CubeRestrictEditor.d.ts +26 -0
- package/lib/components/editors/CubeRestrictEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeRestrictEditor.js +23 -0
- package/lib/components/editors/CubeRestrictEditor.js.map +1 -0
- package/lib/components/editors/CubeRowCountEditor.d.ts +25 -0
- package/lib/components/editors/CubeRowCountEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeRowCountEditor.js +38 -0
- package/lib/components/editors/CubeRowCountEditor.js.map +1 -0
- package/lib/components/editors/CubeSliceEditor.d.ts +25 -0
- package/lib/components/editors/CubeSliceEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeSliceEditor.js +40 -0
- package/lib/components/editors/CubeSliceEditor.js.map +1 -0
- package/lib/components/editors/CubeSortEditor.d.ts +27 -0
- package/lib/components/editors/CubeSortEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeSortEditor.js +72 -0
- package/lib/components/editors/CubeSortEditor.js.map +1 -0
- package/lib/components/editors/CubeSourceEditor.d.ts +25 -0
- package/lib/components/editors/CubeSourceEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeSourceEditor.js +41 -0
- package/lib/components/editors/CubeSourceEditor.js.map +1 -0
- package/lib/components/editors/CubeValueEditor.d.ts +40 -0
- package/lib/components/editors/CubeValueEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeValueEditor.js +178 -0
- package/lib/components/editors/CubeValueEditor.js.map +1 -0
- package/lib/components/grid/CubeGridRegion.d.ts +23 -0
- package/lib/components/grid/CubeGridRegion.d.ts.map +1 -0
- package/lib/components/grid/CubeGridRegion.js +94 -0
- package/lib/components/grid/CubeGridRegion.js.map +1 -0
- package/lib/components/grid/CubeGridValues.d.ts +25 -0
- package/lib/components/grid/CubeGridValues.d.ts.map +1 -0
- package/lib/components/grid/CubeGridValues.js +95 -0
- package/lib/components/grid/CubeGridValues.js.map +1 -0
- package/lib/components/grid/CubeResultGrid.d.ts +39 -0
- package/lib/components/grid/CubeResultGrid.d.ts.map +1 -0
- package/lib/components/grid/CubeResultGrid.js +86 -0
- package/lib/components/grid/CubeResultGrid.js.map +1 -0
- package/lib/components/palette/CubePalette.d.ts +29 -0
- package/lib/components/palette/CubePalette.d.ts.map +1 -0
- package/lib/components/palette/CubePalette.js +73 -0
- package/lib/components/palette/CubePalette.js.map +1 -0
- package/lib/components/show-pure/CubeShowPureDialog.d.ts +23 -0
- package/lib/components/show-pure/CubeShowPureDialog.d.ts.map +1 -0
- package/lib/components/show-pure/CubeShowPureDialog.js +37 -0
- package/lib/components/show-pure/CubeShowPureDialog.js.map +1 -0
- package/lib/components/source-picker/CubeSourcePicker.d.ts +22 -0
- package/lib/components/source-picker/CubeSourcePicker.d.ts.map +1 -0
- package/lib/components/source-picker/CubeSourcePicker.js +89 -0
- package/lib/components/source-picker/CubeSourcePicker.js.map +1 -0
- package/lib/components/spec-transfer/CubeSpecTransferDialog.d.ts +26 -0
- package/lib/components/spec-transfer/CubeSpecTransferDialog.d.ts.map +1 -0
- package/lib/components/spec-transfer/CubeSpecTransferDialog.js +45 -0
- package/lib/components/spec-transfer/CubeSpecTransferDialog.js.map +1 -0
- package/lib/graph-manager/CubeEngine.d.ts +128 -0
- package/lib/graph-manager/CubeEngine.d.ts.map +1 -0
- package/lib/graph-manager/CubeEngine.js +61 -0
- package/lib/graph-manager/CubeEngine.js.map +1 -0
- package/lib/graph-manager/CubeModelOutlineHelper.d.ts +33 -0
- package/lib/graph-manager/CubeModelOutlineHelper.d.ts.map +1 -0
- package/lib/graph-manager/CubeModelOutlineHelper.js +45 -0
- package/lib/graph-manager/CubeModelOutlineHelper.js.map +1 -0
- package/lib/graph-manager/protocol/pure/CubeEngineBuilder.d.ts +26 -0
- package/lib/graph-manager/protocol/pure/CubeEngineBuilder.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/CubeEngineBuilder.js +22 -0
- package/lib/graph-manager/protocol/pure/CubeEngineBuilder.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.d.ts +27 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.js +76 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.d.ts +27 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.js +82 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.d.ts +32 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.js +195 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.d.ts +20 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.js +174 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.d.ts +24 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.js +43 -0
- package/lib/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.d.ts +45 -0
- package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.js +171 -0
- package/lib/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.js.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.d.ts +22 -0
- package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.d.ts.map +1 -0
- package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.js +79 -0
- package/lib/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.js.map +1 -0
- package/lib/index.css +17 -0
- package/lib/index.css.map +1 -0
- package/lib/index.d.ts +25 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +24 -0
- package/lib/index.js.map +1 -0
- package/lib/stores/CubeEditorState.d.ts +236 -0
- package/lib/stores/CubeEditorState.d.ts.map +1 -0
- package/lib/stores/CubeEditorState.js +632 -0
- package/lib/stores/CubeEditorState.js.map +1 -0
- package/lib/stores/CubeExecutionState.d.ts +67 -0
- package/lib/stores/CubeExecutionState.d.ts.map +1 -0
- package/lib/stores/CubeExecutionState.js +212 -0
- package/lib/stores/CubeExecutionState.js.map +1 -0
- package/lib/stores/CubeGridQuickActions.d.ts +40 -0
- package/lib/stores/CubeGridQuickActions.d.ts.map +1 -0
- package/lib/stores/CubeGridQuickActions.js +86 -0
- package/lib/stores/CubeGridQuickActions.js.map +1 -0
- package/lib/stores/CubeHost.d.ts +31 -0
- package/lib/stores/CubeHost.d.ts.map +1 -0
- package/lib/stores/CubeHost.js +17 -0
- package/lib/stores/CubeHost.js.map +1 -0
- package/lib/stores/CubeNodeEditorState.d.ts +103 -0
- package/lib/stores/CubeNodeEditorState.d.ts.map +1 -0
- package/lib/stores/CubeNodeEditorState.js +262 -0
- package/lib/stores/CubeNodeEditorState.js.map +1 -0
- package/lib/stores/CubeShowPureState.d.ts +41 -0
- package/lib/stores/CubeShowPureState.d.ts.map +1 -0
- package/lib/stores/CubeShowPureState.js +100 -0
- package/lib/stores/CubeShowPureState.js.map +1 -0
- package/lib/stores/CubeSourcePickerState.d.ts +98 -0
- package/lib/stores/CubeSourcePickerState.d.ts.map +1 -0
- package/lib/stores/CubeSourcePickerState.js +334 -0
- package/lib/stores/CubeSourcePickerState.js.map +1 -0
- package/lib/stores/CubeSpecTransferState.d.ts +60 -0
- package/lib/stores/CubeSpecTransferState.d.ts.map +1 -0
- package/lib/stores/CubeSpecTransferState.js +167 -0
- package/lib/stores/CubeSpecTransferState.js.map +1 -0
- package/lib/stores/LocalModelCatalog.d.ts +37 -0
- package/lib/stores/LocalModelCatalog.d.ts.map +1 -0
- package/lib/stores/LocalModelCatalog.js +49 -0
- package/lib/stores/LocalModelCatalog.js.map +1 -0
- package/lib/stores/editors/CubeFilterDraft.d.ts +61 -0
- package/lib/stores/editors/CubeFilterDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeFilterDraft.js +186 -0
- package/lib/stores/editors/CubeFilterDraft.js.map +1 -0
- package/lib/stores/editors/CubeIntegerText.d.ts +24 -0
- package/lib/stores/editors/CubeIntegerText.d.ts.map +1 -0
- package/lib/stores/editors/CubeIntegerText.js +33 -0
- package/lib/stores/editors/CubeIntegerText.js.map +1 -0
- package/lib/stores/editors/CubeJoinDraft.d.ts +71 -0
- package/lib/stores/editors/CubeJoinDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeJoinDraft.js +145 -0
- package/lib/stores/editors/CubeJoinDraft.js.map +1 -0
- package/lib/stores/editors/CubeNodeDraft.d.ts +38 -0
- package/lib/stores/editors/CubeNodeDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeNodeDraft.js +35 -0
- package/lib/stores/editors/CubeNodeDraft.js.map +1 -0
- package/lib/stores/editors/CubeNodeDraftRegistry.d.ts +35 -0
- package/lib/stores/editors/CubeNodeDraftRegistry.d.ts.map +1 -0
- package/lib/stores/editors/CubeNodeDraftRegistry.js +55 -0
- package/lib/stores/editors/CubeNodeDraftRegistry.js.map +1 -0
- package/lib/stores/editors/CubeRenameDraft.d.ts +44 -0
- package/lib/stores/editors/CubeRenameDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeRenameDraft.js +79 -0
- package/lib/stores/editors/CubeRenameDraft.js.map +1 -0
- package/lib/stores/editors/CubeRestrictDraft.d.ts +37 -0
- package/lib/stores/editors/CubeRestrictDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeRestrictDraft.js +73 -0
- package/lib/stores/editors/CubeRestrictDraft.js.map +1 -0
- package/lib/stores/editors/CubeRowCountDraft.d.ts +42 -0
- package/lib/stores/editors/CubeRowCountDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeRowCountDraft.js +55 -0
- package/lib/stores/editors/CubeRowCountDraft.js.map +1 -0
- package/lib/stores/editors/CubeSliceDraft.d.ts +42 -0
- package/lib/stores/editors/CubeSliceDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeSliceDraft.js +72 -0
- package/lib/stores/editors/CubeSliceDraft.js.map +1 -0
- package/lib/stores/editors/CubeSortDraft.d.ts +49 -0
- package/lib/stores/editors/CubeSortDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeSortDraft.js +99 -0
- package/lib/stores/editors/CubeSortDraft.js.map +1 -0
- package/lib/stores/fixtures/CubeNorthwindModel.d.ts +23 -0
- package/lib/stores/fixtures/CubeNorthwindModel.d.ts.map +1 -0
- package/lib/stores/fixtures/CubeNorthwindModel.js +338 -0
- package/lib/stores/fixtures/CubeNorthwindModel.js.map +1 -0
- package/package.json +81 -3
- package/src/__lib__/LegendCubeCommand.ts +44 -0
- package/src/__lib__/LegendCubeHelpText.ts +58 -0
- package/src/__lib__/LegendCubeLabels.ts +171 -0
- package/src/__lib__/LegendCubeTesting.ts +33 -0
- package/src/__test-utils__/CubeCanvasTestUtils.ts +53 -0
- package/src/__test-utils__/CubeEngineTestSupport.ts +172 -0
- package/src/__test-utils__/CubeNorthwindTestQueries.ts +165 -0
- package/src/__test-utils__/CubeOperationsTestUtils.ts +177 -0
- package/src/__test-utils__/CubePageTestUtils.tsx +96 -0
- package/src/__test-utils__/CubeTestApplication.ts +82 -0
- package/src/__test-utils__/FakeCubeEngine.ts +145 -0
- package/src/components/CubeButton.tsx +35 -0
- package/src/components/CubeEditor.tsx +239 -0
- package/src/components/CubeNodeIcon.tsx +64 -0
- package/src/components/canvas/CubeCanvas.tsx +262 -0
- package/src/components/canvas/CubeCanvasContext.ts +31 -0
- package/src/components/canvas/CubeCanvasContextMenu.tsx +89 -0
- package/src/components/canvas/CubeCanvasDnd.ts +82 -0
- package/src/components/canvas/CubeCanvasEdge.tsx +57 -0
- package/src/components/canvas/CubeCanvasElements.ts +153 -0
- package/src/components/canvas/CubeCanvasLayout.ts +88 -0
- package/src/components/canvas/CubeCanvasNode.tsx +149 -0
- package/src/components/editors/CubeColumnPicker.tsx +138 -0
- package/src/components/editors/CubeDistinctEditor.tsx +28 -0
- package/src/components/editors/CubeFilterEditor.tsx +309 -0
- package/src/components/editors/CubeIntegerField.tsx +51 -0
- package/src/components/editors/CubeJoinEditor.tsx +247 -0
- package/src/components/editors/CubeNodeEditorPanel.tsx +215 -0
- package/src/components/editors/CubeNodeEditorRegistry.ts +81 -0
- package/src/components/editors/CubeRenameEditor.tsx +143 -0
- package/src/components/editors/CubeRestrictEditor.tsx +103 -0
- package/src/components/editors/CubeRowCountEditor.tsx +53 -0
- package/src/components/editors/CubeSliceEditor.tsx +69 -0
- package/src/components/editors/CubeSortEditor.tsx +206 -0
- package/src/components/editors/CubeSourceEditor.tsx +106 -0
- package/src/components/editors/CubeValueEditor.tsx +333 -0
- package/src/components/grid/CubeGridRegion.tsx +275 -0
- package/src/components/grid/CubeGridValues.ts +125 -0
- package/src/components/grid/CubeResultGrid.tsx +138 -0
- package/src/components/palette/CubePalette.tsx +177 -0
- package/src/components/show-pure/CubeShowPureDialog.tsx +101 -0
- package/src/components/source-picker/CubeSourcePicker.tsx +304 -0
- package/src/components/spec-transfer/CubeSpecTransferDialog.tsx +157 -0
- package/src/graph-manager/CubeEngine.ts +169 -0
- package/src/graph-manager/CubeModelOutlineHelper.ts +58 -0
- package/src/graph-manager/protocol/pure/CubeEngineBuilder.ts +34 -0
- package/src/graph-manager/protocol/pure/v1/V1_CubeEngineErrors.ts +109 -0
- package/src/graph-manager/protocol/pure/v1/V1_CubeExecutionResultReader.ts +115 -0
- package/src/graph-manager/protocol/pure/v1/V1_CubeLambdaSerializer.ts +257 -0
- package/src/graph-manager/protocol/pure/v1/V1_CubeModelOutlineBuilder.ts +243 -0
- package/src/graph-manager/protocol/pure/v1/V1_CubeRelationTypeAdapter.ts +58 -0
- package/src/graph-manager/protocol/pure/v1/V1_LegendCubeEngine.ts +278 -0
- package/src/graph-manager/protocol/pure/v1/__test-utils__/V1_CubeEngineTestUtils.ts +127 -0
- package/src/index.ts +41 -0
- package/src/stores/CubeEditorState.ts +807 -0
- package/src/stores/CubeExecutionState.ts +288 -0
- package/src/stores/CubeGridQuickActions.ts +129 -0
- package/src/stores/CubeHost.ts +32 -0
- package/src/stores/CubeNodeEditorState.ts +324 -0
- package/src/stores/CubeShowPureState.ts +118 -0
- package/src/stores/CubeSourcePickerState.ts +426 -0
- package/src/stores/CubeSpecTransferState.ts +198 -0
- package/src/stores/LocalModelCatalog.ts +70 -0
- package/src/stores/editors/CubeFilterDraft.ts +241 -0
- package/src/stores/editors/CubeIntegerText.ts +34 -0
- package/src/stores/editors/CubeJoinDraft.ts +224 -0
- package/src/stores/editors/CubeNodeDraft.ts +46 -0
- package/src/stores/editors/CubeNodeDraftRegistry.ts +83 -0
- package/src/stores/editors/CubeRenameDraft.ts +110 -0
- package/src/stores/editors/CubeRestrictDraft.ts +83 -0
- package/src/stores/editors/CubeRowCountDraft.ts +69 -0
- package/src/stores/editors/CubeSliceDraft.ts +87 -0
- package/src/stores/editors/CubeSortDraft.ts +135 -0
- package/src/stores/fixtures/CubeNorthwindModel.ts +355 -0
- package/tsconfig.json +133 -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,153 @@
|
|
|
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
|
+
/** It has a warning, stored (a table that changed) or derived (a lost sort order) */
|
|
121
|
+
readonly hasWarnings: boolean;
|
|
122
|
+
/** Its errors, then its warnings, its description and its id, one a line */
|
|
123
|
+
readonly tooltip: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const getCubeCanvasNodeStatus = (
|
|
127
|
+
editorState: CubeEditorState,
|
|
128
|
+
node: QueryNode,
|
|
129
|
+
): CubeCanvasNodeStatus => {
|
|
130
|
+
const ownErrors = editorState.analysis.validity.get(node.id);
|
|
131
|
+
// the tooltip adds the engine's error; the states keep it apart
|
|
132
|
+
const errors = editorState.getNodeErrors(node.id);
|
|
133
|
+
const warnings = editorState.getNodeWarnings(node);
|
|
134
|
+
return {
|
|
135
|
+
isCapture: editorState.document.query.selected === node.id,
|
|
136
|
+
isInvalid: (ownErrors ?? []).some(
|
|
137
|
+
(error) => !isIncompleteError(error) && !isSchemasError(error),
|
|
138
|
+
),
|
|
139
|
+
isIncomplete: (ownErrors ?? []).some(
|
|
140
|
+
(error) => isIncompleteError(error) || isSchemasError(error),
|
|
141
|
+
),
|
|
142
|
+
isResolving: editorState.isPendingSource(node),
|
|
143
|
+
hasEngineError: editorState.hostIssues.has(node.id),
|
|
144
|
+
hasWarnings: warnings.length > 0,
|
|
145
|
+
tooltip: [
|
|
146
|
+
...(ownErrors ? [] : [MISSING_VALIDITY_TOOLTIP]),
|
|
147
|
+
...errors,
|
|
148
|
+
...warnings,
|
|
149
|
+
node.describe(),
|
|
150
|
+
node.id,
|
|
151
|
+
].join('\n'),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
@@ -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,149 @@
|
|
|
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, WarningIcon } 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--warning': status.hasWarnings,
|
|
117
|
+
'legend-cube__node--drop-target outline-dashed outline-2 outline-[var(--color-accent)]':
|
|
118
|
+
isDropTarget,
|
|
119
|
+
},
|
|
120
|
+
)}
|
|
121
|
+
title={status.tooltip}
|
|
122
|
+
aria-current={status.isCapture}
|
|
123
|
+
data-testid={LEGEND_CUBE_TEST_ID.CANVAS_NODE}
|
|
124
|
+
>
|
|
125
|
+
<CubeNodeIcon
|
|
126
|
+
icon={editorState.registry.get(node.type)?.icon}
|
|
127
|
+
className="shrink-0 text-lg text-[var(--color-text-secondary)]"
|
|
128
|
+
/>
|
|
129
|
+
<span className="line-clamp-2 min-w-0 break-words leading-tight">
|
|
130
|
+
{node.describe()}
|
|
131
|
+
</span>
|
|
132
|
+
{status.hasWarnings && (
|
|
133
|
+
// the warning's text is in the node's tooltip
|
|
134
|
+
<WarningIcon
|
|
135
|
+
className="ml-auto shrink-0 text-[var(--color-status-warn)]"
|
|
136
|
+
aria-hidden={true}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
<Handle
|
|
141
|
+
id={CUBE_OUTPUT_HANDLE_ID}
|
|
142
|
+
type="source"
|
|
143
|
+
position={Position.Right}
|
|
144
|
+
isConnectable={!editorState.readOnly}
|
|
145
|
+
/>
|
|
146
|
+
</ContextMenu>
|
|
147
|
+
);
|
|
148
|
+
},
|
|
149
|
+
);
|
|
@@ -0,0 +1,138 @@
|
|
|
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 {
|
|
27
|
+
type CubeType,
|
|
28
|
+
type Schema,
|
|
29
|
+
type SchemaColumn,
|
|
30
|
+
TypeFamily,
|
|
31
|
+
} from '@finos/legend-cube';
|
|
32
|
+
import { getColumnTypeLabel } from '../../__lib__/LegendCubeLabels.js';
|
|
33
|
+
|
|
34
|
+
const FAMILY_ICONS: Readonly<
|
|
35
|
+
Partial<Record<TypeFamily, React.FC<{ className?: string }>>>
|
|
36
|
+
> = {
|
|
37
|
+
[TypeFamily.STRING]: StringTypeIcon,
|
|
38
|
+
[TypeFamily.BOOLEAN]: ToggleIcon,
|
|
39
|
+
[TypeFamily.INTEGER]: HashtagIcon,
|
|
40
|
+
[TypeFamily.FLOAT]: HashtagIcon,
|
|
41
|
+
[TypeFamily.DECIMAL]: HashtagIcon,
|
|
42
|
+
[TypeFamily.NUMBER]: HashtagIcon,
|
|
43
|
+
[TypeFamily.STRICT_DATE]: CalendarIcon,
|
|
44
|
+
[TypeFamily.DATETIME]: CalendarIcon,
|
|
45
|
+
[TypeFamily.DATE]: CalendarIcon,
|
|
46
|
+
[TypeFamily.ENUM]: ListIcon,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** The icon of a column type's family: text, number, date, ...; a question mark for the rest */
|
|
50
|
+
export const CubeColumnTypeIcon: React.FC<{
|
|
51
|
+
type: CubeType;
|
|
52
|
+
className?: string;
|
|
53
|
+
}> = (props) => {
|
|
54
|
+
const Icon = FAMILY_ICONS[props.type.family] ?? QuestionIcon;
|
|
55
|
+
return <Icon className={clsx('shrink-0', props.className)} />;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Picks a column of an input schema, in schema order (spec §17.5: only the
|
|
60
|
+
* columns of the actual input). Each option names its type, e.g.
|
|
61
|
+
* `CUSTOMER_ID: Varchar(5)?`; the picked column's type shows beside, with
|
|
62
|
+
* its family's icon and its full type in the tooltip. A column the input
|
|
63
|
+
* doesn't have stays shown, so the problem can be seen and fixed. A column
|
|
64
|
+
* the editor can't take here is shown, with the reason `isColumnDisabled`
|
|
65
|
+
* gives after its type, but can't be picked.
|
|
66
|
+
*/
|
|
67
|
+
export const CubeColumnPicker: React.FC<{
|
|
68
|
+
/** What the column is for, e.g. `Left join column 1`: the picker's accessible name */
|
|
69
|
+
label: string;
|
|
70
|
+
schema: Schema;
|
|
71
|
+
/** The picked column's name, `''` or `undefined` for none */
|
|
72
|
+
value: string | undefined;
|
|
73
|
+
onChange: (columnName: string) => void;
|
|
74
|
+
disabled?: boolean | undefined;
|
|
75
|
+
/** Marks the pick as wrong, e.g. a type that doesn't match */
|
|
76
|
+
invalid?: boolean | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Why a column can't be picked, shown after its type, e.g. a Sort's Variant
|
|
79
|
+
* column, or one another row has; `undefined` when it can be
|
|
80
|
+
*/
|
|
81
|
+
isColumnDisabled?: ((column: SchemaColumn) => string | undefined) | undefined;
|
|
82
|
+
}> = (props) => {
|
|
83
|
+
const {
|
|
84
|
+
label,
|
|
85
|
+
schema,
|
|
86
|
+
value,
|
|
87
|
+
onChange,
|
|
88
|
+
disabled,
|
|
89
|
+
invalid,
|
|
90
|
+
isColumnDisabled,
|
|
91
|
+
} = props;
|
|
92
|
+
const picked = value ? schema.lookup(value) : undefined;
|
|
93
|
+
return (
|
|
94
|
+
<div className="flex min-w-0 items-center gap-1">
|
|
95
|
+
<select
|
|
96
|
+
aria-label={label}
|
|
97
|
+
aria-invalid={Boolean(invalid) || (Boolean(value) && !picked)}
|
|
98
|
+
className={clsx(
|
|
99
|
+
'h-6 min-w-0 flex-1 rounded-sm border bg-[var(--color-bg-input)] px-1 text-base',
|
|
100
|
+
invalid || (value && !picked)
|
|
101
|
+
? 'border-[var(--color-status-error)]'
|
|
102
|
+
: 'border-[var(--color-border-default)]',
|
|
103
|
+
)}
|
|
104
|
+
value={value ?? ''}
|
|
105
|
+
disabled={disabled}
|
|
106
|
+
onChange={(event) => onChange(event.target.value)}
|
|
107
|
+
>
|
|
108
|
+
{!picked && (
|
|
109
|
+
<option value={value ?? ''} disabled={true}>
|
|
110
|
+
{value ? `${value} (not in the input)` : 'Pick a column'}
|
|
111
|
+
</option>
|
|
112
|
+
)}
|
|
113
|
+
{schema.columns.map((column) => {
|
|
114
|
+
const reason = isColumnDisabled?.(column);
|
|
115
|
+
return (
|
|
116
|
+
<option
|
|
117
|
+
key={column.name}
|
|
118
|
+
value={column.name}
|
|
119
|
+
title={column.type.fullName}
|
|
120
|
+
disabled={reason !== undefined}
|
|
121
|
+
>
|
|
122
|
+
{`${column.name}: ${getColumnTypeLabel(column)}${reason === undefined ? '' : ` (${reason})`}`}
|
|
123
|
+
</option>
|
|
124
|
+
);
|
|
125
|
+
})}
|
|
126
|
+
</select>
|
|
127
|
+
{picked && (
|
|
128
|
+
<span
|
|
129
|
+
className="flex shrink-0 items-center gap-1 text-sm text-[var(--color-text-secondary)]"
|
|
130
|
+
title={picked.type.fullName}
|
|
131
|
+
>
|
|
132
|
+
<CubeColumnTypeIcon type={picked.type} />
|
|
133
|
+
{getColumnTypeLabel(picked)}
|
|
134
|
+
</span>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { observer } from 'mobx-react-lite';
|
|
18
|
+
import { DISTINCT_EDITOR_TEXT } from '../../__lib__/LegendCubeLabels.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The Distinct editor (spec §17.6: "nothing — description only"). Distinct
|
|
22
|
+
* has no settings, so it has no draft, and the panel shows no Apply or Cancel.
|
|
23
|
+
*/
|
|
24
|
+
export const CubeDistinctEditor = observer(() => (
|
|
25
|
+
<div className="text-base text-[var(--color-text-secondary)]">
|
|
26
|
+
{DISTINCT_EDITOR_TEXT}
|
|
27
|
+
</div>
|
|
28
|
+
));
|