@malloydata/malloy-explorer 0.0.278-dev250516210719 → 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.
@@ -4,7 +4,9 @@ import { SearchValueMapResult } from "../contexts/QueryEditorContext";
4
4
  declare export interface MalloyExplorerProviderProps {
5
5
  source: Malloy.SourceInfo;
6
6
  query?: Malloy.Query;
7
- setQuery?: (query: Malloy.Query | void) => void;
7
+ onQueryChange?: (query: Malloy.Query | void) => void;
8
+ focusedNestViewPath: string[];
9
+ onFocusedNestViewPathChange: (path: string[]) => void;
8
10
  children: ReactNode | ReactNode[];
9
11
  topValues?: SearchValueMapResult[];
10
12
  }
@@ -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
- setQuery,
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(QueryEditorContext.Provider, {
3357
- value: {
3358
- source,
3359
- rootQuery,
3360
- setQuery,
3361
- topValues,
3362
- currentNestQueryPanel,
3363
- onCurrentNestQueryPanelChange: setCurrentNestQueryPanel,
3364
- currentNestView,
3365
- onCurrentNestViewChange: setCurrentNestView
3366
- },
3367
- children
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
- focusMainQueryPanel();
25995
+ focusMainView();
25923
25996
  setQuery == null ? void 0 : setQuery(void 0);
25924
25997
  },
25925
25998
  isDisabled: !rootQuery || (rootQuery == null ? void 0 : rootQuery.isEmpty()),
@@ -32419,7 +32492,9 @@ function getOutputNameToInputNameMap(segment) {
32419
32492
  for (const operation of segment.operations.items) {
32420
32493
  if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
32421
32494
  const reference = operation.field.getReference();
32422
- nameMap.set(operation.name, toFullName(reference.path, reference.name));
32495
+ if (reference) {
32496
+ nameMap.set(operation.name, toFullName(reference.path, reference.name));
32497
+ }
32423
32498
  }
32424
32499
  }
32425
32500
  return nameMap;
@@ -32441,8 +32516,11 @@ function segmentHasFieldInOutputSpace(segment, path, name) {
32441
32516
  const match = segment.operations.items.find((operation) => {
32442
32517
  if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
32443
32518
  const reference = operation.field.getReference();
32444
- const isEqual = areReferencesEqual(path, name, reference.path, reference.name);
32445
- return isEqual;
32519
+ if (reference) {
32520
+ return areReferencesEqual(path, name, reference.path, reference.name);
32521
+ } else {
32522
+ return false;
32523
+ }
32446
32524
  }
32447
32525
  return false;
32448
32526
  });
@@ -33159,11 +33237,12 @@ function SortableOperation({
33159
33237
  operation,
33160
33238
  color
33161
33239
  }) {
33240
+ var _a2;
33162
33241
  const {
33163
33242
  setQuery
33164
33243
  } = React.useContext(QueryEditorContext);
33165
33244
  const fieldInfo = operation.getFieldInfo();
33166
- const path = operation.field.getReference().path ?? NULL_PATH;
33245
+ const path = ((_a2 = operation.field.getReference()) == null ? void 0 : _a2.path) ?? NULL_PATH;
33167
33246
  const {
33168
33247
  attributes,
33169
33248
  listeners,
@@ -33364,28 +33443,62 @@ const parsedToLabels = (parsed, filterString) => {
33364
33443
  value = stringClause.escaped_values.join(", ");
33365
33444
  break;
33366
33445
  case "=":
33367
- op = "is";
33368
- value = stringClause.values.join(", ");
33446
+ {
33447
+ const {
33448
+ not,
33449
+ values
33450
+ } = stringClause;
33451
+ op = not ? "is not" : "is";
33452
+ value = values.join(", ");
33453
+ }
33369
33454
  break;
33370
33455
  case "contains":
33371
- op = "contains";
33372
- value = stringClause.values.join(", ");
33456
+ {
33457
+ const {
33458
+ not,
33459
+ values
33460
+ } = stringClause;
33461
+ op = not ? "does not contain" : "contains";
33462
+ value = values.join(", ");
33463
+ }
33373
33464
  break;
33374
33465
  case "starts":
33375
- op = "starts with";
33376
- value = stringClause.values.join(", ");
33466
+ {
33467
+ const {
33468
+ not,
33469
+ values
33470
+ } = stringClause;
33471
+ op = not ? "does not start with" : "starts with";
33472
+ value = values.join(", ");
33473
+ }
33377
33474
  break;
33378
33475
  case "ends":
33379
- op = "is like";
33380
- value = stringClause.values.join(", ");
33476
+ {
33477
+ const {
33478
+ not,
33479
+ values
33480
+ } = stringClause;
33481
+ op = not ? "does not end with" : "ends with";
33482
+ value = values.join(", ");
33483
+ }
33381
33484
  break;
33382
33485
  case "empty":
33383
- op = "is empty";
33384
- value = "";
33486
+ {
33487
+ const {
33488
+ not
33489
+ } = stringClause;
33490
+ op = not ? "is not empty" : "is empty";
33491
+ value = "";
33492
+ }
33385
33493
  break;
33386
33494
  case "null":
33387
- op = stringClause.not ? "is not" : "is";
33388
- value = "null";
33495
+ {
33496
+ const {
33497
+ not
33498
+ } = stringClause;
33499
+ op = not ? "is not" : "is";
33500
+ value = "null";
33501
+ }
33389
33502
  break;
33390
33503
  }
33391
33504
  }
@@ -33549,22 +33662,27 @@ function SingleFilterOperation({
33549
33662
  rootQuery,
33550
33663
  filterOperation
33551
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
+ }
33552
33677
  const {
33553
33678
  fieldReference,
33554
33679
  filterString
33555
33680
  } = filterOperation.filter;
33556
33681
  const filter = filterOperation.filter.getFilter();
33557
33682
  const fieldInfo = fieldReference.getFieldInfo();
33558
- const {
33559
- setQuery
33560
- } = React.useContext(QueryEditorContext);
33561
33683
  if (fieldInfo.kind !== "dimension" && fieldInfo.kind !== "measure") {
33562
33684
  throw new Error(`Invalid filter field kind: ${fieldInfo.kind}`);
33563
33685
  }
33564
- const setFilter = React.useCallback((filter2) => {
33565
- filterOperation.filter.setFilter(filter2);
33566
- setQuery == null ? void 0 : setQuery(rootQuery.build());
33567
- }, [filterOperation.filter, rootQuery, setQuery]);
33568
33686
  const {
33569
33687
  op,
33570
33688
  value
@@ -34175,6 +34293,35 @@ const styles$d = {
34175
34293
  $$css: true
34176
34294
  }
34177
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
+ }
34178
34325
  function NestOperations({
34179
34326
  rootQuery,
34180
34327
  view,
@@ -34198,31 +34345,14 @@ function NestOperation({
34198
34345
  nest
34199
34346
  }) {
34200
34347
  const {
34201
- setQuery,
34202
- currentNestQueryPanel,
34203
- onCurrentNestQueryPanelChange,
34204
- onCurrentNestViewChange
34348
+ setQuery
34205
34349
  } = React.useContext(QueryEditorContext);
34206
34350
  const [renameOpen, setRenameOpen] = React.useState(false);
34207
- const panelRef = React__namespace.useRef(null);
34208
- const isCurrentNestQueryPanelFocused = currentNestQueryPanel !== null && panelRef.current == currentNestQueryPanel;
34209
- React__namespace.useEffect(() => {
34210
- if (isCurrentNestQueryPanelFocused) {
34211
- onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(nest.view);
34212
- }
34213
- }, [nest, isCurrentNestQueryPanelFocused, onCurrentNestViewChange]);
34214
- const focusCurrentNestQueryPanel = () => {
34215
- onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(panelRef.current);
34216
- onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(nest.view);
34217
- };
34218
- const focusParentQueryPanel = () => {
34219
- const currentPanel = panelRef.current;
34220
- const parent = findParentNestQueryPanel(currentPanel);
34221
- onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(parent);
34222
- if (parent === null) {
34223
- onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(null);
34224
- }
34225
- };
34351
+ const parentNestViewPath = React.useContext(NestViewPathContext);
34352
+ const {
34353
+ focusNestView,
34354
+ isNestViewFocused
34355
+ } = useQueryFocus();
34226
34356
  const getControls = (nest2) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
34227
34357
  children: [/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, {
34228
34358
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
@@ -34235,7 +34365,7 @@ function NestOperation({
34235
34365
  icon: "clear",
34236
34366
  label: "Delete Query",
34237
34367
  onClick: () => {
34238
- focusParentQueryPanel();
34368
+ focusNestView([...parentNestViewPath]);
34239
34369
  nest2.delete();
34240
34370
  setQuery == null ? void 0 : setQuery(rootQuery.build());
34241
34371
  }
@@ -34250,21 +34380,19 @@ function NestOperation({
34250
34380
  view: nest2.view
34251
34381
  })]
34252
34382
  });
34253
- return /* @__PURE__ */ jsxRuntime.jsx("div", {
34254
- ...{
34255
- className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
34256
- },
34383
+ return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
34384
+ nest,
34257
34385
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", {
34258
- ref: panelRef,
34259
- onPointerDownCapture: focusCurrentNestQueryPanel,
34260
- "data-nest-panel": true,
34386
+ ...{
34387
+ className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
34388
+ },
34261
34389
  children: [/* @__PURE__ */ jsxRuntime.jsx(CollapsiblePanel, {
34262
34390
  title: nest.name,
34263
34391
  icon: viewToVisualizationIcon(nest.view),
34264
34392
  defaultOpen: true,
34265
34393
  controls: getControls(nest),
34266
34394
  collapsedControls: getControls(nest),
34267
- isFocused: isCurrentNestQueryPanelFocused,
34395
+ isFocused: isNestViewFocused([...parentNestViewPath, nest.name]),
34268
34396
  children: /* @__PURE__ */ jsxRuntime.jsx(View, {
34269
34397
  rootQuery,
34270
34398
  view: nest.view
@@ -34276,14 +34404,8 @@ function NestOperation({
34276
34404
  open: renameOpen,
34277
34405
  setOpen: setRenameOpen
34278
34406
  })]
34279
- })
34280
- }, nest.name);
34281
- }
34282
- function findParentNestQueryPanel(element2) {
34283
- if (!element2 || !element2.parentElement) return null;
34284
- const parentElement = element2.parentElement;
34285
- if (parentElement.dataset.nestPanel !== void 0) return parentElement;
34286
- return findParentNestQueryPanel(parentElement);
34407
+ }, nest.name)
34408
+ });
34287
34409
  }
34288
34410
  function Operations({
34289
34411
  rootQuery,
@@ -34313,7 +34435,8 @@ function Operations({
34313
34435
  orderBys.push(operation);
34314
34436
  } else if (operation instanceof QB.ASTNestViewOperation) {
34315
34437
  nests.push(operation);
34316
- } else {
34438
+ } else if (operation instanceof QB.ASTDrillViewOperation) ;
34439
+ else {
34317
34440
  limit = operation;
34318
34441
  }
34319
34442
  });
@@ -34452,19 +34575,13 @@ function Query({
34452
34575
  setQuery
34453
34576
  }) {
34454
34577
  const {
34455
- currentNestQueryPanel,
34456
- onCurrentNestQueryPanelChange,
34457
- onCurrentNestViewChange
34458
- } = React__namespace.useContext(QueryEditorContext);
34459
- const focusMainQueryPanel = () => {
34460
- onCurrentNestQueryPanelChange == null ? void 0 : onCurrentNestQueryPanelChange(null);
34461
- onCurrentNestViewChange == null ? void 0 : onCurrentNestViewChange(null);
34462
- };
34463
- return /* @__PURE__ */ jsxRuntime.jsx("div", {
34464
- onPointerDownCapture: focusMainQueryPanel,
34578
+ focusMainView,
34579
+ isMainViewFocused
34580
+ } = useQueryFocus();
34581
+ return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
34465
34582
  children: /* @__PURE__ */ jsxRuntime.jsxs(CollapsiblePanel, {
34466
34583
  title: "Main query",
34467
- isFocused: !currentNestQueryPanel,
34584
+ isFocused: isMainViewFocused,
34468
34585
  controls: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
34469
34586
  children: [/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu, {
34470
34587
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
@@ -34478,7 +34595,7 @@ function Query({
34478
34595
  icon: "clear",
34479
34596
  label: "Clear query",
34480
34597
  onClick: () => {
34481
- focusMainQueryPanel();
34598
+ focusMainView();
34482
34599
  setQuery == null ? void 0 : setQuery(void 0);
34483
34600
  },
34484
34601
  disabled: rootQuery.isEmpty()
@@ -36060,10 +36177,12 @@ function FieldTokenWithActions({
36060
36177
  }) {
36061
36178
  const {
36062
36179
  rootQuery,
36063
- setQuery,
36064
- currentNestView
36180
+ setQuery
36065
36181
  } = React.useContext(QueryEditorContext);
36066
- const view = currentNestView ?? viewDef;
36182
+ const {
36183
+ focusedNestView
36184
+ } = useQueryFocus();
36185
+ const view = focusedNestView ?? viewDef;
36067
36186
  const {
36068
36187
  groupByDisabledReason,
36069
36188
  aggregateDisabledReason,
@@ -36164,7 +36283,13 @@ function FieldTokenWithActions({
36164
36283
  onTooltipOpenChange: setIsTooltipOpen
36165
36284
  })]
36166
36285
  }) : null,
36167
- onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => handleAddView() : void 0,
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,
36168
36293
  hoverActionsVisible: isFilterPopoverOpen || isTooltipOpen,
36169
36294
  tooltip: /* @__PURE__ */ jsxRuntime.jsx(FieldHoverCard, {
36170
36295
  field,