@finos/legend-query-builder 1.0.6 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 {