@finos/legend-query-builder 1.0.6 → 2.0.1

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 (71) hide show
  1. package/lib/application/QueryBuilderEvent.d.ts +7 -7
  2. package/lib/application/QueryBuilderEvent.d.ts.map +1 -1
  3. package/lib/application/QueryBuilderEvent.js +7 -7
  4. package/lib/application/QueryBuilderEvent.js.map +1 -1
  5. package/lib/components/QueryBuilder.js +1 -1
  6. package/lib/components/QueryBuilder.js.map +1 -1
  7. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  8. package/lib/components/QueryBuilderResultPanel.js +13 -2
  9. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js +2 -2
  11. package/lib/components/fetch-structure/QueryBuilderFetchStructurePanel.js.map +1 -1
  12. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.d.ts +3 -2
  13. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.js +53 -13
  15. package/lib/components/fetch-structure/QueryBuilderGraphFetchTreePanel.js.map +1 -1
  16. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.d.ts.map +1 -1
  17. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +3 -2
  18. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  19. package/lib/graphManager/QueryBuilderSupportedFunctions.d.ts +1 -0
  20. package/lib/graphManager/QueryBuilderSupportedFunctions.d.ts.map +1 -1
  21. package/lib/graphManager/QueryBuilderSupportedFunctions.js +1 -0
  22. package/lib/graphManager/QueryBuilderSupportedFunctions.js.map +1 -1
  23. package/lib/index.css +2 -2
  24. package/lib/index.css.map +1 -1
  25. package/lib/package.json +7 -7
  26. package/lib/stores/QueryBuilderStateBuilder.d.ts +2 -1
  27. package/lib/stores/QueryBuilderStateBuilder.d.ts.map +1 -1
  28. package/lib/stores/QueryBuilderStateBuilder.js +8 -1
  29. package/lib/stores/QueryBuilderStateBuilder.js.map +1 -1
  30. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts +1 -0
  31. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.d.ts.map +1 -1
  32. package/lib/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.js.map +1 -1
  33. package/lib/stores/fetch-structure/QueryBuilderFetchStructureState.d.ts.map +1 -1
  34. package/lib/stores/fetch-structure/QueryBuilderFetchStructureState.js +3 -2
  35. package/lib/stores/fetch-structure/QueryBuilderFetchStructureState.js.map +1 -1
  36. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts +49 -1
  37. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.d.ts.map +1 -1
  38. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js +126 -0
  39. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js.map +1 -1
  40. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.d.ts +1 -0
  41. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.d.ts.map +1 -1
  42. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.js +85 -4
  43. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.js.map +1 -1
  44. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.d.ts +3 -2
  45. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.d.ts.map +1 -1
  46. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.js +96 -14
  47. package/lib/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.js.map +1 -1
  48. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts +1 -0
  49. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
  50. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +6 -0
  51. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
  52. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts +1 -0
  53. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.d.ts.map +1 -1
  54. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js +10 -1
  55. package/lib/stores/fetch-structure/tds/window/QueryBuilderWindowState.js.map +1 -1
  56. package/package.json +14 -14
  57. package/src/application/QueryBuilderEvent.ts +7 -7
  58. package/src/components/QueryBuilder.tsx +1 -1
  59. package/src/components/QueryBuilderResultPanel.tsx +16 -1
  60. package/src/components/fetch-structure/QueryBuilderFetchStructurePanel.tsx +2 -2
  61. package/src/components/fetch-structure/QueryBuilderGraphFetchTreePanel.tsx +240 -5
  62. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +8 -5
  63. package/src/graphManager/QueryBuilderSupportedFunctions.ts +1 -0
  64. package/src/stores/QueryBuilderStateBuilder.ts +20 -0
  65. package/src/stores/fetch-structure/QueryBuilderFetchStructureImplementationState.ts +2 -0
  66. package/src/stores/fetch-structure/QueryBuilderFetchStructureState.ts +3 -2
  67. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.ts +158 -0
  68. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.ts +258 -4
  69. package/src/stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeValueSpecificationBuilder.ts +166 -24
  70. package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +7 -0
  71. package/src/stores/fetch-structure/tds/window/QueryBuilderWindowState.ts +14 -1
