@finos/legend-application-query 13.8.23 → 13.8.25
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/__lib__/LegendQueryNavigation.d.ts +1 -0
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +3 -0
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/components/DataSpaceArtifactInspector.d.ts +19 -0
- package/lib/components/DataSpaceArtifactInspector.d.ts.map +1 -0
- package/lib/components/DataSpaceArtifactInspector.js +866 -0
- package/lib/components/DataSpaceArtifactInspector.js.map +1 -0
- package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
- package/lib/components/LegendQueryWebApplication.js +2 -1
- package/lib/components/LegendQueryWebApplication.js.map +1 -1
- package/lib/components/QueryEditor.d.ts.map +1 -1
- package/lib/components/QueryEditor.js +48 -10
- package/lib/components/QueryEditor.js.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/light-mode.css +2 -2
- package/lib/light-mode.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/LegendQueryApplicationPlugin.d.ts +29 -4
- package/lib/stores/LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/stores/LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +1 -1
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/package.json +11 -11
- package/src/__lib__/LegendQueryNavigation.ts +3 -0
- package/src/components/DataSpaceArtifactInspector.tsx +1469 -0
- package/src/components/LegendQueryWebApplication.tsx +7 -0
- package/src/components/QueryEditor.tsx +69 -23
- package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +1 -1
- package/src/stores/LegendQueryApplicationPlugin.tsx +27 -4
- package/src/stores/QueryEditorStore.ts +1 -0
- package/tsconfig.json +1 -0
|
@@ -43,6 +43,7 @@ import { DataSpaceTemplateQueryCreator } from './data-space/DataSpaceTemplateQue
|
|
|
43
43
|
import { QueryCreator } from './data-space/DataProductQueryCreator.js';
|
|
44
44
|
import { DataProductSampleQueryCreator } from './data-product/DataProductSampleQueryCreator.js';
|
|
45
45
|
import { ExistingQueryDataCubeViewer } from './data-cube/ExistingQueryDataCubeViewer.js';
|
|
46
|
+
import { DataSpaceArtifactInspector } from './DataSpaceArtifactInspector.js';
|
|
46
47
|
import {
|
|
47
48
|
AuthProvider,
|
|
48
49
|
withAuthenticationRequired,
|
|
@@ -121,6 +122,12 @@ const LegendQueryWebApplicationRouter = observer(() => {
|
|
|
121
122
|
element={<MappingQueryCreator />}
|
|
122
123
|
/>
|
|
123
124
|
|
|
125
|
+
{/* Developer-only diagnostic page (artifact size inspector) */}
|
|
126
|
+
<Route
|
|
127
|
+
path={LEGEND_QUERY_ROUTE_PATTERN.DEV_DATA_SPACE_INSPECTOR}
|
|
128
|
+
element={<DataSpaceArtifactInspector />}
|
|
129
|
+
/>
|
|
130
|
+
|
|
124
131
|
{/* LEGACY DATA SPACE */}
|
|
125
132
|
<Route
|
|
126
133
|
path={generateExtensionUrlPattern(
|
|
@@ -101,6 +101,46 @@ import { QueryEditorDataProductInfoModal } from './data-product/DataProductInfo.
|
|
|
101
101
|
import { DataSpaceQueryBuilderState } from '@finos/legend-extension-dsl-data-space/application';
|
|
102
102
|
import { LegendQueryBareQueryBuilderState } from '../stores/data-space/LegendQueryBareQueryBuilderState.js';
|
|
103
103
|
import { extractQueryParams } from './utils/QueryParameterUtils.js';
|
|
104
|
+
import type { QueryTitleDescriptionAISuggestionRequest } from '../stores/LegendQueryApplicationPlugin.js';
|
|
105
|
+
|
|
106
|
+
const buildAISuggestionRequest = async (
|
|
107
|
+
queryBuilderState: QueryBuilderState,
|
|
108
|
+
name?: string,
|
|
109
|
+
): Promise<QueryTitleDescriptionAISuggestionRequest> => {
|
|
110
|
+
const graphManager = queryBuilderState.graphManagerState.graphManager;
|
|
111
|
+
const lambda = queryBuilderState.buildQuery();
|
|
112
|
+
const content = await graphManager.lambdaToPureCode(lambda);
|
|
113
|
+
const request: QueryTitleDescriptionAISuggestionRequest = { content };
|
|
114
|
+
const execContext = queryBuilderState.getQueryExecutionContext();
|
|
115
|
+
if (execContext instanceof QueryDataSpaceExecutionContext) {
|
|
116
|
+
request.executionContext = {
|
|
117
|
+
dataSpacePath: execContext.dataSpacePath,
|
|
118
|
+
executionKey: execContext.executionKey,
|
|
119
|
+
};
|
|
120
|
+
} else if (execContext instanceof QueryExplicitExecutionContext) {
|
|
121
|
+
request.executionContext = {
|
|
122
|
+
mapping: execContext.mapping.value.path,
|
|
123
|
+
runtime: execContext.runtime.value.path,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const parameterValues = queryBuilderState.getCurrentParameterValues();
|
|
127
|
+
if (parameterValues && parameterValues.size > 0) {
|
|
128
|
+
request.defaultParameterValues = [];
|
|
129
|
+
for (const [paramName, valueSpec] of parameterValues) {
|
|
130
|
+
const serialized = graphManager.serializeValueSpecification(valueSpec);
|
|
131
|
+
const paramContent =
|
|
132
|
+
await graphManager.valueSpecificationToPureCode(serialized);
|
|
133
|
+
request.defaultParameterValues.push({
|
|
134
|
+
name: paramName,
|
|
135
|
+
content: paramContent,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (name) {
|
|
140
|
+
request.name = name;
|
|
141
|
+
}
|
|
142
|
+
return request;
|
|
143
|
+
};
|
|
104
144
|
|
|
105
145
|
const CreateQueryDialog = observer(() => {
|
|
106
146
|
const editorStore = useQueryEditorStore();
|
|
@@ -117,8 +157,8 @@ const CreateQueryDialog = observer(() => {
|
|
|
117
157
|
const isEmptyName = !createQueryState.queryName;
|
|
118
158
|
const isDescriptionEmptyOrValid =
|
|
119
159
|
!description || /[a-zA-Z0-9]/.test(description);
|
|
120
|
-
const descriptionInputRef = useRef<
|
|
121
|
-
const changeDescription: React.ChangeEventHandler<
|
|
160
|
+
const descriptionInputRef = useRef<HTMLTextAreaElement>(null);
|
|
161
|
+
const changeDescription: React.ChangeEventHandler<HTMLTextAreaElement> = (
|
|
122
162
|
event,
|
|
123
163
|
) => {
|
|
124
164
|
createQueryState.setQueryDescription(event.target.value);
|
|
@@ -143,10 +183,10 @@ const CreateQueryDialog = observer(() => {
|
|
|
143
183
|
setIsSuggestingWithAI(true);
|
|
144
184
|
setAISuggestion(undefined);
|
|
145
185
|
try {
|
|
146
|
-
const
|
|
186
|
+
const request = await buildAISuggestionRequest(
|
|
147
187
|
editorStore.queryBuilderState,
|
|
148
|
-
legendAIUrl,
|
|
149
188
|
);
|
|
189
|
+
const suggestion = await aiSuggester(request, legendAIUrl);
|
|
150
190
|
setAISuggestion(suggestion);
|
|
151
191
|
} finally {
|
|
152
192
|
setIsSuggestingWithAI(false);
|
|
@@ -218,8 +258,7 @@ const CreateQueryDialog = observer(() => {
|
|
|
218
258
|
Enter Query Name
|
|
219
259
|
{aiSuggestion && (
|
|
220
260
|
<span className="query-editor__ai-suggestion-badge">
|
|
221
|
-
<SparkleIcon />
|
|
222
|
-
AI Suggestion
|
|
261
|
+
<SparkleIcon /> <span>AI Suggestion</span>
|
|
223
262
|
</span>
|
|
224
263
|
)}
|
|
225
264
|
</div>
|
|
@@ -252,11 +291,14 @@ const CreateQueryDialog = observer(() => {
|
|
|
252
291
|
<div className="input-section" style={{ marginTop: '1rem' }}>
|
|
253
292
|
<div className="input-label">Enter Query Description</div>
|
|
254
293
|
<div className="input--with-validation">
|
|
255
|
-
<
|
|
294
|
+
<textarea
|
|
256
295
|
ref={descriptionInputRef}
|
|
257
|
-
className={clsx(
|
|
258
|
-
'input--
|
|
259
|
-
|
|
296
|
+
className={clsx(
|
|
297
|
+
'input input--dark query-editor__description__textarea',
|
|
298
|
+
{
|
|
299
|
+
'input--ai-suggested': Boolean(aiSuggestion),
|
|
300
|
+
},
|
|
301
|
+
)}
|
|
260
302
|
spellCheck={true}
|
|
261
303
|
value={
|
|
262
304
|
aiSuggestion
|
|
@@ -288,7 +330,7 @@ const CreateQueryDialog = observer(() => {
|
|
|
288
330
|
) : (
|
|
289
331
|
aiSuggester && (
|
|
290
332
|
<button
|
|
291
|
-
className="btn btn--dark query-editor__ai-suggest-btn"
|
|
333
|
+
className="btn btn--dark modal__footer__btn modal__footer__btn--primary query-editor__ai-suggest-btn"
|
|
292
334
|
onClick={(): void => {
|
|
293
335
|
suggestWithAI().catch(applicationStore.alertUnhandledError);
|
|
294
336
|
}}
|
|
@@ -309,7 +351,8 @@ const CreateQueryDialog = observer(() => {
|
|
|
309
351
|
createQueryState.editorStore.isPerformingBlockingAction ||
|
|
310
352
|
Boolean(isExistingQueryName) ||
|
|
311
353
|
isEmptyName ||
|
|
312
|
-
!isDescriptionEmptyOrValid
|
|
354
|
+
!isDescriptionEmptyOrValid ||
|
|
355
|
+
isSuggestingWithAI
|
|
313
356
|
}
|
|
314
357
|
onClick={create}
|
|
315
358
|
/>
|
|
@@ -431,10 +474,11 @@ const RenameQueryDialog = observer(
|
|
|
431
474
|
setIsSuggestingWithAI(true);
|
|
432
475
|
setAISuggestion(undefined);
|
|
433
476
|
try {
|
|
434
|
-
const
|
|
477
|
+
const request = await buildAISuggestionRequest(
|
|
435
478
|
existingEditorStore.queryBuilderState,
|
|
436
|
-
|
|
479
|
+
existingEditorStore.lightQuery.name,
|
|
437
480
|
);
|
|
481
|
+
const suggestion = await aiSuggester(request, legendAIUrl);
|
|
438
482
|
setAISuggestion(suggestion);
|
|
439
483
|
} finally {
|
|
440
484
|
setIsSuggestingWithAI(false);
|
|
@@ -463,7 +507,7 @@ const RenameQueryDialog = observer(
|
|
|
463
507
|
setQueryRenameName(event.target.value);
|
|
464
508
|
};
|
|
465
509
|
|
|
466
|
-
const changeDescription: React.ChangeEventHandler<
|
|
510
|
+
const changeDescription: React.ChangeEventHandler<HTMLTextAreaElement> = (
|
|
467
511
|
event,
|
|
468
512
|
) => {
|
|
469
513
|
setQueryDescription(event.target.value);
|
|
@@ -523,8 +567,7 @@ const RenameQueryDialog = observer(
|
|
|
523
567
|
Update Query Name
|
|
524
568
|
{aiSuggestion && (
|
|
525
569
|
<span className="query-editor__ai-suggestion-badge">
|
|
526
|
-
<SparkleIcon />
|
|
527
|
-
AI Suggestion
|
|
570
|
+
<SparkleIcon /> <span>AI Suggestion</span>
|
|
528
571
|
</span>
|
|
529
572
|
)}
|
|
530
573
|
</div>
|
|
@@ -555,10 +598,13 @@ const RenameQueryDialog = observer(
|
|
|
555
598
|
<div className="input-section" style={{ marginTop: '1rem' }}>
|
|
556
599
|
<div className="input-label">Update Query Description</div>
|
|
557
600
|
<div className="input--with-validation">
|
|
558
|
-
<
|
|
559
|
-
className={clsx(
|
|
560
|
-
'input--
|
|
561
|
-
|
|
601
|
+
<textarea
|
|
602
|
+
className={clsx(
|
|
603
|
+
'input input--dark query-editor__description__textarea',
|
|
604
|
+
{
|
|
605
|
+
'input--ai-suggested': Boolean(aiSuggestion),
|
|
606
|
+
},
|
|
607
|
+
)}
|
|
562
608
|
spellCheck={true}
|
|
563
609
|
value={
|
|
564
610
|
aiSuggestion ? aiSuggestion.description : queryDescription
|
|
@@ -588,7 +634,7 @@ const RenameQueryDialog = observer(
|
|
|
588
634
|
) : (
|
|
589
635
|
aiSuggester && (
|
|
590
636
|
<button
|
|
591
|
-
className="btn btn--dark query-editor__ai-suggest-btn"
|
|
637
|
+
className="btn btn--dark modal__footer__btn modal__footer__btn--primary query-editor__ai-suggest-btn"
|
|
592
638
|
onClick={(): void => {
|
|
593
639
|
suggestWithAI().catch(applicationStore.alertUnhandledError);
|
|
594
640
|
}}
|
|
@@ -598,7 +644,7 @@ const RenameQueryDialog = observer(
|
|
|
598
644
|
title="Use AI to suggest name and description based on the current query"
|
|
599
645
|
>
|
|
600
646
|
<SparkleIcon />
|
|
601
|
-
<span>
|
|
647
|
+
<span style={{ marginLeft: '0.4rem' }}>
|
|
602
648
|
{isSuggestingWithAI ? 'Suggesting...' : 'Suggest with AI'}
|
|
603
649
|
</span>
|
|
604
650
|
</button>
|
|
@@ -53,9 +53,9 @@ import { TEST__getTestLegendQueryApplicationConfig } from '../../stores/__test-u
|
|
|
53
53
|
import { LegendQueryPluginManager } from '../../application/LegendQueryPluginManager.js';
|
|
54
54
|
import { ExistingQueryEditor } from '../QueryEditor.js';
|
|
55
55
|
import type {
|
|
56
|
+
StoredFileGeneration,
|
|
56
57
|
EntitiesWithOrigin,
|
|
57
58
|
Entity,
|
|
58
|
-
StoredFileGeneration,
|
|
59
59
|
} from '@finos/legend-storage';
|
|
60
60
|
import {
|
|
61
61
|
ExistingQueryEditorStore,
|
|
@@ -84,6 +84,29 @@ export type QueryTitleDescriptionSuggestion = {
|
|
|
84
84
|
description: string;
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
+
export type QueryTitleDescriptionAISuggestionRequest = {
|
|
88
|
+
/**
|
|
89
|
+
* Legend Pure expression (the lambda body).
|
|
90
|
+
*/
|
|
91
|
+
content: string;
|
|
92
|
+
/**
|
|
93
|
+
* Execution context (e.g. { dataSpacePath, executionKey } or { mapping, runtime }).
|
|
94
|
+
*/
|
|
95
|
+
executionContext?: Record<string, string | undefined>;
|
|
96
|
+
/**
|
|
97
|
+
* Default parameter values, each with 'name' and 'content' keys.
|
|
98
|
+
*/
|
|
99
|
+
defaultParameterValues?: { name: string; content: string }[];
|
|
100
|
+
/**
|
|
101
|
+
* LLM model override (uses server default if omitted).
|
|
102
|
+
*/
|
|
103
|
+
model?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Existing query title. If omitted, the LLM generates one.
|
|
106
|
+
*/
|
|
107
|
+
name?: string;
|
|
108
|
+
};
|
|
109
|
+
|
|
87
110
|
export class LegendQueryApplicationPlugin
|
|
88
111
|
extends LegendApplicationPlugin
|
|
89
112
|
implements QueryBuilder_LegendApplicationPlugin_Extension
|
|
@@ -105,12 +128,12 @@ export class LegendQueryApplicationPlugin
|
|
|
105
128
|
|
|
106
129
|
/**
|
|
107
130
|
* Get a function that uses AI to suggest a title and description for the current query.
|
|
108
|
-
* The function receives the
|
|
109
|
-
*
|
|
110
|
-
*
|
|
131
|
+
* The function receives the request payload (Pure expression, execution context,
|
|
132
|
+
* parameter values, etc.) and the Legend AI URL, and should return a promise that
|
|
133
|
+
* resolves to the suggested name and description.
|
|
111
134
|
*/
|
|
112
135
|
getExtraQueryTitleDescriptionAISuggester?(): (
|
|
113
|
-
|
|
136
|
+
request: QueryTitleDescriptionAISuggestionRequest,
|
|
114
137
|
legendAIUrl: string,
|
|
115
138
|
) => Promise<QueryTitleDescriptionSuggestion>;
|
|
116
139
|
}
|
package/tsconfig.json
CHANGED
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"./src/components/CloneQueryServiceSetup.tsx",
|
|
93
93
|
"./src/components/Core_LegendQueryApplicationPlugin.tsx",
|
|
94
94
|
"./src/components/CreateMappingQuerySetup.tsx",
|
|
95
|
+
"./src/components/DataSpaceArtifactInspector.tsx",
|
|
95
96
|
"./src/components/EditExistingQuerySetup.tsx",
|
|
96
97
|
"./src/components/LegendQueryAppInfo.tsx",
|
|
97
98
|
"./src/components/LegendQueryFrameworkProvider.tsx",
|