@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/esm/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
|
|
17
17
|
import * as React from "react";
|
|
18
18
|
import React__default, { useLayoutEffect, useEffect, useMemo, useState, useRef, createElement, useContext, useCallback, createContext, memo, useReducer } from "react";
|
|
19
19
|
import * as QB from "@malloydata/malloy-query-builder";
|
|
20
|
-
import { ASTArrowQueryDefinition, ASTSegmentViewDefinition, ASTRefinementViewDefinition, ASTOrderByViewOperation,
|
|
20
|
+
import { ASTArrowQueryDefinition, ASTSegmentViewDefinition, ASTRefinementViewDefinition, ASTOrderByViewOperation, ASTGroupByViewOperation, ASTAggregateViewOperation, ASTLimitViewOperation, ASTNestViewOperation, ASTTimeTruncationExpression, ASTWhereViewOperation, ASTHavingViewOperation, ASTArrowViewDefinition } from "@malloydata/malloy-query-builder";
|
|
21
21
|
import { Tag } from "@malloydata/malloy-tag";
|
|
22
22
|
import { TemporalFilterExpression, BooleanFilterExpression, NumberFilterExpression, StringFilterExpression } from "@malloydata/malloy-filter";
|
|
23
23
|
import "@malloydata/render/webcomponent";
|
|
@@ -29932,6 +29932,11 @@ function getViewDefinition(parent) {
|
|
|
29932
29932
|
return parent instanceof ASTArrowQueryDefinition ? parent.view : parent.definition;
|
|
29933
29933
|
}
|
|
29934
29934
|
function getInputSchemaFromViewParent(parent) {
|
|
29935
|
+
if (!parent) {
|
|
29936
|
+
return {
|
|
29937
|
+
fields: []
|
|
29938
|
+
};
|
|
29939
|
+
}
|
|
29935
29940
|
const definition = getViewDefinition(parent);
|
|
29936
29941
|
return definition.getInputSchema();
|
|
29937
29942
|
}
|
|
@@ -32382,12 +32387,49 @@ const styles$g = {
|
|
|
32382
32387
|
$$css: true
|
|
32383
32388
|
}
|
|
32384
32389
|
};
|
|
32390
|
+
function toFullName(path, name) {
|
|
32391
|
+
return [...path || [], name].join(".");
|
|
32392
|
+
}
|
|
32385
32393
|
function segmentHasLimit(segment) {
|
|
32386
32394
|
return segment.operations.items.find((operation) => operation instanceof ASTLimitViewOperation) !== void 0;
|
|
32387
32395
|
}
|
|
32388
32396
|
function segmentHasOrderBy(segment, name) {
|
|
32389
32397
|
return segment.operations.items.find((operation) => operation instanceof ASTOrderByViewOperation && operation.name === name) !== void 0;
|
|
32390
32398
|
}
|
|
32399
|
+
function getOutputNameToInputNameMap(segment) {
|
|
32400
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
32401
|
+
for (const operation of segment.operations.items) {
|
|
32402
|
+
if (operation instanceof ASTGroupByViewOperation || operation instanceof ASTAggregateViewOperation) {
|
|
32403
|
+
const reference = operation.field.getReference();
|
|
32404
|
+
nameMap.set(operation.name, toFullName(reference.path, reference.name));
|
|
32405
|
+
}
|
|
32406
|
+
}
|
|
32407
|
+
return nameMap;
|
|
32408
|
+
}
|
|
32409
|
+
function segmentHasOrderBySourceField(segment, path, name) {
|
|
32410
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32411
|
+
const fullInputName = toFullName(path, name);
|
|
32412
|
+
return !!segment.operations.items.find((operation) => {
|
|
32413
|
+
if (operation instanceof ASTOrderByViewOperation && nameMap.has(operation.name)) {
|
|
32414
|
+
return fullInputName === nameMap.get(operation.name);
|
|
32415
|
+
}
|
|
32416
|
+
return false;
|
|
32417
|
+
});
|
|
32418
|
+
}
|
|
32419
|
+
function areReferencesEqual(path1, name1, path2, name2) {
|
|
32420
|
+
return name1 === name2 && (path1 || []).join(".") === (path2 || []).join(".");
|
|
32421
|
+
}
|
|
32422
|
+
function segmentHasFieldInOutputSpace(segment, path, name) {
|
|
32423
|
+
const match = segment.operations.items.find((operation) => {
|
|
32424
|
+
if (operation instanceof ASTGroupByViewOperation || operation instanceof ASTAggregateViewOperation) {
|
|
32425
|
+
const reference = operation.field.getReference();
|
|
32426
|
+
const isEqual = areReferencesEqual(path, name, reference.path, reference.name);
|
|
32427
|
+
return isEqual;
|
|
32428
|
+
}
|
|
32429
|
+
return false;
|
|
32430
|
+
});
|
|
32431
|
+
return !!match;
|
|
32432
|
+
}
|
|
32391
32433
|
function segmentNestNo(segment, name) {
|
|
32392
32434
|
return segment.operations.items.reduce((acc, operation) => {
|
|
32393
32435
|
if (operation instanceof ASTNestViewOperation) {
|
|
@@ -32442,6 +32484,19 @@ function addNest(view, field) {
|
|
|
32442
32484
|
}
|
|
32443
32485
|
segment.addNest(field.name, rename);
|
|
32444
32486
|
}
|
|
32487
|
+
function addOrderByFromSource(view, path, name, direction = "desc") {
|
|
32488
|
+
const fullInputName = toFullName(path, name);
|
|
32489
|
+
let orderByName = name;
|
|
32490
|
+
const segment = view.getOrAddDefaultSegment();
|
|
32491
|
+
const nameMap = getOutputNameToInputNameMap(segment);
|
|
32492
|
+
for (const entry of nameMap.entries()) {
|
|
32493
|
+
if (entry[1] === fullInputName) {
|
|
32494
|
+
orderByName = entry[0];
|
|
32495
|
+
break;
|
|
32496
|
+
}
|
|
32497
|
+
}
|
|
32498
|
+
segment.addOrderBy(orderByName, direction);
|
|
32499
|
+
}
|
|
32445
32500
|
function addOrderBy(view, field, direction = "desc") {
|
|
32446
32501
|
const segment = view.getOrAddDefaultSegment();
|
|
32447
32502
|
segment.addOrderBy(field.name, direction);
|
|
@@ -32455,6 +32510,9 @@ function addFilter(view, field, path, filter) {
|
|
|
32455
32510
|
}
|
|
32456
32511
|
}
|
|
32457
32512
|
function getSegmentIfPresent(parent) {
|
|
32513
|
+
if (!parent) {
|
|
32514
|
+
return void 0;
|
|
32515
|
+
}
|
|
32458
32516
|
const definition = getViewDefinition(parent);
|
|
32459
32517
|
if (definition instanceof ASTSegmentViewDefinition) {
|
|
32460
32518
|
return definition;
|
|
@@ -35896,62 +35954,83 @@ const FIELD_KIND_TO_TITLE = {
|
|
|
35896
35954
|
dimension: "Dimensions"
|
|
35897
35955
|
};
|
|
35898
35956
|
function useOperations(view, field, path) {
|
|
35899
|
-
const
|
|
35957
|
+
const fullName = toFullName(path, field.name);
|
|
35958
|
+
const flattenedFields = useMemo(() => {
|
|
35900
35959
|
const {
|
|
35901
35960
|
fields
|
|
35902
35961
|
} = getInputSchemaFromViewParent(view);
|
|
35903
|
-
|
|
35904
|
-
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35908
|
-
|
|
35909
|
-
const
|
|
35910
|
-
const {
|
|
35911
|
-
fields
|
|
35912
|
-
} = getInputSchemaFromViewParent(view);
|
|
35913
|
-
return new Set(flattenFieldsTree(fields).filter(({
|
|
35914
|
-
field: field2
|
|
35915
|
-
}) => field2.kind === "measure").map(({
|
|
35916
|
-
field: field2
|
|
35917
|
-
}) => field2.name));
|
|
35918
|
-
}, [view]);
|
|
35919
|
-
const isGroupByAllowed = useMemo(() => {
|
|
35920
|
-
if (!view) {
|
|
35921
|
-
return false;
|
|
35922
|
-
}
|
|
35962
|
+
const inputPath = path.join(".");
|
|
35963
|
+
return flattenFieldsTree(fields).filter((fieldItem) => {
|
|
35964
|
+
return fieldItem.path.join(".") === inputPath;
|
|
35965
|
+
});
|
|
35966
|
+
}, [path, view]);
|
|
35967
|
+
const matchingFieldItem = flattenedFields.find((fieldItem) => field.name === fieldItem.field.name);
|
|
35968
|
+
const groupByDisabledReason = useMemo(() => {
|
|
35923
35969
|
const segment = getSegmentIfPresent(view);
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
if (
|
|
35928
|
-
return
|
|
35970
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "dimension") {
|
|
35971
|
+
return "Grouping is only available on a dimenion.";
|
|
35972
|
+
}
|
|
35973
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
35974
|
+
return "Cannot group by a field already in the view.";
|
|
35975
|
+
}
|
|
35976
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
35977
|
+
return "This field is annotated with #NO_UI.";
|
|
35978
|
+
}
|
|
35979
|
+
return "";
|
|
35980
|
+
}, [view, matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, field, path]);
|
|
35981
|
+
const aggregateDisabledReason = useMemo(() => {
|
|
35982
|
+
if ((matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind) !== "measure") {
|
|
35983
|
+
return "Aggregation only supports measure fields.";
|
|
35929
35984
|
}
|
|
35930
35985
|
const segment = getSegmentIfPresent(view);
|
|
35931
|
-
|
|
35932
|
-
|
|
35933
|
-
const isFilterAllowed = useMemo(() => {
|
|
35934
|
-
if (!view) {
|
|
35935
|
-
return false;
|
|
35986
|
+
if (segment == null ? void 0 : segment.hasField(field.name, path)) {
|
|
35987
|
+
return "This field is already used in the query.";
|
|
35936
35988
|
}
|
|
35937
|
-
|
|
35938
|
-
|
|
35939
|
-
|
|
35940
|
-
|
|
35941
|
-
|
|
35942
|
-
|
|
35943
|
-
|
|
35989
|
+
if (!isNotAnnotatedFilteredField(field)) {
|
|
35990
|
+
return "This field is annotated with #NO_UI.";
|
|
35991
|
+
}
|
|
35992
|
+
return "";
|
|
35993
|
+
}, [matchingFieldItem == null ? void 0 : matchingFieldItem.field.kind, view, field, path]);
|
|
35994
|
+
const filterDisabledReason = useMemo(() => {
|
|
35995
|
+
if (!matchingFieldItem) {
|
|
35996
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
35997
|
+
}
|
|
35998
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
35999
|
+
return `Filtering is only available for a dimension or measure.`;
|
|
36000
|
+
}
|
|
36001
|
+
if (!FILTERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36002
|
+
return "Filtering only supports string, boolean, number, date and time fields.";
|
|
36003
|
+
}
|
|
36004
|
+
return "";
|
|
36005
|
+
}, [fullName, matchingFieldItem]);
|
|
36006
|
+
const orderByDisabledReason = useMemo(() => {
|
|
36007
|
+
if (!matchingFieldItem) {
|
|
36008
|
+
return `Unexpected Error: Could not find a field ${fullName}.`;
|
|
35944
36009
|
}
|
|
35945
|
-
const fieldName = field.name;
|
|
35946
|
-
const outputSchemaFields = view.getOutputSchema().fields;
|
|
35947
36010
|
const segment = getSegmentIfPresent(view);
|
|
35948
|
-
|
|
35949
|
-
|
|
36011
|
+
if (segment && segmentHasOrderBySourceField(segment, path, field.name)) {
|
|
36012
|
+
return "Query is already ordered by this field.";
|
|
36013
|
+
}
|
|
36014
|
+
if (!segment || !segmentHasFieldInOutputSpace(segment, path, field.name)) {
|
|
36015
|
+
return "Order by is only available for fields in the output.";
|
|
36016
|
+
}
|
|
36017
|
+
if (!["dimension", "measure"].includes(matchingFieldItem.field.kind)) {
|
|
36018
|
+
return "Order By is only available for dimension or measure fields.";
|
|
36019
|
+
}
|
|
36020
|
+
if (!ORDERABLE_TYPES.includes(matchingFieldItem.field.type.kind)) {
|
|
36021
|
+
return "Order By only supports string, boolean, number, date and time fields.";
|
|
36022
|
+
}
|
|
36023
|
+
return "";
|
|
36024
|
+
}, [matchingFieldItem, view, path, field.name, fullName]);
|
|
35950
36025
|
return {
|
|
35951
|
-
isGroupByAllowed,
|
|
35952
|
-
|
|
35953
|
-
|
|
35954
|
-
|
|
36026
|
+
isGroupByAllowed: !groupByDisabledReason,
|
|
36027
|
+
groupByDisabledReason,
|
|
36028
|
+
isAggregateAllowed: !aggregateDisabledReason,
|
|
36029
|
+
aggregateDisabledReason,
|
|
36030
|
+
isFilterAllowed: !filterDisabledReason,
|
|
36031
|
+
filterDisabledReason,
|
|
36032
|
+
isOrderByAllowed: !orderByDisabledReason,
|
|
36033
|
+
orderByDisabledReason
|
|
35955
36034
|
};
|
|
35956
36035
|
}
|
|
35957
36036
|
const FILTERABLE_TYPES = ["string_type", "boolean_type", "number_type", "date_type", "timestamp_type"];
|
|
@@ -35968,22 +36047,22 @@ function FieldTokenWithActions({
|
|
|
35968
36047
|
} = React__default.useContext(QueryEditorContext);
|
|
35969
36048
|
const view = currentNestView ?? viewDef;
|
|
35970
36049
|
const {
|
|
35971
|
-
|
|
35972
|
-
|
|
35973
|
-
|
|
35974
|
-
|
|
36050
|
+
groupByDisabledReason,
|
|
36051
|
+
aggregateDisabledReason,
|
|
36052
|
+
filterDisabledReason,
|
|
36053
|
+
orderByDisabledReason
|
|
35975
36054
|
} = useOperations(view, field, path);
|
|
35976
36055
|
const [isFilterPopoverOpen, setIsFilterPopoverOpen] = useState();
|
|
35977
36056
|
const [isTooltipOpen, setIsTooltipOpen] = useState(false);
|
|
35978
36057
|
const handleAddOperationAction = (operation, filter) => {
|
|
35979
36058
|
if (field.kind === "dimension" || field.kind === "measure") {
|
|
35980
|
-
if (operation === "groupBy" &&
|
|
36059
|
+
if (operation === "groupBy" && !groupByDisabledReason) {
|
|
35981
36060
|
addGroupBy(view, field, path);
|
|
35982
|
-
} else if (operation === "aggregate" &&
|
|
36061
|
+
} else if (operation === "aggregate" && !aggregateDisabledReason) {
|
|
35983
36062
|
addAggregate(view, field, path);
|
|
35984
|
-
} else if (operation === "orderBy" &&
|
|
35985
|
-
|
|
35986
|
-
} else if (operation === "filter" &&
|
|
36063
|
+
} else if (operation === "orderBy" && !orderByDisabledReason) {
|
|
36064
|
+
addOrderByFromSource(view, path, field.name);
|
|
36065
|
+
} else if (operation === "filter" && !filterDisabledReason && filter) {
|
|
35987
36066
|
addFilter(view, field, path, filter);
|
|
35988
36067
|
}
|
|
35989
36068
|
setQuery == null ? void 0 : setQuery(rootQuery == null ? void 0 : rootQuery.build());
|
|
@@ -36008,7 +36087,7 @@ function FieldTokenWithActions({
|
|
|
36008
36087
|
icon: "insert",
|
|
36009
36088
|
disabled: !(rootQuery == null ? void 0 : rootQuery.isEmpty()),
|
|
36010
36089
|
onClick: handleSetView,
|
|
36011
|
-
tooltip: "Add view",
|
|
36090
|
+
tooltip: !(rootQuery == null ? void 0 : rootQuery.isEmpty()) ? "Can only add a view to an empty query." : "Add view",
|
|
36012
36091
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36013
36092
|
}), /* @__PURE__ */ jsx(ActionButton, {
|
|
36014
36093
|
icon: "nest",
|
|
@@ -36019,8 +36098,8 @@ function FieldTokenWithActions({
|
|
|
36019
36098
|
}) : field.kind === "measure" ? /* @__PURE__ */ jsxs(Fragment, {
|
|
36020
36099
|
children: [/* @__PURE__ */ jsx(ActionButton, {
|
|
36021
36100
|
icon: "aggregate",
|
|
36022
|
-
tooltip: "Add as aggregate",
|
|
36023
|
-
disabled:
|
|
36101
|
+
tooltip: aggregateDisabledReason || "Add as aggregate",
|
|
36102
|
+
disabled: !!aggregateDisabledReason,
|
|
36024
36103
|
onClick: () => handleAddOperationAction("aggregate"),
|
|
36025
36104
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36026
36105
|
}), /* @__PURE__ */ jsx(FilterPopover, {
|
|
@@ -36029,23 +36108,23 @@ function FieldTokenWithActions({
|
|
|
36029
36108
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36030
36109
|
trigger: /* @__PURE__ */ jsx(ActionButton, {
|
|
36031
36110
|
icon: "filter",
|
|
36032
|
-
tooltip: "Add as filter",
|
|
36033
|
-
disabled:
|
|
36111
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36112
|
+
disabled: !!filterDisabledReason,
|
|
36034
36113
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36035
36114
|
}),
|
|
36036
36115
|
onOpenChange: setIsFilterPopoverOpen
|
|
36037
36116
|
}), /* @__PURE__ */ jsx(ActionButton, {
|
|
36038
36117
|
icon: "orderBy",
|
|
36039
|
-
tooltip: "Add as order by",
|
|
36040
|
-
disabled:
|
|
36118
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36119
|
+
disabled: !!orderByDisabledReason,
|
|
36041
36120
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36042
36121
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36043
36122
|
})]
|
|
36044
36123
|
}) : field.kind === "dimension" ? /* @__PURE__ */ jsxs(Fragment, {
|
|
36045
36124
|
children: [/* @__PURE__ */ jsx(ActionButton, {
|
|
36046
36125
|
icon: "groupBy",
|
|
36047
|
-
tooltip: "Add as group by",
|
|
36048
|
-
disabled:
|
|
36126
|
+
tooltip: groupByDisabledReason || "Add as group by",
|
|
36127
|
+
disabled: !!groupByDisabledReason,
|
|
36049
36128
|
onClick: () => handleAddOperationAction("groupBy"),
|
|
36050
36129
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36051
36130
|
}), /* @__PURE__ */ jsx(FilterPopover, {
|
|
@@ -36054,20 +36133,20 @@ function FieldTokenWithActions({
|
|
|
36054
36133
|
setFilter: (filter) => handleAddOperationAction("filter", filter),
|
|
36055
36134
|
trigger: /* @__PURE__ */ jsx(ActionButton, {
|
|
36056
36135
|
icon: "filter",
|
|
36057
|
-
tooltip: "Add as filter",
|
|
36058
|
-
disabled:
|
|
36136
|
+
tooltip: filterDisabledReason || "Add as filter",
|
|
36137
|
+
disabled: !!filterDisabledReason,
|
|
36059
36138
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36060
36139
|
}),
|
|
36061
36140
|
onOpenChange: setIsFilterPopoverOpen
|
|
36062
36141
|
}), /* @__PURE__ */ jsx(ActionButton, {
|
|
36063
36142
|
icon: "orderBy",
|
|
36064
|
-
tooltip: "Add as order by",
|
|
36065
|
-
disabled:
|
|
36143
|
+
tooltip: orderByDisabledReason || "Add as order by",
|
|
36144
|
+
disabled: !!orderByDisabledReason,
|
|
36066
36145
|
onClick: () => handleAddOperationAction("orderBy"),
|
|
36067
36146
|
onTooltipOpenChange: setIsTooltipOpen
|
|
36068
36147
|
})]
|
|
36069
36148
|
}) : null,
|
|
36070
|
-
onClick: field.kind === "dimension" &&
|
|
36149
|
+
onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => handleAddView() : void 0,
|
|
36071
36150
|
hoverActionsVisible: isFilterPopoverOpen || isTooltipOpen,
|
|
36072
36151
|
tooltip: /* @__PURE__ */ jsx(FieldHoverCard, {
|
|
36073
36152
|
field,
|