@finos/legend-query-builder 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts +20 -20
  2. package/lib/__lib__/QueryBuilderTelemetryHelper.d.ts.map +1 -1
  3. package/lib/__lib__/QueryBuilderTelemetryHelper.js +40 -40
  4. package/lib/__lib__/QueryBuilderTelemetryHelper.js.map +1 -1
  5. package/lib/components/QueryLoader.d.ts +30 -0
  6. package/lib/components/QueryLoader.d.ts.map +1 -0
  7. package/lib/components/QueryLoader.js +160 -0
  8. package/lib/components/QueryLoader.js.map +1 -0
  9. package/lib/components/shared/QueryBuilderPanelIssueCountBadge.d.ts.map +1 -1
  10. package/lib/components/shared/QueryBuilderPanelIssueCountBadge.js +2 -1
  11. package/lib/components/shared/QueryBuilderPanelIssueCountBadge.js.map +1 -1
  12. package/lib/index.css +2 -2
  13. package/lib/index.css.map +1 -1
  14. package/lib/index.d.ts +3 -0
  15. package/lib/index.d.ts.map +1 -1
  16. package/lib/index.js +3 -0
  17. package/lib/index.js.map +1 -1
  18. package/lib/package.json +1 -1
  19. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts +30 -0
  20. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.d.ts.map +1 -0
  21. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.js +17 -0
  22. package/lib/stores/QueryBuilder_LegendApplicationPlugin_Extension.js.map +1 -0
  23. package/lib/stores/QueryLoaderState.d.ts +67 -0
  24. package/lib/stores/QueryLoaderState.d.ts.map +1 -0
  25. package/lib/stores/QueryLoaderState.js +205 -0
  26. package/lib/stores/QueryLoaderState.js.map +1 -0
  27. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +3 -1
  28. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  29. package/lib/stores/shared/ValueSpecificationEditorHelper.js +7 -1
  30. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  31. package/package.json +8 -8
  32. package/src/__lib__/QueryBuilderTelemetryHelper.ts +40 -59
  33. package/src/components/QueryLoader.tsx +501 -0
  34. package/src/components/shared/QueryBuilderPanelIssueCountBadge.tsx +2 -1
  35. package/src/index.ts +3 -0
  36. package/src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts +36 -0
  37. package/src/stores/QueryLoaderState.ts +298 -0
  38. package/src/stores/shared/ValueSpecificationEditorHelper.ts +39 -2
  39. package/tsconfig.json +3 -0