@@ -15,12 +15,12 @@
15
15
  */
16
16
 
17
17
  export enum QUERY_BUILDER_EVENT {
18
- RUN_QUERY__LAUNCH = 'editor.execution.run-query.launch',
19
- GENERATE_EXECUTION_PLAN__LAUNCH = 'editor.execution.generate-plan.launch',
20
- DEBUG_EXECUTION_PLAN__LAUNCH = 'editor.execution.debug-plan.launch',
18
+ RUN_QUERY__LAUNCH = 'query-builder.run-query.launch',
19
+ GENERATE_EXECUTION_PLAN__LAUNCH = 'query-builder.generate-plan.launch',
20
+ DEBUG_EXECUTION_PLAN__LAUNCH = 'query-builder.debug-plan.launch',
21
21
 
22
- RUN_QUERY__SUCCESS = 'editor.execution.run-query.success',
23
- GENERATE_EXECUTION_PLAN__SUCCESS = 'editor.execution.generate-plan.success',
24
- DEBUG_EXECUTION_PLAN__SUCCESS = 'editor.execution.debug-plan.success',
25
- BUILD_EXECUTION_PLAN__SUCCESS = 'graph-manager.execution.build-plan.success',
22
+ RUN_QUERY__SUCCESS = 'query-builder.run-query.success',
23
+ GENERATE_EXECUTION_PLAN__SUCCESS = 'query-builder.generate-plan.success',
24
+ DEBUG_EXECUTION_PLAN__SUCCESS = 'query-builder.debug-plan.success',
25
+ BUILD_EXECUTION_PLAN__SUCCESS = 'query-builder.build-plan.success',
26
26
  }
@@ -478,7 +478,7 @@ export const QueryBuilder = observer(
478
478
  ) : null}
479
479
  </MenuContentItemIcon>
480
480
  <MenuContentItemLabel className="query-builder__sub-header__menu-content">
481
- Show Window Funcs
481
+ Show Window Func(s)
482
482
  </MenuContentItemLabel>
483
483
  </MenuContentItem>
484
484
  <MenuContentItem
@@ -481,8 +481,19 @@ export const QueryBuilderResultPanel = observer(
481
481
  });
482
482
  };
483
483
  const queryValidationIssues = queryBuilderState.validationIssues;
484
+ const queryWindowValidationIssues =
485
+ queryBuilderState.fetchStructureState.implementation instanceof
486
+ QueryBuilderTDSState
487
+ ? queryBuilderState.fetchStructureState.implementation.windowState
488
+ .validationIssues
489
+ : undefined;
490
+ const queryWindowStateIsValid = !queryWindowValidationIssues;
491
+
492
+ const isSupportedQueryValid =
493
+ queryBuilderState.validationIssues && queryWindowStateIsValid;
484
494
  const isQueryValid =
