@finos/legend-cube-builder 0.0.5 → 0.0.6

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 (245) hide show
  1. package/docs/adding-an-operation.md +4 -2
  2. package/docs/demo/README.md +1 -1
  3. package/docs/hosting.md +40 -9
  4. package/lib/__lib__/LegendCubeHelpText.d.ts.map +1 -1
  5. package/lib/__lib__/LegendCubeHelpText.js +3 -1
  6. package/lib/__lib__/LegendCubeHelpText.js.map +1 -1
  7. package/lib/__lib__/LegendCubeLabels.d.ts +34 -5
  8. package/lib/__lib__/LegendCubeLabels.d.ts.map +1 -1
  9. package/lib/__lib__/LegendCubeLabels.js +45 -8
  10. package/lib/__lib__/LegendCubeLabels.js.map +1 -1
  11. package/lib/__lib__/LegendCubeNavigation.d.ts +23 -0
  12. package/lib/__lib__/LegendCubeNavigation.d.ts.map +1 -0
  13. package/lib/__lib__/LegendCubeNavigation.js +33 -0
  14. package/lib/__lib__/LegendCubeNavigation.js.map +1 -0
  15. package/lib/__lib__/LegendCubeTesting.d.ts +3 -1
  16. package/lib/__lib__/LegendCubeTesting.d.ts.map +1 -1
  17. package/lib/__lib__/LegendCubeTesting.js +2 -0
  18. package/lib/__lib__/LegendCubeTesting.js.map +1 -1
  19. package/lib/__lib__/LegendCubeTour.d.ts +62 -0
  20. package/lib/__lib__/LegendCubeTour.d.ts.map +1 -0
  21. package/lib/__lib__/LegendCubeTour.js +149 -0
  22. package/lib/__lib__/LegendCubeTour.js.map +1 -0
  23. package/lib/__test-utils__/CubeExampleTestUtils.d.ts +34 -0
  24. package/lib/__test-utils__/CubeExampleTestUtils.d.ts.map +1 -0
  25. package/lib/__test-utils__/CubeExampleTestUtils.js +72 -0
  26. package/lib/__test-utils__/CubeExampleTestUtils.js.map +1 -0
  27. package/lib/__test-utils__/CubeVariantTestUtils.d.ts +16 -0
  28. package/lib/__test-utils__/CubeVariantTestUtils.d.ts.map +1 -0
  29. package/lib/__test-utils__/CubeVariantTestUtils.js +66 -0
  30. package/lib/__test-utils__/CubeVariantTestUtils.js.map +1 -0
  31. package/lib/components/CubeAddItems.d.ts.map +1 -1
  32. package/lib/components/CubeAddItems.js +2 -1
  33. package/lib/components/CubeAddItems.js.map +1 -1
  34. package/lib/components/CubeEditor.d.ts.map +1 -1
  35. package/lib/components/CubeEditor.js +11 -5
  36. package/lib/components/CubeEditor.js.map +1 -1
  37. package/lib/components/CubeFileMenu.d.ts.map +1 -1
  38. package/lib/components/CubeFileMenu.js +2 -1
  39. package/lib/components/CubeFileMenu.js.map +1 -1
  40. package/lib/components/CubeNodeIcon.d.ts.map +1 -1
  41. package/lib/components/CubeNodeIcon.js +2 -1
  42. package/lib/components/CubeNodeIcon.js.map +1 -1
  43. package/lib/components/canvas/CubeCanvas.d.ts.map +1 -1
  44. package/lib/components/canvas/CubeCanvas.js +3 -2
  45. package/lib/components/canvas/CubeCanvas.js.map +1 -1
  46. package/lib/components/canvas/CubeCanvasNode.d.ts.map +1 -1
  47. package/lib/components/canvas/CubeCanvasNode.js +4 -1
  48. package/lib/components/canvas/CubeCanvasNode.js.map +1 -1
  49. package/lib/components/dev-settings/CubeDevSettings.d.ts +2 -2
  50. package/lib/components/dev-settings/CubeDevSettings.d.ts.map +1 -1
  51. package/lib/components/dev-settings/CubeDevSettings.js +12 -8
  52. package/lib/components/dev-settings/CubeDevSettings.js.map +1 -1
  53. package/lib/components/editors/CubeColumnPicker.d.ts.map +1 -1
  54. package/lib/components/editors/CubeColumnPicker.js +3 -1
  55. package/lib/components/editors/CubeColumnPicker.js.map +1 -1
  56. package/lib/components/editors/CubeExplodeEditor.d.ts +26 -0
  57. package/lib/components/editors/CubeExplodeEditor.d.ts.map +1 -0
  58. package/lib/components/editors/CubeExplodeEditor.js +61 -0
  59. package/lib/components/editors/CubeExplodeEditor.js.map +1 -0
  60. package/lib/components/editors/CubeExpressionFilterEditor.d.ts.map +1 -1
  61. package/lib/components/editors/CubeExpressionFilterEditor.js +8 -5
  62. package/lib/components/editors/CubeExpressionFilterEditor.js.map +1 -1
  63. package/lib/components/editors/CubeExtendEditor.d.ts +0 -2
  64. package/lib/components/editors/CubeExtendEditor.d.ts.map +1 -1
  65. package/lib/components/editors/CubeExtendEditor.js +12 -11
  66. package/lib/components/editors/CubeExtendEditor.js.map +1 -1
  67. package/lib/components/editors/CubeJsonFieldsTree.d.ts +46 -0
  68. package/lib/components/editors/CubeJsonFieldsTree.d.ts.map +1 -0
  69. package/lib/components/editors/CubeJsonFieldsTree.js +93 -0
  70. package/lib/components/editors/CubeJsonFieldsTree.js.map +1 -0
  71. package/lib/components/editors/CubeNodeEditorRegistry.d.ts.map +1 -1
  72. package/lib/components/editors/CubeNodeEditorRegistry.js +3 -1
  73. package/lib/components/editors/CubeNodeEditorRegistry.js.map +1 -1
  74. package/lib/components/grid/CubeGridRegion.d.ts.map +1 -1
  75. package/lib/components/grid/CubeGridRegion.js +5 -4
  76. package/lib/components/grid/CubeGridRegion.js.map +1 -1
  77. package/lib/components/grid/CubeGridValues.d.ts +5 -3
  78. package/lib/components/grid/CubeGridValues.d.ts.map +1 -1
  79. package/lib/components/grid/CubeGridValues.js +8 -3
  80. package/lib/components/grid/CubeGridValues.js.map +1 -1
  81. package/lib/components/grid/CubeJsonExplorerDialog.d.ts +27 -0
  82. package/lib/components/grid/CubeJsonExplorerDialog.d.ts.map +1 -0
  83. package/lib/components/grid/CubeJsonExplorerDialog.js +102 -0
  84. package/lib/components/grid/CubeJsonExplorerDialog.js.map +1 -0
  85. package/lib/components/grid/CubeJsonViewerDialog.d.ts +27 -0
  86. package/lib/components/grid/CubeJsonViewerDialog.d.ts.map +1 -0
  87. package/lib/components/grid/CubeJsonViewerDialog.js +68 -0
  88. package/lib/components/grid/CubeJsonViewerDialog.js.map +1 -0
  89. package/lib/components/grid/CubeResultGrid.d.ts +15 -3
  90. package/lib/components/grid/CubeResultGrid.d.ts.map +1 -1
  91. package/lib/components/grid/CubeResultGrid.js +95 -3
  92. package/lib/components/grid/CubeResultGrid.js.map +1 -1
  93. package/lib/components/grid/CubeServerSideGrid.d.ts.map +1 -1
  94. package/lib/components/grid/CubeServerSideGrid.js +4 -2
  95. package/lib/components/grid/CubeServerSideGrid.js.map +1 -1
  96. package/lib/components/palette/CubePalette.d.ts.map +1 -1
  97. package/lib/components/palette/CubePalette.js +4 -1
  98. package/lib/components/palette/CubePalette.js.map +1 -1
  99. package/lib/components/source-picker/CubeIngestTab.d.ts +2 -2
  100. package/lib/components/source-picker/CubeIngestTab.d.ts.map +1 -1
  101. package/lib/components/source-picker/CubeIngestTab.js +19 -13
  102. package/lib/components/source-picker/CubeIngestTab.js.map +1 -1
  103. package/lib/components/tour/CubeTour.d.ts +36 -0
  104. package/lib/components/tour/CubeTour.d.ts.map +1 -0
  105. package/lib/components/tour/CubeTour.js +183 -0
  106. package/lib/components/tour/CubeTour.js.map +1 -0
  107. package/lib/index.css +1 -1
  108. package/lib/index.d.ts +1 -0
  109. package/lib/index.d.ts.map +1 -1
  110. package/lib/index.js +1 -0
  111. package/lib/index.js.map +1 -1
  112. package/lib/stores/CubeEditorState.d.ts +17 -1
  113. package/lib/stores/CubeEditorState.d.ts.map +1 -1
  114. package/lib/stores/CubeEditorState.js +35 -5
  115. package/lib/stores/CubeEditorState.js.map +1 -1
  116. package/lib/stores/CubeExamples.d.ts.map +1 -1
  117. package/lib/stores/CubeExamples.js +101 -4
  118. package/lib/stores/CubeExamples.js.map +1 -1
  119. package/lib/stores/CubeExamplesState.d.ts.map +1 -1
  120. package/lib/stores/CubeExamplesState.js +4 -1
  121. package/lib/stores/CubeExamplesState.js.map +1 -1
  122. package/lib/stores/CubeGridQuickActions.d.ts +7 -0
  123. package/lib/stores/CubeGridQuickActions.d.ts.map +1 -1
  124. package/lib/stores/CubeGridQuickActions.js +20 -11
  125. package/lib/stores/CubeGridQuickActions.js.map +1 -1
  126. package/lib/stores/CubePureText.d.ts +20 -0
  127. package/lib/stores/CubePureText.d.ts.map +1 -0
  128. package/lib/stores/CubePureText.js +24 -0
  129. package/lib/stores/CubePureText.js.map +1 -0
  130. package/lib/stores/CubeTourState.d.ts +49 -0
  131. package/lib/stores/CubeTourState.d.ts.map +1 -0
  132. package/lib/stores/CubeTourState.js +92 -0
  133. package/lib/stores/CubeTourState.js.map +1 -0
  134. package/lib/stores/LegendCubeHost.d.ts +88 -0
  135. package/lib/stores/LegendCubeHost.d.ts.map +1 -0
  136. package/lib/stores/LegendCubeHost.js +149 -0
  137. package/lib/stores/LegendCubeHost.js.map +1 -0
  138. package/lib/stores/editors/CubeExplodeDraft.d.ts +87 -0
  139. package/lib/stores/editors/CubeExplodeDraft.d.ts.map +1 -0
  140. package/lib/stores/editors/CubeExplodeDraft.js +221 -0
  141. package/lib/stores/editors/CubeExplodeDraft.js.map +1 -0
  142. package/lib/stores/editors/CubeExpressionFilterDraft.d.ts +3 -0
  143. package/lib/stores/editors/CubeExpressionFilterDraft.d.ts.map +1 -1
  144. package/lib/stores/editors/CubeExpressionFilterDraft.js +4 -0
  145. package/lib/stores/editors/CubeExpressionFilterDraft.js.map +1 -1
  146. package/lib/stores/editors/CubeExtendDraft.d.ts +9 -0
  147. package/lib/stores/editors/CubeExtendDraft.d.ts.map +1 -1
  148. package/lib/stores/editors/CubeExtendDraft.js +26 -0
  149. package/lib/stores/editors/CubeExtendDraft.js.map +1 -1
  150. package/lib/stores/editors/CubeNodeDraftRegistry.d.ts.map +1 -1
  151. package/lib/stores/editors/CubeNodeDraftRegistry.js +6 -1
  152. package/lib/stores/editors/CubeNodeDraftRegistry.js.map +1 -1
  153. package/lib/stores/fixtures/CubeSalesDuckDbModel.d.ts +1 -0
  154. package/lib/stores/fixtures/CubeSalesDuckDbModel.d.ts.map +1 -1
  155. package/lib/stores/fixtures/CubeSalesDuckDbModel.js +8 -2
  156. package/lib/stores/fixtures/CubeSalesDuckDbModel.js.map +1 -1
  157. package/lib/stores/source-picker/CubeIngestTabState.d.ts +48 -14
  158. package/lib/stores/source-picker/CubeIngestTabState.d.ts.map +1 -1
  159. package/lib/stores/source-picker/CubeIngestTabState.js +159 -62
  160. package/lib/stores/source-picker/CubeIngestTabState.js.map +1 -1
  161. package/lib/stores/variant/CubeJson.d.ts +48 -0
  162. package/lib/stores/variant/CubeJson.d.ts.map +1 -0
  163. package/lib/stores/variant/CubeJson.js +207 -0
  164. package/lib/stores/variant/CubeJson.js.map +1 -0
  165. package/lib/stores/variant/CubeJsonExplorerState.d.ts +88 -0
  166. package/lib/stores/variant/CubeJsonExplorerState.d.ts.map +1 -0
  167. package/lib/stores/variant/CubeJsonExplorerState.js +297 -0
  168. package/lib/stores/variant/CubeJsonExplorerState.js.map +1 -0
  169. package/lib/stores/variant/CubeJsonFieldsState.d.ts +83 -0
  170. package/lib/stores/variant/CubeJsonFieldsState.d.ts.map +1 -0
  171. package/lib/stores/variant/CubeJsonFieldsState.js +207 -0
  172. package/lib/stores/variant/CubeJsonFieldsState.js.map +1 -0
  173. package/lib/stores/variant/CubeJsonOffers.d.ts +76 -0
  174. package/lib/stores/variant/CubeJsonOffers.d.ts.map +1 -0
  175. package/lib/stores/variant/CubeJsonOffers.js +250 -0
  176. package/lib/stores/variant/CubeJsonOffers.js.map +1 -0
  177. package/lib/stores/variant/CubeJsonParse.d.ts +28 -0
  178. package/lib/stores/variant/CubeJsonParse.d.ts.map +1 -0
  179. package/lib/stores/variant/CubeJsonParse.js +53 -0
  180. package/lib/stores/variant/CubeJsonParse.js.map +1 -0
  181. package/lib/stores/variant/CubeJsonSampling.d.ts +41 -0
  182. package/lib/stores/variant/CubeJsonSampling.d.ts.map +1 -0
  183. package/lib/stores/variant/CubeJsonSampling.js +59 -0
  184. package/lib/stores/variant/CubeJsonSampling.js.map +1 -0
  185. package/lib/stores/variant/CubeJsonShape.d.ts +87 -0
  186. package/lib/stores/variant/CubeJsonShape.d.ts.map +1 -0
  187. package/lib/stores/variant/CubeJsonShape.js +209 -0
  188. package/lib/stores/variant/CubeJsonShape.js.map +1 -0
  189. package/lib/stores/variant/CubeJsonViewerState.d.ts +33 -0
  190. package/lib/stores/variant/CubeJsonViewerState.d.ts.map +1 -0
  191. package/lib/stores/variant/CubeJsonViewerState.js +53 -0
  192. package/lib/stores/variant/CubeJsonViewerState.js.map +1 -0
  193. package/package.json +2 -2
  194. package/src/__lib__/LegendCubeHelpText.ts +4 -0
  195. package/src/__lib__/LegendCubeLabels.ts +60 -8
  196. package/src/__lib__/LegendCubeNavigation.ts +48 -0
  197. package/src/__lib__/LegendCubeTesting.ts +2 -0
  198. package/src/__lib__/LegendCubeTour.ts +173 -0
  199. package/src/__test-utils__/CubeExampleTestUtils.ts +119 -0
  200. package/src/__test-utils__/CubeVariantTestUtils.ts +103 -0
  201. package/src/components/CubeAddItems.tsx +2 -0
  202. package/src/components/CubeEditor.tsx +15 -0
  203. package/src/components/CubeFileMenu.tsx +2 -0
  204. package/src/components/CubeNodeIcon.tsx +2 -0
  205. package/src/components/canvas/CubeCanvas.tsx +17 -1
  206. package/src/components/canvas/CubeCanvasNode.tsx +7 -0
  207. package/src/components/dev-settings/CubeDevSettings.tsx +17 -2
  208. package/src/components/editors/CubeColumnPicker.tsx +3 -0
  209. package/src/components/editors/CubeExplodeEditor.tsx +207 -0
  210. package/src/components/editors/CubeExpressionFilterEditor.tsx +25 -8
  211. package/src/components/editors/CubeExtendEditor.tsx +32 -19
  212. package/src/components/editors/CubeJsonFieldsTree.tsx +316 -0
  213. package/src/components/editors/CubeNodeEditorRegistry.ts +3 -0
  214. package/src/components/grid/CubeGridRegion.tsx +21 -3
  215. package/src/components/grid/CubeGridValues.ts +8 -3
  216. package/src/components/grid/CubeJsonExplorerDialog.tsx +304 -0
  217. package/src/components/grid/CubeJsonViewerDialog.tsx +190 -0
  218. package/src/components/grid/CubeResultGrid.tsx +144 -2
  219. package/src/components/grid/CubeServerSideGrid.tsx +13 -0
  220. package/src/components/palette/CubePalette.tsx +9 -0
  221. package/src/components/source-picker/CubeIngestTab.tsx +62 -30
  222. package/src/components/tour/CubeTour.tsx +317 -0
  223. package/src/index.ts +7 -0
  224. package/src/stores/CubeEditorState.ts +36 -5
  225. package/src/stores/CubeExamples.ts +120 -2
  226. package/src/stores/CubeExamplesState.ts +9 -1
  227. package/src/stores/CubeGridQuickActions.ts +23 -12
  228. package/src/stores/CubePureText.ts +28 -0
  229. package/src/stores/CubeTourState.ts +116 -0
  230. package/src/stores/LegendCubeHost.ts +243 -0
  231. package/src/stores/editors/CubeExplodeDraft.ts +272 -0
  232. package/src/stores/editors/CubeExpressionFilterDraft.ts +4 -0
  233. package/src/stores/editors/CubeExtendDraft.ts +29 -0
  234. package/src/stores/editors/CubeNodeDraftRegistry.ts +7 -0
  235. package/src/stores/fixtures/CubeSalesDuckDbModel.ts +8 -2
  236. package/src/stores/source-picker/CubeIngestTabState.ts +253 -102
  237. package/src/stores/variant/CubeJson.ts +229 -0
  238. package/src/stores/variant/CubeJsonExplorerState.ts +378 -0
  239. package/src/stores/variant/CubeJsonFieldsState.ts +252 -0
  240. package/src/stores/variant/CubeJsonOffers.ts +359 -0
  241. package/src/stores/variant/CubeJsonParse.ts +75 -0
  242. package/src/stores/variant/CubeJsonSampling.ts +90 -0
  243. package/src/stores/variant/CubeJsonShape.ts +279 -0
  244. package/src/stores/variant/CubeJsonViewerState.ts +59 -0
  245. package/tsconfig.json +22 -1