@@ -0,0 +1,298 @@
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 {
18
+ DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH,
19
+ type GenericLegendApplicationStore,
20
+ } from '@finos/legend-application';
21
+ import {
22
+ type LightQuery,
23
+ QuerySearchSpecification,
24
+ type QueryInfo,
25
+ type BasicGraphManagerState,
26
+ type Query,
27
+ } from '@finos/legend-graph';
28
+ import {
29
+ ActionState,
30
+ type GeneratorFn,
31
+ assertErrorThrown,
32
+ guaranteeNonNullable,
33
+ } from '@finos/legend-shared';
34
+ import { makeObservable, observable, action, flow } from 'mobx';
35
+ import type { QueryBuilderState } from './QueryBuilderState.js';
36
+ import type {
37
+ LoadQueryFilterOption,
38
+ QueryBuilder_LegendApplicationPlugin_Extension,
39
+ } from './QueryBuilder_LegendApplicationPlugin_Extension.js';
40
+
41
+ export const QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT = 20;
42
+
43
+ export class QueryLoaderState {
44
+ readonly applicationStore: GenericLegendApplicationStore;
45
+ readonly graphManagerState: BasicGraphManagerState;
46
+
47
+ readonly searchQueriesState = ActionState.create();
48
+ readonly renameQueryState = ActionState.create();
49
+ readonly deleteQueryState = ActionState.create();
50
+ readonly previewQueryState = ActionState.create();
51
+
52
+ readonly decorateSearchSpecification?:
53
+ | ((val: QuerySearchSpecification) => QuerySearchSpecification)
54
+ | undefined;
55
+
56
+ readonly loadQuery: (query: LightQuery) => void;
57
+ readonly fetchDefaultQueries?: (() => Promise<LightQuery[]>) | undefined;
58
+ readonly generateDefaultQueriesSummaryText?:
59
+ | ((queries: LightQuery[]) => string)
60
+ | undefined;
61
+
62
+ readonly isReadOnly?: boolean | undefined;
63
+ readonly onQueryRenamed?: ((query: LightQuery) => void) | undefined;
64
+ readonly onQueryDeleted?: ((query: LightQuery) => void) | undefined;
65
+
66
+ queryBuilderState?: QueryBuilderState | undefined;
67
+
68
+ searchText = '';
69
+ showCurrentUserQueriesOnly = false; // TODO: if we start having more native filters, we should make them part of `extraFilters`
70
+ extraFilters = new Map<string, boolean>();
71
+ extraFilterOptions: LoadQueryFilterOption[] = [];
72
+ queries: LightQuery[] = [];
73
+
74
+ isQueryLoaderDialogOpen = false;
75
+ showingDefaultQueries = true;
76
+ showPreviewViewer = false;
77
+ queryPreviewContent?: QueryInfo;
78
+
79
+ constructor(
80
+ applicationStore: GenericLegendApplicationStore,
81
+ graphManagerState: BasicGraphManagerState,
82
+ options: {
83
+ decorateSearchSpecification?:
84
+ | ((val: QuerySearchSpecification) => QuerySearchSpecification)
85
+ | undefined;
86
+
87
+ loadQuery: (query: LightQuery) => void;
88
+ fetchDefaultQueries?: (() => Promise<LightQuery[]>) | undefined;
89
+ generateDefaultQueriesSummaryText?:
90
+ | ((queries: LightQuery[]) => string)
91
+ | undefined;
92
+
93
+ isReadOnly?: boolean | undefined;
94
+ onQueryRenamed?: ((query: LightQuery) => void) | undefined;
95
+ onQueryDeleted?: ((query: LightQuery) => void) | undefined;
96
+ },
97
+ ) {
98
+ makeObservable(this, {
99
+ isQueryLoaderDialogOpen: observable,
100
+ queryPreviewContent: observable,
101
+ showingDefaultQueries: observable,
102
+ queries: observable,
103
+ showCurrentUserQueriesOnly: observable,
104
+ showPreviewViewer: observable,
105
+ searchText: observable,
106
+ setSearchText: action,
107
+ setQueryLoaderDialogOpen: action,
108
+ setQueries: action,
109
+ setShowCurrentUserQueriesOnly: action,
110
+ setShowPreviewViewer: action,
111
+ searchQueries: flow,
112
+ getPreviewQueryContent: flow,
113
+ deleteQuery: flow,
114
+ renameQuery: flow,
115
+ initialize: flow,
116
+ });
117
+
118
+ this.applicationStore = applicationStore;
119
+ this.graphManagerState = graphManagerState;
120
+
121
+ this.loadQuery = options.loadQuery;
122
+ this.fetchDefaultQueries = options.fetchDefaultQueries;
123
+ this.generateDefaultQueriesSummaryText =
124
+ options.generateDefaultQueriesSummaryText;
125
+ this.decorateSearchSpecification = options.decorateSearchSpecification;
126
+ this.isReadOnly = options.isReadOnly;
127
+ this.onQueryRenamed = options.onQueryRenamed;
128
+ this.onQueryDeleted = options.onQueryDeleted;
129
+ }
130
+
131
+ setSearchText(val: string): void {
132
+ this.searchText = val;
133
+ }
134
+
135
+ setQueryLoaderDialogOpen(val: boolean): void {
136
+ this.isQueryLoaderDialogOpen = val;
137
+ }
138
+
139
+ setQueries(val: LightQuery[]): void {
140
+ this.queries = val;
141
+ }
142
+
143
+ setShowPreviewViewer(val: boolean): void {
144
+ this.showPreviewViewer = val;
145
+ }
146
+
147
+ setShowCurrentUserQueriesOnly(val: boolean): void {
148
+ this.showCurrentUserQueriesOnly = val;
149
+ }
150
+
151
+ reset(): void {
152
+ this.setShowCurrentUserQueriesOnly(false);
153
+ }
154
+
155
+ *initialize(queryBuilderState: QueryBuilderState): GeneratorFn<void> {
156
+ this.queryBuilderState = queryBuilderState;
157
+ this.extraFilterOptions = this.applicationStore.pluginManager
158
+ .getApplicationPlugins()
159
+ .flatMap(
160
+ (plugin) =>
161
+ (
162
+ plugin as QueryBuilder_LegendApplicationPlugin_Extension
163
+ ).getExtraLoadQueryFilterOptions?.() ?? [],
164
+ );
165
+ const extraFilters = this.extraFilterOptions.map((filterOption) =>
166
+ filterOption.label(guaranteeNonNullable(this.queryBuilderState)),
167
+ );
168
+ extraFilters.forEach(
169
+ (filter) => filter && this.extraFilters.set(filter, false),
170
+ );
171
+ }
172
+
173
+ *searchQueries(searchText: string): GeneratorFn<void> {
174
+ if (
175
+ searchText.length < DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH &&
176
+ !this.showCurrentUserQueriesOnly &&
177
+ Array.from(this.extraFilters.values()).every((value) => value === false)
178
+ ) {
179
+ // if no search text is specified, use fetch the default queries
180
+ if (!searchText) {
181
+ this.showingDefaultQueries = true;
182
+ this.searchQueriesState.inProgress();
183
+ this.queries = [];
184
+ try {
185
+ if (!this.fetchDefaultQueries) {
186
+ return;
187
+ }
188
+ this.queries = (yield this.fetchDefaultQueries()) as LightQuery[];
189
+ this.searchQueriesState.pass();
190
+ } catch (error) {
191
+ this.searchQueriesState.fail();
192
+ assertErrorThrown(error);
193
+ this.applicationStore.notificationService.notifyError(error);
194
+ }
195
+ }
196
+
197
+ // skip otherwise
198
+ return;
199
+ }
200
+
201
+ // search using the search term
202
+ this.showingDefaultQueries = false;
203
+ this.searchQueriesState.inProgress();
204
+ try {
205
+ let searchSpecification = new QuerySearchSpecification();
206
+ searchSpecification.searchTerm = searchText;
207
+ searchSpecification.limit = QUERY_LOADER_TYPEAHEAD_SEARCH_LIMIT + 1;
208
+ searchSpecification.showCurrentUserQueriesOnly =
209
+ this.showCurrentUserQueriesOnly;
210
+ if (this.queryBuilderState) {
211
+ Array.from(this.extraFilters.entries()).forEach(([key, value]) => {
212
+ if (value) {
213
+ const filterOption = this.extraFilterOptions.find(
214
+ (option) =>
215
+ option.label(guaranteeNonNullable(this.queryBuilderState)) ===
216
+ key,
217
+ );
218
+ if (filterOption) {
219
+ searchSpecification = filterOption.filterFunction(
220
+ searchSpecification,
221
+ guaranteeNonNullable(this.queryBuilderState),
222
+ );
223
+ }
224
+ }
225
+ });
226
+ }
227
+ searchSpecification =
228
+ this.decorateSearchSpecification?.(searchSpecification) ??
229
+ searchSpecification;
230
+ this.queries = (yield this.graphManagerState.graphManager.searchQueries(
231
+ searchSpecification,
232
+ )) as LightQuery[];
233
+ this.searchQueriesState.pass();
234
+ } catch (error) {
235
+ assertErrorThrown(error);
236
+ this.applicationStore.notificationService.notifyError(error);
237
+ this.searchQueriesState.fail();
238
+ }
239
+ }
240
+
241
+ *renameQuery(queryId: string, name: string): GeneratorFn<void> {
242
+ this.renameQueryState.inProgress();
243
+ try {
244
+ const query = (yield this.graphManagerState.graphManager.renameQuery(
245
+ queryId,
246
+ name,
247
+ )) as Query;
248
+ this.onQueryRenamed?.(query);
249
+ this.applicationStore.notificationService.notify(
250
+ 'Renamed query successfully',
251
+ );
252
+ this.renameQueryState.pass();
253
+ this.searchQueries(this.searchText); // trigger a search to refresh the query list
254
+ } catch (error) {
255
+ assertErrorThrown(error);
256
+ this.applicationStore.notificationService.notifyError(error);
257
+ this.renameQueryState.fail();
258
+ }
259
+ }
260
+
261
+ *deleteQuery(queryId: string): GeneratorFn<void> {
262
+ this.deleteQueryState.inProgress();
263
+ try {
264
+ const query = (yield this.graphManagerState.graphManager.deleteQuery(
265
+ queryId,
266
+ )) as Query;
267
+ this.onQueryDeleted?.(query);
268
+ this.applicationStore.notificationService.notify(
269
+ 'Deleted query successfully',
270
+ );
271
+ this.deleteQueryState.pass();
272
+ this.searchQueries(this.searchText); // trigger a search to refresh the query list
273
+ } catch (error) {
274
+ assertErrorThrown(error);
275
+ this.applicationStore.notificationService.notifyError(error);
276
+ this.deleteQueryState.fail();
277
+ }
278
+ }
279
+
280
+ *getPreviewQueryContent(queryId: string): GeneratorFn<void> {
281
+ this.previewQueryState.inProgress();
282
+ try {
283
+ const queryInfo = (yield this.graphManagerState.graphManager.getQueryInfo(
284
+ queryId,
285
+ )) as QueryInfo;
286
+ this.queryPreviewContent = queryInfo;
287
+ this.queryPreviewContent.content =
288
+ (yield this.graphManagerState.graphManager.prettyLambdaContent(
289
+ queryInfo.content,
290
+ )) as string;
291
+ this.previewQueryState.pass();
292
+ } catch (error) {
293
+ assertErrorThrown(error);
294
+ this.applicationStore.notificationService.notifyError(error);
295
+ this.previewQueryState.fail();
296
+ }
297
+ }
298
+ }
@@ -16,10 +16,13 @@
16
16
 