485
- !queryBuilderState.isQuerySupported || !queryValidationIssues;
495
+ !queryBuilderState.isQuerySupported || !isSupportedQueryValid;
496
+
486
497
  const runQuery = (): void => {
487
498
  resultState.pressedRunQuery.inProgress();
488
499
  if (queryParametersState.parameterStates.length) {
@@ -614,6 +625,10 @@ export const QueryBuilderResultPanel = observer(
614
625
  ? `Query is not valid:\n${queryValidationIssues
615
626
  .map((issue) => `\u2022 ${issue}`)
616
627
  .join('\n')}`
628
+ : queryWindowValidationIssues
629
+ ? `Query is not valid:\n${queryWindowValidationIssues
630
+ .map((issue) => `\u2022 ${issue}`)
631
+ .join('\n')}`
617
632
  : undefined
618
633
  }
619
634
  disabled={isRunQueryDisabled}
@@ -24,7 +24,7 @@ import {
24
24
  import type { QueryBuilderState } from '../../stores/QueryBuilderState.js';
25
25
  import { prettyCONSTName } from '@finos/legend-shared';
26
26
  import { QueryBuilderTDSPanel } from './QueryBuilderTDSPanel.js';
27
- import { QueryBuilderGraphFetchTreePanel } from './QueryBuilderGraphFetchTreePanel.js';
27
+ import { QueryBuilderGraphFetchPanel } from './QueryBuilderGraphFetchTreePanel.js';
28
28
  import { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
29
29
  import { QueryBuilderGraphFetchTreeState } from '../../stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js';
30
30
  import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
@@ -42,7 +42,7 @@ const QueryBuilderFetchStructureEditor = observer(
42
42
  fetchStructureImplementation instanceof QueryBuilderGraphFetchTreeState
43
43
  ) {
44
44
  return (
45
- <QueryBuilderGraphFetchTreePanel
45
+ <QueryBuilderGraphFetchPanel
46
46
  graphFetchTreeState={fetchStructureImplementation}
47
47
  />
48
48
  );
@@ -29,6 +29,18 @@ import {
29
29
  SquareIcon,
30
30
  InfoCircleIcon,
31
31
  PanelDropZone,
32
+ BlankPanelContent,
33
+ Dialog,
34
+ ModalHeader,
35
+ Modal,
36
+ ModalBody,
37
+ Panel,
38
+ PanelForm,
39
+ PanelFormTextField,
40
+ PanelFormBooleanField,
41
+ ModalFooterButton,
42
+ ModalFooter,
43
+ SerializeIcon,
32
44
  } from '@finos/legend-art';
33
45
  import { QUERY_BUILDER_TEST_ID } from '../../application/QueryBuilderTesting.js';
34
46
  import { isNonNullable } from '@finos/legend-shared';
@@ -42,8 +54,13 @@ import {
42
54
  type QueryBuilderExplorerTreeDragSource,
43
55
  QUERY_BUILDER_EXPLORER_TREE_DND_TYPE,
44
56
  } from '../../stores/explorer/QueryBuilderExplorerState.js';
45
- import type { QueryBuilderGraphFetchTreeState } from '../../stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js';
57
+ import {
58
+ GraphFetchPureSerializationState,
59
+ PureSerializationConfig,
60
+ type QueryBuilderGraphFetchTreeState,
61
+ } from '../../stores/fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeState.js';
46
62
  import { getClassPropertyIcon } from '../shared/ElementIconUtils.js';
63
+ import { QueryBuilderTextEditorMode } from '../../stores/QueryBuilderTextEditorState.js';
47
64
 
48
65
  const QueryBuilderGraphFetchTreeNodeContainer: React.FC<
49
66
  TreeNodeContainerProps<
@@ -134,14 +151,157 @@ const QueryBuilderGraphFetchTreeNodeContainer: React.FC<
134
151
  );
135
152
  };
136
153
 
154
+ const PureSerializationConfigModal = observer(
155
+ (props: {
156
+ pureSerializationState: GraphFetchPureSerializationState;
157
+ graphFetchState: QueryBuilderGraphFetchTreeState;
158
+ config: PureSerializationConfig;
159
+ }) => {
160
+ const { pureSerializationState, graphFetchState, config } = props;
161
+ const applicationStore = graphFetchState.queryBuilderState.applicationStore;
162
+ const toAdd = !pureSerializationState.config;
163
+ const handleAction = (): void => {
164
+ if (toAdd) {
165
+ pureSerializationState.setConfig(config);
166
+ }
167
+ pureSerializationState.setConfigModal(false);
168
+ };
169
+ const removeConfig = (): void => {
170
+ pureSerializationState.setConfig(undefined);
171
+ pureSerializationState.setConfigModal(false);
172
+ graphFetchState.queryBuilderState.applicationStore.notificationService.notifySuccess(
173
+ 'Serialization config removed',
174
+ );
175
+ };
176
+ const close = (): void => pureSerializationState.setConfigModal(false);
177
+ return (
178
+ <Dialog
179
+ open={pureSerializationState.configModal}
180
+ onClose={close}
181
+ classes={{
182
+ root: 'editor-modal__root-container',
183
+ container: 'editor-modal__container',
184
+ paper: 'editor-modal__content',
185
+ }}
186
+ >
187
+ <Modal
188
+ darkMode={
189
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
190
+ }
191
+ className="query-builder-graph-fetch-config"
192
+ >
193
+ <ModalHeader
194
+ title={`${
195
+ toAdd ? 'Add Serialization Config' : 'Edit Serialization Config'
196
+ }`}
197
+ />
198
+ <ModalBody className="query-builder-graph-fetch-config__content">
199
+ <Panel>
200
+ <PanelForm>
201
+ <PanelFormTextField
202
+ name="Type Key Name"
203
+ value={config.typeKeyName}
204
+ isReadOnly={false}
205
+ update={(value: string | undefined): void =>
206
+ config.setTypeName(value ?? '')
207
+ }
208
+ errorMessage={
209
+ config.typeKeyName === ''
210
+ ? `Type key name can't be empty`
211
+ : undefined
212
+ }
213
+ />
214
+ <PanelFormBooleanField
215
+ name="Include Type"
216
+ value={config.includeType}
217
+ isReadOnly={false}
218
+ update={(value: boolean | undefined): void =>
219
+ config.setIncludeType(Boolean(value))
220
+ }
221
+ />
222
+
223
+ <PanelFormBooleanField
224
+ name="Include Enum Type"
225
+ value={config.includeEnumType}
226
+ isReadOnly={false}
227
+ update={(value: boolean | undefined): void =>
228
+ config.setInclueEnumType(Boolean(value))
229
+ }
230
+ />
231
+
232
+ <PanelFormBooleanField
233
+ name="Remove Properties With Null Values"
234
+ value={config.removePropertiesWithNullValues}
235
+ isReadOnly={false}
236
+ update={(value: boolean | undefined): void =>
237
+ config.setRemovePropertiesWithNullValues(Boolean(value))
238
+ }
239
+ />
240
+
241
+ <PanelFormBooleanField
242
+ name="Remove properties with empty sets"
243
+ value={config.removePropertiesWithEmptySets}
244
+ isReadOnly={false}
245
+ update={(value: boolean | undefined): void =>
246
+ config.setRemovePropertiesWithEmptySets(Boolean(value))
247
+ }
248
+ />
249
+
250
+ <PanelFormBooleanField
251
+ name="Use Fully Qualified Type Path"
252
+ value={config.fullyQualifiedTypePath}
253
+ isReadOnly={false}
254
+ update={(value: boolean | undefined): void =>
255
+ config.setFullyQualifiedTypePath(Boolean(value))
256
+ }
257
+ />
258
+ <PanelFormBooleanField
259
+ name="Include Object Reference"
260
+ value={config.includeObjectReference}
261
+ isReadOnly={false}
262
+ update={(value: boolean | undefined): void =>
263
+ config.setIncludeObjectReference(Boolean(value))
264
+ }
265
+ />
266
+ </PanelForm>
267
+ </Panel>
268
+ </ModalBody>
269
+ <ModalFooter>
270
+ {!toAdd && (
271
+ <ModalFooterButton
272
+ className="btn--caution"
273
+ text="Remove Config"
274
+ onClick={removeConfig}
275
+ />
276
+ )}
277
+ <button
278
+ className="btn modal__footer__close-btn btn--dark"
279
+ onClick={handleAction}
280
+ >
281
+ {toAdd ? 'Add Config' : 'Close'}
282
+ </button>
283
+ </ModalFooter>
284
+ </Modal>
285
+ </Dialog>
286
+ );
287
+ },
288
+ );
289
+
137
290
  export const QueryBuilderGraphFetchTreeExplorer = observer(
138
291
  (props: {
139
292
  graphFetchState: QueryBuilderGraphFetchTreeState;
293
+ pureSerializationState: GraphFetchPureSerializationState;
140
294
  treeData: QueryBuilderGraphFetchTreeData;
141
295
  updateTreeData: (data: QueryBuilderGraphFetchTreeData) => void;
142
296
  isReadOnly: boolean;
143
297
  }) => {
144
- const { graphFetchState, treeData, updateTreeData, isReadOnly } = props;
298
+ const {
299
+ graphFetchState,
300
+ pureSerializationState,
301
+ treeData,
302
+ updateTreeData,
303
+ isReadOnly,
304
+ } = props;
145
305
 
146
306
  const onNodeSelect = (node: QueryBuilderGraphFetchTreeNodeData): void => {
147
307
  if (node.childrenIds.length) {
@@ -165,9 +325,30 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
165
325
  const toggleChecked = (): void =>
166
326
  graphFetchState.setChecked(!graphFetchState.isChecked);
167
327
 
328
+ const openConfigModal = (): void => {
329
+ pureSerializationState.setConfigModal(true);
330
+ };
331
+
168
332
  return (
169
333
  <div className="query-builder-graph-fetch-tree">
170
334
  <div className="query-builder-graph-fetch-tree__toolbar">
335
+ <div className="query-builder-graph-fetch-tree__actions">
336
+ <button
337
+ className="query-builder-graph-fetch-tree__actions__action-btn__label"
338
+ onClick={openConfigModal}
339
+ title={`${
340
+ pureSerializationState.config
341
+ ? 'Edit pure serialization config'
342
+ : 'Add pure serialization config'
343
+ }`}
344
+ tabIndex={-1}
345
+ >
346
+ <SerializeIcon className="query-builder-graph-fetch-tree__actions__action-btn__label__icon" />
347
+ <div className="query-builder-graph-fetch-tree__actions__action-btn__label__title">
348
+ {pureSerializationState.config ? 'Edit Config' : 'Add Config'}
349
+ </div>
350
+ </button>
351
+ </div>
171
352
  <div
172
353
  className={clsx('panel__content__form__section__toggler')}
173
354
  onClick={toggleChecked}
@@ -189,6 +370,15 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
189
370
  </div>
190
371
  </div>
191
372
  <div className="query-builder-graph-fetch-tree__container">
373
+ {pureSerializationState.configModal && (
374
+ <PureSerializationConfigModal
375
+ pureSerializationState={pureSerializationState}
376
+ graphFetchState={graphFetchState}
377
+ config={
378
+ pureSerializationState.config ?? new PureSerializationConfig()
379
+ }
380
+ />
381
+ )}
192
382
  <TreeView
193
383
  components={{
194
384
  TreeNodeContainer: QueryBuilderGraphFetchTreeNodeContainer,
@@ -207,9 +397,13 @@ export const QueryBuilderGraphFetchTreeExplorer = observer(
207
397
  },
208
398
  );
209
399
 
210
- export const QueryBuilderGraphFetchTreePanel = observer(
211
- (props: { graphFetchTreeState: QueryBuilderGraphFetchTreeState }) => {
212
- const { graphFetchTreeState } = props;
400
+ const QueryBuilderGraphFetchTreePanel = observer(
401
+ (props: {
402
+ graphFetchTreeState: QueryBuilderGraphFetchTreeState;
403
+
404
+ pureSerializationState: GraphFetchPureSerializationState;
405
+ }) => {
406
+ const { graphFetchTreeState, pureSerializationState } = props;
213
407
  const treeData = graphFetchTreeState.treeData;
214
408
 
215
409
  // Deep/Graph Fetch Tree
@@ -264,6 +458,7 @@ export const QueryBuilderGraphFetchTreePanel = observer(
264
458
  {treeData && !isGraphFetchTreeDataEmpty(treeData) && (
265
459
  <QueryBuilderGraphFetchTreeExplorer
266
460
  graphFetchState={graphFetchTreeState}
461
+ pureSerializationState={pureSerializationState}
267
462
  treeData={treeData}
268
463
  isReadOnly={false}
269
464
  updateTreeData={updateTreeData}
@@ -274,3 +469,43 @@ export const QueryBuilderGraphFetchTreePanel = observer(
274
469
  );
275
470
  },
276
471
  );
472
+
473
+ export const QueryBuilderGraphFetchPanel = observer(
474
+ (props: { graphFetchTreeState: QueryBuilderGraphFetchTreeState }) => {
475
+ const { graphFetchTreeState } = props;
476
+ const serializationState = graphFetchTreeState.serializationState;
477
+ const handleTextModeClick = (): void =>
478
+ graphFetchTreeState.queryBuilderState.textEditorState.openModal(
479
+ QueryBuilderTextEditorMode.TEXT,
480
+ );
481
+ if (serializationState instanceof GraphFetchPureSerializationState) {
482
+ return (
483
+ <QueryBuilderGraphFetchTreePanel
484
+ graphFetchTreeState={graphFetchTreeState}
485
+ pureSerializationState={serializationState}
486
+ />
487
+ );
488
+ }
489
+ return (
490
+ <div
491
+ data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_GRAPH_FETCH}
492
+ className="panel__content"
493
+ >
494
+ <BlankPanelContent>
495
+ <div className="unsupported-element-editor__main">
496
+ <div className="unsupported-element-editor__summary">
497
+ Unsupported Graph Fetch Serialization Type
498
+ </div>
499
+
500
+ <button
501
+ className="btn--dark unsupported-element-editor__to-text-mode__btn"
502
+ onClick={handleTextModeClick}
503
+ >
504
+ Edit in text mode
505
+ </button>
506
+ </div>
507
+ </BlankPanelContent>
508
+ </div>
509
+ );
510
+ },
511
+ );
@@ -63,6 +63,7 @@ import type { QueryBuilderTDSColumnState } from '../../stores/fetch-structure/td
63
63
  import type { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
64
64
  import { COLUMN_SORT_TYPE } from '../../stores/fetch-structure/tds/QueryResultSetModifierState.js';
65
65
  import { QUERY_BUILDER_TEST_ID } from '../../application/QueryBuilderTesting.js';
66
+ import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
66
67
 
67
68
  // helpers
68
69
  const createWindowColumnState = (
@@ -190,7 +191,9 @@ const QueryBuilderWindowColumnModalEditor = observer(
190
191
  const close = (): void => {
191
192
  windowState.setEditColumn(undefined);
192
193
  };
193
- const isDuplicatedColumnName = createNewWindow
194
+ const isDuplicatedColumnName = !windowState.windowColumns.includes(
195
+ windowColumnState,
196
+ )
194
197
  ? windowState.tdsState.tdsColumns
195
198
  .map((c) => c.columnName)
196
199
  .includes(windowColumnState.columnName)
@@ -1167,10 +1170,7 @@ export const QueryBuilderTDSWindowPanel = observer(
1167
1170
  [applicationStore, handleDrop],
1168
1171
  );
1169
1172
  return (
1170
- <div
1171
- data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_WINDOW_GROUPBY}
1172
- className="panel"
1173
- >
1173
+ <div className="panel">
1174
1174
  <div
1175
1175
  data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_WINDOW_GROUPBY}
1176
1176
  className="panel"
@@ -1178,6 +1178,9 @@ export const QueryBuilderTDSWindowPanel = observer(
1178
1178
  <div className="panel__header">
1179
1179
  <div className="panel__header__title">
1180
1180
  <div className="panel__header__title__label">Window Function</div>
1181
+ <QueryBuilderPanelIssueCountBadge
1182
+ issues={tdsWindowState.validationIssues}
1183
+ />
1181
1184
  </div>
1182
1185
  <div className="panel__header__actions">
1183
1186
  <button
@@ -30,6 +30,7 @@ export enum QUERY_BUILDER_SUPPORTED_FUNCTIONS {
30
30
  GRAPH_FETCH = 'meta::pure::graphFetch::execution::graphFetch',
31
31
  GRAPH_FETCH_CHECKED = 'meta::pure::graphFetch::execution::graphFetchChecked',
32
32
  SERIALIZE = 'meta::pure::graphFetch::execution::serialize',
33
+ EXTERNALIZE = 'meta::external::shared::format::functions::externalize',
33
34
 
34
35
  // TDS
35
36
  TDS_FILTER = 'meta::pure::tds::filter',
@@ -32,6 +32,7 @@ import {
32
32
  type InstanceValue,
33
33
  type INTERNAL__UnknownValueSpecification,
34
34
  type LambdaFunction,
35
+ type KeyExpressionInstanceValue,
35
36
  matchFunctionName,
36
37
  Class,
37
38
  type CollectionInstanceValue,
@@ -53,6 +54,7 @@ import {
53
54
  } from './fetch-structure/tds/aggregation/QueryBuilderAggregationStateBuilder.js';
54
55
  import {
55
56
  processGraphFetchExpression,
57
+ processGraphFetchExternalizeExpression,
56
58
  processGraphFetchSerializeExpression,
57
59
  } from './fetch-structure/graph-fetch/QueryBuilderGraphFetchTreeStateBuilder.js';
58
60
  import {
@@ -503,6 +505,18 @@ export class QueryBuilderValueSpecificationProcessor
503
505
  this.parentLambda,
504
506
  );
505
507
  return;
508
+ } else if (
509
+ matchFunctionName(
510
+ functionName,
511
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.EXTERNALIZE,
512
+ )
513
+ ) {
514
+ processGraphFetchExternalizeExpression(
515
+ valueSpecification,
516
+ this.queryBuilderState,
517
+ this.parentLambda,
518
+ );
519
+ return;
506
520
  } else if (
507
521
  matchFunctionName(functionName, [
508
522
  QUERY_BUILDER_SUPPORTED_FUNCTIONS.GRAPH_FETCH_CHECKED,
@@ -563,6 +577,12 @@ export class QueryBuilderValueSpecificationProcessor
563
577
  throw new UnsupportedOperationError();
564
578
  }
565
579
 
580
+ visit_KeyExpressionInstanceValue(
581
+ valueSpecification: KeyExpressionInstanceValue,
582
+ ): void {
583
+ throw new UnsupportedOperationError();
584
+ }
585
+
566
586
  visit_CollectionInstanceValue(
567
587
  valueSpecification: CollectionInstanceValue,
568
588
  ): void {
@@ -55,6 +55,7 @@ export abstract class QueryBuilderFetchStructureImplementationState
55
55
  abstract get type(): string;
56
56
  abstract get usedExplorerTreePropertyNodeIDs(): string[];
57
57
  abstract get validationIssues(): string[] | undefined;
58
+
58
59
  abstract onClassChange(_class: Class | undefined): void;
59
60
  abstract revealCompilationError(compilationError: CompilationError): boolean;
60
61
  abstract clearCompilationError(): void;
@@ -68,6 +69,7 @@ export abstract class QueryBuilderFetchStructureImplementationState
68
69
  lambdaFunction: LambdaFunction,
69
70
  options?: LambdaFunctionBuilderOption,
70
71
  ): void;
72
+ abstract initialize(): void;
71
73
  abstract get hashCode(): string;
72
74
 
73
75
  get TEMPORARY__showPostFetchStructurePanel(): boolean {
@@ -59,20 +59,21 @@ export class QueryBuilderFetchStructureState {
59
59
  this.queryBuilderState,
60
60
  this,
61
61
  );
62
- return;
62
+ break;
63
63
  }
64
64
  case FETCH_STRUCTURE_IMPLEMENTATION.GRAPH_FETCH: {
65
65
  this.implementation = new QueryBuilderGraphFetchTreeState(
66
66
  this.queryBuilderState,
67
67
  this,
68
68
  );
69
- return;
69
+ break;
70
70
  }
71
71
  default:
72
72
  throw new UnsupportedOperationError(
73
73
  `Can't change fetch-structure implementation to unsupported type: '${type}'`,
74
74
  );
75
75
  }
76
+ this.implementation.initialize();
76
77
  }
77
78
 
78
79
  fetchProperty(node: QueryBuilderExplorerTreeNodeData): void {