@finos/legend-lego 2.0.151 → 2.0.153
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/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/sql-playground/SQLPlaygroundEditor.d.ts +26 -0
- package/lib/sql-playground/SQLPlaygroundEditor.d.ts.map +1 -0
- package/lib/sql-playground/SQLPlaygroundEditor.js +122 -0
- package/lib/sql-playground/SQLPlaygroundEditor.js.map +1 -0
- package/lib/sql-playground/SQLPlaygroundGrid.d.ts +24 -0
- package/lib/sql-playground/SQLPlaygroundGrid.d.ts.map +1 -0
- package/lib/sql-playground/SQLPlaygroundGrid.js +143 -0
- package/lib/sql-playground/SQLPlaygroundGrid.js.map +1 -0
- package/lib/sql-playground/SQLPlaygroundPanel.d.ts +20 -0
- package/lib/sql-playground/SQLPlaygroundPanel.d.ts.map +1 -0
- package/lib/sql-playground/SQLPlaygroundPanel.js +39 -0
- package/lib/sql-playground/SQLPlaygroundPanel.js.map +1 -0
- package/lib/sql-playground/index.d.ts +20 -0
- package/lib/sql-playground/index.d.ts.map +1 -0
- package/lib/sql-playground/index.js +20 -0
- package/lib/sql-playground/index.js.map +1 -0
- package/lib/sql-playground/store/AbstractSQLPlaygroundState.d.ts +47 -0
- package/lib/sql-playground/store/AbstractSQLPlaygroundState.d.ts.map +1 -0
- package/lib/sql-playground/store/AbstractSQLPlaygroundState.js +122 -0
- package/lib/sql-playground/store/AbstractSQLPlaygroundState.js.map +1 -0
- package/package.json +6 -5
- package/src/sql-playground/SQLPlaygroundEditor.tsx +197 -0
- package/src/sql-playground/SQLPlaygroundGrid.tsx +245 -0
- package/src/sql-playground/SQLPlaygroundPanel.tsx +150 -0
- package/src/sql-playground/index.ts +20 -0
- package/src/sql-playground/store/AbstractSQLPlaygroundState.ts +152 -0
- package/tsconfig.json +6 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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
|
+
import { ActionState, type GeneratorFn } from '@finos/legend-shared';
|
|
17
|
+
import * as monaco from 'monaco-editor';
|
|
18
|
+
import type { CommandRegistrar } from '@finos/legend-application';
|
|
19
|
+
export type SQLPlaygroundTheme = 'light' | 'dark';
|
|
20
|
+
export interface SQL_ExecutionResult {
|
|
21
|
+
value: string;
|
|
22
|
+
sqlDuration: number;
|
|
23
|
+
}
|
|
24
|
+
export declare abstract class AbstractSQLPlaygroundState implements CommandRegistrar {
|
|
25
|
+
theme: SQLPlaygroundTheme;
|
|
26
|
+
sqlText: string;
|
|
27
|
+
executeRawSQLState: ActionState;
|
|
28
|
+
sqlExecutionResult?: SQL_ExecutionResult | undefined;
|
|
29
|
+
sqlEditorViewState: monaco.editor.ICodeEditorViewState | undefined;
|
|
30
|
+
sqlEditorTextModel: monaco.editor.ITextModel;
|
|
31
|
+
sqlEditor?: monaco.editor.IStandaloneCodeEditor | undefined;
|
|
32
|
+
isLocalModeEnabled: boolean;
|
|
33
|
+
constructor();
|
|
34
|
+
abstract executeRawSQL(): GeneratorFn<void>;
|
|
35
|
+
abstract registerCommands(): void;
|
|
36
|
+
abstract deregisterCommands(): void;
|
|
37
|
+
getCodeCompletionSuggestions(): string[];
|
|
38
|
+
stopExecuteSQL(): void;
|
|
39
|
+
setSQLText(val: string): void;
|
|
40
|
+
setTheme(val: SQLPlaygroundTheme): void;
|
|
41
|
+
setSQLEditorViewState(state: monaco.editor.ICodeEditorViewState | undefined): void;
|
|
42
|
+
setSQLEditor(val: monaco.editor.IStandaloneCodeEditor | undefined): void;
|
|
43
|
+
toggleIsLocalModeEnabled(): void;
|
|
44
|
+
get isExecuting(): boolean;
|
|
45
|
+
get hasResult(): boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=AbstractSQLPlaygroundState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractSQLPlaygroundState.d.ts","sourceRoot":"","sources":["../../../src/sql-playground/store/AbstractSQLPlaygroundState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAOlE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,CAAC;AAClD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAuCD,8BAAsB,0BAA2B,YAAW,gBAAgB;IAC1E,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,SAAM;IACb,kBAAkB,EAAE,WAAW,CAAC;IAChC,kBAAkB,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,GAAG,SAAS,CAAC;IACnE,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,GAAG,SAAS,CAAC;IAC5D,kBAAkB,EAAE,OAAO,CAAC;;IA0B5B,QAAQ,CAAC,aAAa,IAAI,WAAW,CAAC,IAAI,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,IAAI,IAAI;IACjC,QAAQ,CAAC,kBAAkB,IAAI,IAAI;IAEnC,4BAA4B,IAAI,MAAM,EAAE;IAIxC,cAAc,IAAI,IAAI;IAItB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,QAAQ,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAIvC,qBAAqB,CACnB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,GAAG,SAAS,GACpD,IAAI;IAIP,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,GAAG,SAAS,GAAG,IAAI;IAWxE,wBAAwB,IAAI,IAAI;IAKhC,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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
|
+
import { ActionState } from '@finos/legend-shared';
|
|
17
|
+
import * as monaco from 'monaco-editor';
|
|
18
|
+
import { CODE_EDITOR_LANGUAGE, moveCursorToPosition, } from '@finos/legend-code-editor';
|
|
19
|
+
import { action, makeObservable, observable } from 'mobx';
|
|
20
|
+
const SQL_KEYWORDS = [
|
|
21
|
+
'AND',
|
|
22
|
+
'AS',
|
|
23
|
+
'ASC',
|
|
24
|
+
'BETWEEN',
|
|
25
|
+
'DESC',
|
|
26
|
+
'DISTINCT',
|
|
27
|
+
'EXEC',
|
|
28
|
+
'EXISTS',
|
|
29
|
+
'FROM',
|
|
30
|
+
'FULL OUTER JOIN',
|
|
31
|
+
'GROUP BY',
|
|
32
|
+
'HAVING',
|
|
33
|
+
'IN',
|
|
34
|
+
'INNER JOIN',
|
|
35
|
+
'IS NULL',
|
|
36
|
+
'IS NOT NULL',
|
|
37
|
+
'JOIN',
|
|
38
|
+
'LEFT JOIN',
|
|
39
|
+
'LIKE',
|
|
40
|
+
'LIMIT',
|
|
41
|
+
'NOT',
|
|
42
|
+
'NOT NULL',
|
|
43
|
+
'OR',
|
|
44
|
+
'ORDER BY',
|
|
45
|
+
'OUTER JOIN',
|
|
46
|
+
'RIGHT JOIN',
|
|
47
|
+
'SELECT',
|
|
48
|
+
'SELECT DISTINCT',
|
|
49
|
+
'SELECT INTO',
|
|
50
|
+
'SELECT TOP',
|
|
51
|
+
'TOP',
|
|
52
|
+
'UNION',
|
|
53
|
+
'UNION ALL',
|
|
54
|
+
'UNIQUE',
|
|
55
|
+
'WHERE',
|
|
56
|
+
];
|
|
57
|
+
export class AbstractSQLPlaygroundState {
|
|
58
|
+
theme;
|
|
59
|
+
sqlText = '';
|
|
60
|
+
executeRawSQLState;
|
|
61
|
+
sqlExecutionResult;
|
|
62
|
+
sqlEditorViewState;
|
|
63
|
+
sqlEditorTextModel;
|
|
64
|
+
sqlEditor;
|
|
65
|
+
isLocalModeEnabled;
|
|
66
|
+
constructor() {
|
|
67
|
+
this.sqlEditorTextModel = monaco.editor.createModel(this.sqlText, CODE_EDITOR_LANGUAGE.SQL);
|
|
68
|
+
this.isLocalModeEnabled = false;
|
|
69
|
+
this.executeRawSQLState = ActionState.create();
|
|
70
|
+
this.theme = 'light';
|
|
71
|
+
makeObservable(this, {
|
|
72
|
+
sqlExecutionResult: observable,
|
|
73
|
+
isLocalModeEnabled: observable,
|
|
74
|
+
sqlText: observable,
|
|
75
|
+
executeRawSQLState: observable,
|
|
76
|
+
stopExecuteSQL: action,
|
|
77
|
+
setSQLEditor: action,
|
|
78
|
+
setSQLEditorViewState: action,
|
|
79
|
+
setSQLText: action,
|
|
80
|
+
setTheme: action,
|
|
81
|
+
toggleIsLocalModeEnabled: action,
|
|
82
|
+
sqlEditorViewState: observable.ref,
|
|
83
|
+
sqlEditor: observable.ref,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
getCodeCompletionSuggestions() {
|
|
87
|
+
return SQL_KEYWORDS;
|
|
88
|
+
}
|
|
89
|
+
stopExecuteSQL() {
|
|
90
|
+
this.sqlExecutionResult = undefined;
|
|
91
|
+
}
|
|
92
|
+
setSQLText(val) {
|
|
93
|
+
this.sqlText = val;
|
|
94
|
+
}
|
|
95
|
+
setTheme(val) {
|
|
96
|
+
this.theme = val;
|
|
97
|
+
}
|
|
98
|
+
setSQLEditorViewState(state) {
|
|
99
|
+
this.sqlEditorViewState = state;
|
|
100
|
+
}
|
|
101
|
+
setSQLEditor(val) {
|
|
102
|
+
this.sqlEditor = val;
|
|
103
|
+
if (val) {
|
|
104
|
+
const lines = this.sqlText.split('\n');
|
|
105
|
+
moveCursorToPosition(val, {
|
|
106
|
+
lineNumber: lines.length,
|
|
107
|
+
column: lines.at(-1)?.length ?? 0,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
toggleIsLocalModeEnabled() {
|
|
112
|
+
this.isLocalModeEnabled = !this.isLocalModeEnabled;
|
|
113
|
+
this.sqlExecutionResult = undefined;
|
|
114
|
+
}
|
|
115
|
+
get isExecuting() {
|
|
116
|
+
return this.executeRawSQLState.isInProgress;
|
|
117
|
+
}
|
|
118
|
+
get hasResult() {
|
|
119
|
+
return this.sqlExecutionResult !== undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=AbstractSQLPlaygroundState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractSQLPlaygroundState.js","sourceRoot":"","sources":["../../../src/sql-playground/store/AbstractSQLPlaygroundState.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finos/legend-lego",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.153",
|
|
4
4
|
"description": "Legend code editor support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"legend",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
"./application": "./lib/application/index.js",
|
|
23
23
|
"./code-editor": "./lib/code-editor/index.js",
|
|
24
|
+
"./sql-playground": "./lib/sql-playground/index.js",
|
|
24
25
|
"./code-editor/test": "./lib/code-editor/__test__.js",
|
|
25
26
|
"./code-editor/test/MockedMonacoEditor.js": "./lib/code-editor/__test-utils__/MockedMonacoEditor.js",
|
|
26
27
|
"./data-grid": "./lib/data-grid/index.js",
|
|
@@ -47,10 +48,10 @@
|
|
|
47
48
|
"test:watch": "jest --watch"
|
|
48
49
|
},
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@finos/legend-application": "16.0.
|
|
51
|
-
"@finos/legend-art": "7.1.
|
|
52
|
-
"@finos/legend-code-editor": "2.0.
|
|
53
|
-
"@finos/legend-graph": "32.3.
|
|
51
|
+
"@finos/legend-application": "16.0.85",
|
|
52
|
+
"@finos/legend-art": "7.1.135",
|
|
53
|
+
"@finos/legend-code-editor": "2.0.139",
|
|
54
|
+
"@finos/legend-graph": "32.3.19",
|
|
54
55
|
"@finos/legend-shared": "11.0.21",
|
|
55
56
|
"@types/css-font-loading-module": "0.0.14",
|
|
56
57
|
"@types/react": "19.0.10",
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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 { PanelDropZone } from '@finos/legend-art';
|
|
19
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
20
|
+
import { useCommands } from '@finos/legend-application';
|
|
21
|
+
import {
|
|
22
|
+
CODE_EDITOR_LANGUAGE,
|
|
23
|
+
CODE_EDITOR_THEME,
|
|
24
|
+
getBaseCodeEditorOptions,
|
|
25
|
+
} from '@finos/legend-code-editor';
|
|
26
|
+
import {
|
|
27
|
+
editor as monacoEditorAPI,
|
|
28
|
+
languages as monacoLanguagesAPI,
|
|
29
|
+
type IDisposable,
|
|
30
|
+
} from 'monaco-editor';
|
|
31
|
+
import { useDrop } from 'react-dnd';
|
|
32
|
+
import { isString } from '@finos/legend-shared';
|
|
33
|
+
import type { AbstractSQLPlaygroundState } from './store/AbstractSQLPlaygroundState.js';
|
|
34
|
+
|
|
35
|
+
export interface SQLPlaygroundPanelProps {
|
|
36
|
+
playgroundState: AbstractSQLPlaygroundState;
|
|
37
|
+
advancedMode: boolean;
|
|
38
|
+
disableDragDrop?: boolean;
|
|
39
|
+
enableDarkMode?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const toCompletionItems = (
|
|
43
|
+
labels: string[],
|
|
44
|
+
): monacoLanguagesAPI.CompletionItem[] =>
|
|
45
|
+
labels.map(
|
|
46
|
+
(label) =>
|
|
47
|
+
({
|
|
48
|
+
label,
|
|
49
|
+
kind: monacoLanguagesAPI.CompletionItemKind.Keyword,
|
|
50
|
+
insertTextRules:
|
|
51
|
+
monacoLanguagesAPI.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
52
|
+
insertText: `${label} `,
|
|
53
|
+
}) as monacoLanguagesAPI.CompletionItem,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export const PlaygroundSQLCodeEditor = observer(
|
|
57
|
+
(props: SQLPlaygroundPanelProps) => {
|
|
58
|
+
const {
|
|
59
|
+
playgroundState,
|
|
60
|
+
disableDragDrop = false,
|
|
61
|
+
enableDarkMode = false,
|
|
62
|
+
} = props;
|
|
63
|
+
const codeEditorRef = useRef<HTMLDivElement>(null);
|
|
64
|
+
const sqlIdentifierSuggestionProviderDisposer = useRef<
|
|
65
|
+
IDisposable | undefined
|
|
66
|
+
>(undefined);
|
|
67
|
+
const [editor, setEditor] = useState<
|
|
68
|
+
monacoEditorAPI.IStandaloneCodeEditor | undefined
|
|
69
|
+
>();
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (!editor && codeEditorRef.current) {
|
|
72
|
+
const element = codeEditorRef.current;
|
|
73
|
+
playgroundState.setTheme(enableDarkMode ? 'dark' : 'light');
|
|
74
|
+
const newEditor = monacoEditorAPI.create(element, {
|
|
75
|
+
...getBaseCodeEditorOptions(),
|
|
76
|
+
theme:
|
|
77
|
+
playgroundState.theme === 'light'
|
|
78
|
+
? CODE_EDITOR_THEME.GITHUB_LIGHT
|
|
79
|
+
: CODE_EDITOR_THEME.DEFAULT_DARK,
|
|
80
|
+
language: CODE_EDITOR_LANGUAGE.SQL,
|
|
81
|
+
padding: {
|
|
82
|
+
top: 10,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
newEditor.onDidChangeModelContent(() => {
|
|
87
|
+
const currentVal = newEditor.getValue();
|
|
88
|
+
playgroundState.setSQLText(currentVal);
|
|
89
|
+
});
|
|
90
|
+
newEditor.setModel(playgroundState.sqlEditorTextModel);
|
|
91
|
+
if (playgroundState.sqlEditorViewState) {
|
|
92
|
+
newEditor.restoreViewState(playgroundState.sqlEditorViewState);
|
|
93
|
+
}
|
|
94
|
+
newEditor.focus();
|
|
95
|
+
playgroundState.setSQLEditor(newEditor);
|
|
96
|
+
setEditor(newEditor);
|
|
97
|
+
}
|
|
98
|
+
}, [playgroundState, editor, enableDarkMode]);
|
|
99
|
+
useCommands(playgroundState);
|
|
100
|
+
if (editor) {
|
|
101
|
+
sqlIdentifierSuggestionProviderDisposer.current?.dispose();
|
|
102
|
+
sqlIdentifierSuggestionProviderDisposer.current =
|
|
103
|
+
monacoLanguagesAPI.registerCompletionItemProvider(
|
|
104
|
+
CODE_EDITOR_LANGUAGE.SQL,
|
|
105
|
+
{
|
|
106
|
+
triggerCharacters: [],
|
|
107
|
+
provideCompletionItems: async (model, position, context) => {
|
|
108
|
+
let suggestions: monacoLanguagesAPI.CompletionItem[] = [];
|
|
109
|
+
if (
|
|
110
|
+
context.triggerKind ===
|
|
111
|
+
monacoLanguagesAPI.CompletionTriggerKind.Invoke
|
|
112
|
+
) {
|
|
113
|
+
const labels = playgroundState.getCodeCompletionSuggestions();
|
|
114
|
+
suggestions = suggestions.concat(toCompletionItems(labels));
|
|
115
|
+
}
|
|
116
|
+
return { suggestions };
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
useEffect(
|
|
122
|
+
() => (): void => {
|
|
123
|
+
if (editor) {
|
|
124
|
+
playgroundState.setSQLEditorViewState(
|
|
125
|
+
editor.saveViewState() ?? undefined,
|
|
126
|
+
);
|
|
127
|
+
editor.dispose();
|
|
128
|
+
|
|
129
|
+
sqlIdentifierSuggestionProviderDisposer.current?.dispose();
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
[playgroundState, editor],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
type DatabaseNodeDragType = { text: string };
|
|
136
|
+
const DATABASE_NODE_DND_TYPE = 'DATABASE_NODE_DND_TYPE';
|
|
137
|
+
const handleDatabaseNodeDrop = useCallback(
|
|
138
|
+
(item: DatabaseNodeDragType): void => {
|
|
139
|
+
if (isString(item.text)) {
|
|
140
|
+
if (playgroundState.sqlEditor) {
|
|
141
|
+
const currentValue = playgroundState.sqlEditorTextModel.getValue();
|
|
142
|
+
const lines = currentValue.split('\n');
|
|
143
|
+
const position = playgroundState.sqlEditor.getPosition() ?? {
|
|
144
|
+
lineNumber: lines.length,
|
|
145
|
+
column: lines.at(-1)?.length ?? 0,
|
|
146
|
+
};
|
|
147
|
+
playgroundState.sqlEditor.executeEdits('', [
|
|
148
|
+
{
|
|
149
|
+
range: {
|
|
150
|
+
startLineNumber: position.lineNumber,
|
|
151
|
+
startColumn: position.column,
|
|
152
|
+
endLineNumber: position.lineNumber,
|
|
153
|
+
endColumn: position.column,
|
|
154
|
+
},
|
|
155
|
+
text: item.text,
|
|
156
|
+
forceMoveMarkers: true,
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
playgroundState.setSQLText(
|
|
160
|
+
playgroundState.sqlEditorTextModel.getValue(),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
[playgroundState],
|
|
166
|
+
);
|
|
167
|
+
const [{ isDatabaseNodeDragOver }, dropConnector] = useDrop<
|
|
168
|
+
DatabaseNodeDragType,
|
|
169
|
+
void,
|
|
170
|
+
{ isDatabaseNodeDragOver: boolean }
|
|
171
|
+
>(
|
|
172
|
+
() => ({
|
|
173
|
+
accept: DATABASE_NODE_DND_TYPE,
|
|
174
|
+
drop: (item): void => handleDatabaseNodeDrop(item),
|
|
175
|
+
collect: (monitor) => ({
|
|
176
|
+
isDatabaseNodeDragOver: monitor.isOver({ shallow: true }),
|
|
177
|
+
}),
|
|
178
|
+
}),
|
|
179
|
+
[handleDatabaseNodeDrop],
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div className="sql-playground__code-editor">
|
|
184
|
+
<PanelDropZone
|
|
185
|
+
className="sql-playground__code-editor__content"
|
|
186
|
+
isDragOver={isDatabaseNodeDragOver}
|
|
187
|
+
dropTargetConnector={dropConnector}
|
|
188
|
+
disabled={disableDragDrop}
|
|
189
|
+
>
|
|
190
|
+
<div className="code-editor__container">
|
|
191
|
+
<div className="code-editor__body" ref={codeEditorRef} />
|
|
192
|
+
</div>
|
|
193
|
+
</PanelDropZone>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
},
|
|
197
|
+
);
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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 { BlankPanelContent, clsx } from '@finos/legend-art';
|
|
19
|
+
import { useCallback } from 'react';
|
|
20
|
+
import {
|
|
21
|
+
at,
|
|
22
|
+
isString,
|
|
23
|
+
parseCSVString,
|
|
24
|
+
isNonNullable,
|
|
25
|
+
isNumber,
|
|
26
|
+
isValidURL,
|
|
27
|
+
} from '@finos/legend-shared';
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
DataGrid,
|
|
31
|
+
type DataGridCellRendererParams,
|
|
32
|
+
type DataGridColumnDefinition,
|
|
33
|
+
type DataGridDefaultMenuItem,
|
|
34
|
+
type DataGridGetContextMenuItemsParams,
|
|
35
|
+
type DataGridMenuItemDef,
|
|
36
|
+
} from '../data-grid/DataGrid.js';
|
|
37
|
+
|
|
38
|
+
const parseExecutionResultData = (
|
|
39
|
+
data: string,
|
|
40
|
+
): { rowData: Record<string, string>[]; columns: string[] } | undefined => {
|
|
41
|
+
const lines = data.split('\n').filter((line) => line.trim().length);
|
|
42
|
+
if (lines.length) {
|
|
43
|
+
const columns = parseCSVString(at(lines, 0)) ?? [];
|
|
44
|
+
const rowData = lines
|
|
45
|
+
.slice(1)
|
|
46
|
+
.map((item) => {
|
|
47
|
+
const rowItems = parseCSVString(item);
|
|
48
|
+
if (!rowItems) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const row: Record<string, string> = {};
|
|
52
|
+
columns.forEach((column, idx) => {
|
|
53
|
+
row[column] = rowItems[idx] ?? '';
|
|
54
|
+
});
|
|
55
|
+
return row;
|
|
56
|
+
})
|
|
57
|
+
.filter(isNonNullable);
|
|
58
|
+
return { rowData, columns };
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const TDSResultCellRenderer = observer((params: DataGridCellRendererParams) => {
|
|
64
|
+
const cellValue = params.value as string;
|
|
65
|
+
const formattedCellValue = (): string => {
|
|
66
|
+
if (isNumber(cellValue)) {
|
|
67
|
+
return Intl.NumberFormat('en-US', {
|
|
68
|
+
maximumFractionDigits: 4,
|
|
69
|
+
}).format(Number(cellValue));
|
|
70
|
+
}
|
|
71
|
+
return cellValue;
|
|
72
|
+
};
|
|
73
|
+
const cellValueUrlLink =
|
|
74
|
+
isString(cellValue) && isValidURL(cellValue) ? cellValue : undefined;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={clsx('query-builder__result__values__table__cell')}>
|
|
78
|
+
{cellValueUrlLink ? (
|
|
79
|
+
<a href={cellValueUrlLink} target="_blank" rel="noreferrer">
|
|
80
|
+
{cellValueUrlLink}
|
|
81
|
+
</a>
|
|
82
|
+
) : (
|
|
83
|
+
<span>{formattedCellValue()}</span>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
export const PlayGroundSQLExecutionResultGrid = observer(
|
|
90
|
+
(props: {
|
|
91
|
+
result: string;
|
|
92
|
+
useAdvancedGrid?: boolean;
|
|
93
|
+
useLocalMode?: boolean;
|
|
94
|
+
enableDarkMode?: boolean;
|
|
95
|
+
}) => {
|
|
96
|
+
const {
|
|
97
|
+
result,
|
|
98
|
+
useAdvancedGrid,
|
|
99
|
+
useLocalMode,
|
|
100
|
+
enableDarkMode = false,
|
|
101
|
+
} = props;
|
|
102
|
+
const data = parseExecutionResultData(result);
|
|
103
|
+
const darkMode = enableDarkMode;
|
|
104
|
+
|
|
105
|
+
if (!data) {
|
|
106
|
+
return (
|
|
107
|
+
<BlankPanelContent>{`Can't parse result, displaying raw form:\n${result}`}</BlankPanelContent>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (useAdvancedGrid) {
|
|
111
|
+
if (useLocalMode) {
|
|
112
|
+
const localcolDefs = data.columns.map(
|
|
113
|
+
(colName) =>
|
|
114
|
+
({
|
|
115
|
+
minWidth: 50,
|
|
116
|
+
sortable: true,
|
|
117
|
+
resizable: true,
|
|
118
|
+
field: colName,
|
|
119
|
+
flex: 1,
|
|
120
|
+
enablePivot: true,
|
|
121
|
+
enableRowGroup: true,
|
|
122
|
+
enableValue: true,
|
|
123
|
+
allowedAggFuncs: ['count'],
|
|
124
|
+
}) as DataGridColumnDefinition,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div
|
|
129
|
+
className={clsx('sql-playground__result__grid', {
|
|
130
|
+
'ag-theme-balham': !darkMode,
|
|
131
|
+
'ag-theme-balham-dark': darkMode,
|
|
132
|
+
})}
|
|
133
|
+
>
|
|
134
|
+
<DataGrid
|
|
135
|
+
rowData={data.rowData}
|
|
136
|
+
gridOptions={{
|
|
137
|
+
suppressScrollOnNewData: true,
|
|
138
|
+
rowSelection: {
|
|
139
|
+
mode: 'multiRow',
|
|
140
|
+
checkboxes: false,
|
|
141
|
+
headerCheckbox: false,
|
|
142
|
+
},
|
|
143
|
+
pivotPanelShow: 'always',
|
|
144
|
+
rowGroupPanelShow: 'always',
|
|
145
|
+
cellSelection: true,
|
|
146
|
+
}}
|
|
147
|
+
// NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
|
|
148
|
+
// See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
|
|
149
|
+
onRowDataUpdated={(params) => {
|
|
150
|
+
params.api.refreshCells({ force: true });
|
|
151
|
+
}}
|
|
152
|
+
suppressFieldDotNotation={true}
|
|
153
|
+
suppressContextMenu={false}
|
|
154
|
+
columnDefs={localcolDefs}
|
|
155
|
+
sideBar={['columns', 'filters']}
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const colDefs = data.columns.map(
|
|
161
|
+
(colName) =>
|
|
162
|
+
({
|
|
163
|
+
minWidth: 50,
|
|
164
|
+
sortable: true,
|
|
165
|
+
resizable: true,
|
|
166
|
+
field: colName,
|
|
167
|
+
flex: 1,
|
|
168
|
+
cellRenderer: TDSResultCellRenderer,
|
|
169
|
+
filter: true,
|
|
170
|
+
}) as DataGridColumnDefinition,
|
|
171
|
+
);
|
|
172
|
+
const getContextMenuItems = useCallback(
|
|
173
|
+
(
|
|
174
|
+
params: DataGridGetContextMenuItemsParams<{
|
|
175
|
+
[key: string]: string;
|
|
176
|
+
}>,
|
|
177
|
+
): (DataGridDefaultMenuItem | DataGridMenuItemDef)[] => [
|
|
178
|
+
'copy',
|
|
179
|
+
'copyWithHeaders',
|
|
180
|
+
{
|
|
181
|
+
name: 'Copy Row Value',
|
|
182
|
+
action: () => {
|
|
183
|
+
params.api.copySelectedRowsToClipboard();
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
[],
|
|
188
|
+
);
|
|
189
|
+
return (
|
|
190
|
+
<div
|
|
191
|
+
className={clsx('sql-playground__result__grid', {
|
|
192
|
+
'ag-theme-balham': !darkMode,
|
|
193
|
+
'ag-theme-balham-dark': darkMode,
|
|
194
|
+
})}
|
|
195
|
+
>
|
|
196
|
+
<DataGrid
|
|
197
|
+
rowData={data.rowData}
|
|
198
|
+
overlayNoRowsTemplate={`<div class="sql-playground__result__grid--empty">No results</div>`}
|
|
199
|
+
gridOptions={{
|
|
200
|
+
suppressScrollOnNewData: true,
|
|
201
|
+
rowSelection: {
|
|
202
|
+
mode: 'multiRow',
|
|
203
|
+
checkboxes: false,
|
|
204
|
+
headerCheckbox: false,
|
|
205
|
+
},
|
|
206
|
+
cellSelection: true,
|
|
207
|
+
}}
|
|
208
|
+
onRowDataUpdated={(params) => {
|
|
209
|
+
params.api.refreshCells({ force: true });
|
|
210
|
+
}}
|
|
211
|
+
suppressFieldDotNotation={true}
|
|
212
|
+
suppressClipboardPaste={false}
|
|
213
|
+
suppressContextMenu={false}
|
|
214
|
+
columnDefs={colDefs}
|
|
215
|
+
getContextMenuItems={(params) => getContextMenuItems(params)}
|
|
216
|
+
/>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<div
|
|
223
|
+
className={clsx('sql-playground__result__grid', {
|
|
224
|
+
'ag-theme-balham': !darkMode,
|
|
225
|
+
'ag-theme-balham-dark': darkMode,
|
|
226
|
+
})}
|
|
227
|
+
>
|
|
228
|
+
<DataGrid
|
|
229
|
+
rowData={data.rowData}
|
|
230
|
+
overlayNoRowsTemplate={`<div class="sql-playground__result__grid--empty">No results</div>`}
|
|
231
|
+
alwaysShowVerticalScroll={true}
|
|
232
|
+
suppressFieldDotNotation={true}
|
|
233
|
+
columnDefs={data.columns.map((column) => ({
|
|
234
|
+
minWidth: 50,
|
|
235
|
+
sortable: true,
|
|
236
|
+
resizable: true,
|
|
237
|
+
headerName: column,
|
|
238
|
+
field: column,
|
|
239
|
+
flex: 1,
|
|
240
|
+
}))}
|
|
241
|
+
/>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
);
|