@@ -67,6 +67,12 @@ export const CUBE_INGEST_TAB_MESSAGE = {
67
67
  'The cube changed while the data set was being added; pick it again.',
68
68
  } as const;
69
69
 
70
+ /** A data set picked to add: the URN of its definition, and its name */
71
+ export interface CubeIngestPick {
72
+ readonly definitionUrn: string;
73
+ readonly dataSet: string;
74
+ }
75
+
70
76
  const toError = (error: unknown): CubeIngestTabError => {
71
77
  if (error instanceof CubeEngineError) {
72
78
  return {
@@ -80,10 +86,11 @@ const toError = (error: unknown): CubeIngestTabError => {
80
86
  /**
81
87
  * The source dialog's Ingest tab (PLAN §6.7), as Data Cube's producer
82
88
  * source picks: the Mode (class), the viewer's environment for it, a
83
- * producer deployment, one of its SDLC-deployed definitions, then one or
84
- * several of its data sets, typed from what the definition declares. The
85
- * first Add saves the class, the producer deployment and the warehouse as
86
- * the cube's model; then the tab offers only that deployment's definitions.
89
+ * producer deployment, one of its SDLC-deployed definitions, or several
90
+ * ticked, then one or several of their data sets, typed from what each
91
+ * definition declares. The first Add saves the class, the producer
92
+ * deployment and the warehouse as the cube's model; then the tab offers only
93
+ * that deployment's definitions.
87
94
  */
88
95
  export class CubeIngestTabState implements CubeSourcePickerTab {
89
96
  readonly key = CubeSourcePickerTabKey.INGEST;
@@ -96,20 +103,24 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
96
103
  producerDeploymentId: string | undefined;
97
104
  definitionList: CubeIngestDefinitionList | undefined;
98
105
  definitionSearch = '';
99
- definition: CubeIngestDefinitionCandidate | undefined;
100
- dataSets: readonly CubeIngestDataSet[] | undefined;
101
- /** The picked data sets, by name, in the order picked; several are added at once */
102
- dataSetNames: readonly string[] = [];
106
+ /** The definitions opened, in the order opened: one picked alone, or several ticked */
107
+ definitions: readonly CubeIngestDefinitionCandidate[] = [];
108
+ /** The data sets of each opened definition, by its URN, once read */
109
+ dataSetsByDefinition: ReadonlyMap<string, readonly CubeIngestDataSet[]> =
110
+ new Map();
111
+ /** The picked data sets, in the order picked, of any opened definition; several are added at once */
112
+ picks: readonly CubeIngestPick[] = [];
103
113
  /** The warehouse of a cube without one yet: the one the viewer last picked, else the default */
104
114
  warehouse = CUBE_DEFAULT_CONSUMER_WAREHOUSE;
105
115
  isLoadingEnvironment = false;
106
116
  isListingDefinitions = false;
107
- isDescribing = false;
108
117
  isAdding = false;
109
118
  error: CubeIngestTabError | undefined;
110
119
 
111
120
  /** The class the environment and producers were read for */
112
121
  private loadedEnvironmentType: CubeDataProductEnvironmentType | undefined;
122
+ /** The definitions whose data sets are being read, by URN, each with its request */
123
+ private describing: ReadonlyMap<string, number> = new Map();
113
124
  /** Each counts its calls: a later call, or closing the dialog, drops an earlier answer */
114
125
  private environmentRequest = 0;
115
126
  private definitionsRequest = 0;
@@ -117,46 +128,55 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
117
128
  private confirmRequest = 0;
118
129
 
119
130
  constructor(editorState: CubeEditorState) {
120
- makeObservable<CubeIngestTabState, 'loadedEnvironmentType'>(this, {
121
- environmentType: observable,
122
- environment: observable.ref,
123
- producers: observable.ref,
124
- producerDeploymentId: observable,
125
- definitionList: observable.ref,
126
- definitionSearch: observable,
127
- definition: observable.ref,
128
- dataSets: observable.ref,
129
- dataSetNames: observable.ref,
130
- dataSetName: computed,
131
- pickedDataSets: computed,
132
- warehouse: observable,
133
- isLoadingEnvironment: observable,
134
- isListingDefinitions: observable,
135
- isDescribing: observable,
136
- isAdding: observable,
137
- error: observable.ref,
138
- loadedEnvironmentType: observable,
139
- fixedSettings: computed,
140
- isAvailable: computed,
141
- isBusy: computed,
142
- shownDefinitions: computed,
143
- dataSet: computed,
144
- canConfirm: computed,
145
- setEnvironmentType: action,
146
- selectProducer: action,
147
- setDefinitionSearch: action,
148
- selectDefinition: action,
149
- selectDataSet: action,
150
- toggleDataSet: action,
151
- setWarehouse: action,
152
- retry: action,
153
- open: action,
154
- close: action,
155
- loadEnvironment: flow,
156
- listDefinitions: flow,
157
- describeDefinition: flow,
158
- confirm: flow,
159
- });
131
+ makeObservable<CubeIngestTabState, 'loadedEnvironmentType' | 'describing'>(
132
+ this,
133
+ {
134
+ environmentType: observable,
135
+ environment: observable.ref,
136
+ producers: observable.ref,
137
+ producerDeploymentId: observable,
138
+ definitionList: observable.ref,
139
+ definitionSearch: observable,
140
+ definitions: observable.ref,
141
+ dataSetsByDefinition: observable.ref,
142
+ picks: observable.ref,
143
+ definition: computed,
144
+ dataSets: computed,
145
+ dataSetNames: computed,
146
+ dataSetName: computed,
147
+ pickedDataSets: computed,
148
+ previewedDefinition: computed,
149
+ warehouse: observable,
150
+ isLoadingEnvironment: observable,
151
+ isListingDefinitions: observable,
152
+ isDescribing: computed,
153
+ isAdding: observable,
154
+ error: observable.ref,
155
+ loadedEnvironmentType: observable,
156
+ describing: observable.ref,
157
+ fixedSettings: computed,
158
+ isAvailable: computed,
159
+ isBusy: computed,
160
+ shownDefinitions: computed,
161
+ dataSet: computed,
162
+ canConfirm: computed,
163
+ setEnvironmentType: action,
164
+ selectProducer: action,
165
+ setDefinitionSearch: action,
166
+ selectDefinition: action,
167
+ toggleDefinition: action,
168
+ selectDataSet: action,
169
+ toggleDataSet: action,
170
+ setWarehouse: action,
171
+ retry: action,
172
+ open: action,
173
+ close: action,
174
+ loadEnvironment: flow,
175
+ listDefinitions: flow,
176
+ describeDefinition: flow,
177
+ confirm: flow,
178
+ },
179
+ );
160
180
  this.editorState = editorState;
161
181
  }
162
182
 
@@ -175,6 +195,11 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
175
195
  return model ? getCubeIngestSettings(model) : undefined;
176
196
  }
177
197
 
198
+ /** Whether data sets of an opened definition are being read */
199
+ get isDescribing(): boolean {
200
+ return this.describing.size > 0;
201
+ }
202
+
178
203
  get isBusy(): boolean {
179
204
  return (
180
205
  this.isLoadingEnvironment ||
@@ -199,34 +224,77 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
199
224
  );
200
225
  }
201
226
 
227
+ /** The definition opened last */
228
+ get definition(): CubeIngestDefinitionCandidate | undefined {
229
+ return this.definitions.at(-1);
230
+ }
231
+
232
+ /** The data sets of the definition opened last, once read */
233
+ get dataSets(): readonly CubeIngestDataSet[] | undefined {
234
+ const { definition } = this;
235
+ return definition
236
+ ? this.dataSetsByDefinition.get(definition.urn)
237
+ : undefined;
238
+ }
239
+
240
+ isDefinitionOpened(candidate: CubeIngestDefinitionCandidate): boolean {
241
+ return this.definitions.some((each) => each.urn === candidate.urn);
242
+ }
243
+
244
+ /** The data sets of an opened definition, once read */
245
+ getDataSets(definitionUrn: string): readonly CubeIngestDataSet[] | undefined {
246
+ return this.dataSetsByDefinition.get(definitionUrn);
247
+ }
248
+
249
+ /** The names of the picked data sets, in the order picked */
250
+ get dataSetNames(): readonly string[] {
251
+ return this.picks.map((pick) => pick.dataSet);
252
+ }
253
+
202
254
  /** The data set picked last, the one previewed */
203
255
  get dataSetName(): string | undefined {
204
- return this.dataSetNames.at(-1);
256
+ return this.picks.at(-1)?.dataSet;
205
257
  }
206
258
 
207
259
  /** The data set picked last, the one previewed */
208
260
  get dataSet(): CubeIngestDataSet | undefined {
209
- return this.findDataSet(this.dataSetName);
261
+ return this.findDataSet(this.picks.at(-1));
262
+ }
263
+
264
+ /** The definition of the data set picked last */
265
+ get previewedDefinition(): CubeIngestDefinitionCandidate | undefined {
266
+ const urn = this.picks.at(-1)?.definitionUrn;
267
+ return this.definitions.find((each) => each.urn === urn);
210
268
  }
211
269
 
212
270
  /** The picked data sets, in the order picked */
213
271
  get pickedDataSets(): readonly (CubeIngestDataSet | undefined)[] {
214
- return this.dataSetNames.map((name) => this.findDataSet(name));
272
+ return this.picks.map((pick) => this.findDataSet(pick));
215
273
  }
216
274
 
217
275
  /** How many data sets Add adds */
218
276
  get pickedCount(): number {
219
- return this.dataSetNames.length;
277
+ return this.picks.length;
220
278
  }
221
279
 
222
- isDataSetPicked(name: string): boolean {
223
- return this.dataSetNames.includes(name);
280
+ /** Whether a data set of an opened definition, by default the one opened last, is picked */
281
+ isDataSetPicked(
282
+ name: string,
283
+ definitionUrn: string | undefined = this.definition?.urn,
284
+ ): boolean {
285
+ return this.picks.some(
286
+ (pick) => pick.definitionUrn === definitionUrn && pick.dataSet === name,
287
+ );
224
288
  }
225
289
 
226
- private findDataSet(name: string | undefined): CubeIngestDataSet | undefined {
227
- return name === undefined
228
- ? undefined
229
- : this.dataSets?.find((each) => each.name === name);
290
+ private findDataSet(
291
+ pick: CubeIngestPick | undefined,
292
+ ): CubeIngestDataSet | undefined {
293
+ return pick
294
+ ? this.dataSetsByDefinition
295
+ .get(pick.definitionUrn)
296
+ ?.find((each) => each.name === pick.dataSet)
297
+ : undefined;
230
298
  }
231
299
 
232
300
  get canConfirm(): boolean {
@@ -236,7 +304,6 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
236
304
  !this.isDescribing &&
237
305
  !this.isAdding &&
238
306
  this.producerDeploymentId !== undefined &&
239
- this.definition !== undefined &&
240
307
  this.pickedDataSets.length > 0 &&
241
308
  this.pickedDataSets.every((each) => each?.isPickable === true) &&
242
309
  this.warehouse.trim() !== ''
@@ -273,33 +340,66 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
273
340
  this.definitionSearch = search;
274
341
  }
275
342
 
276
- /** Picks a definition and reads its data sets */
343
+ /**
344
+ * Opens a definition alone, in place of any opened, and reads its data
345
+ * sets; one already opened among others keeps its data sets and picks
346
+ */
277
347
  selectDefinition(candidate: CubeIngestDefinitionCandidate | undefined): void {
278
- if (candidate?.urn === this.definition?.urn) {
348
+ if (
349
+ this.definitions.length <= 1 &&
350
+ candidate?.urn === this.definition?.urn
351
+ ) {
352
+ return;
353
+ }
354
+ if (candidate && this.isDefinitionOpened(candidate)) {
355
+ this.closeDefinitions((each) => each.urn !== candidate.urn);
279
356
  return;
280
357
  }
281
358
  this.resetDefinition();
282
- this.definition = candidate;
283
359
  if (candidate) {
284
- flowResult(this.describeDefinition(candidate)).catch(
285
- this.editorState.host.applicationStore.alertUnhandledError,
286
- );
360
+ this.openDefinition(candidate);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Opens a definition beside those opened, to add data sets of several at
366
+ * once, and reads its data sets; or closes it, its picks dropped
367
+ */
368
+ toggleDefinition(candidate: CubeIngestDefinitionCandidate): void {
369
+ if (this.isDefinitionOpened(candidate)) {
370
+ this.closeDefinitions((each) => each.urn === candidate.urn);
371
+ } else {
372
+ this.openDefinition(candidate);
287
373
  }
288
374
  }
289
375
 
290
376
  /** Picks a data set that can be added, alone, in place of any picked */
291
- selectDataSet(name: string): void {
292
- if (this.findDataSet(name)?.isPickable) {
293
- this.dataSetNames = [name];
377
+ selectDataSet(
378
+ name: string,
379
+ definitionUrn: string | undefined = this.definition?.urn,
380
+ ): void {
381
+ if (
382
+ definitionUrn !== undefined &&
383
+ this.findDataSet({ definitionUrn, dataSet: name })?.isPickable
384
+ ) {
385
+ this.picks = [{ definitionUrn, dataSet: name }];
294
386
  }
295
387
  }
296
388
 
297
389
  /** Adds a data set that can be added to the picked ones, or takes it out */
298
- toggleDataSet(name: string): void {
299
- if (this.isDataSetPicked(name)) {
300
- this.dataSetNames = this.dataSetNames.filter((each) => each !== name);
301
- } else if (this.findDataSet(name)?.isPickable) {
302
- this.dataSetNames = [...this.dataSetNames, name];
390
+ toggleDataSet(
391
+ name: string,
392
+ definitionUrn: string | undefined = this.definition?.urn,
393
+ ): void {
394
+ if (definitionUrn === undefined) {
395
+ return;
396
+ }
397
+ if (this.isDataSetPicked(name, definitionUrn)) {
398
+ this.picks = this.picks.filter(
399
+ (pick) => pick.definitionUrn !== definitionUrn || pick.dataSet !== name,
400
+ );
401
+ } else if (this.findDataSet({ definitionUrn, dataSet: name })?.isPickable) {
402
+ this.picks = [...this.picks, { definitionUrn, dataSet: name }];
303
403
  }
304
404
  }
305
405
 
@@ -321,10 +421,16 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
321
421
  !this.definitionList
322
422
  ) {
323
423
  flowResult(this.listDefinitions()).catch(alertUnhandledError);
324
- } else if (this.definition && !this.dataSets) {
325
- flowResult(this.describeDefinition(this.definition)).catch(
326
- alertUnhandledError,
327
- );
424
+ } else {
425
+ this.definitions
426
+ .filter(
427
+ (each) =>
428
+ !this.dataSetsByDefinition.has(each.urn) &&
429
+ !this.describing.has(each.urn),
430
+ )
431
+ .forEach((each) => {
432
+ flowResult(this.describeDefinition(each)).catch(alertUnhandledError);
433
+ });
328
434
  }
329
435
  }
330
436
 
@@ -374,10 +480,8 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
374
480
  this.isListingDefinitions = false;
375
481
  this.isAdding = false;
376
482
  // a definition whose data sets haven't arrived would show none
377
- if (this.definition && !this.dataSets) {
378
- this.resetDefinition();
379
- }
380
- this.isDescribing = false;
483
+ this.describing = new Map();
484
+ this.closeDefinitions((each) => !this.dataSetsByDefinition.has(each.urn));
381
485
  // read again on reopening
382
486
  if (!this.environment || !this.producers) {
383
487
  this.loadedEnvironmentType = undefined;
@@ -463,7 +567,7 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
463
567
  }
464
568
  }
465
569
 
466
- /** Reads the definition's data sets */
570
+ /** Reads an opened definition's data sets */
467
571
  *describeDefinition(
468
572
  candidate: CubeIngestDefinitionCandidate,
469
573
  ): GeneratorFn<void> {
@@ -472,29 +576,45 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
472
576
  return;
473
577
  }
474
578
  const request = ++this.describeRequest;
475
- this.isDescribing = true;
579
+ this.describing = new Map([...this.describing, [candidate.urn, request]]);
476
580
  this.error = undefined;
581
+ // an answer counts while the definition is open and this is its last read
582
+ const isCurrent = (): boolean =>
583
+ this.describing.get(candidate.urn) === request;
477
584
  try {
478
585
  const dataSets = (yield catalog.describe(
479
586
  candidate.urn,
480
587
  this.environmentType,
481
588
  )) as readonly CubeIngestDataSet[];
482
- if (request === this.describeRequest) {
483
- this.dataSets = dataSets;
484
- // the only data set that can be added is picked
589
+ if (isCurrent()) {
590
+ this.dataSetsByDefinition = new Map([
591
+ ...this.dataSetsByDefinition,
592
+ [candidate.urn, dataSets],
593
+ ]);
594
+ // the only data set of it that can be added is picked
485
595
  const [onlyPickable, ...otherPickable] = dataSets.filter(
486
596
  (each) => each.isPickable,
487
597
  );
488
- this.dataSetNames =
489
- onlyPickable && !otherPickable.length ? [onlyPickable.name] : [];
598
+ if (
599
+ onlyPickable &&
600
+ !otherPickable.length &&
601
+ !this.isDataSetPicked(onlyPickable.name, candidate.urn)
602
+ ) {
603
+ this.picks = [
604
+ ...this.picks,
605
+ { definitionUrn: candidate.urn, dataSet: onlyPickable.name },
606
+ ];
607
+ }
490
608
  }
491
609
  } catch (error) {
492
- if (request === this.describeRequest) {
610
+ if (isCurrent()) {
493
611
  this.error = toError(error);
494
612
  }
495
613
  } finally {
496
- if (request === this.describeRequest) {
497
- this.isDescribing = false;
614
+ if (isCurrent()) {
615
+ this.describing = new Map(
616
+ [...this.describing].filter(([urn]) => urn !== candidate.urn),
617
+ );
498
618
  }
499
619
  }
500
620
  }
@@ -510,8 +630,13 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
510
630
  return false;
511
631
  }
512
632
  const { editorState } = this;
513
- const definition = this.definition as CubeIngestDefinitionCandidate;
514
- const picked = this.pickedDataSets as readonly CubeIngestDataSet[];
633
+ // each picked data set with its definition, as picked
634
+ const picked = this.picks.map((pick) => ({
635
+ definition: this.definitions.find(
636
+ (each) => each.urn === pick.definitionUrn,
637
+ ) as CubeIngestDefinitionCandidate,
638
+ dataSet: this.findDataSet(pick) as CubeIngestDataSet,
639
+ }));
515
640
  const producerDeploymentId = this.producerDeploymentId as string;
516
641
  const warehouse = this.warehouse.trim();
517
642
  const request = ++this.confirmRequest;
@@ -529,7 +654,7 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
529
654
  IngestDatasetSource.TYPE,
530
655
  picked.length,
531
656
  );
532
- const nodes = picked.map((dataSet, index) =>
657
+ const nodes = picked.map(({ definition, dataSet }, index) =>
533
658
  INGEST_DATASET_SOURCE_DEFINITION.resolve(
534
659
  INGEST_DATASET_SOURCE_DEFINITION.fromCoordinates(
535
660
  ids[index] as string,
@@ -580,8 +705,8 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
580
705
  if (!settings) {
581
706
  editorState.dataProductRuntime.remember(warehouse);
582
707
  }
583
- // the definition stays open, to add others of its data sets
584
- this.dataSetNames = [];
708
+ // the definitions stay open, to add others of their data sets
709
+ this.picks = [];
585
710
  return true;
586
711
  } catch (error) {
587
712
  if (request === this.confirmRequest) {
@@ -616,10 +741,36 @@ export class CubeIngestTabState implements CubeSourcePickerTab {
616
741
  }
617
742
 
618
743
  private resetDefinition(): void {
619
- this.describeRequest++;
620
- this.isDescribing = false;
621
- this.definition = undefined;
622
- this.dataSets = undefined;
623
- this.dataSetNames = [];
744
+ this.describing = new Map();
745
+ this.definitions = [];
746
+ this.dataSetsByDefinition = new Map();
747
+ this.picks = [];
748
+ }
749
+
750
+ private openDefinition(candidate: CubeIngestDefinitionCandidate): void {
751
+ this.definitions = [...this.definitions, candidate];
752
+ flowResult(this.describeDefinition(candidate)).catch(
753
+ this.editorState.host.applicationStore.alertUnhandledError,
754
+ );
755
+ }
756
+
757
+ /** Closes the opened definitions given, their data sets, reads and picks dropped */
758
+ private closeDefinitions(
759
+ closes: (candidate: CubeIngestDefinitionCandidate) => boolean,
760
+ ): void {
761
+ const closed = new Set(
762
+ this.definitions.filter(closes).map((each) => each.urn),
763
+ );
764
+ if (!closed.size) {
765
+ return;
766
+ }
767
+ this.definitions = this.definitions.filter((each) => !closed.has(each.urn));
768
+ this.dataSetsByDefinition = new Map(
769
+ [...this.dataSetsByDefinition].filter(([urn]) => !closed.has(urn)),
770
+ );
771
+ this.describing = new Map(
772
+ [...this.describing].filter(([urn]) => !closed.has(urn)),
773
+ );
774
+ this.picks = this.picks.filter((pick) => !closed.has(pick.definitionUrn));
624
775
  }
625
776
  }