@finos/legend-query-builder 4.14.10 → 4.14.11
Sign up to get free protection for your applications and to get access to all the features.
- 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 {
|