@malloydata/malloy-explorer 0.0.278-dev250515234639 → 0.0.282-dev250527225235
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/@flowtypes/components/MalloyExplorerProvider.flow.js +3 -1
- package/dist/cjs/index.cjs +372 -168
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +373 -169
- package/dist/esm/index.js.map +1 -1
- package/dist/types/components/MalloyExplorerProvider.d.ts +4 -2
- package/dist/types/components/MalloyQueryFocusProvider.d.ts +18 -0
- package/dist/types/components/QueryPanel/FocusableView.d.ts +7 -0
- package/dist/types/components/SourcePanel/hooks/useOperations.d.ts +4 -0
- package/dist/types/components/contexts/NestViewPathContext.d.ts +2 -0
- package/dist/types/components/utils/segment.d.ts +4 -0
- package/dist/types/contexts/QueryEditorContext.d.ts +2 -13
- package/package.json +9 -6
package/dist/cjs/index.cjs
CHANGED
|
@@ -3342,29 +3342,105 @@ function useQueryBuilder(source, query) {
|
|
|
3342
3342
|
}
|
|
3343
3343
|
}, [source, query]);
|
|
3344
3344
|
}
|
|
3345
|
+
const MalloyQueryFocusContext = /* @__PURE__ */ React__namespace.createContext({
|
|
3346
|
+
focusMainView: () => {
|
|
3347
|
+
},
|
|
3348
|
+
isMainViewFocused: true,
|
|
3349
|
+
focusNestView: () => {
|
|
3350
|
+
},
|
|
3351
|
+
isNestViewFocused: () => false,
|
|
3352
|
+
focusedNestView: null
|
|
3353
|
+
});
|
|
3354
|
+
function MalloyQueryFocusProvider({
|
|
3355
|
+
rootQuery,
|
|
3356
|
+
focusedNestViewPath,
|
|
3357
|
+
onFocusedNestViewPathChange,
|
|
3358
|
+
children
|
|
3359
|
+
}) {
|
|
3360
|
+
const focusedNestView = React__namespace.useMemo(() => {
|
|
3361
|
+
if (focusedNestViewPath.length === 0) {
|
|
3362
|
+
return null;
|
|
3363
|
+
}
|
|
3364
|
+
if (rootQuery) {
|
|
3365
|
+
const queryDef = rootQuery.definition;
|
|
3366
|
+
if (queryDef instanceof QB.ASTArrowQueryDefinition) {
|
|
3367
|
+
return findNestView(queryDef.view, [...focusedNestViewPath].reverse());
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
return null;
|
|
3371
|
+
}, [rootQuery, focusedNestViewPath]);
|
|
3372
|
+
const focusMainView = React__namespace.useCallback(() => {
|
|
3373
|
+
onFocusedNestViewPathChange([]);
|
|
3374
|
+
}, [onFocusedNestViewPathChange]);
|
|
3375
|
+
const focusNestView = React__namespace.useCallback((path) => {
|
|
3376
|
+
onFocusedNestViewPathChange([...path]);
|
|
3377
|
+
}, [onFocusedNestViewPathChange]);
|
|
3378
|
+
const isNestViewFocused = React__namespace.useCallback((path) => {
|
|
3379
|
+
return JSON.stringify(path) === JSON.stringify(focusedNestViewPath);
|
|
3380
|
+
}, [focusedNestViewPath]);
|
|
3381
|
+
const isMainViewFocused = focusedNestViewPath.length === 0;
|
|
3382
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MalloyQueryFocusContext.Provider, {
|
|
3383
|
+
value: {
|
|
3384
|
+
focusMainView,
|
|
3385
|
+
isMainViewFocused,
|
|
3386
|
+
focusNestView,
|
|
3387
|
+
isNestViewFocused,
|
|
3388
|
+
focusedNestView
|
|
3389
|
+
},
|
|
3390
|
+
children
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
function useQueryFocus() {
|
|
3394
|
+
return React__namespace.useContext(MalloyQueryFocusContext);
|
|
3395
|
+
}
|
|
3396
|
+
const findNestView = (currentView, remainingPath) => {
|
|
3397
|
+
if (remainingPath.length === 0) {
|
|
3398
|
+
return null;
|
|
3399
|
+
}
|
|
3400
|
+
if (currentView instanceof QB.ASTArrowViewDefinition) {
|
|
3401
|
+
return findNestView(currentView.view, remainingPath);
|
|
3402
|
+
}
|
|
3403
|
+
if (currentView instanceof QB.ASTSegmentViewDefinition) {
|
|
3404
|
+
const currentNestName = remainingPath.pop();
|
|
3405
|
+
const currentNestOperation = currentView.operations.items.find((operation) => operation instanceof QB.ASTNestViewOperation && operation.name === currentNestName);
|
|
3406
|
+
if (currentNestOperation === void 0) {
|
|
3407
|
+
remainingPath.push(currentNestName);
|
|
3408
|
+
return null;
|
|
3409
|
+
} else if (remainingPath.length === 0) {
|
|
3410
|
+
return currentNestOperation.view;
|
|
3411
|
+
} else {
|
|
3412
|
+
return findNestView(currentNestOperation.view.definition, remainingPath);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
if (currentView instanceof QB.ASTRefinementViewDefinition) {
|
|
3416
|
+
return findNestView(currentView.refinement, remainingPath);
|
|
3417
|
+
}
|
|
3418
|
+
return null;
|
|
3419
|
+
};
|
|
3345
3420
|
function MalloyExplorerProvider({
|
|
3346
3421
|
source,
|
|
3347
3422
|
query,
|
|
3348
|
-
|
|
3423
|
+
onQueryChange,
|
|
3424
|
+
focusedNestViewPath,
|
|
3425
|
+
onFocusedNestViewPathChange,
|
|
3349
3426
|
children,
|
|
3350
3427
|
topValues
|
|
3351
3428
|
}) {
|
|
3352
3429
|
const rootQuery = useQueryBuilder(source, query);
|
|
3353
|
-
const [currentNestView, setCurrentNestView] = React__namespace.useState(null);
|
|
3354
|
-
const [currentNestQueryPanel, setCurrentNestQueryPanel] = React__namespace.useState(null);
|
|
3355
3430
|
return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, {
|
|
3356
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3431
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MalloyQueryFocusProvider, {
|
|
3432
|
+
rootQuery,
|
|
3433
|
+
focusedNestViewPath,
|
|
3434
|
+
onFocusedNestViewPathChange,
|
|
3435
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(QueryEditorContext.Provider, {
|
|
3436
|
+
value: {
|
|
3437
|
+
source,
|
|
3438
|
+
rootQuery,
|
|
3439
|
+
setQuery: onQueryChange,
|
|
3440
|
+
topValues
|
|
3441
|
+
},
|
|
3442
|
+
children
|
|
3443
|
+
})
|
|
3368
3444
|
})
|
|
3369
3445
|
});
|
|
3370
3446
|
}
|
|
@@ -25881,13 +25957,14 @@ function QueryActionBar({
|
|
|
25881
25957
|
const {
|
|
25882
25958
|
rootQuery,
|
|
25883
25959
|
setQuery,
|
|
25884
|
-
source
|
|
25885
|
-
onCurrentNestQueryPanelChange,
|
|
25886
|
-
onCurrentNestViewChange
|
|
25960
|
+
source
|
|
25887
25961
|
} = React.useContext(QueryEditorContext);
|
|
25888
25962
|
const {
|
|
25889
25963
|
onCollapse
|
|
25890
25964
|
} = React.useContext(ResizableCollapsiblePanelContext);
|
|
25965
|
+
const {
|
|
25966
|
+
focusMainView
|
|
25967
|
+
} = useQueryFocus();
|
|
25891
25968
|
const isQueryEmpty = !rootQuery || rootQuery.isEmpty();
|
|
25892
25969
|
const isRunEnabled = rootQuery == null ? void 0 : rootQuery.isRunnable();
|
|
25893
25970
|
const onRunQuery = () => {
|
|
@@ -25895,10 +25972,6 @@ function QueryActionBar({
|
|
|
25895
25972
|
runQuery(source, rootQuery.build());
|
|
25896
25973
|
}
|
|
25897
25974
|
};
|
|
25898
|
-
const focusMainQueryPanel = () => {
|
|
25899
|
-
onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(null);
|
|
25900
|
-
onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(null);
|
|
25901
|
-
};
|
|
25902
25975
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
25903
25976
|
...{
|
|
25904
25977
|
className: "mly78zum5 mly1qughib mly6s0dn4 mlye8ttls"
|
|
@@ -25919,7 +25992,7 @@ function QueryActionBar({
|
|
|
25919
25992
|
},
|
|
25920
25993
|
children: [/* @__PURE__ */ jsxRuntime.jsx(Button, {
|
|
25921
25994
|
onClick: () => {
|
|
25922
|
-
|
|
25995
|
+
focusMainView();
|
|
25923
25996
|
setQuery == null ? void 0 : setQuery(void 0);
|
|
25924
25997
|
},
|
|
25925
25998
|
isDisabled: !rootQuery || (rootQuery == null ? void 0 : rootQuery.isEmpty()),
|
|
@@ -29950,6 +30023,11 @@ function getViewDefinition(parent) {
|
|
|
29950
30023
|
return parent instanceof QB.ASTArrowQueryDefinition ? parent.view : parent.definition;
|
|
29951
30024
|
}
|
|
29952
30025
|
function getInputSchemaFromViewParent(parent) {
|
|
30026
|
+
if (!parent) {
|
|
30027
|
+
return {
|
|
30028
|
+
fields: []
|
|
30029
|
+
};
|
|
30030
|
+
}
|
|
29953
30031
|
const definition = getViewDefinition(parent);
|
|
29954
30032
|
return definition.getInputSchema();
|
|
29955
30033
|
}
|
|
@@ -32400,12 +32478,54 @@ const styles$g = {
|
|
|
32400
32478
|
$$css: true
|
|
32401
32479
|
}
|
|
32402
32480
|
};
|
|
32481
|
+
function toFullName(path, name) {
|
|
32482
|
+
return [...path || [], name].join(".");
|
|
32483
|
+
}
|
|
32403
32484
|
function segmentHasLimit(segment) {
|
|
32404
32485
|
return segment.operations.items.find((operation) => operation instanceof QB.ASTLimitViewOperation) !== void 0;
|
|
32405
32486
|
}
|
|
32406
32487
|
function segmentHasOrderBy(segment, name) {
|
|
32407
32488
|
return segment.operations.items.find((operation) => operation instanceof QB.ASTOrderByViewOperation && operation.name === name) !== void 0;
|
|
32408
32489
|
}
|
|
32490
|
+
function getOutputNameToInputNameMap(segment) {
|
|
32491
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
32492
|
+
for (const operation of segment.operations.items) {
|
|
32493
|
+
if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
|
|
32494
|
+
const reference = operation.field.getReference();
|
|
32495
|
+
if (reference) {
|
|
32496
|
+
nameMap.set(operation.name, toFullName(reference.path, reference.name));
|
|
32497
|
+
}
|
|
32498
|
+
}
|
|
32499
|
+
}
|
|
32500
|
+
return nameMap;
|
|
32501
|
+
}
|
|
32502
|
+
function segmentHasOrderBySourceField(segment, path, name) {
|
|
32503
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32504
|
+
const fullInputName = toFullName(path, name);
|
|
32505
|
+
return !!segment.operations.items.find((operation) => {
|
|
32506
|
+
if (operation instanceof QB.ASTOrderByViewOperation && nameMap.has(operation.name)) {
|
|
32507
|
+
return fullInputName === nameMap.get(operation.name);
|
|
32508
|
+
}
|
|
32509
|
+
return false;
|
|
32510
|
+
});
|
|
32511
|
+
}
|
|
32512
|
+
function areReferencesEqual(path1, name1, path2, name2) {
|
|
32513
|
+
return name1 === name2 && (path1 || []).join(".") === (path2 || []).join(".");
|
|
32514
|
+
}
|
|
32515
|
+
function segmentHasFieldInOutputSpace(segment, path, name) {
|
|
32516
|
+
const match = segment.operations.items.find((operation) => {
|
|
32517
|
+
if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
|
|
32518
|
+
const reference = operation.field.getReference();
|
|
32519
|
+
if (reference) {
|
|
32520
|
+
return areReferencesEqual(path, name, reference.path, reference.name);
|
|
32521
|
+
} else {
|
|
32522
|
+
return false;
|
|
32523
|
+
}
|
|
32524
|
+
}
|
|
32525
|
+
return false;
|
|
32526
|
+
});
|
|
32527
|
+
return !!match;
|
|
32528
|
+
}
|
|
32409
32529
|
function segmentNestNo(segment, name) {
|
|
32410
32530
|
return segment.operations.items.reduce((acc, operation) => {
|
|
32411
32531
|
if (operation instanceof QB.ASTNestViewOperation) {
|
|
@@ -32460,6 +32580,19 @@ function addNest(view, field) {
|
|
|
32460
32580
|
}
|
|
32461
32581
|
segment.addNest(field.name, rename);
|
|
32462
32582
|
}
|
|
32583
|
+
function addOrderByFromSource(view, path, name, direction = "desc") {
|
|
32584
|
+
const fullInputName = toFullName(path, name);
|
|
32585
|
+
let orderByName = name;
|
|
32586
|
+
const segment = view.getOrAddDefaultSegment();
|
|
32587
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32588
|
+
for (const entry of nameMap.entries()) {
|
|
32589
|
+
if (entry[1] === fullInputName) {
|
|
32590
|
+
orderByName = entry[0];
|
|
32591
|
+
break;
|
|
32592
|
+
}
|
|
32593
|
+
}
|
|
32594
|
+
segment.addOrderBy(orderByName, direction);
|
|
32595
|
+
}
|
|
32463
32596
|
function addOrderBy(view, field, direction = "desc") {
|
|
32464
32597
|
const segment = view.getOrAddDefaultSegment();
|
|
32465
32598
|
segment.addOrderBy(field.name, direction);
|
|
@@ -32473,6 +32606,9 @@ function addFilter(view, field, path, filter) {
|
|
|
32473
32606
|
}
|
|
32474
32607
|
}
|
|
32475
32608
|
function getSegmentIfPresent(parent) {
|
|
32609
|
+
if (!parent) {
|
|
32610
|
+
return void 0;
|
|
32611
|
+
}
|
|
32476
32612
|
const definition = getViewDefinition(parent);
|
|
32477
32613
|
if (definition instanceof QB.ASTSegmentViewDefinition) {
|
|
32478
32614
|
return definition;
|
|
@@ -33101,11 +33237,12 @@ function SortableOperation({
|
|
|
33101
33237
|
operation,
|
|
33102
33238
|
color
|
|
33103
33239
|
}) {
|
|
33240
|
+
var _a2;
|
|
33104
33241
|
const {
|
|
33105
33242
|
setQuery
|
|
33106
33243
|
} = React.useContext(QueryEditorContext);
|
|
33107
33244
|
const fieldInfo = operation.getFieldInfo();
|
|
33108
|
-
const path = operation.field.getReference().path ?? NULL_PATH;
|
|
33245
|
+
const path = ((_a2 = operation.field.getReference()) == null ? void 0 : _a2.path) ?? NULL_PATH;
|
|
33109
33246
|
const {
|
|
33110
33247
|
attributes,
|
|
33111
33248
|
listeners,
|
|
@@ -33306,28 +33443,62 @@ const parsedToLabels = (parsed, filterString) => {
|
|
|
33306
33443
|
value = stringClause.escaped_values.join(", ");
|
|
33307
33444
|
break;
|
|
33308
33445
|
case "=":
|
|
33309
|
-
|
|
33310
|
-
|
|
33446
|
+
{
|
|
33447
|
+
const {
|
|
33448
|
+
not,
|
|
33449
|
+
values
|
|
33450
|
+
} = stringClause;
|
|
33451
|
+
op = not ? "is not" : "is";
|
|
33452
|
+
value = values.join(", ");
|
|
33453
|
+
}
|
|
33311
33454
|
break;
|
|
33312
33455
|
case "contains":
|
|
33313
|
-
|
|
33314
|
-
|
|
33456
|
+
{
|
|
33457
|
+
const {
|
|
33458
|
+
not,
|
|
33459
|
+
values
|
|
33460
|
+
} = stringClause;
|
|
33461
|
+
op = not ? "does not contain" : "contains";
|
|
33462
|
+
value = values.join(", ");
|
|
33463
|
+
}
|
|
33315
33464
|
break;
|
|
33316
33465
|
case "starts":
|
|
33317
|
-
|
|
33318
|
-
|
|
33466
|
+
{
|
|
33467
|
+
const {
|
|
33468
|
+
not,
|
|
33469
|
+
values
|
|
33470
|
+
} = stringClause;
|
|
33471
|
+
op = not ? "does not start with" : "starts with";
|
|
33472
|
+
value = values.join(", ");
|
|
33473
|
+
}
|
|
33319
33474
|
break;
|
|
33320
33475
|
case "ends":
|
|
33321
|
-
|
|
33322
|
-
|
|
33476
|
+
{
|
|
33477
|
+
const {
|
|
33478
|
+
not,
|
|
33479
|
+
values
|
|
33480
|
+
} = stringClause;
|
|
33481
|
+
op = not ? "does not end with" : "ends with";
|
|
33482
|
+
value = values.join(", ");
|
|
33483
|
+
}
|
|
33323
33484
|
break;
|
|
33324
33485
|
case "empty":
|
|
33325
|
-
|
|
33326
|
-
|
|
33486
|
+
{
|
|
33487
|
+
const {
|
|
33488
|
+
not
|
|
33489
|
+
} = stringClause;
|
|
33490
|
+
op = not ? "is not empty" : "is empty";
|
|
33491
|
+
value = "";
|
|
33492
|
+
}
|
|
33327
33493
|
break;
|
|
33328
33494
|
case "null":
|
|
33329
|
-
|
|
33330
|
-
|
|
33495
|
+
{
|
|
33496
|
+
const {
|
|
33497
|
+
not
|
|
33498
|
+
} = stringClause;
|
|
33499
|
+
op = not ? "is not" : "is";
|
|
33500
|
+
value = "null";
|
|
33501
|
+
}
|
|
33331
33502
|
break;
|
|
33332
33503
|
}
|
|
33333
33504
|
}
|
|
@@ -33491,22 +33662,27 @@ function SingleFilterOperation({
|
|
|
33491
33662
|
rootQuery,
|
|
33492
33663
|
filterOperation
|
|
33493
33664
|
}) {
|
|
33665
|
+
const {
|
|
33666
|
+
setQuery
|
|
33667
|
+
} = React.useContext(QueryEditorContext);
|
|
33668
|
+
const setFilter = React.useCallback((filter2) => {
|
|
33669
|
+
if (filterOperation.filter instanceof QB.ASTFilterWithFilterString) {
|
|
33670
|
+
filterOperation.filter.setFilter(filter2);
|
|
33671
|
+
}
|
|
33672
|
+
setQuery == null ? void 0 : setQuery(rootQuery.build());
|
|
33673
|
+
}, [filterOperation.filter, rootQuery, setQuery]);
|
|
33674
|
+
if (!(filterOperation.filter instanceof QB.ASTFilterWithFilterString)) {
|
|
33675
|
+
return null;
|
|
33676
|
+
}
|
|
33494
33677
|
const {
|
|
33495
33678
|
fieldReference,
|
|
33496
33679
|
filterString
|
|
33497
33680
|
} = filterOperation.filter;
|
|
33498
33681
|
const filter = filterOperation.filter.getFilter();
|
|
33499
33682
|
const fieldInfo = fieldReference.getFieldInfo();
|
|
33500
|
-
const {
|
|
33501
|
-
setQuery
|
|
33502
|
-
} = React.useContext(QueryEditorContext);
|
|
33503
33683
|
if (fieldInfo.kind !== "dimension" && fieldInfo.kind !== "measure") {
|
|
33504
33684
|
throw new Error(`Invalid filter field kind: ${fieldInfo.kind}`);
|
|
33505
33685
|
}
|
|
33506
|
-
const setFilter = React.useCallback((filter2) => {
|
|
33507
|
-
filterOperation.filter.setFilter(filter2);
|
|
33508
|
-
setQuery == null ? void 0 : setQuery(rootQuery.build());
|
|
33509
|
-
}, [filterOperation.filter, rootQuery, setQuery]);
|
|
33510
33686
|
const {
|
|
33511
33687
|
op,
|
|
33512
33688
|
value
|
|
@@ -34117,6 +34293,35 @@ const styles$d = {
|
|
|
34117
34293
|
$$css: true
|
|
34118
34294
|
}
|
|
34119
34295
|
};
|
|
34296
|
+
const NestViewPathContext = /* @__PURE__ */ React.createContext([]);
|
|
34297
|
+
function FocusableView({
|
|
34298
|
+
children,
|
|
34299
|
+
nest
|
|
34300
|
+
}) {
|
|
34301
|
+
const {
|
|
34302
|
+
focusNestView,
|
|
34303
|
+
focusMainView
|
|
34304
|
+
} = useQueryFocus();
|
|
34305
|
+
const parentNestViewPath = React.useContext(NestViewPathContext);
|
|
34306
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
34307
|
+
onPointerDown: (e) => {
|
|
34308
|
+
e.stopPropagation();
|
|
34309
|
+
if (nest) {
|
|
34310
|
+
focusNestView([...parentNestViewPath, nest.name]);
|
|
34311
|
+
} else {
|
|
34312
|
+
focusMainView();
|
|
34313
|
+
}
|
|
34314
|
+
},
|
|
34315
|
+
children: nest ? /* @__PURE__ */ jsxRuntime.jsx(NestViewPathContext.Provider, {
|
|
34316
|
+
value: [...parentNestViewPath, nest.name],
|
|
34317
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
34318
|
+
children
|
|
34319
|
+
})
|
|
34320
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
34321
|
+
children
|
|
34322
|
+
})
|
|
34323
|
+
});
|
|
34324
|
+
}
|
|
34120
34325
|
function NestOperations({
|
|
34121
34326
|
rootQuery,
|
|
34122
34327
|
view,
|
|
@@ -34140,31 +34345,14 @@ function NestOperation({
|
|
|
34140
34345
|
nest
|
|
34141
34346
|
}) {
|
|
34142
34347
|
const {
|
|
34143
|
-
setQuery
|
|
34144
|
-
currentNestQueryPanel,
|
|
34145
|
-
onCurrentNestQueryPanelChange,
|
|
34146
|
-
onCurrentNestViewChange
|
|
34348
|
+
setQuery
|
|
34147
34349
|
} = React.useContext(QueryEditorContext);
|
|
34148
34350
|
const [renameOpen, setRenameOpen] = React.useState(false);
|
|
34149
|
-
const
|
|
34150
|
-
const
|
|
34151
|
-
|
|
34152
|
-
|
|
34153
|
-
|
|
34154
|
-
}
|
|
34155
|
-
}, [nest, isCurrentNestQueryPanelFocused, onCurrentNestViewChange]);
|
|
34156
|
-
const focusCurrentNestQueryPanel = () => {
|
|
34157
|
-
onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(panelRef.current);
|
|
34158
|
-
onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(nest.view);
|
|
34159
|
-
};
|
|
34160
|
-
const focusParentQueryPanel = () => {
|
|
34161
|
-
const currentPanel = panelRef.current;
|
|
34162
|
-
const parent = findParentNestQueryPanel(currentPanel);
|
|
34163
|
-
onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(parent);
|
|
34164
|
-
if (parent === null) {
|
|
34165
|
-
onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(null);
|
|
34166
|
-
}
|
|
34167
|
-
};
|
|
34351
|
+
const parentNestViewPath = React.useContext(NestViewPathContext);
|
|
34352
|
+
const {
|
|
34353
|
+
focusNestView,
|
|
34354
|
+
isNestViewFocused
|
|
34355
|
+
} = useQueryFocus();
|
|
34168
34356
|
const getControls = (nest2) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
34169
34357
|
children: [/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, {
|
|
34170
34358
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
|
|
@@ -34177,7 +34365,7 @@ function NestOperation({
|
|
|
34177
34365
|
icon: "clear",
|
|
34178
34366
|
label: "Delete Query",
|
|
34179
34367
|
onClick: () => {
|
|
34180
|
-
|
|
34368
|
+
focusNestView([...parentNestViewPath]);
|
|
34181
34369
|
nest2.delete();
|
|
34182
34370
|
setQuery == null ? void 0 : setQuery(rootQuery.build());
|
|
34183
34371
|
}
|
|
@@ -34192,21 +34380,19 @@ function NestOperation({
|
|
|
34192
34380
|
view: nest2.view
|
|
34193
34381
|
})]
|
|
34194
34382
|
});
|
|
34195
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
34196
|
-
|
|
34197
|
-
className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
|
|
34198
|
-
},
|
|
34383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
|
|
34384
|
+
nest,
|
|
34199
34385
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
34200
|
-
|
|
34201
|
-
|
|
34202
|
-
|
|
34386
|
+
...{
|
|
34387
|
+
className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
|
|
34388
|
+
},
|
|
34203
34389
|
children: [/* @__PURE__ */ jsxRuntime.jsx(CollapsiblePanel, {
|
|
34204
34390
|
title: nest.name,
|
|
34205
34391
|
icon: viewToVisualizationIcon(nest.view),
|
|
34206
34392
|
defaultOpen: true,
|
|
34207
34393
|
controls: getControls(nest),
|
|
34208
34394
|
collapsedControls: getControls(nest),
|
|
34209
|
-
isFocused:
|
|
34395
|
+
isFocused: isNestViewFocused([...parentNestViewPath, nest.name]),
|
|
34210
34396
|
children: /* @__PURE__ */ jsxRuntime.jsx(View, {
|
|
34211
34397
|
rootQuery,
|
|
34212
34398
|
view: nest.view
|
|
@@ -34218,14 +34404,8 @@ function NestOperation({
|
|
|
34218
34404
|
open: renameOpen,
|
|
34219
34405
|
setOpen: setRenameOpen
|
|
34220
34406
|
})]
|
|
34221
|
-
})
|
|
34222
|
-
}
|
|
34223
|
-
}
|
|
34224
|
-
function findParentNestQueryPanel(element2) {
|
|
34225
|
-
if (!element2 || !element2.parentElement) return null;
|
|
34226
|
-
const parentElement = element2.parentElement;
|
|
34227
|
-
if (parentElement.dataset.nestPanel !== void 0) return parentElement;
|
|
34228
|
-
return findParentNestQueryPanel(parentElement);
|
|
34407
|
+
}, nest.name)
|
|
34408
|
+
});
|
|
34229
34409
|
}
|
|
34230
34410
|
function Operations({
|
|
34231
34411
|
rootQuery,
|
|
@@ -34255,7 +34435,8 @@ function Operations({
|
|
|
34255
34435
|
orderBys.push(operation);
|
|
34256
34436
|
} else if (operation instanceof QB.ASTNestViewOperation) {
|
|
34257
34437
|
nests.push(operation);
|
|
34258
|
-
} else
|
|
34438
|
+
} else if (operation instanceof QB.ASTDrillViewOperation) ;
|
|
34439
|
+
else {
|
|
34259
34440
|
limit = operation;
|
|
34260
34441
|
}
|
|
34261
34442
|
});
|
|
@@ -34394,19 +34575,13 @@ function Query({
|
|
|
34394
34575
|
setQuery
|
|
34395
34576
|
}) {
|
|
34396
34577
|
const {
|
|
34397
|
-
|
|
34398
|
-
|
|
34399
|
-
|
|
34400
|
-
|
|
34401
|
-
const focusMainQueryPanel = () => {
|
|
34402
|
-
onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(null);
|
|
34403
|
-
onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(null);
|
|
34404
|
-
};
|
|
34405
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
34406
|
-
onPointerDownCapture: focusMainQueryPanel,
|
|
34578
|
+
focusMainView,
|
|
34579
|
+
isMainViewFocused
|
|
34580
|
+
} = useQueryFocus();
|
|
34581
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
|
|
34407
34582
|
children: /* @__PURE__ */ jsxRuntime.jsxs(CollapsiblePanel, {
|
|
34408
34583
|
title: "Main query",
|
|
34409
|
-
isFocused:
|
|
34584
|
+
isFocused: isMainViewFocused,
|
|
34410
34585
|
controls: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
34411
34586
|
children: [/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu, {
|
|
34412
34587
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
|
|
@@ -34420,7 +34595,7 @@ function Query({
|
|
|
34420
34595
|
icon: "clear",
|
|
34421
34596
|
label: "Clear query",
|
|
34422
34597
|
onClick: () => {
|
|
34423
|
-
|
|
34598
|
+
focusMainView();
|
|
34424
34599
|
setQuery == null ? void 0 : setQuery(void 0);
|
|
34425
34600
|
},
|
|
34426
34601
|
disabled: rootQuery.isEmpty()
|
|
@@ -35914,62 +36089,83 @@ const FIELD_KIND_TO_TITLE = {
|
|
|
35914
36089
|
dimension: "Dimensions"
|
|
35915
36090
|
};
|
|
35916
36091
|
function useOperations(view, field, path) {
|
|
35917
|
-
const
|
|
36092
|
+
const fullName = toFullName(path, field.name);
|
|
36093
|
+
const flattenedFields = React.useMemo(() => {
|
|
35918
36094
|
const {
|
|
35919
36095
|
fields
|
|
35920
36096
|
} = getInputSchemaFromViewParent(view);
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
const
|
|
35928
|
-
const {
|
|
35929
|
-
fields
|
|
35930
|
-
} = getInputSchemaFromViewParent(view);
|
|
35931
|
-
return new Set(flattenFieldsTree(fields).filter(({
|
|
35932
|
-
field: field2
|
|
35933
|
-
}) => field2.kind === "measure").map(({
|
|
35934
|
-
field: field2
|
|
35935
|
-
}) => field2.name));
|
|
35936
|
-
}, [view]);
|
|
35937
|
-
const isGroupByAllowed = React.useMemo(() => {
|
|
35938
|
-
if (!view) {
|
|
35939
|
-
return false;
|
|
35940
|
-
}
|
|
36097
|
+
const inputPath = path.join(".");
|
|
36098
|
+
return flattenFieldsTree(fields).filter((fieldItem) => {
|
|
36099
|
+
return fieldItem.path.join(".") === inputPath;
|
|
36100
|
+
});
|
|
36101
|
+
}, [path, view]);
|
|
36102
|
+
const matchingFieldItem = flattenedFields.find((fieldItem) => field.name === fieldItem.field.name);
|
|
36103
|
+
const groupByDisabledReason = React.useMemo(() => {
|
|
35941
36104
|
const segment = getSegmentIfPresent(view);
|
|
35942
|
-
|
|
35943
|
-
|
|
35944
|
-
|
|
35945
|
-
if (
|
|
35946
|
-
return
|
|
36105
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "dimension") {
|
|
36106
|
+
return "Grouping is only available on a dimenion.";
|
|
36107
|
+
}
|
|
36108
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
36109
|
+
return "Cannot group by a field already in the view.";
|
|
36110
|
+
}
|
|
36111
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
36112
|
+
return "This field is annotated with #NO_UI.";
|
|
36113
|
+
}
|
|
36114
|
+
return "";
|
|
36115
|
+
}, [view, matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, field, path]);
|
|
36116
|
+
const aggregateDisabledReason = React.useMemo(() => {
|
|
36117
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "measure") {
|
|
36118
|
+
return "Aggregation only supports measure fields.";
|
|
35947
36119
|
}
|
|
35948
36120
|
const segment = getSegmentIfPresent(view);
|
|
35949
|
-
|
|
35950
|
-
|
|
35951
|
-
const isFilterAllowed = React.useMemo(() => {
|
|
35952
|
-
if (!view) {
|
|
35953
|
-
return false;
|
|
36121
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
36122
|
+
return "This field is already used in the query.";
|
|
35954
36123
|
}
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
36124
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
36125
|
+
return "This field is annotated with #NO_UI.";
|
|
36126
|
+
}
|
|
36127
|
+
return "";
|
|
36128
|
+
}, [matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, view, field, path]);
|
|
36129
|
+
const filterDisabledReason = React.useMemo(() => {
|
|
36130
|
+
if (!matchingFieldItem) {
|
|
36131
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
36132
|
+
}
|
|
36133
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
36134
|
+
return `Filtering is only available for a dimension or measure.`;
|
|
36135
|
+
}
|
|
36136
|
+
if (!FILTERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36137
|
+
return "Filtering only supports string, boolean, number, date and time fields.";
|
|
36138
|
+
}
|
|
36139
|
+
return "";
|
|
36140
|
+
}, [fullName, matchingFieldItem]);
|
|
36141
|
+
const orderByDisabledReason = React.useMemo(() => {
|
|
36142
|
+
if (!matchingFieldItem) {
|
|
36143
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
35962
36144
|
}
|
|
35963
|
-
const fieldName = field.name;
|
|
35964
|
-
const outputSchemaFields = view.getOutputSchema().fields;
|
|
35965
36145
|
const segment = getSegmentIfPresent(view);
|
|
35966
|
-
|
|
35967
|
-
|
|
36146
|
+
if (segment && segmentHasOrderBySourceField(segment, path, field.name)) {
|
|
36147
|
+
return "Query is already ordered by this field.";
|
|
36148
|
+
}
|
|
36149
|
+
if (!segment || !segmentHasFieldInOutputSpace(segment, path, field.name)) {
|
|
36150
|
+
return "Order by is only available for fields in the output.";
|
|
36151
|
+
}
|
|
36152
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
36153
|
+
return "Order By is only available for dimension or measure fields.";
|
|
36154
|
+
}
|
|
36155
|
+
if (!ORDERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36156
|
+
return "Order By only supports string, boolean, number, date and time fields.";
|
|
36157
|
+
}
|
|
36158
|
+
return "";
|
|
36159
|
+
}, [matchingFieldItem, view, path, field.name, fullName]);
|
|
35968
36160
|
return {
|
|
35969
|
-
isGroupByAllowed,
|
|
35970
|
-
|
|
35971
|
-
|
|
35972
|
-
|
|
36161
|
+
isGroupByAllowed: !groupByDisabledReason,
|
|
36162
|
+
groupByDisabledReason,
|
|
36163
|
+
isAggregateAllowed: !aggregateDisabledReason,
|
|
36164
|
+
aggregateDisabledReason,
|
|
36165
|
+
isFilterAllowed: !filterDisabledReason,
|
|
36166
|
+
filterDisabledReason,
|
|
36167
|
+
isOrderByAllowed: !orderByDisabledReason,
|
|
36168
|
+
orderByDisabledReason
|
|
35973
36169
|
};
|
|
35974
36170
|
}
|
|
35975
36171
|
const FILTERABLE_TYPES = ["string_type", "boolean_type", "number_type", "date_type", "timestamp_type"];
|
|
@@ -35981,27 +36177,29 @@ function FieldTokenWithActions({
|
|
|
35981
36177
|
}) {
|
|
35982
36178
|
const {
|
|
35983
36179
|
rootQuery,
|
|
35984
|
-
setQuery
|
|
35985
|
-
currentNestView
|
|
36180
|
+
setQuery
|
|
35986
36181
|
} = React.useContext(QueryEditorContext);
|
|
35987
|
-
const view = currentNestView ?? viewDef;
|
|
35988
36182
|
const {
|
|
35989
|
-
|
|
35990
|
-
|
|
35991
|
-
|
|
35992
|
-
|
|
36183
|
+
focusedNestView
|
|
36184
|
+
} = useQueryFocus();
|
|
36185
|
+
const view = focusedNestView ?? viewDef;
|
|
36186
|
+
const {
|
|
36187
|
+
groupByDisabledReason,
|
|
36188
|
+
aggregateDisabledReason,
|
|
36189
|
+
filterDisabledReason,
|
|
36190
|
+
orderByDisabledReason
|
|
35993
36191
|
} = useOperations(view, field, path);
|
|
35994
36192
|
const [isFilterPopoverOpen, setIsFilterPopoverOpen] = React.useState();
|
|
35995
36193
|
const [isTooltipOpen, setIsTooltipOpen] = React.useState(false);
|
|
35996
36194
|
const handleAddOperationAction = (operation, filter) => {
|
|
35997
36195
|
if (field.kind === "dimension" || field.kind === "measure") {
|
|
35998
|
-
if (operation === "groupBy" &&
|
|
36196
|
+
if (operation === "groupBy" && !groupByDisabledReason) {
|
|
35999
36197
|
addGroupBy(view, field, path);
|
|
36000
|
-
} else if (operation === "aggregate" &&
|
|
36198
|
+
} else if (operation === "aggregate" && !aggregateDisabledReason) {
|
|
36001
36199
|
addAggregate(view, field, path);
|
|
36002
|
-
} else if (operation === "orderBy" &&
|
|
36003
|
-
|
|
36004
|
-
} else if (operation === "filter" &&
|
|
36200
|
+
} else if (operation === "orderBy" && !orderByDisabledReason) {
|
|
36201
|
+
addOrderByFromSource(view, path, field.name);
|
|
36202
|
+
} else if (operation === "filter" && !filterDisabledReason && filter) {
|
|
36005
36203
|
addFilter(view, field, path, filter);
|
|
36006
36204
|
}
|
|
36007
36205
|
setQuery == null ? void 0 : setQuery(rootQuery == null ? void 0 : rootQuery.build());
|
|
@@ -36026,7 +36224,7 @@ function FieldTokenWithActions({
|
|
|
36026
36224
|
icon: "insert",
|
|
36027
36225
|
disabled: !(rootQuery == null ? void 0 : rootQuery.isEmpty()),
|
|
36028
36226
|
onClick: handleSetView,
|
|
36029
|
-
tooltip: "Add view",
|
|
36227
|
+
tooltip: !(rootQuery == null ? void 0 : rootQuery.isEmpty()) ? "Can only add a view to an empty query." : "Add view",
|
|
36030
36228
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36031
36229
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36032
36230
|
icon: "nest",
|
|
@@ -36037,8 +36235,8 @@ function FieldTokenWithActions({
|
|
|
36037
36235
|
}) : field.kind === "measure" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
36038
36236
|
children: [/* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36039
36237
|
icon: "aggregate",
|
|
36040
|
-
tooltip: "Add as aggregate",
|
|
36041
|
-
disabled:
|
|
36238
|
+
tooltip: aggregateDisabledReason || "Add as aggregate",
|
|
36239
|
+
disabled: !!aggregateDisabledReason,
|
|
36042
36240
|
onClick: () => handleAddOperationAction("aggregate"),
|
|
36043
36241
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36044
36242
|
}), /* @__PURE__ */ jsxRuntime.jsx(FilterPopover, {
|
|
@@ -36047,23 +36245,23 @@ function FieldTokenWithActions({
|
|
|
36047
36245
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36048
36246
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36049
36247
|
icon: "filter",
|
|
36050
|
-
tooltip: "Add as filter",
|
|
36051
|
-
disabled:
|
|
36248
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36249
|
+
disabled: !!filterDisabledReason,
|
|
36052
36250
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36053
36251
|
}),
|
|
36054
36252
|
onOpenChange: setIsFilterPopoverOpen
|
|
36055
36253
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36056
36254
|
icon: "orderBy",
|
|
36057
|
-
tooltip: "Add as order by",
|
|
36058
|
-
disabled:
|
|
36255
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36256
|
+
disabled: !!orderByDisabledReason,
|
|
36059
36257
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36060
36258
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36061
36259
|
})]
|
|
36062
36260
|
}) : field.kind === "dimension" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
36063
36261
|
children: [/* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36064
36262
|
icon: "groupBy",
|
|
36065
|
-
tooltip: "Add as group by",
|
|
36066
|
-
disabled:
|
|
36263
|
+
tooltip: groupByDisabledReason || "Add as group by",
|
|
36264
|
+
disabled: !!groupByDisabledReason,
|
|
36067
36265
|
onClick: () => handleAddOperationAction("groupBy"),
|
|
36068
36266
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36069
36267
|
}), /* @__PURE__ */ jsxRuntime.jsx(FilterPopover, {
|
|
@@ -36072,20 +36270,26 @@ function FieldTokenWithActions({
|
|
|
36072
36270
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36073
36271
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36074
36272
|
icon: "filter",
|
|
36075
|
-
tooltip: "Add as filter",
|
|
36076
|
-
disabled:
|
|
36273
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36274
|
+
disabled: !!filterDisabledReason,
|
|
36077
36275
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36078
36276
|
}),
|
|
36079
36277
|
onOpenChange: setIsFilterPopoverOpen
|
|
36080
36278
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36081
36279
|
icon: "orderBy",
|
|
36082
|
-
tooltip: "Add as order by",
|
|
36083
|
-
disabled:
|
|
36280
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36281
|
+
disabled: !!orderByDisabledReason,
|
|
36084
36282
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36085
36283
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36086
36284
|
})]
|
|
36087
36285
|
}) : null,
|
|
36088
|
-
onClick: field.kind === "dimension" &&
|
|
36286
|
+
onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => {
|
|
36287
|
+
if (rootQuery == null ? void 0 : rootQuery.isEmpty()) {
|
|
36288
|
+
handleSetView();
|
|
36289
|
+
} else {
|
|
36290
|
+
handleAddView();
|
|
36291
|
+
}
|
|
36292
|
+
} : void 0,
|
|
36089
36293
|
hoverActionsVisible: isFilterPopoverOpen || isTooltipOpen,
|
|
36090
36294
|
tooltip: /* @__PURE__ */ jsxRuntime.jsx(FieldHoverCard, {
|
|
36091
36295
|
field,
|