@finos/legend-data-cube 0.1.12 → 0.1.13

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 (44) hide show
  1. package/lib/components/DataCubePlaceholder.d.ts.map +1 -1
  2. package/lib/components/DataCubePlaceholder.js +2 -1
  3. package/lib/components/DataCubePlaceholder.js.map +1 -1
  4. package/lib/components/core/DataCubePureCodeEditorUtils.d.ts +2 -1
  5. package/lib/components/core/DataCubePureCodeEditorUtils.d.ts.map +1 -1
  6. package/lib/components/core/DataCubePureCodeEditorUtils.js.map +1 -1
  7. package/lib/components/view/extend/DataCubeCodeEditor.d.ts +22 -0
  8. package/lib/components/view/extend/DataCubeCodeEditor.d.ts.map +1 -0
  9. package/lib/components/view/extend/DataCubeCodeEditor.js +114 -0
  10. package/lib/components/view/extend/DataCubeCodeEditor.js.map +1 -0
  11. package/lib/components/view/extend/DataCubeCodeEditorState.d.ts +43 -0
  12. package/lib/components/view/extend/DataCubeCodeEditorState.d.ts.map +1 -0
  13. package/lib/components/view/extend/DataCubeCodeEditorState.js +37 -0
  14. package/lib/components/view/extend/DataCubeCodeEditorState.js.map +1 -0
  15. package/lib/components/view/extend/DataCubeColumnEditor.d.ts.map +1 -1
  16. package/lib/components/view/extend/DataCubeColumnEditor.js +5 -84
  17. package/lib/components/view/extend/DataCubeColumnEditor.js.map +1 -1
  18. package/lib/index.css +1 -1
  19. package/lib/index.d.ts +3 -0
  20. package/lib/index.d.ts.map +1 -1
  21. package/lib/index.js +3 -0
  22. package/lib/index.js.map +1 -1
  23. package/lib/package.json +1 -1
  24. package/lib/stores/core/DataCubeEngine.d.ts +1 -1
  25. package/lib/stores/core/DataCubeEngine.d.ts.map +1 -1
  26. package/lib/stores/core/model/AdhocQueryDataCubeSource.d.ts +2 -0
  27. package/lib/stores/core/model/AdhocQueryDataCubeSource.d.ts.map +1 -1
  28. package/lib/stores/core/model/AdhocQueryDataCubeSource.js +3 -0
  29. package/lib/stores/core/model/AdhocQueryDataCubeSource.js.map +1 -1
  30. package/lib/stores/view/extend/DataCubeColumnEditorState.d.ts +7 -14
  31. package/lib/stores/view/extend/DataCubeColumnEditorState.d.ts.map +1 -1
  32. package/lib/stores/view/extend/DataCubeColumnEditorState.js +14 -22
  33. package/lib/stores/view/extend/DataCubeColumnEditorState.js.map +1 -1
  34. package/package.json +3 -3
  35. package/src/components/DataCubePlaceholder.tsx +2 -0
  36. package/src/components/core/DataCubePureCodeEditorUtils.tsx +2 -1
  37. package/src/components/view/extend/DataCubeCodeEditor.tsx +175 -0
  38. package/src/components/view/extend/DataCubeCodeEditorState.tsx +72 -0
  39. package/src/components/view/extend/DataCubeColumnEditor.tsx +5 -133
  40. package/src/index.tsx +3 -0
  41. package/src/stores/core/DataCubeEngine.tsx +1 -1
  42. package/src/stores/core/model/AdhocQueryDataCubeSource.ts +3 -0
  43. package/src/stores/view/extend/DataCubeColumnEditorState.tsx +16 -26
  44. package/tsconfig.json +2 -0
@@ -19,22 +19,6 @@ import {
19
19
  DataCubeExistingColumnEditorState,
20
20
  type DataCubeColumnBaseEditorState,
21
21
  } from '../../../stores/view/extend/DataCubeColumnEditorState.js';
