@finos/legend-query-builder 4.14.10 → 4.14.11
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__/QueryBuilderTesting.d.ts +3 -1
- package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderTesting.js +3 -0
- package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +86 -44
- package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
- package/lib/components/shared/LambdaEditor.d.ts.map +1 -1
- package/lib/components/shared/LambdaEditor.js +10 -5
- package/lib/components/shared/LambdaEditor.js.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js +12 -11
- package/lib/components/shared/QueryBuilderPropertyInfoTooltip.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.d.ts +2 -2
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js +7 -7
- package/lib/stores/fetch-structure/tds/QueryResultSetModifierState.js.map +1 -1
- package/package.json +5 -5
- package/src/__lib__/QueryBuilderTesting.ts +3 -0
- package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +174 -94
- package/src/components/shared/LambdaEditor.tsx +10 -8
- package/src/components/shared/QueryBuilderPropertyInfoTooltip.tsx +81 -65
- package/src/stores/fetch-structure/tds/QueryResultSetModifierState.ts +7 -12
@@ -31,20 +31,32 @@ import {
|
|
31
31
|
MenuContent,
|
32
32
|
MenuContentItem,
|
33
33
|
ModalFooterButton,
|
34
|
+
InputWithInlineValidation,
|
34
35
|
} from '@finos/legend-art';
|
35
36
|
import { SortColumnState } from '../../stores/fetch-structure/tds/QueryResultSetModifierState.js';
|
36
|
-
import {
|
37
|
+
import {
|
38
|
+
addUniqueEntry,
|
39
|
+
deleteEntry,
|
40
|
+
guaranteeNonNullable,
|
41
|
+
} from '@finos/legend-shared';
|
37
42
|
import { useApplicationStore } from '@finos/legend-application';
|
38
43
|
import type { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
|
39
44
|
import type { QueryBuilderTDSColumnState } from '../../stores/fetch-structure/tds/QueryBuilderTDSColumnState.js';
|
40
45
|
import { COLUMN_SORT_TYPE } from '../../graph/QueryBuilderMetaModelConst.js';
|
46
|
+
import { useEffect, useState } from 'react';
|
47
|
+
import type { QueryBuilderProjectionColumnState } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
|
48
|
+
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
|
41
49
|
|
42
50
|
const ColumnSortEditor = observer(
|
43
|
-
(props: {
|
44
|
-
|
51
|
+
(props: {
|
52
|
+
sortColumns: SortColumnState[];
|
53
|
+
setSortColumns: (sortColumns: SortColumnState[]) => void;
|
54
|
+
sortState: SortColumnState;
|
55
|
+
tdsColumns: QueryBuilderTDSColumnState[];
|
56
|
+
}) => {
|
57
|
+
const { sortColumns, setSortColumns, sortState, tdsColumns } = props;
|
45
58
|
const applicationStore = useApplicationStore();
|
46
|
-
const
|
47
|
-
const projectionOptions = tdsState.tdsColumns
|
59
|
+
const projectionOptions = tdsColumns
|
48
60
|
.filter(
|
49
61
|
(projectionCol) =>
|
50
62
|
projectionCol === sortState.columnState ||
|
@@ -58,6 +70,8 @@ const ColumnSortEditor = observer(
|
|
58
70
|
label: sortState.columnState.columnName,
|
59
71
|
value: sortState,
|
60
72
|
};
|
73
|
+
const sortType = sortState.sortType;
|
74
|
+
|
61
75
|
const onChange = (
|
62
76
|
val: { label: string; value: QueryBuilderTDSColumnState } | null,
|
63
77
|
): void => {
|
@@ -65,13 +79,17 @@ const ColumnSortEditor = observer(
|
|
65
79
|
sortState.setColumnState(val.value);
|
66
80
|
}
|
67
81
|
};
|
68
|
-
const sortType = sortState.sortType;
|
69
82
|
|
70
|
-
const deleteColumnSort = (): void =>
|
71
|
-
|
83
|
+
const deleteColumnSort = (): void => {
|
84
|
+
const newSortColumns = [...sortColumns];
|
85
|
+
deleteEntry(newSortColumns, sortState);
|
86
|
+
setSortColumns(newSortColumns);
|
87
|
+
};
|
88
|
+
|
72
89
|
const changeSortBy = (sortOp: COLUMN_SORT_TYPE) => (): void => {
|
73
90
|
sortState.setSortType(sortOp);
|
74
91
|
};
|
92
|
+
|
75
93
|
return (
|
76
94
|
<div className="panel__content__form__section__list__item query-builder__projection__options__sort">
|
77
95
|
<CustomSelectorInput
|
@@ -120,6 +138,9 @@ const ColumnSortEditor = observer(
|
|
120
138
|
onClick={deleteColumnSort}
|
121
139
|
tabIndex={-1}
|
122
140
|
title="Remove"
|
141
|
+
data-testid={
|
142
|
+
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL_SORT_REMOVE_BTN
|
143
|
+
}
|
123
144
|
>
|
124
145
|
<TimesIcon />
|
125
146
|
</button>
|
@@ -129,11 +150,15 @@ const ColumnSortEditor = observer(
|
|
129
150
|
);
|
130
151
|
|
131
152
|
const ColumnsSortEditor = observer(
|
132
|
-
(props: {
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
153
|
+
(props: {
|
154
|
+
projectionColumns: QueryBuilderProjectionColumnState[];
|
155
|
+
sortColumns: SortColumnState[];
|
156
|
+
setSortColumns: (sortColumns: SortColumnState[]) => void;
|
157
|
+
tdsColumns: QueryBuilderTDSColumnState[];
|
158
|
+
}) => {
|
159
|
+
const { projectionColumns, sortColumns, setSortColumns, tdsColumns } =
|
160
|
+
props;
|
161
|
+
const projectionOptions = projectionColumns
|
137
162
|
.filter(
|
138
163
|
(projectionCol) =>
|
139
164
|
!sortColumns.some((sortCol) => sortCol.columnState === projectionCol),
|
@@ -147,7 +172,9 @@ const ColumnsSortEditor = observer(
|
|
147
172
|
const sortColumn = new SortColumnState(
|
148
173
|
guaranteeNonNullable(projectionOptions[0]).value,
|
149
174
|
);
|
150
|
-
|
175
|
+
const newSortColumns = [...sortColumns];
|
176
|
+
addUniqueEntry(newSortColumns, sortColumn);
|
177
|
+
setSortColumns(newSortColumns);
|
151
178
|
}
|
152
179
|
};
|
153
180
|
|
@@ -166,8 +193,10 @@ const ColumnsSortEditor = observer(
|
|
166
193
|
{sortColumns.map((value) => (
|
167
194
|
<ColumnSortEditor
|
168
195
|
key={value.columnState.uuid}
|
169
|
-
|
196
|
+
sortColumns={sortColumns}
|
197
|
+
setSortColumns={setSortColumns}
|
170
198
|
sortState={value}
|
199
|
+
tdsColumns={tdsColumns}
|
171
200
|
/>
|
172
201
|
))}
|
173
202
|
</div>
|
@@ -189,75 +218,127 @@ const ColumnsSortEditor = observer(
|
|
189
218
|
|
190
219
|
export const QueryResultModifierModal = observer(
|
191
220
|
(props: { tdsState: QueryBuilderTDSState }) => {
|
192
|
-
|
221
|
+
// Read current state
|
222
|
+
const { tdsState } = props;
|
193
223
|
const resultSetModifierState = tdsState.resultSetModifierState;
|
194
|
-
const
|
195
|
-
const
|
196
|
-
const
|
197
|
-
const
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
224
|
+
const stateSortColumns = resultSetModifierState.sortColumns;
|
225
|
+
const stateDistinct = resultSetModifierState.distinct;
|
226
|
+
const stateLimitResults = resultSetModifierState.limit;
|
227
|
+
const stateSlice = resultSetModifierState.slice;
|
228
|
+
|
229
|
+
// Set up temp state for modal lifecycle
|
230
|
+
const [sortColumns, setSortColumns] = useState([...stateSortColumns]);
|
231
|
+
const [distinct, setDistinct] = useState(stateDistinct);
|
232
|
+
const [limitResults, setLimitResults] = useState(stateLimitResults);
|
233
|
+
const [slice, setSlice] = useState<
|
234
|
+
[number | undefined, number | undefined]
|
235
|
+
>(stateSlice ?? [undefined, undefined]);
|
204
236
|
|
205
|
-
|
206
|
-
|
207
|
-
|
237
|
+
// Sync temp state with tdsState when modal is opened/closed
|
238
|
+
useEffect(() => {
|
239
|
+
setSortColumns([...stateSortColumns]);
|
240
|
+
setDistinct(stateDistinct);
|
241
|
+
setLimitResults(stateLimitResults);
|
242
|
+
setSlice(stateSlice ?? [undefined, undefined]);
|
243
|
+
}, [
|
244
|
+
resultSetModifierState.showModal,
|
245
|
+
stateSortColumns,
|
246
|
+
stateDistinct,
|
247
|
+
stateLimitResults,
|
248
|
+
stateSlice,
|
249
|
+
]);
|
250
|
+
|
251
|
+
// Handle user actions
|
252
|
+
const closeModal = (): void => resultSetModifierState.setShowModal(false);
|
253
|
+
const applyChanges = (): void => {
|
254
|
+
resultSetModifierState.setSortColumns(sortColumns);
|
255
|
+
resultSetModifierState.setDistinct(distinct);
|
256
|
+
resultSetModifierState.setLimit(limitResults);
|
257
|
+
if (slice[0] !== undefined && slice[1] !== undefined) {
|
258
|
+
resultSetModifierState.setSlice([slice[0], slice[1]]);
|
259
|
+
} else {
|
260
|
+
resultSetModifierState.setSlice(undefined);
|
261
|
+
}
|
262
|
+
resultSetModifierState.setShowModal(false);
|
208
263
|
};
|
209
264
|
|
210
|
-
const
|
211
|
-
|
265
|
+
const handleLimitResultsChange: React.ChangeEventHandler<
|
266
|
+
HTMLInputElement
|
267
|
+
> = (event) => {
|
268
|
+
const val = event.target.value.replace(/[^0-9]/g, '');
|
269
|
+
setLimitResults(val === '' ? undefined : parseInt(val, 10));
|
212
270
|
};
|
213
271
|
|
214
|
-
const
|
215
|
-
|
272
|
+
const handleSliceChange = (
|
273
|
+
start: number | undefined,
|
274
|
+
end: number | undefined,
|
275
|
+
): void => {
|
276
|
+
const newSlice: [number | undefined, number | undefined] = [start, end];
|
277
|
+
setSlice(newSlice);
|
216
278
|
};
|
217
279
|
|
218
280
|
const changeSliceStart: React.ChangeEventHandler<HTMLInputElement> = (
|
219
281
|
event,
|
220
282
|
) => {
|
221
|
-
const
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
283
|
+
const val = event.target.value.replace(/[^0-9]/g, '');
|
284
|
+
if (val === '') {
|
285
|
+
handleSliceChange(undefined, slice[1]);
|
286
|
+
} else {
|
287
|
+
const start = typeof val === 'number' ? val : parseInt(val, 10);
|
288
|
+
handleSliceChange(start, slice[1]);
|
226
289
|
}
|
227
290
|
};
|
228
291
|
const changeSliceEnd: React.ChangeEventHandler<HTMLInputElement> = (
|
229
292
|
event,
|
230
293
|
) => {
|
231
|
-
const
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
294
|
+
const val = event.target.value.replace(/[^0-9]/g, '');
|
295
|
+
if (val === '') {
|
296
|
+
handleSliceChange(slice[0], undefined);
|
297
|
+
} else {
|
298
|
+
const end = typeof val === 'number' ? val : parseInt(val, 10);
|
299
|
+
handleSliceChange(slice[0], end);
|
236
300
|
}
|
237
301
|
};
|
238
302
|
|
303
|
+
// Error states
|
304
|
+
const isInvalidSlice =
|
305
|
+
(slice[0] === undefined && slice[1] !== undefined) ||
|
306
|
+
(slice[0] !== undefined && slice[1] === undefined) ||
|
307
|
+
(slice[0] !== undefined &&
|
308
|
+
slice[1] !== undefined &&
|
309
|
+
slice[0] >= slice[1]);
|
310
|
+
|
239
311
|
return (
|
240
312
|
<Dialog
|
241
313
|
open={Boolean(resultSetModifierState.showModal)}
|
242
|
-
onClose={
|
314
|
+
onClose={closeModal}
|
243
315
|
classes={{
|
244
316
|
root: 'editor-modal__root-container',
|
245
317
|
container: 'editor-modal__container',
|
246
318
|
paper: 'editor-modal__content',
|
247
319
|
}}
|
320
|
+
data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL}
|
248
321
|
>
|
249
|
-
<Modal
|
322
|
+
<Modal
|
323
|
+
darkMode={true}
|
324
|
+
className="editor-modal query-builder__projection__modal"
|
325
|
+
>
|
250
326
|
<ModalHeader title="Result Set Modifier" />
|
251
327
|
<ModalBody className="query-builder__projection__modal__body">
|
252
328
|
<div className="query-builder__projection__options">
|
253
|
-
<ColumnsSortEditor
|
329
|
+
<ColumnsSortEditor
|
330
|
+
projectionColumns={tdsState.projectionColumns}
|
331
|
+
sortColumns={sortColumns}
|
332
|
+
setSortColumns={setSortColumns}
|
333
|
+
tdsColumns={tdsState.tdsColumns}
|
334
|
+
/>
|
254
335
|
<div className="panel__content__form__section">
|
255
336
|
<div className="panel__content__form__section__header__label">
|
256
337
|
Eliminate Duplicate Rows
|
257
338
|
</div>
|
258
339
|
<div
|
259
340
|
className="panel__content__form__section__toggler"
|
260
|
-
onClick={
|
341
|
+
onClick={() => setDistinct(!distinct)}
|
261
342
|
>
|
262
343
|
<button
|
263
344
|
className={clsx(
|
@@ -277,75 +358,74 @@ export const QueryResultModifierModal = observer(
|
|
277
358
|
</div>
|
278
359
|
</div>
|
279
360
|
<div className="panel__content__form__section">
|
280
|
-
<
|
361
|
+
<label
|
362
|
+
htmlFor="query-builder__projection__modal__limit-results-input"
|
363
|
+
className="panel__content__form__section__header__label"
|
364
|
+
>
|
281
365
|
Limit Results
|
282
|
-
</
|
366
|
+
</label>
|
283
367
|
<div className="panel__content__form__section__header__prompt">
|
284
368
|
Specify the maximum total number of rows the output will
|
285
369
|
produce
|
286
370
|
</div>
|
287
371
|
<input
|
372
|
+
id="query-builder__projection__modal__limit-results-input"
|
288
373
|
className="panel__content__form__section__input panel__content__form__section__number-input"
|
289
374
|
spellCheck={false}
|
290
|
-
type="
|
375
|
+
type="text"
|
291
376
|
value={limitResults ?? ''}
|
292
|
-
onChange={
|
377
|
+
onChange={handleLimitResultsChange}
|
293
378
|
/>
|
294
379
|
</div>
|
295
380
|
<div className="panel__content__form__section">
|
296
|
-
<
|
381
|
+
<label
|
382
|
+
htmlFor="query-builder__projection__modal__slice-start-input"
|
383
|
+
className="panel__content__form__section__header__label"
|
384
|
+
>
|
297
385
|
Slice
|
298
|
-
</
|
386
|
+
</label>
|
299
387
|
<div className="panel__content__form__section__header__prompt">
|
300
388
|
Reduce the number of rows in the provided TDS, selecting the
|
301
389
|
set of rows in the specified range between start and stop
|
302
390
|
</div>
|
303
|
-
|
304
|
-
|
305
|
-
<
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
onClick={clearSlice}
|
326
|
-
tabIndex={-1}
|
327
|
-
title="Remove"
|
328
|
-
>
|
329
|
-
<TimesIcon />
|
330
|
-
</button>
|
331
|
-
</div>
|
332
|
-
</>
|
333
|
-
) : (
|
334
|
-
<div className="panel__content__form__section__list__new-item__add">
|
335
|
-
<button
|
336
|
-
className="panel__content__form__section__list__new-item__add-btn btn btn--dark"
|
337
|
-
onClick={addSlice}
|
338
|
-
tabIndex={-1}
|
339
|
-
>
|
340
|
-
Add Slice
|
341
|
-
</button>
|
391
|
+
<div className="query-builder__result__slice">
|
392
|
+
<div className="query-builder__result__slice__input__wrapper">
|
393
|
+
<InputWithInlineValidation
|
394
|
+
id="query-builder__projection__modal__slice-start-input"
|
395
|
+
className="input--dark query-builder__result__slice__input"
|
396
|
+
spellCheck={false}
|
397
|
+
value={slice[0] ?? ''}
|
398
|
+
onChange={changeSliceStart}
|
399
|
+
type="text"
|
400
|
+
error={isInvalidSlice ? 'Invalid slice' : undefined}
|
401
|
+
/>
|
402
|
+
</div>
|
403
|
+
<div className="query-builder__result__slice__range">..</div>
|
404
|
+
<div className="query-builder__result__slice__input__wrapper">
|
405
|
+
<InputWithInlineValidation
|
406
|
+
className="input--dark query-builder__result__slice__input"
|
407
|
+
spellCheck={false}
|
408
|
+
value={slice[1] ?? ''}
|
409
|
+
onChange={changeSliceEnd}
|
410
|
+
type="text"
|
411
|
+
error={isInvalidSlice ? 'Invalid slice' : undefined}
|
412
|
+
/>
|
342
413
|
</div>
|
343
|
-
|
414
|
+
</div>
|
344
415
|
</div>
|
345
416
|
</div>
|
346
417
|
</ModalBody>
|
347
418
|
<ModalFooter>
|
348
|
-
<ModalFooterButton
|
419
|
+
<ModalFooterButton
|
420
|
+
onClick={applyChanges}
|
421
|
+
text="Apply"
|
422
|
+
disabled={isInvalidSlice}
|
423
|
+
/>
|
424
|
+
<ModalFooterButton
|
425
|
+
onClick={closeModal}
|
426
|
+
text="Cancel"
|
427
|
+
type="secondary"
|
428
|
+
/>
|
349
429
|
</ModalFooter>
|
350
430
|
</Modal>
|
351
431
|
</Dialog>
|
@@ -159,6 +159,8 @@ const LambdaEditor_Inner = observer(
|
|
159
159
|
applicationStore.alertUnhandledError,
|
160
160
|
);
|
161
161
|
setExpanded(!isExpanded);
|
162
|
+
} else if (!forceExpansion && parserError) {
|
163
|
+
setExpanded(!isExpanded);
|
162
164
|
}
|
163
165
|
};
|
164
166
|
|
@@ -399,7 +401,6 @@ const LambdaEditor_Inner = observer(
|
|
399
401
|
<button
|
400
402
|
className="lambda-editor__editor__expand-btn"
|
401
403
|
onClick={toggleExpandedMode}
|
402
|
-
disabled={Boolean(parserError)}
|
403
404
|
tabIndex={-1}
|
404
405
|
title="Toggle Expand"
|
405
406
|
>
|
@@ -410,7 +411,6 @@ const LambdaEditor_Inner = observer(
|
|
410
411
|
<button
|
411
412
|
className="lambda-editor__action"
|
412
413
|
onClick={openInPopUp}
|
413
|
-
disabled={Boolean(parserError)}
|
414
414
|
tabIndex={-1}
|
415
415
|
title="Open in a popup..."
|
416
416
|
>
|
@@ -569,12 +569,14 @@ const LambdaEditor_PopUp = observer(
|
|
569
569
|
}
|
570
570
|
|
571
571
|
useEffect(() => {
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
572
|
+
if (!lambdaEditorState.parserError) {
|
573
|
+
flowResult(
|
574
|
+
lambdaEditorState.convertLambdaObjectToGrammarString({
|
575
|
+
pretty: true,
|
576
|
+
preserveCompilationError: true,
|
577
|
+
}),
|
578
|
+
).catch(applicationStore.alertUnhandledError);
|
579
|
+
}
|
578
580
|
}, [applicationStore, lambdaEditorState]);
|
579
581
|
|
580
582
|
// dispose editor
|
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
ShareBoxIcon,
|
19
19
|
type TooltipPlacement,
|
20
20
|
Tooltip,
|
21
|
+
ClickAwayListener,
|
21
22
|
} from '@finos/legend-art';
|
22
23
|
import {
|
23
24
|
type AbstractProperty,
|
@@ -137,73 +138,88 @@ export const QueryBuilderPropertyInfoTooltip: React.FC<{
|
|
137
138
|
explorerState,
|
138
139
|
} = props;
|
139
140
|
|
141
|
+
const [open, setIsOpen] = useState(false);
|
142
|
+
|
140
143
|
return (
|
141
|
-
<
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
onClick={() => explorerState.highlightTreeNode(path)}
|
171
|
-
title="Show in tree"
|
172
|
-
>
|
173
|
-
<ShareBoxIcon color="white" />
|
174
|
-
</button>
|
144
|
+
<ClickAwayListener onClickAway={() => setIsOpen(false)}>
|
145
|
+
<div>
|
146
|
+
<Tooltip
|
147
|
+
arrow={true}
|
148
|
+
{...(placement !== undefined ? { placement } : {})}
|
149
|
+
classes={{
|
150
|
+
tooltip: 'query-builder__tooltip',
|
151
|
+
arrow: 'query-builder__tooltip__arrow',
|
152
|
+
tooltipPlacementRight: 'query-builder__tooltip--right',
|
153
|
+
}}
|
154
|
+
open={open}
|
155
|
+
onClose={() => setIsOpen(false)}
|
156
|
+
TransitionProps={{
|
157
|
+
// disable transition
|
158
|
+
// NOTE: somehow, this is the only workaround we have, if for example
|
159
|
+
// we set `appear = true`, the tooltip will jump out of position
|
160
|
+
timeout: 0,
|
161
|
+
}}
|
162
|
+
disableFocusListener={true}
|
163
|
+
disableHoverListener={true}
|
164
|
+
disableTouchListener={true}
|
165
|
+
title={
|
166
|
+
<div className="query-builder__tooltip__content">
|
167
|
+
<div className="query-builder__tooltip__header">{title}</div>
|
168
|
+
<div className="query-builder__tooltip__item">
|
169
|
+
<div className="query-builder__tooltip__item__label">Type</div>
|
170
|
+
<div className="query-builder__tooltip__item__value">
|
171
|
+
{type?.path ?? property.genericType.value.rawType.path}
|
172
|
+
</div>
|
175
173
|
</div>
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
174
|
+
<div className="query-builder__tooltip__item">
|
175
|
+
<div className="query-builder__tooltip__item__label">Path</div>
|
176
|
+
<div className="query-builder__tooltip__item__value">
|
177
|
+
{path}
|
178
|
+
</div>
|
179
|
+
{explorerState && (
|
180
|
+
<div className="query-builder__tooltip__item__action">
|
181
|
+
<button
|
182
|
+
onClick={() => explorerState.highlightTreeNode(path)}
|
183
|
+
title="Show in tree"
|
184
|
+
>
|
185
|
+
<ShareBoxIcon color="white" />
|
186
|
+
</button>
|
187
|
+
</div>
|
188
|
+
)}
|
189
|
+
</div>
|
190
|
+
<div className="query-builder__tooltip__item">
|
191
|
+
<div className="query-builder__tooltip__item__label">
|
192
|
+
Multiplicity
|
193
|
+
</div>
|
194
|
+
<div className="query-builder__tooltip__item__value">
|
195
|
+
{getMultiplicityDescription(property.multiplicity)}
|
196
|
+
</div>
|
197
|
+
</div>
|
198
|
+
<div className="query-builder__tooltip__item">
|
199
|
+
<div className="query-builder__tooltip__item__label">
|
200
|
+
Derived Property
|
201
|
+
</div>
|
202
|
+
<div className="query-builder__tooltip__item__value">
|
203
|
+
{property instanceof DerivedProperty ? 'Yes' : 'No'}
|
204
|
+
</div>
|
205
|
+
</div>
|
206
|
+
<div className="query-builder__tooltip__item">
|
207
|
+
<div className="query-builder__tooltip__item__label">
|
208
|
+
Mapped
|
209
|
+
</div>
|
210
|
+
<div className="query-builder__tooltip__item__value">
|
211
|
+
{isMapped ? 'Yes' : 'No'}
|
212
|
+
</div>
|
213
|
+
</div>
|
214
|
+
<QueryBuilderTaggedValueInfoTooltip
|
215
|
+
taggedValues={property.taggedValues}
|
216
|
+
/>
|
198
217
|
</div>
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
>
|
206
|
-
{children}
|
207
|
-
</Tooltip>
|
218
|
+
}
|
219
|
+
>
|
220
|
+
<div onClick={() => setIsOpen(true)}>{children}</div>
|
221
|
+
</Tooltip>
|
222
|
+
</div>
|
223
|
+
</ClickAwayListener>
|
208
224
|
);
|
209
225
|
};
|
@@ -16,12 +16,7 @@
|
|
16
16
|
|
17
17
|
import { action, computed, makeObservable, observable } from 'mobx';
|
18
18
|
import type { QueryBuilderTDSState } from './QueryBuilderTDSState.js';
|
19
|
-
import {
|
20
|
-
addUniqueEntry,
|
21
|
-
deleteEntry,
|
22
|
-
type Hashable,
|
23
|
-
hashArray,
|
24
|
-
} from '@finos/legend-shared';
|
19
|
+
import { addUniqueEntry, type Hashable, hashArray } from '@finos/legend-shared';
|
25
20
|
import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../../QueryBuilderStateHashUtils.js';
|
26
21
|
import type { QueryBuilderTDSColumnState } from './QueryBuilderTDSColumnState.js';
|
27
22
|
import { COLUMN_SORT_TYPE } from '../../../graph/QueryBuilderMetaModelConst.js';
|
@@ -76,8 +71,8 @@ export class QueryResultSetModifierState implements Hashable {
|
|
76
71
|
slice: observable.ref,
|
77
72
|
setShowModal: action,
|
78
73
|
setLimit: action,
|
79
|
-
|
80
|
-
|
74
|
+
setDistinct: action,
|
75
|
+
setSortColumns: action,
|
81
76
|
addSortColumn: action,
|
82
77
|
updateSortColumns: action,
|
83
78
|
setSlice: action,
|
@@ -96,12 +91,12 @@ export class QueryResultSetModifierState implements Hashable {
|
|
96
91
|
this.limit = val === undefined || val <= 0 ? undefined : val;
|
97
92
|
}
|
98
93
|
|
99
|
-
|
100
|
-
this.distinct =
|
94
|
+
setDistinct(val: boolean): void {
|
95
|
+
this.distinct = val;
|
101
96
|
}
|
102
97
|
|
103
|
-
|
104
|
-
|
98
|
+
setSortColumns(val: SortColumnState[]): void {
|
99
|
+
this.sortColumns = val;
|
105
100
|
}
|
106
101
|
|
107
102
|
addSortColumn(val: SortColumnState): void {
|