@malloydata/malloy-explorer 0.0.278-dev250516210719 → 0.0.282-dev250528154617

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()),
@@ -26045,6 +26118,85 @@ const styles$s = {
26045
26118
  $$css: true
26046
26119
  }
26047
26120
  };
26121
+ function LiteralValue({
26122
+ value,
26123
+ customStyle
26124
+ }) {
26125
+ if (!value) {
26126
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26127
+ label: "∅"
26128
+ });
26129
+ }
26130
+ switch (value.kind) {
26131
+ case "boolean_literal":
26132
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26133
+ label: value.boolean_value ? "true" : "false",
26134
+ customStyle
26135
+ });
26136
+ case "date_literal":
26137
+ case "timestamp_literal":
26138
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26139
+ label: "TODO",
26140
+ customStyle
26141
+ });
26142
+ case "null_literal":
26143
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26144
+ label: "∅"
26145
+ });
26146
+ case "number_literal":
26147
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26148
+ label: value.number_value.toLocaleString(),
26149
+ customStyle
26150
+ });
26151
+ case "string_literal":
26152
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26153
+ label: value.string_value,
26154
+ customStyle
26155
+ });
26156
+ case "filter_expression_literal":
26157
+ return /* @__PURE__ */ jsxRuntime.jsx(Token, {
26158
+ label: value.filter_expression_value,
26159
+ customStyle
26160
+ });
26161
+ }
26162
+ }
26163
+ function DrillOperations({
26164
+ drills
26165
+ }) {
26166
+ if (!drills.length) {
26167
+ return null;
26168
+ }
26169
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", {
26170
+ children: [/* @__PURE__ */ jsxRuntime.jsx("div", {
26171
+ ..._stylex.props(styles$s.title),
26172
+ children: "drills"
26173
+ }), /* @__PURE__ */ jsxRuntime.jsx("div", {
26174
+ ...{
26175
+ className: "mly78zum5 mlydt5ytf mly1jnr06f"
26176
+ },
26177
+ children: drills.map((drill, key2) => /* @__PURE__ */ jsxRuntime.jsxs(TokenGroup, {
26178
+ color: "cyan",
26179
+ customStyle: localStyles.tokenGroup,
26180
+ children: [/* @__PURE__ */ jsxRuntime.jsx(Token, {
26181
+ label: drill.filter.fieldReference.name,
26182
+ icon: "filter"
26183
+ }), /* @__PURE__ */ jsxRuntime.jsx(Token, {
26184
+ label: "="
26185
+ }), drill.filter instanceof QB.ASTFilterWithLiteralEquality ? /* @__PURE__ */ jsxRuntime.jsx(LiteralValue, {
26186
+ value: drill.filter.value.node
26187
+ }) : /* @__PURE__ */ jsxRuntime.jsx(Token, {
26188
+ label: drill.filter.filterString
26189
+ })]
26190
+ }, key2))
26191
+ })]
26192
+ });
26193
+ }
26194
+ const localStyles = {
26195
+ tokenGroup: {
26196
+ display: "mly78zum5",
26197
+ $$css: true
26198
+ }
26199
+ };
26048
26200
  function useCombinedRefs() {
26049
26201
  for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) {
26050
26202
  refs[_key] = arguments[_key];
@@ -32419,7 +32571,9 @@ function getOutputNameToInputNameMap(segment) {
32419
32571
  for (const operation of segment.operations.items) {
32420
32572
  if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
32421
32573
  const reference = operation.field.getReference();
32422
- nameMap.set(operation.name, toFullName(reference.path, reference.name));
32574
+ if (reference) {
32575
+ nameMap.set(operation.name, toFullName(reference.path, reference.name));
32576
+ }
32423
32577
  }
32424
32578
  }
32425
32579
  return nameMap;
@@ -32441,8 +32595,11 @@ function segmentHasFieldInOutputSpace(segment, path, name) {
32441
32595
  const match = segment.operations.items.find((operation) => {
32442
32596
  if (operation instanceof QB.ASTGroupByViewOperation || operation instanceof QB.ASTAggregateViewOperation) {
32443
32597
  const reference = operation.field.getReference();
32444
- const isEqual = areReferencesEqual(path, name, reference.path, reference.name);
32445
- return isEqual;
32598
+ if (reference) {
32599
+ return areReferencesEqual(path, name, reference.path, reference.name);
32600
+ } else {
32601
+ return false;
32602
+ }
32446
32603
  }
32447
32604
  return false;
32448
32605
  });
@@ -33159,11 +33316,12 @@ function SortableOperation({
33159
33316
  operation,
33160
33317
  color
33161
33318
  }) {
33319
+ var _a2;
33162
33320
  const {
33163
33321
  setQuery
33164
33322
  } = React.useContext(QueryEditorContext);
33165
33323
  const fieldInfo = operation.getFieldInfo();
33166
- const path = operation.field.getReference().path ?? NULL_PATH;
33324
+ const path = ((_a2 = operation.field.getReference()) == null ? void 0 : _a2.path) ?? NULL_PATH;
33167
33325
  const {
33168
33326
  attributes,
33169
33327
  listeners,
@@ -33364,28 +33522,62 @@ const parsedToLabels = (parsed, filterString) => {
33364
33522
  value = stringClause.escaped_values.join(", ");
33365
33523
  break;
33366
33524
  case "=":
33367
- op = "is";
33368
- value = stringClause.values.join(", ");
33525
+ {
33526
+ const {
33527
+ not,
33528
+ values
33529
+ } = stringClause;
33530
+ op = not ? "is not" : "is";
33531
+ value = values.join(", ");
33532
+ }
33369
33533
  break;
33370
33534
  case "contains":
33371
- op = "contains";
33372
- value = stringClause.values.join(", ");
33535
+ {
33536
+ const {
33537
+ not,
33538
+ values
33539
+ } = stringClause;
33540
+ op = not ? "does not contain" : "contains";
33541
+ value = values.join(", ");
33542
+ }
33373
33543
  break;
33374
33544
  case "starts":
33375
- op = "starts with";
33376
- value = stringClause.values.join(", ");
33545
+ {
33546
+ const {
33547
+ not,
33548
+ values
33549
+ } = stringClause;
33550
+ op = not ? "does not start with" : "starts with";
33551
+ value = values.join(", ");
33552
+ }
33377
33553
  break;
33378
33554
  case "ends":
33379
- op = "is like";
33380
- value = stringClause.values.join(", ");
33555
+ {
33556
+ const {
33557
+ not,
33558
+ values
33559
+ } = stringClause;
33560
+ op = not ? "does not end with" : "ends with";
33561
+ value = values.join(", ");
33562
+ }
33381
33563
  break;
33382
33564
  case "empty":
33383
- op = "is empty";
33384
- value = "";
33565
+ {
33566
+ const {
33567
+ not
33568
+ } = stringClause;
33569
+ op = not ? "is not empty" : "is empty";
33570
+ value = "";
33571
+ }
33385
33572
  break;
33386
33573
  case "null":
33387
- op = stringClause.not ? "is not" : "is";
33388
- value = "null";
33574
+ {
33575
+ const {
33576
+ not
33577
+ } = stringClause;
33578
+ op = not ? "is not" : "is";
33579
+ value = "null";
33580
+ }
33389
33581
  break;
33390
33582
  }
33391
33583
  }
@@ -33549,22 +33741,27 @@ function SingleFilterOperation({
33549
33741
  rootQuery,
33550
33742
  filterOperation
33551
33743
  }) {
33744
+ const {
33745
+ setQuery
33746
+ } = React.useContext(QueryEditorContext);
33747
+ const setFilter = React.useCallback((filter2) => {
33748
+ if (filterOperation.filter instanceof QB.ASTFilterWithFilterString) {
33749
+ filterOperation.filter.setFilter(filter2);
33750
+ }
33751
+ setQuery == null ? void 0 : setQuery(rootQuery.build());
33752
+ }, [filterOperation.filter, rootQuery, setQuery]);
33753
+ if (!(filterOperation.filter instanceof QB.ASTFilterWithFilterString)) {
33754
+ return null;
33755
+ }
33552
33756
  const {
33553
33757
  fieldReference,
33554
33758
  filterString
33555
33759
  } = filterOperation.filter;
33556
33760
  const filter = filterOperation.filter.getFilter();
33557
33761
  const fieldInfo = fieldReference.getFieldInfo();
33558
- const {
33559
- setQuery
33560
- } = React.useContext(QueryEditorContext);
33561
33762
  if (fieldInfo.kind !== "dimension" && fieldInfo.kind !== "measure") {
33562
33763
  throw new Error(`Invalid filter field kind: ${fieldInfo.kind}`);
33563
33764
  }
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
33765
  const {
33569
33766
  op,
33570
33767
  value
@@ -34175,6 +34372,35 @@ const styles$d = {
34175
34372
  $$css: true
34176
34373
  }
34177
34374
  };
34375
+ const NestViewPathContext = /* @__PURE__ */ React.createContext([]);
34376
+ function FocusableView({
34377
+ children,
34378
+ nest
34379
+ }) {
34380
+ const {
34381
+ focusNestView,
34382
+ focusMainView
34383
+ } = useQueryFocus();
34384
+ const parentNestViewPath = React.useContext(NestViewPathContext);
34385
+ return /* @__PURE__ */ jsxRuntime.jsx("div", {
34386
+ onPointerDown: (e) => {
34387
+ e.stopPropagation();
34388
+ if (nest) {
34389
+ focusNestView([...parentNestViewPath, nest.name]);
34390
+ } else {
34391
+ focusMainView();
34392
+ }
34393
+ },
34394
+ children: nest ? /* @__PURE__ */ jsxRuntime.jsx(NestViewPathContext.Provider, {
34395
+ value: [...parentNestViewPath, nest.name],
34396
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", {
34397
+ children
34398
+ })
34399
+ }) : /* @__PURE__ */ jsxRuntime.jsx("div", {
34400
+ children
34401
+ })
34402
+ });
34403
+ }
34178
34404
  function NestOperations({
34179
34405
  rootQuery,
34180
34406
  view,
@@ -34198,31 +34424,14 @@ function NestOperation({
34198
34424
  nest
34199
34425
  }) {
34200
34426
  const {
34201
- setQuery,
34202
- currentNestQueryPanel,
34203
- onCurrentNestQueryPanelChange,
34204
- onCurrentNestViewChange
34427
+ setQuery
34205
34428
  } = React.useContext(QueryEditorContext);
34206
34429
  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
- };
34430
+ const parentNestViewPath = React.useContext(NestViewPathContext);
34431
+ const {
34432
+ focusNestView,
34433
+ isNestViewFocused
34434
+ } = useQueryFocus();
34226
34435
  const getControls = (nest2) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
34227
34436
  children: [/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, {
34228
34437
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
@@ -34235,7 +34444,7 @@ function NestOperation({
34235
34444
  icon: "clear",
34236
34445
  label: "Delete Query",
34237
34446
  onClick: () => {
34238
- focusParentQueryPanel();
34447
+ focusNestView([...parentNestViewPath]);
34239
34448
  nest2.delete();
34240
34449
  setQuery == null ? void 0 : setQuery(rootQuery.build());
34241
34450
  }
@@ -34250,21 +34459,19 @@ function NestOperation({
34250
34459
  view: nest2.view
34251
34460
  })]
34252
34461
  });
34253
- return /* @__PURE__ */ jsxRuntime.jsx("div", {
34254
- ...{
34255
- className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
34256
- },
34462
+ return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
34463
+ nest,
34257
34464
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", {
34258
- ref: panelRef,
34259
- onPointerDownCapture: focusCurrentNestQueryPanel,
34260
- "data-nest-panel": true,
34465
+ ...{
34466
+ className: "mlyj3b58b mly1yf7rl7 mly1xmf6yo mlyh8yej3"
34467
+ },
34261
34468
  children: [/* @__PURE__ */ jsxRuntime.jsx(CollapsiblePanel, {
34262
34469
  title: nest.name,
34263
34470
  icon: viewToVisualizationIcon(nest.view),
34264
34471
  defaultOpen: true,
34265
34472
  controls: getControls(nest),
34266
34473
  collapsedControls: getControls(nest),
34267
- isFocused: isCurrentNestQueryPanelFocused,
34474
+ isFocused: isNestViewFocused([...parentNestViewPath, nest.name]),
34268
34475
  children: /* @__PURE__ */ jsxRuntime.jsx(View, {
34269
34476
  rootQuery,
34270
34477
  view: nest.view
@@ -34276,14 +34483,8 @@ function NestOperation({
34276
34483
  open: renameOpen,
34277
34484
  setOpen: setRenameOpen
34278
34485
  })]
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);
34486
+ }, nest.name)
34487
+ });
34287
34488
  }
34288
34489
  function Operations({
34289
34490
  rootQuery,
@@ -34292,6 +34493,7 @@ function Operations({
34292
34493
  }) {
34293
34494
  const groupBys = [];
34294
34495
  const aggregates = [];
34496
+ const drills = [];
34295
34497
  const filters = [];
34296
34498
  const orderBys = [];
34297
34499
  const nests = [];
@@ -34313,6 +34515,8 @@ function Operations({
34313
34515
  orderBys.push(operation);
34314
34516
  } else if (operation instanceof QB.ASTNestViewOperation) {
34315
34517
  nests.push(operation);
34518
+ } else if (operation instanceof QB.ASTDrillViewOperation) {
34519
+ drills.push(operation);
34316
34520
  } else {
34317
34521
  limit = operation;
34318
34522
  }
@@ -34331,6 +34535,9 @@ function Operations({
34331
34535
  segment,
34332
34536
  view,
34333
34537
  aggregates
34538
+ }), /* @__PURE__ */ jsxRuntime.jsx(DrillOperations, {
34539
+ rootQuery,
34540
+ drills
34334
34541
  }), /* @__PURE__ */ jsxRuntime.jsx(FilterOperations, {
34335
34542
  rootQuery,
34336
34543
  filters
@@ -34452,19 +34659,13 @@ function Query({
34452
34659
  setQuery
34453
34660
  }) {
34454
34661
  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,
34662
+ focusMainView,
34663
+ isMainViewFocused
34664
+ } = useQueryFocus();
34665
+ return /* @__PURE__ */ jsxRuntime.jsx(FocusableView, {
34465
34666
  children: /* @__PURE__ */ jsxRuntime.jsxs(CollapsiblePanel, {
34466
34667
  title: "Main query",
34467
- isFocused: !currentNestQueryPanel,
34668
+ isFocused: isMainViewFocused,
34468
34669
  controls: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
34469
34670
  children: [/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu, {
34470
34671
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, {
@@ -34478,7 +34679,7 @@ function Query({
34478
34679
  icon: "clear",
34479
34680
  label: "Clear query",
34480
34681
  onClick: () => {
34481
- focusMainQueryPanel();
34682
+ focusMainView();
34482
34683
  setQuery == null ? void 0 : setQuery(void 0);
34483
34684
  },
34484
34685
  disabled: rootQuery.isEmpty()
@@ -35359,6 +35560,7 @@ const styles$5 = {
35359
35560
  }
35360
35561
  };
35361
35562
  function ResultDisplay({
35563
+ source,
35362
35564
  query
35363
35565
  }) {
35364
35566
  let displayComponent;
@@ -35392,6 +35594,7 @@ function ResultDisplay({
35392
35594
  break;
35393
35595
  case "finished":
35394
35596
  displayComponent = /* @__PURE__ */ jsxRuntime.jsx(ResponseDisplay, {
35597
+ source,
35395
35598
  response: query.response
35396
35599
  });
35397
35600
  break;
@@ -35399,6 +35602,7 @@ function ResultDisplay({
35399
35602
  return displayComponent;
35400
35603
  }
35401
35604
  function ResponseDisplay({
35605
+ source,
35402
35606
  response
35403
35607
  }) {
35404
35608
  let messageComponent = null;
@@ -35424,7 +35628,8 @@ function ResponseDisplay({
35424
35628
  children: [(response == null ? void 0 : response.runInfo) && /* @__PURE__ */ jsxRuntime.jsx(RunInfoHover, {
35425
35629
  runInfo: response.runInfo
35426
35630
  }), messageComponent, (response == null ? void 0 : response.result) && /* @__PURE__ */ jsxRuntime.jsx(RenderedResult, {
35427
- result: response.result
35631
+ result: response.result,
35632
+ source
35428
35633
  })]
35429
35634
  });
35430
35635
  }
@@ -35467,14 +35672,30 @@ function Banners({
35467
35672
  });
35468
35673
  }
35469
35674
  function RenderedResult({
35470
- result
35675
+ result,
35676
+ source
35471
35677
  }) {
35472
35678
  const [renderer, setRenderer] = React.useState();
35679
+ const {
35680
+ setQuery
35681
+ } = React.useContext(QueryEditorContext);
35473
35682
  React.useEffect(() => {
35474
35683
  const renderer2 = document.createElement("malloy-render");
35475
35684
  renderer2.malloyResult = result;
35685
+ renderer2.onDrill = ({
35686
+ stableQuery
35687
+ }) => {
35688
+ const rootQuery = new QB.ASTQuery({
35689
+ query: stableQuery,
35690
+ source
35691
+ });
35692
+ setQuery == null ? void 0 : setQuery(rootQuery.build());
35693
+ };
35694
+ renderer2.tableConfig = {
35695
+ enableDrill: true
35696
+ };
35476
35697
  setRenderer(renderer2);
35477
- }, [result]);
35698
+ }, [result, source, setQuery]);
35478
35699
  if (renderer) {
35479
35700
  return /* @__PURE__ */ jsxRuntime.jsx(DOMElement, {
35480
35701
  element: renderer,
@@ -35714,6 +35935,7 @@ function ResultPanel({
35714
35935
  })]
35715
35936
  })]
35716
35937
  }), /* @__PURE__ */ jsxRuntime.jsx(ResultDisplay, {
35938
+ source,
35717
35939
  query: submittedQuery
35718
35940
  })]
35719
35941
  })
@@ -36060,10 +36282,12 @@ function FieldTokenWithActions({
36060
36282
  }) {
36061
36283
  const {
36062
36284
  rootQuery,
36063
- setQuery,
36064
- currentNestView
36285
+ setQuery
36065
36286
  } = React.useContext(QueryEditorContext);
36066
- const view = currentNestView ?? viewDef;
36287
+ const {
36288
+ focusedNestView
36289
+ } = useQueryFocus();
36290
+ const view = focusedNestView ?? viewDef;
36067
36291
  const {
36068
36292
  groupByDisabledReason,
36069
36293
  aggregateDisabledReason,
@@ -36164,7 +36388,13 @@ function FieldTokenWithActions({
36164
36388
  onTooltipOpenChange: setIsTooltipOpen
36165
36389
  })]
36166
36390
  }) : null,
36167
- onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => handleAddView() : void 0,
36391
+ onClick: field.kind === "dimension" && !groupByDisabledReason ? () => handleAddOperationAction("groupBy") : field.kind === "measure" && !aggregateDisabledReason ? () => handleAddOperationAction("aggregate") : field.kind === "view" ? () => {
36392
+ if (rootQuery == null ? void 0 : rootQuery.isEmpty()) {
36393
+ handleSetView();
36394
+ } else {
36395
+ handleAddView();
36396
+ }
36397
+ } : void 0,
36168
36398
  hoverActionsVisible: isFilterPopoverOpen || isTooltipOpen,
36169
36399
  tooltip: /* @__PURE__ */ jsxRuntime.jsx(FieldHoverCard, {
36170
36400
  field,