@malloydata/malloy-explorer 0.0.278-dev250515234639 → 0.0.278-dev250516210719
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/dist/cjs/index.cjs
CHANGED
|
@@ -29950,6 +29950,11 @@ function getViewDefinition(parent) {
|
|
|
29950
29950
|
return parent instanceof QB.ASTArrowQueryDefinition ? parent.view : parent.definition;
|
|
29951
29951
|
}
|
|
29952
29952
|
function getInputSchemaFromViewParent(parent) {
|
|
29953
|
+
if (!parent) {
|
|
29954
|
+
return {
|
|
29955
|
+
fields: []
|
|
29956
|
+
};
|
|
29957
|
+
}
|
|
29953
29958
|
const definition = getViewDefinition(parent);
|
|
29954
29959
|
return definition.getInputSchema();
|
|
29955
29960
|
}
|
|
@@ -32400,12 +32405,49 @@ const styles$g = {
|
|
|
32400
32405
|
$$css: true
|
|
32401
32406
|
}
|
|
32402
32407
|
};
|
|
32408
|
+
function toFullName(path, name) {
|
|
32409
|
+
return [...path || [], name].join(".");
|
|
32410
|
+
}
|
|
32403
32411
|
function segmentHasLimit(segment) {
|
|
32404
32412
|
return segment.operations.items.find((operation) => operation instanceof QB.ASTLimitViewOperation) !== void 0;
|
|
32405
32413
|
}
|
|
32406
32414
|
function segmentHasOrderBy(segment, name) {
|
|
32407
32415
|
return segment.operations.items.find((operation) => operation instanceof QB.ASTOrderByViewOperation && operation.name === name) !== void 0;
|
|
32408
32416
|
}
|
|
32417
|
+
function getOutputNameToInputNameMap(segment) {
|
|
32418
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
32419
|
+
for (const operation of segment.operations.items) {
|
|
32420
|
+
if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
|
|
32421
|
+
const reference = operation.field.getReference();
|
|
32422
|
+
nameMap.set(operation.name, toFullName(reference.path, reference.name));
|
|
32423
|
+
}
|
|
32424
|
+
}
|
|
32425
|
+
return nameMap;
|
|
32426
|
+
}
|
|
32427
|
+
function segmentHasOrderBySourceField(segment, path, name) {
|
|
32428
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32429
|
+
const fullInputName = toFullName(path, name);
|
|
32430
|
+
return !!segment.operations.items.find((operation) => {
|
|
32431
|
+
if (operation instanceof QB.ASTOrderByViewOperation && nameMap.has(operation.name)) {
|
|
32432
|
+
return fullInputName === nameMap.get(operation.name);
|
|
32433
|
+
}
|
|
32434
|
+
return false;
|
|
32435
|
+
});
|
|
32436
|
+
}
|
|
32437
|
+
function areReferencesEqual(path1, name1, path2, name2) {
|
|
32438
|
+
return name1 === name2 && (path1 || []).join(".") === (path2 || []).join(".");
|
|
32439
|
+
}
|
|
32440
|
+
function segmentHasFieldInOutputSpace(segment, path, name) {
|
|
32441
|
+
const match = segment.operations.items.find((operation) => {
|
|
32442
|
+
if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
|
|
32443
|
+
const reference = operation.field.getReference();
|
|
32444
|
+
const isEqual = areReferencesEqual(path, name, reference.path, reference.name);
|
|
32445
|
+
return isEqual;
|
|
32446
|
+
}
|
|
32447
|
+
return false;
|
|
32448
|
+
});
|
|
32449
|
+
return !!match;
|
|
32450
|
+
}
|
|
32409
32451
|
function segmentNestNo(segment, name) {
|
|
32410
32452
|
return segment.operations.items.reduce((acc, operation) => {
|
|
32411
32453
|
if (operation instanceof QB.ASTNestViewOperation) {
|
|
@@ -32460,6 +32502,19 @@ function addNest(view, field) {
|
|
|
32460
32502
|
}
|
|
32461
32503
|
segment.addNest(field.name, rename);
|
|
32462
32504
|
}
|
|
32505
|
+
function addOrderByFromSource(view, path, name, direction = "desc") {
|
|
32506
|
+
const fullInputName = toFullName(path, name);
|
|
32507
|
+
let orderByName = name;
|
|
32508
|
+
const segment = view.getOrAddDefaultSegment();
|
|
32509
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32510
|
+
for (const entry of nameMap.entries()) {
|
|
32511
|
+
if (entry[1] === fullInputName) {
|
|
32512
|
+
orderByName = entry[0];
|
|
32513
|
+
break;
|
|
32514
|
+
}
|
|
32515
|
+
}
|
|
32516
|
+
segment.addOrderBy(orderByName, direction);
|
|
32517
|
+
}
|
|
32463
32518
|
function addOrderBy(view, field, direction = "desc") {
|
|
32464
32519
|
const segment = view.getOrAddDefaultSegment();
|
|
32465
32520
|
segment.addOrderBy(field.name, direction);
|
|
@@ -32473,6 +32528,9 @@ function addFilter(view, field, path, filter) {
|
|
|
32473
32528
|
}
|
|
32474
32529
|
}
|
|
32475
32530
|
function getSegmentIfPresent(parent) {
|
|
32531
|
+
if (!parent) {
|
|
32532
|
+
return void 0;
|
|
32533
|
+
}
|
|
32476
32534
|
const definition = getViewDefinition(parent);
|
|
32477
32535
|
if (definition instanceof QB.ASTSegmentViewDefinition) {
|
|
32478
32536
|
return definition;
|
|
@@ -35914,62 +35972,83 @@ const FIELD_KIND_TO_TITLE = {
|
|
|
35914
35972
|
dimension: "Dimensions"
|
|
35915
35973
|
};
|
|
35916
35974
|
function useOperations(view, field, path) {
|
|
35917
|
-
const
|
|
35975
|
+
const fullName = toFullName(path, field.name);
|
|
35976
|
+
const flattenedFields = React.useMemo(() => {
|
|
35918
35977
|
const {
|
|
35919
35978
|
fields
|
|
35920
35979
|
} = 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
|
-
}
|
|
35980
|
+
const inputPath = path.join(".");
|
|
35981
|
+
return flattenFieldsTree(fields).filter((fieldItem) => {
|
|
35982
|
+
return fieldItem.path.join(".") === inputPath;
|
|
35983
|
+
});
|
|
35984
|
+
}, [path, view]);
|
|
35985
|
+
const matchingFieldItem = flattenedFields.find((fieldItem) => field.name === fieldItem.field.name);
|
|
35986
|
+
const groupByDisabledReason = React.useMemo(() => {
|
|
35941
35987
|
const segment = getSegmentIfPresent(view);
|
|
35942
|
-
|
|
35943
|
-
|
|
35944
|
-
|
|
35945
|
-
if (
|
|
35946
|
-
return
|
|
35988
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "dimension") {
|
|
35989
|
+
return "Grouping is only available on a dimenion.";
|
|
35990
|
+
}
|
|
35991
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
35992
|
+
return "Cannot group by a field already in the view.";
|
|
35993
|
+
}
|
|
35994
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
35995
|
+
return "This field is annotated with #NO_UI.";
|
|
35996
|
+
}
|
|
35997
|
+
return "";
|
|
35998
|
+
}, [view, matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, field, path]);
|
|
35999
|
+
const aggregateDisabledReason = React.useMemo(() => {
|
|
36000
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "measure") {
|
|
36001
|
+
return "Aggregation only supports measure fields.";
|
|
35947
36002
|
}
|
|
35948
36003
|
const segment = getSegmentIfPresent(view);
|
|
35949
|
-
|
|
35950
|
-
|
|
35951
|
-
const isFilterAllowed = React.useMemo(() => {
|
|
35952
|
-
if (!view) {
|
|
35953
|
-
return false;
|
|
36004
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
36005
|
+
return "This field is already used in the query.";
|
|
35954
36006
|
}
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
36007
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
36008
|
+
return "This field is annotated with #NO_UI.";
|
|
36009
|
+
}
|
|
36010
|
+
return "";
|
|
36011
|
+
}, [matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, view, field, path]);
|
|
36012
|
+
const filterDisabledReason = React.useMemo(() => {
|
|
36013
|
+
if (!matchingFieldItem) {
|
|
36014
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
36015
|
+
}
|
|
36016
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
36017
|
+
return `Filtering is only available for a dimension or measure.`;
|
|
36018
|
+
}
|
|
36019
|
+
if (!FILTERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36020
|
+
return "Filtering only supports string, boolean, number, date and time fields.";
|
|
36021
|
+
}
|
|
36022
|
+
return "";
|
|
36023
|
+
}, [fullName, matchingFieldItem]);
|
|
36024
|
+
const orderByDisabledReason = React.useMemo(() => {
|
|
36025
|
+
if (!matchingFieldItem) {
|
|
36026
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
35962
36027
|
}
|
|
35963
|
-
const fieldName = field.name;
|
|
35964
|
-
const outputSchemaFields = view.getOutputSchema().fields;
|
|
35965
36028
|
const segment = getSegmentIfPresent(view);
|
|
35966
|
-
|
|
35967
|
-
|
|
36029
|
+
if (segment && segmentHasOrderBySourceField(segment, path, field.name)) {
|
|
36030
|
+
return "Query is already ordered by this field.";
|
|
36031
|
+
}
|
|
36032
|
+
if (!segment || !segmentHasFieldInOutputSpace(segment, path, field.name)) {
|
|
36033
|
+
return "Order by is only available for fields in the output.";
|
|
36034
|
+
}
|
|
36035
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
36036
|
+
return "Order By is only available for dimension or measure fields.";
|
|
36037
|
+
}
|
|
36038
|
+
if (!ORDERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36039
|
+
return "Order By only supports string, boolean, number, date and time fields.";
|
|
36040
|
+
}
|
|
36041
|
+
return "";
|
|
36042
|
+
}, [matchingFieldItem, view, path, field.name, fullName]);
|
|
35968
36043
|
return {
|
|
35969
|
-
isGroupByAllowed,
|
|
35970
|
-
|
|
35971
|
-
|
|
35972
|
-
|
|
36044
|
+
isGroupByAllowed: !groupByDisabledReason,
|
|
36045
|
+
groupByDisabledReason,
|
|
36046
|
+
isAggregateAllowed: !aggregateDisabledReason,
|
|
36047
|
+
aggregateDisabledReason,
|
|
36048
|
+
isFilterAllowed: !filterDisabledReason,
|
|
36049
|
+
filterDisabledReason,
|
|
36050
|
+
isOrderByAllowed: !orderByDisabledReason,
|
|
36051
|
+
orderByDisabledReason
|
|
35973
36052
|
};
|
|
35974
36053
|
}
|
|
35975
36054
|
const FILTERABLE_TYPES = ["string_type", "boolean_type", "number_type", "date_type", "timestamp_type"];
|
|
@@ -35986,22 +36065,22 @@ function FieldTokenWithActions({
|
|
|
35986
36065
|
} = React.useContext(QueryEditorContext);
|
|
35987
36066
|
const view = currentNestView ?? viewDef;
|
|
35988
36067
|
const {
|
|
35989
|
-
|
|
35990
|
-
|
|
35991
|
-
|
|
35992
|
-
|
|
36068
|
+
groupByDisabledReason,
|
|
36069
|
+
aggregateDisabledReason,
|
|
36070
|
+
filterDisabledReason,
|
|
36071
|
+
orderByDisabledReason
|
|
35993
36072
|
} = useOperations(view, field, path);
|
|
35994
36073
|
const [isFilterPopoverOpen, setIsFilterPopoverOpen] = React.useState();
|
|
35995
36074
|
const [isTooltipOpen, setIsTooltipOpen] = React.useState(false);
|
|
35996
36075
|
const handleAddOperationAction = (operation, filter) => {
|
|
35997
36076
|
if (field.kind === "dimension" || field.kind === "measure") {
|
|
35998
|
-
if (operation === "groupBy" &&
|
|
36077
|
+
if (operation === "groupBy" && !groupByDisabledReason) {
|
|
35999
36078
|
addGroupBy(view, field, path);
|
|
36000
|
-
} else if (operation === "aggregate" &&
|
|
36079
|
+
} else if (operation === "aggregate" && !aggregateDisabledReason) {
|
|
36001
36080
|
addAggregate(view, field, path);
|
|
36002
|
-
} else if (operation === "orderBy" &&
|
|
36003
|
-
|
|
36004
|
-
} else if (operation === "filter" &&
|
|
36081
|
+
} else if (operation === "orderBy" && !orderByDisabledReason) {
|
|
36082
|
+
addOrderByFromSource(view, path, field.name);
|
|
36083
|
+
} else if (operation === "filter" && !filterDisabledReason && filter) {
|
|
36005
36084
|
addFilter(view, field, path, filter);
|
|
36006
36085
|
}
|
|
36007
36086
|
setQuery == null ? void 0 : setQuery(rootQuery == null ? void 0 : rootQuery.build());
|
|
@@ -36026,7 +36105,7 @@ function FieldTokenWithActions({
|
|
|
36026
36105
|
icon: "insert",
|
|
36027
36106
|
disabled: !(rootQuery == null ? void 0 : rootQuery.isEmpty()),
|
|
36028
36107
|
onClick: handleSetView,
|
|
36029
|
-
tooltip: "Add view",
|
|
36108
|
+
tooltip: !(rootQuery == null ? void 0 : rootQuery.isEmpty()) ? "Can only add a view to an empty query." : "Add view",
|
|
36030
36109
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36031
36110
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36032
36111
|
icon: "nest",
|
|
@@ -36037,8 +36116,8 @@ function FieldTokenWithActions({
|
|
|
36037
36116
|
}) : field.kind === "measure" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
36038
36117
|
children: [/* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36039
36118
|
icon: "aggregate",
|
|
36040
|
-
tooltip: "Add as aggregate",
|
|
36041
|
-
disabled:
|
|
36119
|
+
tooltip: aggregateDisabledReason || "Add as aggregate",
|
|
36120
|
+
disabled: !!aggregateDisabledReason,
|
|
36042
36121
|
onClick: () => handleAddOperationAction("aggregate"),
|
|
36043
36122
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36044
36123
|
}), /* @__PURE__ */ jsxRuntime.jsx(FilterPopover, {
|
|
@@ -36047,23 +36126,23 @@ function FieldTokenWithActions({
|
|
|
36047
36126
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36048
36127
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36049
36128
|
icon: "filter",
|
|
36050
|
-
tooltip: "Add as filter",
|
|
36051
|
-
disabled:
|
|
36129
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36130
|
+
disabled: !!filterDisabledReason,
|
|
36052
36131
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36053
36132
|
}),
|
|
36054
36133
|
onOpenChange: setIsFilterPopoverOpen
|
|
36055
36134
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36056
36135
|
icon: "orderBy",
|
|
36057
|
-
tooltip: "Add as order by",
|
|
36058
|
-
disabled:
|
|
36136
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36137
|
+
disabled: !!orderByDisabledReason,
|
|
36059
36138
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36060
36139
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36061
36140
|
})]
|
|
36062
36141
|
}) : field.kind === "dimension" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
36063
36142
|
children: [/* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36064
36143
|
icon: "groupBy",
|
|
36065
|
-
tooltip: "Add as group by",
|
|
36066
|
-
disabled:
|
|
36144
|
+
tooltip: groupByDisabledReason || "Add as group by",
|
|
36145
|
+
disabled: !!groupByDisabledReason,
|
|
36067
36146
|
onClick: () => handleAddOperationAction("groupBy"),
|
|
36068
36147
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36069
36148
|
}), /* @__PURE__ */ jsxRuntime.jsx(FilterPopover, {
|
|
@@ -36072,20 +36151,20 @@ function FieldTokenWithActions({
|
|
|
36072
36151
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36073
36152
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36074
36153
|
icon: "filter",
|
|
36075
|
-
tooltip: "Add as filter",
|
|
36076
|
-
disabled:
|
|
36154
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36155
|
+
disabled: !!filterDisabledReason,
|
|
36077
36156
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36078
36157
|
}),
|
|
36079
36158
|
onOpenChange: setIsFilterPopoverOpen
|
|
36080
36159
|
}), /* @__PURE__ */ jsxRuntime.jsx(ActionButton, {
|
|
36081
36160
|
icon: "orderBy",
|
|
36082
|
-
tooltip: "Add as order by",
|
|
36083
|
-
disabled:
|
|
36161
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36162
|
+
disabled: !!orderByDisabledReason,
|
|
36084
36163
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36085
36164
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36086
36165
|
})]
|
|
36087
36166
|
}) : null,
|
|
36088
|
-
onClick: field.kind === "dimension" &&
|
|
36167
|
+
onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => handleAddView() : void 0,
|
|
36089
36168
|
hoverActionsVisible: isFilterPopoverOpen || isTooltipOpen,
|
|
36090
36169
|
tooltip: /* @__PURE__ */ jsxRuntime.jsx(FieldHoverCard, {
|
|
36091
36170
|
field,
|