@finos/legend-query-builder 4.0.11 → 4.0.13

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 (33) hide show
  1. package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
  2. package/lib/components/QueryBuilderResultPanel.js +14 -14
  3. package/lib/components/QueryBuilderResultPanel.js.map +1 -1
  4. package/lib/components/data-access/DataAccessOverview.d.ts.map +1 -1
  5. package/lib/components/data-access/DataAccessOverview.js +7 -3
  6. package/lib/components/data-access/DataAccessOverview.js.map +1 -1
  7. package/lib/components/execution-plan/SQLExecutionNodeViewer.d.ts.map +1 -1
  8. package/lib/components/execution-plan/SQLExecutionNodeViewer.js +2 -1
  9. package/lib/components/execution-plan/SQLExecutionNodeViewer.js.map +1 -1
  10. package/lib/components/explorer/QueryBuilderMilestoningEditor.d.ts.map +1 -1
  11. package/lib/components/explorer/QueryBuilderMilestoningEditor.js +1 -1
  12. package/lib/components/explorer/QueryBuilderMilestoningEditor.js.map +1 -1
  13. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +1 -1
  15. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  16. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js +1 -1
  17. package/lib/components/fetch-structure/QueryBuilderTDSWindowPanel.js.map +1 -1
  18. package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
  19. package/lib/components/shared/BasicValueSpecificationEditor.js +5 -4
  20. package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
  21. package/lib/index.css +17 -1
  22. package/lib/index.css.map +1 -1
  23. package/lib/package.json +6 -6
  24. package/lib/stores/QueryBuilderResultState.js +1 -1
  25. package/package.json +14 -14
  26. package/src/components/QueryBuilderResultPanel.tsx +69 -66
  27. package/src/components/data-access/DataAccessOverview.tsx +16 -2
  28. package/src/components/execution-plan/SQLExecutionNodeViewer.tsx +10 -3
  29. package/src/components/explorer/QueryBuilderMilestoningEditor.tsx +5 -3
  30. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +1 -2
  31. package/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx +2 -2
  32. package/src/components/shared/BasicValueSpecificationEditor.tsx +11 -7
  33. package/src/stores/QueryBuilderResultState.ts +1 -1
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-query-builder",
3
- "version": "4.0.11",
3
+ "version": "4.0.13",
4
4
  "description": "Legend query builder core",
5
5
  "keywords": [
6
6
  "legend",
@@ -50,8 +50,8 @@
50
50
  "@finos/legend-shared": "workspace:*",
51
51
  "@finos/legend-storage": "workspace:*",
52
52
  "@testing-library/react": "14.0.0",
53
- "@types/react": "18.2.12",
54
- "@types/react-dom": "18.2.5",
53
+ "@types/react": "18.2.13",
54
+ "@types/react-dom": "18.2.6",
55
55
  "chart.js": "4.3.0",
56
56
  "mathjs": "11.8.1",
57
57
  "mobx": "6.9.0",
@@ -62,17 +62,17 @@
62
62
  "react-dnd": "16.0.1",
63
63
  "react-dom": "18.2.0",
64
64
  "serializr": "3.0.2",
65
- "sql-formatter": "12.2.2"
65
+ "sql-formatter": "12.2.3"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@finos/legend-dev-utils": "workspace:*",
69
69
  "@jest/globals": "29.5.0",
70
70
  "cross-env": "7.0.3",
71
- "eslint": "8.42.0",
71
+ "eslint": "8.43.0",
72
72
  "jest": "29.5.0",
73
73
  "npm-run-all": "4.1.5",
74
74
  "rimraf": "5.0.1",
75
- "sass": "1.63.3",
75
+ "sass": "1.63.4",
76
76
  "typescript": "5.1.3"
77
77
  },
78
78
  "peerDependencies": {
@@ -200,7 +200,7 @@ export class QueryBuilderResultState {
200
200
  }
201
201
  }