22
- import {
23
- editor as monacoEditorAPI,
24
- languages as monacoLanguagesAPI,
25
- type IDisposable,
26
- } from 'monaco-editor';
27
- import { useEffect, useMemo, useRef, useState } from 'react';
28
- import {
29
- CODE_EDITOR_THEME,
30
- PURE_CODE_EDITOR_WORD_SEPARATORS,
31
- CODE_EDITOR_LANGUAGE,
32
- getBaseCodeEditorOptions,
33
- } from '@finos/legend-code-editor';
34
- import {
35
- getCodeSuggestions,
36
- MONACO_EDITOR_OVERFLOW_WIDGETS_ROOT_ID,
37
- } from '../../core/DataCubePureCodeEditorUtils.js';
38
22
  import {
39
23
  FormButton,
40
24
  FormDocumentation,
@@ -43,14 +27,16 @@ import {
43
27
  FormDropdownMenuTrigger,
44
28
  FormTextInput,
45
29
  } from '../../core/DataCubeFormUtils.js';
46
- import { debounce, isNonNullable } from '@finos/legend-shared';
47
- import { cn, DataCubeIcon, useDropdownMenu } from '@finos/legend-art';
30
+ import { DataCubeIcon, useDropdownMenu } from '@finos/legend-art';
48
31
  import {
49
32
  DataCubeColumnDataType,
50
33
  DataCubeColumnKind,
51
34
  } from '../../../stores/core/DataCubeQueryEngine.js';
52
35
  import { DataCubeDocumentationKey } from '../../../__lib__/DataCubeDocumentation.js';
53
36
  import { useDataCube } from '../../DataCubeProvider.js';
37
+ import { useMemo, useRef } from 'react';
38
+ import { debounce } from '@finos/legend-shared';
39
+ import { DataCubeCodeEditor } from './DataCubeCodeEditor.js';
54
40
 
55
41
  enum DataCubeExtendedColumnKind {
56
42
  LEAF_LEVEL_MEASURE = 'Leaf Level Measure',
@@ -84,11 +70,6 @@ export const DataCubeColumnCreator = observer(
84
70
  typeDropPropsOpen,
85
71
  ] = useDropdownMenu();
86
72
 
87
- const suggestionsProvider = useRef<IDisposable | undefined>(undefined);
88
- const editorRef = useRef<HTMLDivElement>(null);
89
- const [editor, setEditor] = useState<
90
- monacoEditorAPI.IStandaloneCodeEditor | undefined
91
- >();
92
73
  const debouncedCheckReturnType = useMemo(
93
74
  () =>
94
75
  debounce((): void => {
@@ -99,103 +80,6 @@ export const DataCubeColumnCreator = observer(
99
80
  [state, dataCube],
100
81
  );
101
82
 
102
- useEffect(() => {
103
- if (!editor && editorRef.current) {
104
- const element = editorRef.current;
105
- const widgetRoot = document.getElementById(
106
- MONACO_EDITOR_OVERFLOW_WIDGETS_ROOT_ID,
107
- );
108
- const newEditor = monacoEditorAPI.create(element, {
109
- ...getBaseCodeEditorOptions(),
110
- fontSize: 12,
111
- language: CODE_EDITOR_LANGUAGE.PURE,
112
- theme: CODE_EDITOR_THEME.GITHUB_LIGHT,
113
- wordSeparators: PURE_CODE_EDITOR_WORD_SEPARATORS,
114
- // Make sure the widgets (tooltips, menus) are not clipped by the container bounds
115
- // and fix the problem where widgets are rendered with position=fixed not working well with parent
116
- // containers (i.e. the draggable window) which has been transformed
117
- // See https://dev.to/salilnaik/the-uncanny-relationship-between-position-fixed-and-transform-property-32f6
118
- // See https://github.com/microsoft/monaco-editor/issues/2793#issuecomment-999337740
119
- fixedOverflowWidgets: true,
120
- ...(isNonNullable(widgetRoot)
121
- ? { overflowWidgetsDomNode: widgetRoot }
122
- : {}),
123
- });
124
-
125
- // NOTE: since engine suggestions are computed based on the current text content
126
- // we put it in this block to simplify the flow and really to "bend" monaco-editor
127
- // suggestion provider to our needs. But we also need to make sure this suggestion
128
- // provider is scoped to the current editor only by checking the editor model
129
- suggestionsProvider.current?.dispose();
130
- suggestionsProvider.current =
131
- monacoLanguagesAPI.registerCompletionItemProvider(
132
- CODE_EDITOR_LANGUAGE.PURE,
133
- {
134
- // NOTE: this is a hack to fetch suggestions from engine for every keystroke
135
- triggerCharacters: [...PURE_CODE_EDITOR_WORD_SEPARATORS, '$'],
136
- provideCompletionItems: async (model, position, context) => {
137
- let suggestions: monacoLanguagesAPI.CompletionItem[] = [];
138
-
139
- if (model.uri === state.editorModelUri) {
140
- suggestions = suggestions.concat(
141
- await getCodeSuggestions(
142
- position,
143
- model,
144
- state.codePrefix,
145
- view.engine,
146
- view.source,
147
- () => state.buildExtendBaseQuery(),
148
- ),
149
- );
150
- }
151
-
152
- return { suggestions };
153
- },
154
- },
155
- );
156
-
157
- newEditor.setModel(state.editorModel);
158
- newEditor.onDidChangeModelContent(() => {
159
- const currentVal = newEditor.getValue();
160
- if (currentVal !== state.code) {
161
- state.code = currentVal;
162
- // clear error on content change/typing
163
- state.clearError();
164
- state.setReturnType(undefined);
165
- debouncedCheckReturnType.cancel();
166
- debouncedCheckReturnType();
167
- }
168
- });
169
- // focus on the editor initially and set the cursor to the end
170
- // since we're trying to create a new column
171
- newEditor.focus();
172
- newEditor.setPosition({
173
- lineNumber: 1,
174
- column: state.code.length + 1,
175
- });
176
- state.setEditor(newEditor);
177
- setEditor(newEditor);
178
- }
179
- }, [state, editor, debouncedCheckReturnType, view]);
180
-
181
- // clean up
182
- useEffect(
183
- () => (): void => {
184
- if (editor) {
185
- editor.dispose();
186
-
187
- suggestionsProvider.current?.dispose();
188
- }
189
- },
190
- [editor],
191
- );
192
-
193
- useEffect(() => {
194
- state.editor?.updateOptions({
195
- readOnly: state.finalizationState.isInProgress,
196
- });
197
- }, [state, state.finalizationState.isInProgress]);
198
-
199
83
  return (
200
84
  <>
201
85
  <div className="h-[calc(100%_-_40px)] w-full px-2 pt-2">
@@ -329,19 +213,7 @@ export const DataCubeColumnCreator = observer(
329
213
  </div>
330
214
  </div>
331
215
  <div className="h-[calc(100%_-_96px)] w-full p-2 pt-1">
332
- <div
333
- className={cn(
334
- 'relative h-full w-full border border-neutral-200',
335
- {
336
- 'border-red-500': Boolean(state.codeError),
337
- },
338
- )}
339
- >
340
- <div
341
- className="absolute left-0 top-0 h-full w-full overflow-hidden"
342
- ref={editorRef}
343
- />
344
- </div>
216
+ <DataCubeCodeEditor state={state} />
345
217
  </div>
346
218
  </div>
347
219
  </div>
package/src/index.tsx CHANGED
@@ -45,8 +45,11 @@ export {
45
45
  export * from './stores/services/DataCubeTaskService.js';
46
46
  export * from './stores/services/DataCubeLogService.js';
47
47
  export * from './stores/services/DataCubeAlertService.js';
48
+ export * from './components/view/extend/DataCubeCodeEditor.js';
49
+ export * from './components/view/extend/DataCubeCodeEditorState.js';
48
50
  export * from './components/core/DataCubeAlert.js';
49
51
  export * from './components/core/DataCubeLayout.js';
52
+ export { INTERNAL__MonacoEditorWidgetsRoot } from './components/core/DataCubePureCodeEditorUtils.js';
50
53
 
51
54
  export { useDataCube } from './components/DataCubeProvider.js';
52
55
  export { type DataCubeAPI } from './stores/DataCubeAPI.js';
@@ -253,7 +253,7 @@ export abstract class DataCubeEngine {
253
253
  abstract getQueryTypeahead(
254
254
  code: string,
255
255
  baseQuery: V1_Lambda,
256
- source: DataCubeSource,
256
+ context: DataCubeSource | PlainObject,
257
257
  ): Promise<CompletionItem[]>;
258
258
 
259
259
  abstract getQueryRelationReturnType(
@@ -25,6 +25,7 @@ import type { V1_PureModelContext } from '@finos/legend-graph';
25
25
 
26
26
  export class AdhocQueryDataCubeSource extends DataCubeSource {
27
27
  runtime!: string;
28
+ mapping?: string;
28
29
  model!: PlainObject<V1_PureModelContext>;
29
30
  }
30
31
 
@@ -40,6 +41,7 @@ export const ADHOC_FUNCTION_DATA_CUBE_SOURCE_TYPE = 'userDefinedFunction';
40
41
  export class RawAdhocQueryDataCubeSource {
41
42
  query!: string;
42
43
  runtime!: string;
44
+ mapping?: string;
43
45
  model!: PlainObject<V1_PureModelContext>;
44
46
 
45
47
  static readonly serialization = new SerializationFactory(
@@ -48,6 +50,7 @@ export class RawAdhocQueryDataCubeSource {
48
50
  model: raw(),
49
51
  query: primitive(),
50
52
  runtime: primitive(),
53
+ mapping: optional(primitive()),
51
54
  }),
52
55
  );
53
56
  }
@@ -35,7 +35,6 @@ import {
35
35
  isPrimitiveType,
36
36
  } from '../../core/DataCubeQueryEngine.js';
37
37
  import {
38
- clearMarkers,
39
38
  CODE_EDITOR_LANGUAGE,
40
39
  setErrorMarkers,
41
40
  } from '@finos/legend-code-editor';
@@ -49,9 +48,11 @@ import type { DataCubeColumnConfiguration } from '../../core/model/DataCubeConfi
49
48
  import type { DataCubeSnapshotExtendedColumn } from '../../core/DataCubeSnapshot.js';
50
49
  import { _lambda } from '../../core/DataCubeQueryBuilderUtils.js';
51
50
  import { _findCol } from '../../core/model/DataCubeColumn.js';
51
+ import { DataCubeCodeEditorState } from '../../../components/view/extend/DataCubeCodeEditorState.js';
52
+ import type { DataCubeSource } from '../../core/model/DataCubeSource.js';
52
53
 
53
- export abstract class DataCubeColumnBaseEditorState {
54
- protected readonly uuid = uuid();
54
+ export abstract class DataCubeColumnBaseEditorState extends DataCubeCodeEditorState {
55
+ protected override readonly uuid = uuid();
55
56
  protected readonly _manager: DataCubeExtendManagerState;
56
57
  readonly view: DataCubeViewState;
57
58
 
@@ -60,22 +61,16 @@ export abstract class DataCubeColumnBaseEditorState {
60
61
  private readonly _name = `col_${this.uuid.replaceAll('-', '_')}`;
61
62
  readonly display: DisplayState;
62
63
  readonly validationState = ActionState.create();
63
- readonly finalizationState = ActionState.create();
64
64
 
65
65
  name: string;
66
66
  expectedType: string;
67
67
  isGroupLevel: boolean;
68
68
  columnKind?: DataCubeColumnKind | undefined;
69
69
 
70
- code = '';
71
- codePrefix: string;
72
70
  codeSuffix: string;
73
71
 
74
- editor?: monacoEditorAPI.IStandaloneCodeEditor | undefined;
75
- readonly editorModel: monacoEditorAPI.ITextModel;
76
- readonly editorModelUri: Uri;
77
- codeError?: EngineError | undefined;
78
- returnType?: string | undefined;
72
+ override model: DataCubeSource;
73
+ queryLambda: () => V1_Lambda;
79
74
 
80
75
  constructor(
81
76
  manager: DataCubeExtendManagerState,
@@ -84,6 +79,7 @@ export abstract class DataCubeColumnBaseEditorState {
84
79
  isGroupLevel: boolean,
85
80
  columnKind: DataCubeColumnKind | undefined,
86
81
  ) {
82
+ super(manager.view.engine);
87
83
  makeObservable(this, {
88
84
  name: observable,
89
85
  setName: action,
@@ -110,6 +106,8 @@ export abstract class DataCubeColumnBaseEditorState {
110
106
 
111
107
  this._manager = manager;
112
108
  this.view = manager.view;
109
+ this.model = manager.view.source;
110
+ this.engine = this.view.engine;
113
111
  this.display = this.newDisplay(this);
114
112
 
115
113
  this.name = name;
@@ -126,8 +124,13 @@ export abstract class DataCubeColumnBaseEditorState {
126
124
  CODE_EDITOR_LANGUAGE.PURE,
127
125
  this.editorModelUri,
128
126
  );
127
+ this.queryLambda = this.buildExtendBaseQuery;
129
128
  }
130
129
 
130
+ alertHandler = (error: Error): void => {
131
+ this.view.dataCube.alertService.alertUnhandledError(error);
132
+ };
133
+
131
134
  abstract getInitialCode(): Promise<string>;
132
135
 
133
136
  async initialize() {
@@ -166,14 +169,6 @@ export abstract class DataCubeColumnBaseEditorState {
166
169
  this.columnKind = columnKind;
167
170
  }
168
171
 
169
- setEditor(editor: monacoEditorAPI.IStandaloneCodeEditor) {
170
- this.editor = editor;
171
- }
172
-
173
- setReturnType(value: string | undefined) {
174
- this.returnType = value;
175
- }
176
-
177
172
  showError(error: EngineError) {
178
173
  this.codeError = error;
179
174
  if (error.sourceInformation) {
@@ -193,12 +188,7 @@ export abstract class DataCubeColumnBaseEditorState {
193
188
  }
194
189
  }
195
190
 
196
- clearError() {
197
- this.codeError = undefined;
198
- clearMarkers(this.uuid);
199
- }
200
-
201
- buildExtendBaseQuery() {
191
+ buildExtendBaseQuery = () => {
202
192
  const currentSnapshot = guaranteeNonNullable(
203
193
  this._manager.getLatestSnapshot(),
204
194
  );
@@ -221,7 +211,7 @@ export abstract class DataCubeColumnBaseEditorState {
221
211
  }),
222
212
  ],
223
213
  );
224
- }
214
+ };
225
215
 
226
216
  async getReturnType() {
227
217
  this.validationState.inProgress();
package/tsconfig.json CHANGED
@@ -121,6 +121,8 @@
121
121
  "./src/components/view/editor/DataCubeEditorHorizontalPivotsPanel.tsx",
122
122
  "./src/components/view/editor/DataCubeEditorSortsPanel.tsx",
123
123
  "./src/components/view/editor/DataCubeEditorVerticalPivotsPanel.tsx",
124
+ "./src/components/view/extend/DataCubeCodeEditor.tsx",
125
+ "./src/components/view/extend/DataCubeCodeEditorState.tsx",
124
126
  "./src/components/view/extend/DataCubeColumnEditor.tsx",
125
127
  "./src/components/view/filter/DataCubeFilterEditor.tsx",
126
128
  "./src/components/view/grid/DataCubeGrid.tsx",