@finos/legend-application-studio 28.19.73 → 28.19.75
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/components/editor/__test-utils__/EditorComponentTestUtils.d.ts.map +1 -1
- package/lib/components/editor/__test-utils__/EditorComponentTestUtils.js +4 -0
- package/lib/components/editor/__test-utils__/EditorComponentTestUtils.js.map +1 -1
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.js +26 -338
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.js.map +1 -1
- package/lib/components/editor/panel-group/SQLPlaygroundPanel.d.ts.map +1 -1
- package/lib/components/editor/panel-group/SQLPlaygroundPanel.js +9 -298
- package/lib/components/editor/panel-group/SQLPlaygroundPanel.js.map +1 -1
- package/lib/components/editor/side-bar/Explorer.js +1 -1
- package/lib/components/editor/side-bar/Explorer.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
- package/lib/stores/editor/EditorGraphState.js +1 -7
- package/lib/stores/editor/EditorGraphState.js.map +1 -1
- package/lib/stores/editor/EditorStore.d.ts +2 -2
- package/lib/stores/editor/EditorStore.d.ts.map +1 -1
- package/lib/stores/editor/EditorStore.js +3 -3
- package/lib/stores/editor/EditorStore.js.map +1 -1
- package/lib/stores/editor/GraphEditFormModeState.js +1 -1
- package/lib/stores/editor/GraphEditFormModeState.js.map +1 -1
- package/lib/stores/editor/__test-utils__/EditorStoreTestUtils.d.ts.map +1 -1
- package/lib/stores/editor/__test-utils__/EditorStoreTestUtils.js +4 -0
- package/lib/stores/editor/__test-utils__/EditorStoreTestUtils.js.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts +0 -2
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js +0 -19
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts +1 -16
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js +1 -112
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js.map +1 -1
- package/lib/stores/editor/panel-group/{SQLPlaygroundPanelState.d.ts → StudioSQLPlaygroundPanelState.d.ts} +8 -15
- package/lib/stores/editor/panel-group/StudioSQLPlaygroundPanelState.d.ts.map +1 -0
- package/lib/stores/editor/panel-group/{SQLPlaygroundPanelState.js → StudioSQLPlaygroundPanelState.js} +29 -44
- package/lib/stores/editor/panel-group/StudioSQLPlaygroundPanelState.js.map +1 -0
- package/package.json +13 -13
- package/src/components/editor/__test-utils__/EditorComponentTestUtils.tsx +4 -0
- package/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx +53 -599
- package/src/components/editor/panel-group/SQLPlaygroundPanel.tsx +12 -576
- package/src/components/editor/side-bar/Explorer.tsx +1 -1
- package/src/stores/editor/EditorGraphState.ts +4 -11
- package/src/stores/editor/EditorStore.ts +3 -3
- package/src/stores/editor/GraphEditFormModeState.ts +1 -1
- package/src/stores/editor/__test-utils__/EditorStoreTestUtils.ts +4 -1
- package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.ts +0 -26
- package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.ts +1 -178
- package/src/stores/editor/panel-group/{SQLPlaygroundPanelState.ts → StudioSQLPlaygroundPanelState.ts} +47 -60
- package/tsconfig.json +1 -1
- package/lib/stores/editor/panel-group/SQLPlaygroundPanelState.d.ts.map +0 -1
- package/lib/stores/editor/panel-group/SQLPlaygroundPanelState.js.map +0 -1
|
@@ -25,40 +25,21 @@ import {
|
|
|
25
25
|
PURE_ConnectionIcon,
|
|
26
26
|
BlankPanelPlaceholder,
|
|
27
27
|
PanelDropZone,
|
|
28
|
-
ResizablePanelSplitterLine,
|
|
29
|
-
PlayIcon,
|
|
30
28
|
PanelLoadingIndicator,
|
|
31
|
-
BlankPanelContent,
|
|
32
29
|
PURE_DatabaseIcon,
|
|
33
30
|
SyncIcon,
|
|
34
|
-
clsx,
|
|
35
|
-
CheckSquareIcon,
|
|
36
|
-
SquareIcon,
|
|
37
31
|
} from '@finos/legend-art';
|
|
38
|
-
import
|
|
32
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
39
33
|
import {
|
|
40
34
|
useApplicationStore,
|
|
41
|
-
useCommands,
|
|
42
35
|
useConditionedApplicationNavigationContext,
|
|
43
36
|
} from '@finos/legend-application';
|
|
44
37
|
import { flowResult } from 'mobx';
|
|
45
|
-
import {
|
|
46
|
-
CODE_EDITOR_LANGUAGE,
|
|
47
|
-
CODE_EDITOR_THEME,
|
|
48
|
-
getBaseCodeEditorOptions,
|
|
49
|
-
} from '@finos/legend-code-editor';
|
|
50
|
-
import {
|
|
51
|
-
editor as monacoEditorAPI,
|
|
52
|
-
languages as monacoLanguagesAPI,
|
|
53
|
-
type IDisposable,
|
|
54
|
-
type IPosition,
|
|
55
|
-
} from 'monaco-editor';
|
|
56
38
|
import {
|
|
57
39
|
PackageableConnection,
|
|
58
40
|
RelationalDatabaseConnection,
|
|
59
41
|
} from '@finos/legend-graph';
|
|
60
42
|
import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../__lib__/LegendStudioApplicationNavigationContext.js';
|
|
61
|
-
import { type SQLPlaygroundPanelState } from '../../../stores/editor/panel-group/SQLPlaygroundPanelState.js';
|
|
62
43
|
import { useEditorStore } from '../EditorStoreProvider.js';
|
|
63
44
|
import { PANEL_MODE } from '../../../stores/editor/EditorConfig.js';
|
|
64
45
|
import { useDrag, useDrop } from 'react-dnd';
|
|
@@ -66,24 +47,6 @@ import {
|
|
|
66
47
|
CORE_DND_TYPE,
|
|
67
48
|
type ElementDragSource,
|
|
68
49
|
} from '../../../stores/editor/utils/DnDUtils.js';
|
|
69
|
-
import {
|
|
70
|
-
DataGrid,
|
|
71
|
-
type DataGridCellRendererParams,
|
|
72
|
-
type DataGridColumnDefinition,
|
|
73
|
-
type DataGridDefaultMenuItem,
|
|
74
|
-
type DataGridGetContextMenuItemsParams,
|
|
75
|
-
type DataGridMenuItemDef,
|
|
76
|
-
} from '@finos/legend-lego/data-grid';
|
|
77
|
-
import {
|
|
78
|
-
at,
|
|
79
|
-
isNonNullable,
|
|
80
|
-
isNumber,
|
|
81
|
-
isString,
|
|
82
|
-
isValidURL,
|
|
83
|
-
parseCSVString,
|
|
84
|
-
prettyDuration,
|
|
85
|
-
uniqBy,
|
|
86
|
-
} from '@finos/legend-shared';
|
|
87
50
|
import {
|
|
88
51
|
DatabaseSchemaExplorer,
|
|
89
52
|
DatabaseSchemaExplorerTreeNodeContainer,
|
|
@@ -94,6 +57,7 @@ import {
|
|
|
94
57
|
buildRelationalDatabaseConnectionOption,
|
|
95
58
|
type RelationalDatabaseConnectionOption,
|
|
96
59
|
} from '../editor-group/connection-editor/RelationalDatabaseConnectionEditor.js';
|
|
60
|
+
import { SQLPlaygroundEditorResultPanel } from '@finos/legend-lego/sql-playground';
|
|
97
61
|
|
|
98
62
|
const DATABASE_NODE_DND_TYPE = 'DATABASE_NODE_DND_TYPE';
|
|
99
63
|
type DatabaseNodeDragType = { text: string };
|
|
@@ -121,449 +85,11 @@ const SQLPlaygroundDatabaseSchemaExplorerTreeNodeContainer = observer(
|
|
|
121
85
|
},
|
|
122
86
|
);
|
|
123
87
|
|
|
124
|
-
// List of most popular SQL keywords
|
|
125
|
-
// See https://www.w3schools.com/sql/sql_ref_keywords.asp
|
|
126
|
-
const SQL_KEYWORDS = [
|
|
127
|
-
'AND',
|
|
128
|
-
'AS',
|
|
129
|
-
'ASC',
|
|
130
|
-
'BETWEEN',
|
|
131
|
-
'DESC',
|
|
132
|
-
'DISTINCT',
|
|
133
|
-
'EXEC',
|
|
134
|
-
'EXISTS',
|
|
135
|
-
'FROM',
|
|
136
|
-
'FULL OUTER JOIN',
|
|
137
|
-
'GROUP BY',
|
|
138
|
-
'HAVING',
|
|
139
|
-
'IN',
|
|
140
|
-
'INNER JOIN',
|
|
141
|
-
'IS NULL',
|
|
142
|
-
'IS NOT NULL',
|
|
143
|
-
'JOIN',
|
|
144
|
-
'LEFT JOIN',
|
|
145
|
-
'LIKE',
|
|
146
|
-
'LIMIT',
|
|
147
|
-
'NOT',
|
|
148
|
-
'NOT NULL',
|
|
149
|
-
'OR',
|
|
150
|
-
'ORDER BY',
|
|
151
|
-
'OUTER JOIN',
|
|
152
|
-
'RIGHT JOIN',
|
|
153
|
-
'SELECT',
|
|
154
|
-
'SELECT DISTINCT',
|
|
155
|
-
'SELECT INTO',
|
|
156
|
-
'SELECT TOP',
|
|
157
|
-
'TOP',
|
|
158
|
-
'UNION',
|
|
159
|
-
'UNION ALL',
|
|
160
|
-
'UNIQUE',
|
|
161
|
-
'WHERE',
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
const getKeywordSuggestions = async (
|
|
165
|
-
position: IPosition,
|
|
166
|
-
model: monacoEditorAPI.ITextModel,
|
|
167
|
-
): Promise<monacoLanguagesAPI.CompletionItem[]> =>
|
|
168
|
-
SQL_KEYWORDS.map(
|
|
169
|
-
(keyword) =>
|
|
170
|
-
({
|
|
171
|
-
label: keyword,
|
|
172
|
-
kind: monacoLanguagesAPI.CompletionItemKind.Keyword,
|
|
173
|
-
insertTextRules:
|
|
174
|
-
monacoLanguagesAPI.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
175
|
-
insertText: `${keyword} `,
|
|
176
|
-
}) as monacoLanguagesAPI.CompletionItem,
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
const getDatabaseSchemaEntities = async (
|
|
180
|
-
position: IPosition,
|
|
181
|
-
model: monacoEditorAPI.ITextModel,
|
|
182
|
-
playgroundState: SQLPlaygroundPanelState,
|
|
183
|
-
): Promise<monacoLanguagesAPI.CompletionItem[]> => {
|
|
184
|
-
if (playgroundState.schemaExplorerState?.treeData) {
|
|
185
|
-
return uniqBy(
|
|
186
|
-
Array.from(
|
|
187
|
-
playgroundState.schemaExplorerState.treeData.nodes.values(),
|
|
188
|
-
).map(
|
|
189
|
-
(value) =>
|
|
190
|
-
({
|
|
191
|
-
label: value.label,
|
|
192
|
-
kind: monacoLanguagesAPI.CompletionItemKind.Field,
|
|
193
|
-
insertTextRules:
|
|
194
|
-
monacoLanguagesAPI.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
195
|
-
insertText: `${value.label} `,
|
|
196
|
-
}) as monacoLanguagesAPI.CompletionItem,
|
|
197
|
-
),
|
|
198
|
-
(val) => val.label,
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
return [];
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const PlaygroundSQLCodeEditor = observer(() => {
|
|
205
|
-
const editorStore = useEditorStore();
|
|
206
|
-
const playgroundState = editorStore.sqlPlaygroundState;
|
|
207
|
-
const applicationStore = useApplicationStore();
|
|
208
|
-
const codeEditorRef = useRef<HTMLDivElement>(null);
|
|
209
|
-
const [editor, setEditor] = useState<
|
|
210
|
-
monacoEditorAPI.IStandaloneCodeEditor | undefined
|
|
211
|
-
>();
|
|
212
|
-
const sqlIdentifierSuggestionProviderDisposer = useRef<
|
|
213
|
-
IDisposable | undefined
|
|
214
|
-
>(undefined);
|
|
215
|
-
|
|
216
|
-
useEffect(() => {
|
|
217
|
-
if (!editor && codeEditorRef.current) {
|
|
218
|
-
const element = codeEditorRef.current;
|
|
219
|
-
const newEditor = monacoEditorAPI.create(element, {
|
|
220
|
-
...getBaseCodeEditorOptions(),
|
|
221
|
-
theme: CODE_EDITOR_THEME.DEFAULT_DARK,
|
|
222
|
-
language: CODE_EDITOR_LANGUAGE.SQL,
|
|
223
|
-
padding: {
|
|
224
|
-
top: 10,
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
newEditor.onDidChangeModelContent(() => {
|
|
229
|
-
const currentVal = newEditor.getValue();
|
|
230
|
-
playgroundState.setSQLText(currentVal);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Restore the editor model and view state
|
|
234
|
-
newEditor.setModel(playgroundState.sqlEditorTextModel);
|
|
235
|
-
if (playgroundState.sqlEditorViewState) {
|
|
236
|
-
newEditor.restoreViewState(playgroundState.sqlEditorViewState);
|
|
237
|
-
}
|
|
238
|
-
newEditor.focus(); // focus on the editor initially
|
|
239
|
-
playgroundState.setSQLEditor(newEditor);
|
|
240
|
-
setEditor(newEditor);
|
|
241
|
-
}
|
|
242
|
-
}, [playgroundState, applicationStore, editor]);
|
|
243
|
-
|
|
244
|
-
useCommands(playgroundState);
|
|
245
|
-
|
|
246
|
-
if (editor) {
|
|
247
|
-
sqlIdentifierSuggestionProviderDisposer.current?.dispose();
|
|
248
|
-
sqlIdentifierSuggestionProviderDisposer.current =
|
|
249
|
-
monacoLanguagesAPI.registerCompletionItemProvider(
|
|
250
|
-
CODE_EDITOR_LANGUAGE.SQL,
|
|
251
|
-
{
|
|
252
|
-
triggerCharacters: [],
|
|
253
|
-
provideCompletionItems: async (model, position, context) => {
|
|
254
|
-
let suggestions: monacoLanguagesAPI.CompletionItem[] = [];
|
|
255
|
-
if (
|
|
256
|
-
context.triggerKind ===
|
|
257
|
-
monacoLanguagesAPI.CompletionTriggerKind.Invoke
|
|
258
|
-
) {
|
|
259
|
-
// keywords
|
|
260
|
-
suggestions = suggestions.concat(
|
|
261
|
-
await getKeywordSuggestions(position, model),
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
// database schema entities
|
|
265
|
-
suggestions = suggestions.concat(
|
|
266
|
-
await getDatabaseSchemaEntities(
|
|
267
|
-
position,
|
|
268
|
-
model,
|
|
269
|
-
playgroundState,
|
|
270
|
-
),
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return { suggestions };
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// clean up
|
|
281
|
-
useEffect(
|
|
282
|
-
() => (): void => {
|
|
283
|
-
if (editor) {
|
|
284
|
-
// persist editor view state (cursor, scroll, etc.) to restore on re-open
|
|
285
|
-
playgroundState.setSQLEditorViewState(
|
|
286
|
-
editor.saveViewState() ?? undefined,
|
|
287
|
-
);
|
|
288
|
-
editor.dispose();
|
|
289
|
-
|
|
290
|
-
// Dispose the providers properly to avoid ending up with duplicated suggestions
|
|
291
|
-
sqlIdentifierSuggestionProviderDisposer.current?.dispose();
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
[playgroundState, editor],
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
const handleDatabaseNodeDrop = useCallback(
|
|
298
|
-
(item: DatabaseNodeDragType): void => {
|
|
299
|
-
if (isString(item.text)) {
|
|
300
|
-
if (playgroundState.sqlEditor) {
|
|
301
|
-
const currentValue = playgroundState.sqlEditorTextModel.getValue();
|
|
302
|
-
const lines = currentValue.split('\n');
|
|
303
|
-
const position = playgroundState.sqlEditor.getPosition() ?? {
|
|
304
|
-
lineNumber: lines.length,
|
|
305
|
-
column: lines.at(-1)?.length ?? 0,
|
|
306
|
-
};
|
|
307
|
-
playgroundState.sqlEditor.executeEdits('', [
|
|
308
|
-
{
|
|
309
|
-
range: {
|
|
310
|
-
startLineNumber: position.lineNumber,
|
|
311
|
-
startColumn: position.column,
|
|
312
|
-
endLineNumber: position.lineNumber,
|
|
313
|
-
endColumn: position.column,
|
|
314
|
-
},
|
|
315
|
-
text: item.text,
|
|
316
|
-
forceMoveMarkers: true,
|
|
317
|
-
},
|
|
318
|
-
]);
|
|
319
|
-
playgroundState.setSQLText(
|
|
320
|
-
playgroundState.sqlEditorTextModel.getValue(),
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
[playgroundState],
|
|
326
|
-
);
|
|
327
|
-
const [{ isDatabaseNodeDragOver }, dropConnector] = useDrop<
|
|
328
|
-
DatabaseNodeDragType,
|
|
329
|
-
void,
|
|
330
|
-
{ isDatabaseNodeDragOver: boolean }
|
|
331
|
-
>(
|
|
332
|
-
() => ({
|
|
333
|
-
accept: DATABASE_NODE_DND_TYPE,
|
|
334
|
-
drop: (item): void => handleDatabaseNodeDrop(item),
|
|
335
|
-
collect: (monitor) => ({
|
|
336
|
-
isDatabaseNodeDragOver: monitor.isOver({ shallow: true }),
|
|
337
|
-
}),
|
|
338
|
-
}),
|
|
339
|
-
[handleDatabaseNodeDrop],
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
return (
|
|
343
|
-
<div className="sql-playground__code-editor">
|
|
344
|
-
<PanelDropZone
|
|
345
|
-
className="sql-playground__code-editor__content"
|
|
346
|
-
isDragOver={isDatabaseNodeDragOver}
|
|
347
|
-
dropTargetConnector={dropConnector}
|
|
348
|
-
>
|
|
349
|
-
<div className="code-editor__container">
|
|
350
|
-
<div className="code-editor__body" ref={codeEditorRef} />
|
|
351
|
-
</div>
|
|
352
|
-
</PanelDropZone>
|
|
353
|
-
</div>
|
|
354
|
-
);
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
const parseExecutionResultData = (
|
|
358
|
-
data: string,
|
|
359
|
-
): { rowData: Record<string, string>[]; columns: string[] } | undefined => {
|
|
360
|
-
const lines = data.split('\n').filter((line) => line.trim().length);
|
|
361
|
-
if (lines.length) {
|
|
362
|
-
const columns = parseCSVString(at(lines, 0)) ?? [];
|
|
363
|
-
const rowData = lines
|
|
364
|
-
.slice(1)
|
|
365
|
-
.map((item) => {
|
|
366
|
-
const rowItems = parseCSVString(item);
|
|
367
|
-
if (!rowItems) {
|
|
368
|
-
return undefined;
|
|
369
|
-
}
|
|
370
|
-
const row: Record<string, string> = {};
|
|
371
|
-
columns.forEach((column, idx) => {
|
|
372
|
-
row[column] = rowItems[idx] ?? '';
|
|
373
|
-
});
|
|
374
|
-
return row;
|
|
375
|
-
})
|
|
376
|
-
.filter(isNonNullable);
|
|
377
|
-
return { rowData, columns };
|
|
378
|
-
}
|
|
379
|
-
return undefined;
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
const TDSResultCellRenderer = observer((params: DataGridCellRendererParams) => {
|
|
383
|
-
const cellValue = params.value as string;
|
|
384
|
-
const formattedCellValue = (): string => {
|
|
385
|
-
if (isNumber(cellValue)) {
|
|
386
|
-
return Intl.NumberFormat('en-US', {
|
|
387
|
-
maximumFractionDigits: 4,
|
|
388
|
-
}).format(Number(cellValue));
|
|
389
|
-
}
|
|
390
|
-
return cellValue;
|
|
391
|
-
};
|
|
392
|
-
const cellValueUrlLink =
|
|
393
|
-
isString(cellValue) && isValidURL(cellValue) ? cellValue : undefined;
|
|
394
|
-
|
|
395
|
-
return (
|
|
396
|
-
<div className={clsx('query-builder__result__values__table__cell')}>
|
|
397
|
-
{cellValueUrlLink ? (
|
|
398
|
-
<a href={cellValueUrlLink} target="_blank" rel="noreferrer">
|
|
399
|
-
{cellValueUrlLink}
|
|
400
|
-
</a>
|
|
401
|
-
) : (
|
|
402
|
-
<span>{formattedCellValue()}</span>
|
|
403
|
-
)}
|
|
404
|
-
</div>
|
|
405
|
-
);
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
const PlayGroundSQLExecutionResultGrid = observer(
|
|
409
|
-
(props: {
|
|
410
|
-
result: string;
|
|
411
|
-
useAdvancedGrid?: boolean;
|
|
412
|
-
useLocalMode?: boolean;
|
|
413
|
-
}) => {
|
|
414
|
-
const { result, useAdvancedGrid, useLocalMode } = props;
|
|
415
|
-
const data = parseExecutionResultData(result);
|
|
416
|
-
const applicationStore = useApplicationStore();
|
|
417
|
-
const darkMode =
|
|
418
|
-
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled;
|
|
419
|
-
|
|
420
|
-
if (!data) {
|
|
421
|
-
return (
|
|
422
|
-
<BlankPanelContent>{`Can't parse result, displaying raw form:\n${result}`}</BlankPanelContent>
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
if (useAdvancedGrid) {
|
|
426
|
-
if (useLocalMode) {
|
|
427
|
-
const localcolDefs = data.columns.map(
|
|
428
|
-
(colName) =>
|
|
429
|
-
({
|
|
430
|
-
minWidth: 50,
|
|
431
|
-
sortable: true,
|
|
432
|
-
resizable: true,
|
|
433
|
-
field: colName,
|
|
434
|
-
flex: 1,
|
|
435
|
-
enablePivot: true,
|
|
436
|
-
enableRowGroup: true,
|
|
437
|
-
enableValue: true,
|
|
438
|
-
allowedAggFuncs: ['count'],
|
|
439
|
-
}) as DataGridColumnDefinition,
|
|
440
|
-
);
|
|
441
|
-
|
|
442
|
-
return (
|
|
443
|
-
<div
|
|
444
|
-
className={clsx('sql-playground__result__grid', {
|
|
445
|
-
'ag-theme-balham': !darkMode,
|
|
446
|
-
'ag-theme-balham-dark': darkMode,
|
|
447
|
-
})}
|
|
448
|
-
>
|
|
449
|
-
<DataGrid
|
|
450
|
-
rowData={data.rowData}
|
|
451
|
-
gridOptions={{
|
|
452
|
-
suppressScrollOnNewData: true,
|
|
453
|
-
rowSelection: {
|
|
454
|
-
mode: 'multiRow',
|
|
455
|
-
checkboxes: false,
|
|
456
|
-
headerCheckbox: false,
|
|
457
|
-
},
|
|
458
|
-
pivotPanelShow: 'always',
|
|
459
|
-
rowGroupPanelShow: 'always',
|
|
460
|
-
cellSelection: true,
|
|
461
|
-
}}
|
|
462
|
-
// NOTE: when column definition changed, we need to force refresh the cell to make sure the cell renderer is updated
|
|
463
|
-
// See https://stackoverflow.com/questions/56341073/how-to-refresh-an-ag-grid-when-a-change-occurs-inside-a-custom-cell-renderer-com
|
|
464
|
-
onRowDataUpdated={(params) => {
|
|
465
|
-
params.api.refreshCells({ force: true });
|
|
466
|
-
}}
|
|
467
|
-
suppressFieldDotNotation={true}
|
|
468
|
-
suppressContextMenu={false}
|
|
469
|
-
columnDefs={localcolDefs}
|
|
470
|
-
sideBar={['columns', 'filters']}
|
|
471
|
-
/>
|
|
472
|
-
</div>
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
const colDefs = data.columns.map(
|
|
476
|
-
(colName) =>
|
|
477
|
-
({
|
|
478
|
-
minWidth: 50,
|
|
479
|
-
sortable: true,
|
|
480
|
-
resizable: true,
|
|
481
|
-
field: colName,
|
|
482
|
-
flex: 1,
|
|
483
|
-
cellRenderer: TDSResultCellRenderer,
|
|
484
|
-
filter: true,
|
|
485
|
-
}) as DataGridColumnDefinition,
|
|
486
|
-
);
|
|
487
|
-
const getContextMenuItems = useCallback(
|
|
488
|
-
(
|
|
489
|
-
params: DataGridGetContextMenuItemsParams<{
|
|
490
|
-
[key: string]: string;
|
|
491
|
-
}>,
|
|
492
|
-
): (DataGridDefaultMenuItem | DataGridMenuItemDef)[] => [
|
|
493
|
-
'copy',
|
|
494
|
-
'copyWithHeaders',
|
|
495
|
-
{
|
|
496
|
-
name: 'Copy Row Value',
|
|
497
|
-
action: () => {
|
|
498
|
-
params.api.copySelectedRowsToClipboard();
|
|
499
|
-
},
|
|
500
|
-
},
|
|
501
|
-
],
|
|
502
|
-
[],
|
|
503
|
-
);
|
|
504
|
-
return (
|
|
505
|
-
<div
|
|
506
|
-
className={clsx('sql-playground__result__grid', {
|
|
507
|
-
'ag-theme-balham': !darkMode,
|
|
508
|
-
'ag-theme-balham-dark': darkMode,
|
|
509
|
-
})}
|
|
510
|
-
>
|
|
511
|
-
<DataGrid
|
|
512
|
-
rowData={data.rowData}
|
|
513
|
-
overlayNoRowsTemplate={`<div class="sql-playground__result__grid--empty">No results</div>`}
|
|
514
|
-
gridOptions={{
|
|
515
|
-
suppressScrollOnNewData: true,
|
|
516
|
-
rowSelection: {
|
|
517
|
-
mode: 'multiRow',
|
|
518
|
-
checkboxes: false,
|
|
519
|
-
headerCheckbox: false,
|
|
520
|
-
},
|
|
521
|
-
cellSelection: true,
|
|
522
|
-
}}
|
|
523
|
-
onRowDataUpdated={(params) => {
|
|
524
|
-
params.api.refreshCells({ force: true });
|
|
525
|
-
}}
|
|
526
|
-
suppressFieldDotNotation={true}
|
|
527
|
-
suppressClipboardPaste={false}
|
|
528
|
-
suppressContextMenu={false}
|
|
529
|
-
columnDefs={colDefs}
|
|
530
|
-
getContextMenuItems={(params) => getContextMenuItems(params)}
|
|
531
|
-
/>
|
|
532
|
-
</div>
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
return (
|
|
537
|
-
<div
|
|
538
|
-
className={clsx('sql-playground__result__grid', {
|
|
539
|
-
'ag-theme-balham': !darkMode,
|
|
540
|
-
'ag-theme-balham-dark': darkMode,
|
|
541
|
-
})}
|
|
542
|
-
>
|
|
543
|
-
<DataGrid
|
|
544
|
-
rowData={data.rowData}
|
|
545
|
-
overlayNoRowsTemplate={`<div class="sql-playground__result__grid--empty">No results</div>`}
|
|
546
|
-
alwaysShowVerticalScroll={true}
|
|
547
|
-
suppressFieldDotNotation={true}
|
|
548
|
-
columnDefs={data.columns.map((column) => ({
|
|
549
|
-
minWidth: 50,
|
|
550
|
-
sortable: true,
|
|
551
|
-
resizable: true,
|
|
552
|
-
headerName: column,
|
|
553
|
-
field: column,
|
|
554
|
-
flex: 1,
|
|
555
|
-
}))}
|
|
556
|
-
/>
|
|
557
|
-
</div>
|
|
558
|
-
);
|
|
559
|
-
},
|
|
560
|
-
);
|
|
561
|
-
|
|
562
88
|
type SQLPlaygroundPanelDropTarget = ElementDragSource;
|
|
563
89
|
|
|
564
90
|
export const SQLPlaygroundPanel = observer(() => {
|
|
565
91
|
const editorStore = useEditorStore();
|
|
566
|
-
const playgroundState = editorStore.
|
|
92
|
+
const playgroundState = editorStore.studioSqlPlaygroundState;
|
|
567
93
|
const applicationStore = useApplicationStore();
|
|
568
94
|
|
|
569
95
|
// connection
|
|
@@ -640,26 +166,6 @@ export const SQLPlaygroundPanel = observer(() => {
|
|
|
640
166
|
}
|
|
641
167
|
};
|
|
642
168
|
|
|
643
|
-
const executeRawSQL = (): void => {
|
|
644
|
-
flowResult(playgroundState.executeRawSQL()).catch(
|
|
645
|
-
applicationStore.alertUnhandledError,
|
|
646
|
-
);
|
|
647
|
-
};
|
|
648
|
-
const advancedMode = Boolean(
|
|
649
|
-
editorStore.applicationStore.config.options.queryBuilderConfig
|
|
650
|
-
?.TEMPORARY__enableGridEnterpriseMode,
|
|
651
|
-
);
|
|
652
|
-
const resultDescription = playgroundState.sqlExecutionResult
|
|
653
|
-
? `query ran in ${prettyDuration(
|
|
654
|
-
playgroundState.sqlExecutionResult.sqlDuration,
|
|
655
|
-
{
|
|
656
|
-
ms: true,
|
|
657
|
-
},
|
|
658
|
-
)}`
|
|
659
|
-
: undefined;
|
|
660
|
-
const toggleocalMode = (): void => {
|
|
661
|
-
playgroundState.toggleIsLocalModeEnabled();
|
|
662
|
-
};
|
|
663
169
|
useEffect(() => {
|
|
664
170
|
if (playgroundState.schemaExplorerState) {
|
|
665
171
|
flowResult(
|
|
@@ -668,6 +174,10 @@ export const SQLPlaygroundPanel = observer(() => {
|
|
|
668
174
|
}
|
|
669
175
|
}, [playgroundState, applicationStore, playgroundState.schemaExplorerState]);
|
|
670
176
|
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
playgroundState.fetchSchemaMetaData();
|
|
179
|
+
}, [playgroundState]);
|
|
180
|
+
|
|
671
181
|
useConditionedApplicationNavigationContext(
|
|
672
182
|
LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.SQL_PLAYGROUND,
|
|
673
183
|
editorStore.activePanelMode === PANEL_MODE.SQL_PLAYGROUND,
|
|
@@ -749,85 +259,11 @@ export const SQLPlaygroundPanel = observer(() => {
|
|
|
749
259
|
<ResizablePanelSplitter />
|
|
750
260
|
<ResizablePanel>
|
|
751
261
|
<div className="panel sql-playground__sql-editor">
|
|
752
|
-
<
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
<ResizablePanelSplitterLine color="var(--color-dark-grey-250)" />
|
|
758
|
-
</ResizablePanelSplitter>
|
|
759
|
-
<ResizablePanel size={300}>
|
|
760
|
-
<div className="panel__header">
|
|
761
|
-
<div className="panel__header__title">
|
|
762
|
-
<div className="panel__header__title__label">
|
|
763
|
-
result
|
|
764
|
-
</div>
|
|
765
|
-
|
|
766
|
-
{playgroundState.executeRawSQLState.isInProgress && (
|
|
767
|
-
<div className="panel__header__title__label__status">
|
|
768
|
-
Running SQL...
|
|
769
|
-
</div>
|
|
770
|
-
)}
|
|
771
|
-
|
|
772
|
-
<div className="query-builder__result__analytics">
|
|
773
|
-
{resultDescription ?? ''}
|
|
774
|
-
</div>
|
|
775
|
-
</div>
|
|
776
|
-
<div className="panel__header__actions query-builder__result__header__actions">
|
|
777
|
-
{advancedMode && (
|
|
778
|
-
<div className="query-builder__result__advanced__mode">
|
|
779
|
-
<div className="query-builder__result__advanced__mode__label">
|
|
780
|
-
Local Mode
|
|
781
|
-
</div>
|
|
782
|
-
<button
|
|
783
|
-
className={clsx(
|
|
784
|
-
'query-builder__result__advanced__mode__toggler__btn',
|
|
785
|
-
{
|
|
786
|
-
'query-builder__result__advanced__mode__toggler__btn--toggled':
|
|
787
|
-
playgroundState.isLocalModeEnabled,
|
|
788
|
-
},
|
|
789
|
-
)}
|
|
790
|
-
onClick={toggleocalMode}
|
|
791
|
-
tabIndex={-1}
|
|
792
|
-
>
|
|
793
|
-
{playgroundState.isLocalModeEnabled ? (
|
|
794
|
-
<CheckSquareIcon />
|
|
795
|
-
) : (
|
|
796
|
-
<SquareIcon />
|
|
797
|
-
)}
|
|
798
|
-
</button>
|
|
799
|
-
</div>
|
|
800
|
-
)}
|
|
801
|
-
|
|
802
|
-
<div className="query-builder__result__execute-btn btn__dropdown-combo btn__dropdown-combo--primary">
|
|
803
|
-
<button
|
|
804
|
-
className="btn__dropdown-combo__label"
|
|
805
|
-
onClick={executeRawSQL}
|
|
806
|
-
disabled={
|
|
807
|
-
playgroundState.executeRawSQLState.isInProgress
|
|
808
|
-
}
|
|
809
|
-
tabIndex={-1}
|
|
810
|
-
>
|
|
811
|
-
<PlayIcon className="btn__dropdown-combo__label__icon" />
|
|
812
|
-
<div className="btn__dropdown-combo__label__title">
|
|
813
|
-
Run Query
|
|
814
|
-
</div>
|
|
815
|
-
</button>
|
|
816
|
-
</div>
|
|
817
|
-
</div>
|
|
818
|
-
</div>
|
|
819
|
-
{playgroundState.sqlExecutionResult !== undefined && (
|
|
820
|
-
<PlayGroundSQLExecutionResultGrid
|
|
821
|
-
result={playgroundState.sqlExecutionResult.value}
|
|
822
|
-
useAdvancedGrid={advancedMode}
|
|
823
|
-
useLocalMode={playgroundState.isLocalModeEnabled}
|
|
824
|
-
/>
|
|
825
|
-
)}
|
|
826
|
-
{playgroundState.sqlExecutionResult === undefined && (
|
|
827
|
-
<div />
|
|
828
|
-
)}
|
|
829
|
-
</ResizablePanel>
|
|
830
|
-
</ResizablePanelGroup>
|
|
262
|
+
<SQLPlaygroundEditorResultPanel
|
|
263
|
+
playgroundState={playgroundState}
|
|
264
|
+
advancedMode={true}
|
|
265
|
+
enableDarkMode={true}
|
|
266
|
+
/>
|
|
831
267
|
</div>
|
|
832
268
|
</ResizablePanel>
|
|
833
269
|
</ResizablePanelGroup>
|
|
@@ -618,7 +618,7 @@ const ExplorerContextMenu = observer(
|
|
|
618
618
|
if (isRelationalDatabaseConnection(node?.packageableElement)) {
|
|
619
619
|
editorStore.panelGroupDisplayState.open();
|
|
620
620
|
editorStore.setActivePanelMode(PANEL_MODE.SQL_PLAYGROUND);
|
|
621
|
-
editorStore.
|
|
621
|
+
editorStore.studioSqlPlaygroundState.setConnection(
|
|
622
622
|
guaranteeType(node?.packageableElement, PackageableConnection),
|
|
623
623
|
);
|
|
624
624
|
}
|
|
@@ -799,22 +799,15 @@ export class EditorGraphState {
|
|
|
799
799
|
projectDependencies: ProjectDependency[],
|
|
800
800
|
): Promise<ProjectDependencyCoordinates[]> {
|
|
801
801
|
return Promise.all(
|
|
802
|
-
projectDependencies.map(async (dep) =>
|
|
803
|
-
|
|
804
|
-
(exclusion) => ({
|
|
805
|
-
groupId: guaranteeNonNullable(exclusion.groupId),
|
|
806
|
-
artifactId: guaranteeNonNullable(exclusion.artifactId),
|
|
807
|
-
}),
|
|
808
|
-
);
|
|
809
|
-
return Promise.resolve(
|
|
802
|
+
projectDependencies.map(async (dep) =>
|
|
803
|
+
Promise.resolve(
|
|
810
804
|
new ProjectDependencyCoordinates(
|
|
811
805
|
guaranteeNonNullable(dep.groupId),
|
|
812
806
|
guaranteeNonNullable(dep.artifactId),
|
|
813
807
|
dep.versionId,
|
|
814
|
-
exclusionCoordinates.length > 0 ? exclusionCoordinates : undefined,
|
|
815
808
|
),
|
|
816
|
-
)
|
|
817
|
-
|
|
809
|
+
),
|
|
810
|
+
),
|
|
818
811
|
);
|
|
819
812
|
}
|
|
820
813
|
|