202
202
  catch (error) {
203
- // When user cancels the query by calling the cancelQuery api, it will throw an exeuction failure error.
203
+ // When user cancels the query by calling the cancelQuery api, it will throw an execution failure error.
204
204
  // For now, we don't want to notify users about this failure. Therefore we check to ensure the promise is still the same one.
205
205
  // When cancelled the query, we set the queryRunPromise as undefined.
206
206
  if (this.queryRunPromise === promise) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-query-builder",
3
- "version": "4.0.11",
3
+ "version": "4.0.13",
4
4
  "description": "Legend query builder core",
5
5
  "keywords": [
6
6
  "legend",
@@ -42,16 +42,16 @@
42
42
  "test:watch": "jest --watch"
43
43
  },
44
44
  "dependencies": {
45
- "@finos/legend-application": "15.0.22",
46
- "@finos/legend-art": "7.0.22",
47
- "@finos/legend-graph": "30.0.7",
48
- "@finos/legend-lego": "1.0.20",
49
- "@finos/legend-server-depot": "6.0.14",
50
- "@finos/legend-shared": "10.0.13",
51
- "@finos/legend-storage": "3.0.63",
45
+ "@finos/legend-application": "15.0.24",
46
+ "@finos/legend-art": "7.0.24",
47
+ "@finos/legend-graph": "30.0.9",
48
+ "@finos/legend-lego": "1.1.0",
49
+ "@finos/legend-server-depot": "6.0.16",
50
+ "@finos/legend-shared": "10.0.15",
51
+ "@finos/legend-storage": "3.0.65",
52
52
  "@testing-library/react": "14.0.0",
53
- "@types/react": "18.2.12",
54
- "@types/react-dom": "18.2.5",
53
+ "@types/react": "18.2.13",
54
+ "@types/react-dom": "18.2.6",
55
55
  "chart.js": "4.3.0",
56
56
  "mathjs": "11.8.1",
57
57
  "mobx": "6.9.0",
@@ -62,17 +62,17 @@
62
62
  "react-dnd": "16.0.1",
63
63
  "react-dom": "18.2.0",
64
64
  "serializr": "3.0.2",
65
- "sql-formatter": "12.2.2"
65
+ "sql-formatter": "12.2.3"
66
66
  },
67
67
  "devDependencies": {
68
- "@finos/legend-dev-utils": "2.0.67",
68
+ "@finos/legend-dev-utils": "2.0.69",
69
69
  "@jest/globals": "29.5.0",
70
70
  "cross-env": "7.0.3",
71
- "eslint": "8.42.0",
71
+ "eslint": "8.43.0",
72
72
  "jest": "29.5.0",
73
73
  "npm-run-all": "4.1.5",
74
74
  "rimraf": "5.0.1",
75
- "sass": "1.63.3",
75
+ "sass": "1.63.4",
76
76
  "typescript": "5.1.3"
77
77
  },
78
78
  "peerDependencies": {
@@ -126,11 +126,11 @@ const QueryBuilderGridResultContextMenu = observer(
126
126
  forwardRef<
127
127
  HTMLDivElement,
128
128
  {
129
- event: QueryBuilderTDSResultCellData | null;
129
+ data: QueryBuilderTDSResultCellData | null;
130
130
  tdsState: QueryBuilderTDSState;
131
131
  }
132
132
  >(function QueryBuilderResultContextMenu(props, ref) {
133
- const { event, tdsState } = props;
133
+ const { data, tdsState } = props;
134
134
  const applicationStore = useApplicationStore();
135
135
  const postFilterEqualOperator = new QueryBuilderPostFilterOperator_Equal();
136
136
  const postFilterInOperator = new QueryBuilderPostFilterOperator_In();
@@ -145,10 +145,10 @@ const QueryBuilderGridResultContextMenu = observer(
145
145
  const postFilterState = tdsState.postFilterState;
146
146
 
147
147
  const projectionColumnState = tdsState.projectionColumns
148
- .filter((c) => c.columnName === event?.columnName)
148
+ .filter((c) => c.columnName === data?.columnName)
149
149
  .concat(
150
150
  tdsState.aggregationState.columns
151
- .filter((c) => c.columnName === event?.columnName)
151
+ .filter((c) => c.columnName === data?.columnName)
152
152
  .map((ag) => ag.projectionColumnState),
153
153
  )[0];
154
154
  const getExistingPostFilterNode = (
@@ -319,7 +319,7 @@ const QueryBuilderGridResultContextMenu = observer(
319
319
  : (v as InstanceValue).values,
320
320
  )
321
321
  .flat()
322
- .includes(cellData.value ?? event?.value);
322
+ .includes(cellData.value ?? data?.value);
323
323
 
324
324
  if (!doesValueAlreadyExist) {
325
325
  const newValueSpecification = (
@@ -399,7 +399,7 @@ const QueryBuilderGridResultContextMenu = observer(
399
399
 
400
400
  const handleCopyCellValue = applicationStore.guardUnhandledError(() =>
401
401
  applicationStore.clipboardService.copyTextToClipboard(
402
- event?.value?.toString() ?? '',
402
+ data?.value?.toString() ?? '',
403
403
  ),
404
404
  );
405
405
 
@@ -597,7 +597,7 @@ const QueryResultCellRenderer = observer(
597
597
  // NOTE: we only support this functionality for grid result with a projection fetch-structure
598
598
  fetchStructureImplementation instanceof QueryBuilderTDSState ? (
599
599
  <QueryBuilderGridResultContextMenu
600
- event={resultState.mousedOverCell}
600
+ data={resultState.mousedOverCell}
601
601
  tdsState={fetchStructureImplementation}
602
602
  />
603
603
  ) : null
@@ -960,70 +960,73 @@ export const QueryBuilderResultPanel = observer(
960
960
  />
961
961
  </div>
962
962
  )}
963
- {resultState.isRunningQuery ? (
964
- <button
965
- className="query-builder__result__stop-btn"
966
- onClick={cancelQuery}
967
- tabIndex={-1}
968
- disabled={!isQueryValid}
969
- >
970
- <div className="btn--dark btn--caution query-builder__result__stop-btn__label">
971
- <PauseCircleIcon className="query-builder__result__stop-btn__label__icon" />
972
- <div className="query-builder__result__stop-btn__label__title">
973
- Stop
974
- </div>
975
- </div>
976
- </button>
977
- ) : (
978
- <div className="query-builder__result__execute-btn">
963
+
964
+ <div className="query-builder__result__execute-btn btn__dropdown-combo btn__dropdown-combo--primary">
965
+ {resultState.isRunningQuery ? (
979
966
  <button
980
- className="query-builder__result__execute-btn__label"
981
- onClick={runQuery}
967
+ className="btn__dropdown-combo__canceler"
968
+ onClick={cancelQuery}
982
969
  tabIndex={-1}
983
- title={
984
- allValidationIssues.length
985
- ? `Query is not valid:\n${allValidationIssues
986
- .map((issue) => `\u2022 ${issue}`)
987
- .join('\n')}`
988
- : undefined
989
- }
990
- disabled={isRunQueryDisabled}
970
+ disabled={!isQueryValid}
991
971
  >
992
- <PlayIcon className="query-builder__result__execute-btn__label__icon" />
993
- <div className="query-builder__result__execute-btn__label__title">
994
- Run Query
972
+ <div className="btn--dark btn--caution btn__dropdown-combo__canceler__label">
973
+ <PauseCircleIcon className="btn__dropdown-combo__canceler__label__icon" />
974
+ <div className="btn__dropdown-combo__canceler__label__title">
975
+ Stop
976
+ </div>
995
977
  </div>
996
978
  </button>
997
- <DropdownMenu
998
- className="query-builder__result__execute-btn__dropdown-btn"
999
- disabled={isRunQueryDisabled}
1000
- content={
1001
- <MenuContent>
1002
- <MenuContentItem
1003
- className="query-builder__result__execute-btn__option"
1004
- onClick={generatePlan}
1005
- disabled={isRunQueryDisabled}
1006
- >
1007
- Generate Plan
1008
- </MenuContentItem>
1009
- <MenuContentItem
1010
- className="query-builder__result__execute-btn__option"
1011
- onClick={debugPlanGeneration}
1012
- disabled={isRunQueryDisabled}
1013
- >
1014
- Debug
1015
- </MenuContentItem>
1016
- </MenuContent>
1017
- }
1018
- menuProps={{
1019
- anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
1020
- transformOrigin: { vertical: 'top', horizontal: 'right' },
1021
- }}
1022
- >
1023
- <CaretDownIcon />
1024
- </DropdownMenu>
1025
- </div>
1026
- )}
979
+ ) : (
980
+ <>
981
+ <button
982
+ className="btn__dropdown-combo__label"
983
+ onClick={runQuery}
984
+ tabIndex={-1}
985
+ title={
986
+ allValidationIssues.length
987
+ ? `Query is not valid:\n${allValidationIssues
988
+ .map((issue) => `\u2022 ${issue}`)
989
+ .join('\n')}`
990
+ : undefined
991
+ }
992
+ disabled={isRunQueryDisabled}
993
+ >
994
+ <PlayIcon className="btn__dropdown-combo__label__icon" />
995
+ <div className="btn__dropdown-combo__label__title">
996
+ Run Query
997
+ </div>
998
+ </button>
999
+ <DropdownMenu
1000
+ className="btn__dropdown-combo__dropdown-btn"
1001
+ disabled={isRunQueryDisabled}
1002
+ content={
1003
+ <MenuContent>
1004
+ <MenuContentItem
1005
+ className="btn__dropdown-combo__option"
1006
+ onClick={generatePlan}
1007
+ disabled={isRunQueryDisabled}
1008
+ >
1009
+ Generate Plan
1010
+ </MenuContentItem>
1011
+ <MenuContentItem
1012
+ className="btn__dropdown-combo__option"
1013
+ onClick={debugPlanGeneration}
1014
+ disabled={isRunQueryDisabled}
1015
+ >
1016
+ Debug
1017
+ </MenuContentItem>
1018
+ </MenuContent>
1019
+ }
1020
+ menuProps={{
1021
+ anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
1022
+ transformOrigin: { vertical: 'top', horizontal: 'right' },
1023
+ }}
1024
+ >
1025
+ <CaretDownIcon />
1026
+ </DropdownMenu>
1027
+ </>
1028
+ )}
1029
+ </div>
1027
1030
  <DropdownMenu
1028
1031
  className="query-builder__result__export__dropdown"
1029
1032
  title="Export"
@@ -72,6 +72,17 @@ const DataAccessOverviewChart = observer(
72
72
  <RefreshIcon />
73
73
  </button>
74
74
  </div>
75
+ {Boolean(
76
+ dataAccessState.datasets.find(
77
+ (dataset) =>
78
+ dataset.entitlementReport instanceof
79
+ DatasetEntitlementUnsupportedReport,
80
+ ),
81
+ ) && (
82
+ <div className="data-access-overview__chart__warning">
83
+ Use case is not fully supported!
84
+ </div>
85
+ )}
75
86
  <div className="data-access-overview__chart__container">
76
87
  <Doughnut
77
88
  data={{
@@ -109,7 +120,7 @@ const DataAccessOverviewChart = observer(
109
120
  />
110
121
  <div className="data-access-overview__chart__stats">
111
122
  <div className="data-access-overview__chart__stats__percentage">
112
- {accessGrantedPercentage}%
123
+ {total === 0 ? 0 : accessGrantedPercentage}%
113
124
  </div>
114
125
  <div className="data-access-overview__chart__stats__tally">
115
126
  {total === 0 ? 0 : accessGrantedCount}/{total}
@@ -285,7 +296,10 @@ export const DataAccessOverview = observer(
285
296
  const applicationStore = useApplicationStore();
286
297
 
287
298
  useEffect(() => {
288
- dataAccessState.intialize().catch(applicationStore.alertUnhandledError);
299
+ // NOTE: @YannanGao-gs - force refresh for now, let's investigate why the data is empty
300
+ // when we fetched it from cache
301
+ dataAccessState.refresh().catch(applicationStore.alertUnhandledError);
302
+ // dataAccessState.intialize().catch(applicationStore.alertUnhandledError);
289
303
  }, [applicationStore, dataAccessState]);
290
304
 
291
305
  return (
@@ -28,6 +28,10 @@ import {
28
28
  PanelContent,
29
29
  } from '@finos/legend-art';
30
30
  import { tryToFormatSql } from '../QueryBuilderResultPanel.js';
31
+ import {
32
+ CodeEditor,
33
+ CODE_EDITOR_LANGUAGE,
34
+ } from '@finos/legend-lego/code-editor';
31
35
 
32
36
  /**
33
37
  * TODO: Create a new `AbstractPlugin` for this, called `ExecutionPlanViewerPlugin`
@@ -81,9 +85,12 @@ export const SQLExecutionNodeViewer: React.FC<{
81
85
  </div>
82
86
  </PanelListItem>
83
87
  </div>
84
- <PanelListItem className="query-builder__sql__container__item">
85
- <pre>{tryToFormatSql(query)} </pre>
86
- </PanelListItem>
88
+ <div className="query-builder__sql__container__code-editor">
89
+ <CodeEditor
90
+ inputValue={tryToFormatSql(query)}
91
+ language={CODE_EDITOR_LANGUAGE.SQL}
92
+ />
93
+ </div>
87
94
  <PanelDivider />
88
95
  </div>
89
96
  </div>
@@ -271,9 +271,11 @@ export const MilestoningParametersEditor = observer(
271
271
  <ModalHeader title="Milestoning Parameters" />
272
272
  <ModalBody className="query-builder__variables__modal__body">
273
273
  <TemporalMilestoningEditor queryBuilderState={queryBuilderState} />
274
- <div className="panel__content__form__section__header__label">
275
- List of compatible milestoning parameters
276
- </div>
274
+ <PanelFormSection>
275
+ <div className="panel__content__form__section__header__label">
276
+ List of compatible milestoning parameters
277
+ </div>
278
+ </PanelFormSection>
277
279
  <div className="panel__content__form__section__list__items">
278
280
  <VariableSelector
279
281
  queryBuilderState={queryBuilderState}
@@ -1075,8 +1075,7 @@ const QueryBuilderPostFilterPanelContent = observer(
1075
1075
  <QueryBuilderPostFilterTree tdsState={tdsState} />
1076
1076
  </>
1077
1077
  )}
1078
-
1079
- {showDroppableSuggestion && (
1078
+ {showDroppableSuggestion && !postFilterState.isEmpty && (
1080
1079
  <div
1081
1080
  ref={dropTargetConnector}
1082
1081
  className={clsx(
@@ -1186,8 +1186,8 @@ export const QueryBuilderTDSWindowPanel = observer(
1186
1186
  >
1187
1187
  <PanelHeader>
1188
1188
  <div className="panel__header__title">
1189
- <div className="panel__header__title__label">Window Function</div>
1190
- {tdsWindowState.windowValidationIssues.length && (
1189
+ <div className="panel__header__title__label">window function</div>
1190
+ {tdsWindowState.windowValidationIssues.length > 0 && (
1191
1191
  <QueryBuilderPanelIssueCountBadge
1192
1192
  issues={tdsWindowState.windowValidationIssues}
1193
1193
  />
@@ -665,7 +665,8 @@ const CollectionValueInstanceValueEditor = observer(
665
665
  setValueSpecification,
666
666
  obseverContext,
667
667
  } = props;
668
- const inputRef = useRef<HTMLInputElement>(null);
668
+ const inputRef = useRef<HTMLTextAreaElement>(null);
669
+
669
670
  const [text, setText] = useState(stringifyValue(valueSpecification.values));
670
671
  const [editable, setEditable] = useState(false);
671
672
  const [showAdvancedEditorPopover, setShowAdvancedEditorPopover] =
@@ -697,9 +698,7 @@ const CollectionValueInstanceValueEditor = observer(
697
698
  setText(stringifyValue(valueSpecification.values));
698
699
  setValueSpecification(valueSpecification);
699
700
  };
700
- const changeValue: React.ChangeEventHandler<HTMLInputElement> = (event) => {
701
- setText(event.target.value);
702
- };
701
+
703
702
  const changeValueTextArea: React.ChangeEventHandler<HTMLTextAreaElement> = (
704
703
  event,
705
704
  ) => {
@@ -742,15 +741,20 @@ const CollectionValueInstanceValueEditor = observer(
742
741
  </BasePopover>
743
742
  )}
744
743
  <div className={clsx('value-spec-editor', className)}>
745
- <input
744
+ <textarea
746
745
  ref={inputRef}
747
746
  className={clsx(
748
- 'panel__content__form__section__input value-spec-editor__input',
747
+ 'panel__content__form__section__input value-spec-editor__input value-spec-editor__textarea ',
749
748
  )}
750
749
  spellCheck={false}
751
750
  value={text}
752
751
  placeholder={text === '' ? '(empty)' : undefined}
753
- onChange={changeValue}
752
+ onChange={changeValueTextArea}
753
+ onKeyDown={(event): void => {
754
+ if (event.key === 'Enter' && !event.shiftKey) {
755
+ saveEdit();
756
+ }
757
+ }}
754
758
  />
755
759
  <button
756
760
  className="value-spec-editor__list-editor__expand-button btn--dark"
@@ -345,7 +345,7 @@ export class QueryBuilderResultState {
345
345
  );
346
346
  }
347
347
  } catch (error) {
348
- // When user cancels the query by calling the cancelQuery api, it will throw an exeuction failure error.
348
+ // When user cancels the query by calling the cancelQuery api, it will throw an execution failure error.
349
349
  // For now, we don't want to notify users about this failure. Therefore we check to ensure the promise is still the same one.
350
350
  // When cancelled the query, we set the queryRunPromise as undefined.
351
351
  if (this.queryRunPromise === promise) {