17
17
  import {
18
18
  type PureModel,
19
- VariableExpression,
19
+ type GraphManagerState,
20
20
  type ValueSpecification,
21
21
  type Type,
22
22
  type Enum,
23
+ type ObserverContext,
24
+ type RawLambda,
25
+ VariableExpression,
23
26
  CollectionInstanceValue,
24
27
  Enumeration,
25
28
  EnumValueExplicitReference,
@@ -32,7 +35,12 @@ import {
32
35
  PRIMITIVE_TYPE,
33
36
  INTERNAL__PropagatedValue,
34
37
  SimpleFunctionExpression,
35
- type ObserverContext,
38
+ LambdaFunction,
39
+ FunctionType,
40
+ PackageableElementExplicitReference,
41
+ Multiplicity,
42
+ CORE_PURE_PATH,
43
+ buildRawLambdaFromLambdaFunction,
36
44
  } from '@finos/legend-graph';
37
45
  import { Randomizer, UnsupportedOperationError } from '@finos/legend-shared';
38
46
  import { generateDefaultValueForPrimitiveType } from '../QueryBuilderValueSpecificationHelper.js';
@@ -177,6 +185,35 @@ export const buildDefaultInstanceValue = (
177
185
  }
178
186
  };
179
187
 
188
+ export const buildDefaultEmptyStringLambda = (
189
+ graph: PureModel,
190
+ observerContext: ObserverContext,
191
+ ): LambdaFunction => {
192
+ const lambdaFunction = new LambdaFunction(
193
+ new FunctionType(
194
+ PackageableElementExplicitReference.create(
195
+ graph.getType(CORE_PURE_PATH.ANY),
196
+ ),
197
+ Multiplicity.ONE,
198
+ ),
199
+ );
200
+ lambdaFunction.expressionSequence[0] = buildDefaultInstanceValue(
201
+ graph,
202
+ PrimitiveType.STRING,
203
+ observerContext,
204
+ );
205
+ return lambdaFunction;
206
+ };
207
+
208
+ export const buildDefaultEmptyStringRawLambda = (
209
+ graphState: GraphManagerState,
210
+ observerContext: ObserverContext,
211
+ ): RawLambda =>
212
+ buildRawLambdaFromLambdaFunction(
213
+ buildDefaultEmptyStringLambda(graphState.graph, observerContext),
214
+ graphState,
215
+ );
216
+
180
217
  export const generateVariableExpressionMockValue = (
181
218
  parameter: VariableExpression,
182
219
  graph: PureModel,
package/tsconfig.json CHANGED
@@ -71,6 +71,8 @@
71
71
  "./src/stores/QueryBuilderValueSpecificationBuilder.ts",
72
72
  "./src/stores/QueryBuilderValueSpecificationBuilderHelper.ts",
73
73
  "./src/stores/QueryBuilderValueSpecificationHelper.ts",
74
+ "./src/stores/QueryBuilder_LegendApplicationPlugin_Extension.ts",
75
+ "./src/stores/QueryLoaderState.ts",
74
76
  "./src/stores/ServiceInfo.ts",
75
77
  "./src/stores/__test-utils__/QueryBuilderStateTestUtils.ts",
76
78
  "./src/stores/entitlements/QueryBuilderCheckEntitlementsState.ts",
@@ -213,6 +215,7 @@
213
215
  "./src/components/QueryBuilderSideBar.tsx",
214
216
  "./src/components/QueryBuilderTextEditor.tsx",
215
217
  "./src/components/QueryBuilderUnsupportedQueryEditor.tsx",
218
+ "./src/components/QueryLoader.tsx",
216
219
  "./src/components/ServiceQuerySetupUtils.tsx",
217
220
  "./src/components/__test-utils__/QueryBuilderComponentTestUtils.tsx",
218
221
  "./src/components/execution-plan/ExecutionPlanViewer.tsx",