@elaraai/e3-ui-components 1.0.18 → 1.0.20

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/index.js CHANGED
@@ -27,8 +27,9 @@ import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
27
27
  import * as React from "react";
28
28
  import React__default, { useId, useMemo, useContext, createContext, useRef, useEffect, useState, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
29
29
  import { Box, Flex, Text, HStack, Input, useSlotRecipe, useRecipe, VStack, useToken, Drawer, Portal, Field, NativeSelect, Textarea, chakra, Tooltip, SegmentGroup, Menu, HoverCard, useChakraContext, Spinner, Code, Clipboard, IconButton, Badge, Button, Tabs, useTabs } from "@chakra-ui/react";
30
- import { implementUIComponent, SliceEditPopover, SlicePredicateBuilder, formatPredicate, getSomeorUndefined, StateRuntime, buildSliceHandle, DEFAULT_SLICE_STATE, registerPlatformImplementation as registerPlatformImplementation$1, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, OverlayImpl, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
30
+ import { implementUIComponent, getSomeorUndefined, SliceEditPopover, SlicePredicateBuilder, formatPredicate, StateRuntime, buildSliceHandle, DEFAULT_SLICE_STATE, registerPlatformImplementation as registerPlatformImplementation$1, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, OverlayImpl, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
31
31
  import { createPortal } from "react-dom";
32
+ import "@elaraai/e3-ui";
32
33
  import { sliceMatches } from "@elaraai/east-ui/internal";
33
34
  import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery } from "@tanstack/react-query";
34
35
  import { useVirtualizer } from "@tanstack/react-virtual";
@@ -8326,7 +8327,7 @@ function parseManualDraft(leafType, draft) {
8326
8327
  }
8327
8328
  }
8328
8329
  const diffValueEqual = equalFor(Diff.Component.schema);
8329
- function getOpt$2(opt) {
8330
+ function getOpt$1(opt) {
8330
8331
  return opt.type === "some" ? opt.value : void 0;
8331
8332
  }
8332
8333
  const DENSITY_METRICS = {
@@ -8970,9 +8971,9 @@ const EastChakraDiff = memo(function EastChakraDiff2({ value }) {
8970
8971
  () => value.bindings ?? [],
8971
8972
  [value.bindings]
8972
8973
  );
8973
- const interactive = !(getOpt$2(value.readonly) ?? false);
8974
- const onCommittedFn = getOpt$2(value.onCommitted);
8975
- const onDiscardedFn = getOpt$2(value.onDiscarded);
8974
+ const interactive = !(getOpt$1(value.readonly) ?? false);
8975
+ const onCommittedFn = getOpt$1(value.onCommitted);
8976
+ const onDiscardedFn = getOpt$1(value.onDiscarded);
8976
8977
  const density = resolveDensity(value.density);
8977
8978
  const metrics = DENSITY_METRICS[density];
8978
8979
  const eyebrow = useSlotRecipe({ key: "eyebrowRow" });
@@ -56718,7 +56719,7 @@ function freshNodeId() {
56718
56719
  }
56719
56720
  const NODE_TYPES = { ontology: OntologyNode };
56720
56721
  const EDGE_TYPES = { ontology: OntologyEdge };
56721
- function getOpt$1(opt) {
56722
+ function getOpt(opt) {
56722
56723
  return opt.type === "some" ? opt.value : void 0;
56723
56724
  }
56724
56725
  function nextLinkId(existing) {
@@ -57033,10 +57034,10 @@ const EastChakraOntology = memo(function EastChakraOntology2({ value }) {
57033
57034
  var _a2;
57034
57035
  const binding = value.binding;
57035
57036
  const { ontology, pending, mutate } = useBindingOntology(binding);
57036
- const readonly = getOpt$1(value.readonly) ?? false;
57037
- const hideMiniMap = getOpt$1(value.hideMiniMap) ?? false;
57038
- const hideSearch = getOpt$1(value.hideSearch) ?? false;
57039
- const defaultView2 = ((_a2 = getOpt$1(value.defaultView)) == null ? void 0 : _a2.type) ?? "graph";
57037
+ const readonly = getOpt(value.readonly) ?? false;
57038
+ const hideMiniMap = getOpt(value.hideMiniMap) ?? false;
57039
+ const hideSearch = getOpt(value.hideSearch) ?? false;
57040
+ const defaultView2 = ((_a2 = getOpt(value.defaultView)) == null ? void 0 : _a2.type) ?? "graph";
57040
57041
  const [view, setView] = useState(defaultView2);
57041
57042
  const [tableSelectedId, setTableSelectedId] = useState(null);
57042
57043
  const handlers = useMemo(() => {
@@ -57249,12 +57250,13 @@ function useBindingValue(binding) {
57249
57250
  if (!types) return null;
57250
57251
  return defaultBindRuntime.buildBindHandle(types.sourceType, sourcePath, patchPath, mode);
57251
57252
  }, [binding, workspace, sourcePath, patchPath, mode]);
57252
- const { value, pending } = useMemo(() => {
57253
- if (!handle || !handle.has()) return { value: null, pending: false };
57253
+ const { value, pending, error: error3 } = useMemo(() => {
57254
+ if (!handle || !handle.has()) return { value: null, pending: false, error: void 0 };
57254
57255
  try {
57255
- return { value: handle.read(), pending: handle.pending() };
57256
- } catch {
57257
- return { value: null, pending: false };
57256
+ return { value: handle.read(), pending: handle.pending(), error: void 0 };
57257
+ } catch (e3) {
57258
+ console.error(`[Experiment] failed to read binding "${String(sourcePath)}":`, e3);
57259
+ return { value: null, pending: false, error: e3 };
57258
57260
  }
57259
57261
  }, [handle, version2]);
57260
57262
  const mutate = useCallback((next2) => {
@@ -57267,7 +57269,7 @@ function useBindingValue(binding) {
57267
57269
  const discard = useCallback(() => {
57268
57270
  handle == null ? void 0 : handle.discard();
57269
57271
  }, [handle]);
57270
- return { value, mode, pending, mutate, commit, discard };
57272
+ return { value, mode, pending, error: error3, mutate, commit, discard };
57271
57273
  }
57272
57274
  const IDLE = { call: () => {
57273
57275
  }, result: null, status: "idle", pending: false, error: null };
@@ -60112,7 +60114,6 @@ function OverlapHistogram({ treated, control, domain = [0, 1], supportLabel, pos
60112
60114
  }
60113
60115
  const arr = (v3) => v3 ? Array.from(v3, Number) : [];
60114
60116
  const arrI = (v3) => v3 ? Array.from(v3, Number) : [];
60115
- const getOpt = (o2) => o2 && o2.type === "some" ? o2.value : void 0;
60116
60117
  const fmt$1 = (x2) => {
60117
60118
  const r2 = Number.isInteger(x2) ? String(x2) : x2.toFixed(1);
60118
60119
  return r2 === "-0.0" ? "0.0" : r2;
@@ -60130,7 +60131,7 @@ function band(absStd) {
60130
60131
  const colMeta = (meta3, col) => meta3 == null ? void 0 : meta3.get(col);
60131
60132
  const unitOf = (meta3, col) => {
60132
60133
  var _a2;
60133
- return getOpt((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.unit) ?? "";
60134
+ return getSomeorUndefined((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.unit) ?? "";
60134
60135
  };
60135
60136
  const kindOf = (cols, name) => {
60136
60137
  var _a2;
@@ -60186,9 +60187,9 @@ function deriveSpec(config2, cols, result, meta3, dataLen) {
60186
60187
  const inPlay = /* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes]);
60187
60188
  const suggest = cols.find((c2) => !inPlay.has(c2.name));
60188
60189
  const suggestion = suggest ? `add ${suggest.name}` : "";
60189
- const methodV = getOpt(config2.method);
60190
+ const methodV = getSomeorUndefined(config2.method);
60190
60191
  const method = (methodV == null ? void 0 : methodV.type) === "propensity_score_weighting" ? "reweighting" : "regression";
60191
- const targetV = getOpt(config2.estimand);
60192
+ const targetV = getSomeorUndefined(config2.estimand);
60192
60193
  const target = targetV && (targetV.type === "att" || targetV.type === "atc") ? "treated" : "all";
60193
60194
  return {
60194
60195
  treatment: config2.treatment,
@@ -60208,9 +60209,9 @@ function balanceDisplay(b2, categorical) {
60208
60209
  return isProp ? `${Math.round(b2.treated_mean * 100)}% vs ${Math.round(b2.control_mean * 100)}%` : `${b2.treated_mean.toFixed(1)} vs ${b2.control_mean.toFixed(1)}`;
60209
60210
  }
60210
60211
  function deriveAnswer(config2, result, adj, meta3) {
60211
- const ci = getOpt(adj.ci);
60212
- const nci = getOpt(result.naive_ci);
60213
- const categorical = new Set(getOpt(config2.categorical) ?? []);
60212
+ const ci = getSomeorUndefined(adj.ci);
60213
+ const nci = getSomeorUndefined(result.naive_ci);
60214
+ const categorical = new Set(getSomeorUndefined(config2.categorical) ?? []);
60214
60215
  const balance = [...result.balance].sort((a2, b2) => Math.abs(b2.std_diff) - Math.abs(a2.std_diff)).map((b2) => ({
60215
60216
  col: b2.column,
60216
60217
  treated: b2.treated_mean,
@@ -60308,43 +60309,43 @@ function zeroCrossing(xs, ys) {
60308
60309
  function deriveRefute(r2, adj) {
60309
60310
  const checks = [];
60310
60311
  const est = (adj == null ? void 0 : adj.effect) ?? 0;
60311
- const placeboEffect = getOpt(r2.placebo_effect);
60312
- const placeboPasses = getOpt(r2.placebo_passes);
60312
+ const placeboEffect = getSomeorUndefined(r2.placebo_effect);
60313
+ const placeboPasses = getSomeorUndefined(r2.placebo_passes);
60313
60314
  if (placeboEffect !== void 0 || placeboPasses !== void 0) {
60314
60315
  checks.push({
60315
60316
  name: "Shuffle test",
60316
60317
  desc: "Shuffle which rows were treated; a real effect should collapse to zero.",
60317
60318
  value: placeboEffect !== void 0 ? `→ ${signed(placeboEffect)}` : placeboPasses ? "passed" : "failed",
60318
60319
  passed: placeboPasses ?? (placeboEffect !== void 0 && Math.abs(placeboEffect) < Math.max(0.5, Math.abs(est) * 0.15)),
60319
- tip: { type: "some", value: "Randomly re-label which rows were treated. A genuine effect should vanish." },
60320
+ tip: some("Randomly re-label which rows were treated. A genuine effect should vanish."),
60320
60321
  help: "check_shuffle"
60321
60322
  });
60322
60323
  }
60323
- const ds = getOpt(r2.data_subset_effect);
60324
+ const ds = getSomeorUndefined(r2.data_subset_effect);
60324
60325
  if (ds !== void 0) {
60325
- const dstd = getOpt(r2.data_subset_std) ?? 0;
60326
+ const dstd = getSomeorUndefined(r2.data_subset_std) ?? 0;
60326
60327
  checks.push({
60327
60328
  name: "Drop-some test",
60328
60329
  desc: "Re-estimate on random subsamples; a trustworthy effect stays put.",
60329
60330
  value: `${fmt$1(ds)} ± ${fmt$1(dstd)}`,
60330
60331
  passed: Math.abs(ds - est) < Math.max(0.5, Math.abs(est) * 0.2),
60331
- tip: { type: "none", value: null },
60332
+ tip: none$1,
60332
60333
  help: "check_dropsome"
60333
60334
  });
60334
60335
  }
60335
- const rcc = getOpt(r2.random_cc_within_ci);
60336
+ const rcc = getSomeorUndefined(r2.random_cc_within_ci);
60336
60337
  if (rcc !== void 0) {
60337
60338
  checks.push({
60338
60339
  name: "Decoy cause",
60339
60340
  desc: "Add an irrelevant random factor; the answer should not move.",
60340
60341
  value: rcc ? "within range" : "moved",
60341
60342
  passed: rcc,
60342
- tip: { type: "none", value: null },
60343
+ tip: none$1,
60343
60344
  help: "check_decoy"
60344
60345
  });
60345
60346
  }
60346
- const sens = getOpt(r2.sensitivity);
60347
- const evalue = getOpt(r2.robustness_value);
60347
+ const sens = getSomeorUndefined(r2.sensitivity);
60348
+ const evalue = getSomeorUndefined(r2.robustness_value);
60348
60349
  if (sens !== void 0 || evalue !== void 0) {
60349
60350
  const strengths = sens ? arr(sens.strengths) : [];
60350
60351
  const effects = sens ? arr(sens.effects) : [];
@@ -60355,7 +60356,7 @@ function deriveRefute(r2, adj) {
60355
60356
  desc: "How strong an unrecorded common cause would need to be to overturn the result.",
60356
60357
  value,
60357
60358
  passed: tip === null,
60358
- tip: { type: "some", value: "Something unrecorded could drive both the treatment choice and the outcome." },
60359
+ tip: some("Something unrecorded could drive both the treatment choice and the outcome."),
60359
60360
  help: "check_hidden"
60360
60361
  });
60361
60362
  }
@@ -60363,7 +60364,7 @@ function deriveRefute(r2, adj) {
60363
60364
  if (sens !== void 0) {
60364
60365
  const mid = arr(sens.effects);
60365
60366
  if (mid.length) {
60366
- const ci = getOpt(adj == null ? void 0 : adj.ci);
60367
+ const ci = getSomeorUndefined(adj == null ? void 0 : adj.ci);
60367
60368
  const half = ci ? Math.abs(ci.upper - ci.lower) / 2 : 0;
60368
60369
  const lo2 = mid.map((m2) => m2 - half);
60369
60370
  const hi = mid.map((m2) => m2 + half);
@@ -60376,8 +60377,8 @@ function deriveRefute(r2, adj) {
60376
60377
  function deriveDose(dose, config2, meta3) {
60377
60378
  const grid = arr(dose.grid);
60378
60379
  const mid = arr(dose.effect);
60379
- const lo2 = getOpt(dose.lower) ? arr(getOpt(dose.lower)) : mid.slice();
60380
- const hi = getOpt(dose.upper) ? arr(getOpt(dose.upper)) : mid.slice();
60380
+ const lo2 = getSomeorUndefined(dose.lower) ? arr(getSomeorUndefined(dose.lower)) : mid.slice();
60381
+ const hi = getSomeorUndefined(dose.upper) ? arr(getSomeorUndefined(dose.upper)) : mid.slice();
60381
60382
  const sizes = arrI(dose.size);
60382
60383
  const featureUnit = unitOf(meta3, dose.feature);
60383
60384
  const here = sizes.length ? sizes.indexOf(Math.max(...sizes)) : 0;
@@ -60437,7 +60438,7 @@ const VERDICT_WORD = {
60437
60438
  not_estimable: "n/a"
60438
60439
  };
60439
60440
  function deriveJournalRow(row, now2) {
60440
- const adj = getOpt(row.adjusted);
60441
+ const adj = getSomeorUndefined(row.adjusted);
60441
60442
  return {
60442
60443
  treatment: row.config.treatment,
60443
60444
  outcome: row.config.outcome,
@@ -60446,13 +60447,16 @@ function deriveJournalRow(row, now2) {
60446
60447
  verdict: VERDICT_WORD[row.verdict.type],
60447
60448
  verdictTone: VERDICT_TONE[row.verdict.type],
60448
60449
  who: row.committed_by,
60449
- when: relTime(row.committed_at, now2)
60450
+ when: relTime(row.committed_at, now2),
60451
+ // The originating preset id (resolved to a label by the surface); `none` for a
60452
+ // free-form / pre-presets row.
60453
+ preset: row.preset
60450
60454
  };
60451
60455
  }
60452
60456
  function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2) {
60453
- const adj = result ? getOpt(result.adjusted) : void 0;
60454
- const refutation = result ? getOpt(result.refutation) : void 0;
60455
- const doseR = result ? getOpt(result.dose_response) : void 0;
60457
+ const adj = result ? getSomeorUndefined(result.adjusted) : void 0;
60458
+ const refutation = result ? getSomeorUndefined(result.refutation) : void 0;
60459
+ const doseR = result ? getSomeorUndefined(result.dose_response) : void 0;
60456
60460
  return {
60457
60461
  // The set-up rail reflects the LIVE config (the editor); the result deck
60458
60462
  // reflects RANCONFIG — the config that produced `result` — so the result
@@ -60499,7 +60503,7 @@ function deriveDesign(d2, result, ranConfig, meta3) {
60499
60503
  const b2 = balByCol.get(col);
60500
60504
  const absStd = b2 ? Math.abs(b2.std_diff) : 0;
60501
60505
  const { tone } = band(absStd);
60502
- return { col, frac: clamp01(absStd), tone, display: getOpt((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.label) ?? col };
60506
+ return { col, frac: clamp01(absStd), tone, display: getSomeorUndefined((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.label) ?? col };
60503
60507
  });
60504
60508
  const ns = arrI(d2.power_curve.n);
60505
60509
  const powers = arr(d2.power_curve.power);
@@ -60518,7 +60522,7 @@ function deriveDesign(d2, result, ranConfig, meta3) {
60518
60522
  const xTicks = len ? [String(ns[0]), String(ns[Math.floor((len - 1) / 2)]), String(ns[len - 1])] : [];
60519
60523
  const marks = [];
60520
60524
  if (len) marks.push({ at: nearest(primary.nTotal), label: `target ${(d2.target_power * 100).toFixed(0)}%`, tone: "pos", help: "validate_power" });
60521
- const cp = getOpt(d2.current_power);
60525
+ const cp = getSomeorUndefined(d2.current_power);
60522
60526
  if (cp !== void 0 && len) {
60523
60527
  const curN = result ? Number(result.n_total) : 0;
60524
60528
  if (curN > 0) {
@@ -60720,8 +60724,20 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60720
60724
  const configBind = useBindingValue(v3.config);
60721
60725
  const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
60722
60726
  const populationBind = useBindingValue(v3.population.type === "some" ? v3.population.value : null);
60723
- const meta3 = getOpt(v3.columnMeta);
60724
- const readonly = getOpt(v3.readonly) ?? false;
60727
+ const meta3 = getSomeorUndefined(v3.columnMeta);
60728
+ const readonly = getSomeorUndefined(v3.readonly) ?? false;
60729
+ const presets = useMemo(() => getSomeorUndefined(v3.presets) ?? [], [v3.presets]);
60730
+ const [currentPreset, setCurrentPreset] = useState(void 0);
60731
+ const presetGroups = useMemo(() => {
60732
+ const buckets = /* @__PURE__ */ new Map();
60733
+ for (const p2 of presets) {
60734
+ const label = getSomeorUndefined(p2.group) ?? "Saved questions";
60735
+ const bucket = buckets.get(label);
60736
+ if (bucket) bucket.push(p2);
60737
+ else buckets.set(label, [p2]);
60738
+ }
60739
+ return [...buckets].map(([label, items]) => ({ label, items }));
60740
+ }, [presets]);
60725
60741
  const { columns, rowArrayType } = useColumns(workspace, v3.data.source);
60726
60742
  const config2 = configBind.value;
60727
60743
  const [localPop, setLocalPop] = useState([]);
@@ -60735,7 +60751,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60735
60751
  var _a3;
60736
60752
  return {
60737
60753
  fieldId: c2.name,
60738
- label: getOpt((_a3 = meta3 == null ? void 0 : meta3.get(c2.name)) == null ? void 0 : _a3.label) ?? c2.name,
60754
+ label: getSomeorUndefined((_a3 = meta3 == null ? void 0 : meta3.get(c2.name)) == null ? void 0 : _a3.label) ?? c2.name,
60739
60755
  kind: c2.kind
60740
60756
  };
60741
60757
  }),
@@ -60773,17 +60789,24 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60773
60789
  if (experiment.result !== null) setRanConfig(pendingConfigRef.current);
60774
60790
  }, [experiment.result]);
60775
60791
  const [stale, setStale] = useState(false);
60776
- const editConfig = useCallback((next2) => {
60792
+ const editConfig = useCallback((next2, fromPreset) => {
60777
60793
  if (readonly) return;
60778
60794
  setStale(true);
60795
+ setCurrentPreset(fromPreset);
60779
60796
  queueMicrotask(() => configBind.mutate(next2));
60780
60797
  }, [readonly, configBind]);
60781
- const editPopulation = useCallback((next2) => {
60798
+ const editPopulation = useCallback((next2, fromPreset) => {
60782
60799
  if (readonly) return;
60783
60800
  setStale(true);
60801
+ setCurrentPreset(fromPreset);
60784
60802
  if (v3.population.type === "some") queueMicrotask(() => populationBind.mutate(next2));
60785
60803
  else setLocalPop(next2);
60786
60804
  }, [readonly, v3.population.type, populationBind]);
60805
+ const selectPreset = useCallback((p2) => {
60806
+ if (readonly) return;
60807
+ editConfig(p2.config, p2.id);
60808
+ editPopulation(getSomeorUndefined(p2.population) ?? [], p2.id);
60809
+ }, [readonly, editConfig, editPopulation]);
60787
60810
  const onRun = useCallback(() => {
60788
60811
  runAll();
60789
60812
  setStale(false);
@@ -60797,7 +60820,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60797
60820
  naive: r2.naive,
60798
60821
  adjusted: r2.adjusted.type === "some" ? some(r2.adjusted.value.effect) : none$1,
60799
60822
  committed_at: /* @__PURE__ */ new Date(),
60800
- committed_by: "you"
60823
+ committed_by: "you",
60824
+ // Record which preset framed this experiment (none for a free-form run).
60825
+ preset: currentPreset !== void 0 ? some(currentPreset) : none$1
60801
60826
  };
60802
60827
  journalBind.mutate([row, ...journalBind.value ?? []]);
60803
60828
  try {
@@ -60807,8 +60832,8 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60807
60832
  setStale(false);
60808
60833
  } catch {
60809
60834
  }
60810
- }, [config2, experiment.result, journalBind, configBind, populationBind, v3.population.type]);
60811
- const [tab, setTab] = useState(((_a2 = getOpt(v3.defaultTab)) == null ? void 0 : _a2.type) ?? "answer");
60835
+ }, [config2, experiment.result, journalBind, configBind, populationBind, v3.population.type, currentPreset]);
60836
+ const [tab, setTab] = useState(((_a2 = getSomeorUndefined(v3.defaultTab)) == null ? void 0 : _a2.type) ?? "answer");
60812
60837
  const [guidance, setGuidance] = useState(true);
60813
60838
  const now2 = useMemo(() => /* @__PURE__ */ new Date(), []);
60814
60839
  const nRows = (filteredRows == null ? void 0 : filteredRows.length) ?? 0;
@@ -60816,7 +60841,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60816
60841
  const rc = ranConfig ?? config2;
60817
60842
  const labelOf = (col) => {
60818
60843
  var _a3;
60819
- return col ? getOpt((_a3 = meta3 == null ? void 0 : meta3.get(col)) == null ? void 0 : _a3.label) ?? col : "";
60844
+ return col ? getSomeorUndefined((_a3 = meta3 == null ? void 0 : meta3.get(col)) == null ? void 0 : _a3.label) ?? col : "";
60820
60845
  };
60821
60846
  return { treatment: labelOf(rc == null ? void 0 : rc.treatment), outcome: labelOf(rc == null ? void 0 : rc.outcome), subject: SUBJECT_ONE, subjects: SUBJECT_MANY };
60822
60847
  }, [ranConfig, config2, meta3]);
@@ -60846,10 +60871,18 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60846
60871
  const designFresh = design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === experiment.result && !design.pending;
60847
60872
  if (!config2 || !view) {
60848
60873
  const failed2 = experiment.status === "failed";
60849
- return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: failed2 && experiment.error ? /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) : /* @__PURE__ */ jsx$1(Text, { className: failed2 ? void 0 : "elara-skeleton", textStyle: "body.sm", color: "fg.muted", children: failed2 ? "Could not run the experiment." : "Loading experiment…" }) });
60874
+ const which = data4.error ? "dataset" : configBind.error ? "config" : journalBind.error ? "journal" : populationBind.error ? "population filter" : null;
60875
+ const bindError = data4.error ?? configBind.error ?? journalBind.error ?? populationBind.error;
60876
+ const bindMsg = bindError instanceof Error ? bindError.message : bindError != null ? String(bindError) : null;
60877
+ return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: bindMsg ? /* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.danger", children: [
60878
+ "Couldn’t load the experiment ",
60879
+ which,
60880
+ ": ",
60881
+ bindMsg
60882
+ ] }) : failed2 && experiment.error ? /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) : /* @__PURE__ */ jsx$1(Text, { className: failed2 ? void 0 : "elara-skeleton", textStyle: "body.sm", color: "fg.muted", children: failed2 ? "Could not run the experiment." : "Loading experiment…" }) });
60850
60883
  }
60851
60884
  const { spec: vs, answer: a2, refusal: ref, overlap: ov, refute: vr, dose: vd, journal, verdict } = view;
60852
- const higherBetter = getOpt((_c2 = meta3 == null ? void 0 : meta3.get(vs.outcome)) == null ? void 0 : _c2.higherIsBetter);
60885
+ const higherBetter = getSomeorUndefined((_c2 = meta3 == null ? void 0 : meta3.get(vs.outcome)) == null ? void 0 : _c2.higherIsBetter);
60853
60886
  const dataStatus = statusR({ status: "success", size: "sm" });
60854
60887
  const barList = (rows) => /* @__PURE__ */ jsx$1(Box, { css: bs.root, children: rows.map((r2, i) => /* @__PURE__ */ jsxs(Box, { css: bs.row, children: [
60855
60888
  /* @__PURE__ */ jsx$1(Text, { css: bs.label, textStyle: "mono.sm", color: "fg.default", truncate: true, children: r2.label }),
@@ -60867,7 +60900,25 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60867
60900
  const tabKeys = [...["answer", "trust", "dose"], ...hasDesign ? ["validate"] : []];
60868
60901
  return /* @__PURE__ */ jsx$1(GuidanceProvider, { on: guidance, vars: helpVars, children: /* @__PURE__ */ jsxs(Box, { layerStyle: "frame", overflow: "visible", children: [
60869
60902
  /* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
60870
- /* @__PURE__ */ jsx$1(Text, { textStyle: "title.card", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "header", children: [
60903
+ presets.length > 0 && !readonly ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
60904
+ /* @__PURE__ */ jsx$1(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Box, { as: "button", bg: "transparent", border: "0", p: "0", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: "2", textAlign: "start", children: [
60905
+ /* @__PURE__ */ jsxs(Text, { textStyle: "title.card", color: "fg.muted", children: [
60906
+ "Does ",
60907
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.treatment }),
60908
+ " change ",
60909
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.outcome }),
60910
+ "?"
60911
+ ] }),
60912
+ /* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.subtle", fontSize: "11px", lineHeight: "1", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown }) })
60913
+ ] }) }),
60914
+ /* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { minW: "280px", children: presetGroups.map((g2) => /* @__PURE__ */ jsxs(Menu.ItemGroup, { children: [
60915
+ g2.label !== "Saved questions" && /* @__PURE__ */ jsx$1(Menu.ItemGroupLabel, { textStyle: "caption.eyebrow", fontSize: "9px", children: g2.label }),
60916
+ g2.items.map((p2) => /* @__PURE__ */ jsxs(Menu.Item, { value: p2.id, onClick: () => selectPreset(p2), gap: "2", children: [
60917
+ /* @__PURE__ */ jsx$1(Box, { as: "span", width: "14px", flexShrink: "0", color: "brand.fg", children: p2.id === currentPreset && /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faCheck, style: { fontSize: "10px" } }) }),
60918
+ p2.label
60919
+ ] }, p2.id))
60920
+ ] }, g2.label)) }) }) })
60921
+ ] }) : /* @__PURE__ */ jsx$1(Text, { textStyle: "title.card", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "header", children: [
60871
60922
  "Does ",
60872
60923
  /* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.treatment }),
60873
60924
  " change ",
@@ -61115,7 +61166,20 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61115
61166
  /* @__PURE__ */ jsxs(Text, { as: "span", color: "fg.muted", children: [
61116
61167
  "· vs ",
61117
61168
  r2.confounders
61118
- ] })
61169
+ ] }),
61170
+ (() => {
61171
+ var _a3;
61172
+ const id3 = getSomeorUndefined(r2.preset);
61173
+ if (id3 === void 0) return null;
61174
+ const label = ((_a3 = presets.find((p2) => p2.id === id3)) == null ? void 0 : _a3.label) ?? id3;
61175
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
61176
+ " ",
61177
+ /* @__PURE__ */ jsxs(Box, { as: "span", css: chip({ tone: "brand", size: "sm" }), children: [
61178
+ "from ",
61179
+ label
61180
+ ] })
61181
+ ] });
61182
+ })()
61119
61183
  ] }),
61120
61184
  /* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", fontWeight: "semibold", textAlign: "right", fontVariantNumeric: "tabular-nums", color: r2.verdictTone === "pos" ? "fg.success" : "fg.default", children: r2.effect }),
61121
61185
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", textAlign: "right", color: toneToken(r2.verdictTone), children: r2.verdict }),