@elaraai/e3-ui-components 1.0.22 → 1.0.24

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,9 +27,8 @@ 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, 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";
30
+ import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, 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";
33
32
  import { sliceMatches } from "@elaraai/east-ui/internal";
34
33
  import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery } from "@tanstack/react-query";
35
34
  import { useVirtualizer } from "@tanstack/react-virtual";
@@ -8372,6 +8371,7 @@ function useDatasetKeyVersions(workspace, paths) {
8372
8371
  );
8373
8372
  return useSyncExternalStore(subscribe, getSnapshot);
8374
8373
  }
8374
+ const warnedDirectNoPatch = /* @__PURE__ */ new Set();
8375
8375
  function pickCommitKind(mode, patchPath) {
8376
8376
  if (mode === "staged" && !patchPath) return "apply-buffer-to-source";
8377
8377
  if (mode === "staged" && patchPath) return "publish-buffer-to-patch";
@@ -8389,7 +8389,16 @@ function deriveBindings(workspace, bindings) {
8389
8389
  const types = getBindingTypes(workspace, sourcePath);
8390
8390
  if (!types) continue;
8391
8391
  const commitKind = pickCommitKind(mode, patchPath);
8392
- if (!commitKind) continue;
8392
+ if (!commitKind) {
8393
+ const key = datasetPathToString(sourcePath);
8394
+ if (!warnedDirectNoPatch.has(key)) {
8395
+ warnedDirectNoPatch.add(key);
8396
+ console.warn(
8397
+ `[Diff] binding "${key}" is mode="direct" with no patch dataset — it writes through immediately, so the Diff has nothing to review. Pass { mode: "staged" } to Data.bind (or give it a patch dataset) to surface its edits here.`
8398
+ );
8399
+ }
8400
+ continue;
8401
+ }
8393
8402
  const sourceType = types.sourceType;
8394
8403
  const patchType = types.patchType;
8395
8404
  const label = formatBindingLabel(sourcePath);
@@ -60709,9 +60718,28 @@ function DeckSkeleton({ tab }) {
60709
60718
  ] })
60710
60719
  ] });
60711
60720
  }
60721
+ function LoadingSkeleton() {
60722
+ const sk = useRecipe({ key: "skeleton" });
60723
+ const line2 = (w2, h2) => /* @__PURE__ */ jsx$1(Box, { css: sk({ variant: "line" }), width: w2, height: h2 });
60724
+ const block = (h2) => /* @__PURE__ */ jsx$1(Box, { css: sk({ variant: "block" }), width: "100%", minHeight: h2 });
60725
+ return /* @__PURE__ */ jsxs(Box, { layerStyle: "frame", overflow: "visible", children: [
60726
+ /* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
60727
+ line2("260px", "20px"),
60728
+ /* @__PURE__ */ jsx$1(Box, { flex: "1" }),
60729
+ line2("72px", "16px")
60730
+ ] }),
60731
+ /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "304px minmax(0,1fr)", alignItems: "start", children: [
60732
+ /* @__PURE__ */ jsx$1(Box, { borderRightWidth: "1px", borderColor: "border.subtle", p: "4.5", display: "flex", flexDirection: "column", gap: "5", children: [0, 1, 2, 3].map((n2) => /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "2", children: [
60733
+ line2("150px", "12px"),
60734
+ block("40px")
60735
+ ] }, n2)) }),
60736
+ /* @__PURE__ */ jsx$1(DeckSkeleton, { tab: "answer" })
60737
+ ] })
60738
+ ] });
60739
+ }
60712
60740
  const experimentValueEqual = equalFor(Experiment.Component.schema);
60713
60741
  const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60714
- var _a2, _b2, _c2, _d2;
60742
+ var _a2, _b2, _c2;
60715
60743
  const v3 = value;
60716
60744
  const button = useRecipe({ key: "button" });
60717
60745
  const chip = useRecipe({ key: "chip" });
@@ -60721,27 +60749,48 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60721
60749
  const es = useSlotRecipe({ key: "eyebrowRow" })({});
60722
60750
  const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
60723
60751
  const data4 = useBindingValue(v3.data);
60724
- const configBind = useBindingValue(v3.config);
60725
60752
  const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
60726
- const populationBind = useBindingValue(v3.population.type === "some" ? v3.population.value : null);
60727
60753
  const meta3 = getSomeorUndefined(v3.columnMeta);
60728
60754
  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(() => {
60755
+ const configsBind = useBindingValue(v3.configs);
60756
+ const configs = useMemo(() => configsBind.value ?? [], [configsBind.value]);
60757
+ const [currentConfigId, setCurrentConfigId] = useState(void 0);
60758
+ const selectedEntry = useMemo(
60759
+ () => configs.find((c2) => c2.id === currentConfigId) ?? configs[0],
60760
+ [configs, currentConfigId]
60761
+ );
60762
+ useEffect(() => {
60763
+ const first2 = configs[0];
60764
+ if (currentConfigId === void 0 && first2 !== void 0) setCurrentConfigId(first2.id);
60765
+ }, [configs, currentConfigId]);
60766
+ const configGroups = useMemo(() => {
60732
60767
  const buckets = /* @__PURE__ */ new Map();
60733
- for (const p2 of presets) {
60734
- const label = getSomeorUndefined(p2.group) ?? "Saved questions";
60768
+ for (const c2 of configs) {
60769
+ const label = getSomeorUndefined(c2.group) ?? "Questions";
60735
60770
  const bucket = buckets.get(label);
60736
- if (bucket) bucket.push(p2);
60737
- else buckets.set(label, [p2]);
60771
+ if (bucket) bucket.push(c2);
60772
+ else buckets.set(label, [c2]);
60738
60773
  }
60739
60774
  return [...buckets].map(([label, items]) => ({ label, items }));
60740
- }, [presets]);
60775
+ }, [configs]);
60741
60776
  const { columns, rowArrayType } = useColumns(workspace, v3.data.source);
60742
- const config2 = configBind.value;
60777
+ const [workingConfig, setWorkingConfig] = useState(void 0);
60743
60778
  const [localPop, setLocalPop] = useState([]);
60744
- const population = populationBind.value ?? localPop;
60779
+ const [stale, setStale] = useState(false);
60780
+ const seededIdRef = useRef(void 0);
60781
+ useEffect(() => {
60782
+ const id3 = selectedEntry == null ? void 0 : selectedEntry.id;
60783
+ if (id3 === seededIdRef.current) return;
60784
+ const switching = seededIdRef.current !== void 0;
60785
+ seededIdRef.current = id3;
60786
+ setWorkingConfig(selectedEntry == null ? void 0 : selectedEntry.spec);
60787
+ setLocalPop(getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.population) ?? []);
60788
+ const precomputed = (selectedEntry == null ? void 0 : selectedEntry.result.type) === "some";
60789
+ const hasEstimator = v3.experiment.type === "some";
60790
+ setStale(switching && hasEstimator && !precomputed);
60791
+ }, [selectedEntry, v3.experiment.type]);
60792
+ const config2 = workingConfig;
60793
+ const population = localPop;
60745
60794
  const filteredRows = useMemo(() => {
60746
60795
  if (!data4.value) return null;
60747
60796
  return population.length ? data4.value.filter((r2) => rowMatchesAll(r2, population)) : data4.value;
@@ -60758,7 +60807,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60758
60807
  [columns, meta3]
60759
60808
  );
60760
60809
  const estInputs = useMemo(() => rowArrayType ? [rowArrayType, Experiment.Types.Config] : null, [rowArrayType]);
60761
- const experiment = useFuncCall(v3.experiment.name, estInputs, Experiment.Types.Result);
60810
+ const experiment = useFuncCall(v3.experiment.type === "some" ? v3.experiment.value.name : null, estInputs, Experiment.Types.Result);
60811
+ const hasExperiment = v3.experiment.type === "some";
60812
+ const shownResult = experiment.result ?? getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.result) ?? null;
60762
60813
  const hasDesign = v3.design.type === "some";
60763
60814
  const designInputs = useMemo(
60764
60815
  () => rowArrayType ? [rowArrayType, Experiment.Types.Config, Experiment.Types.Result, Experiment.Types.DesignConfig] : null,
@@ -60773,8 +60824,13 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60773
60824
  experiment.call(filteredRows, config2);
60774
60825
  }, [filteredRows, config2, experiment]);
60775
60826
  const autoRan = useRef(false);
60827
+ const hasPrecomputed = selectedEntry !== void 0 && selectedEntry.result.type === "some";
60776
60828
  useEffect(() => {
60777
60829
  if (autoRan.current) return;
60830
+ if (hasPrecomputed || !hasExperiment) {
60831
+ autoRan.current = true;
60832
+ return;
60833
+ }
60778
60834
  if (!filteredRows || !config2 || !rowArrayType) return;
60779
60835
  if (experiment.result !== null || experiment.status === "running") {
60780
60836
  autoRan.current = true;
@@ -60784,29 +60840,23 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60784
60840
  autoRan.current = true;
60785
60841
  if (filteredRows.length > AUTORUN_MAX_ROWS) return;
60786
60842
  runAll();
60787
- }, [filteredRows, config2, rowArrayType, experiment.result, experiment.status, runAll]);
60843
+ }, [hasPrecomputed, hasExperiment, filteredRows, config2, rowArrayType, experiment.result, experiment.status, runAll]);
60788
60844
  useEffect(() => {
60789
60845
  if (experiment.result !== null) setRanConfig(pendingConfigRef.current);
60790
60846
  }, [experiment.result]);
60791
- const [stale, setStale] = useState(false);
60792
- const editConfig = useCallback((next2, fromPreset) => {
60793
- if (readonly) return;
60794
- setStale(true);
60795
- setCurrentPreset(fromPreset);
60796
- queueMicrotask(() => configBind.mutate(next2));
60797
- }, [readonly, configBind]);
60798
- const editPopulation = useCallback((next2, fromPreset) => {
60847
+ const editConfig = useCallback((next2) => {
60799
60848
  if (readonly) return;
60800
- setStale(true);
60801
- setCurrentPreset(fromPreset);
60802
- if (v3.population.type === "some") queueMicrotask(() => populationBind.mutate(next2));
60803
- else setLocalPop(next2);
60804
- }, [readonly, v3.population.type, populationBind]);
60805
- const selectPreset = useCallback((p2) => {
60849
+ if (v3.experiment.type === "some") setStale(true);
60850
+ setWorkingConfig(next2);
60851
+ }, [readonly, v3.experiment.type]);
60852
+ const editPopulation = useCallback((next2) => {
60806
60853
  if (readonly) return;
60807
- editConfig(p2.config, p2.id);
60808
- editPopulation(getSomeorUndefined(p2.population) ?? [], p2.id);
60809
- }, [readonly, editConfig, editPopulation]);
60854
+ if (v3.experiment.type === "some") setStale(true);
60855
+ setLocalPop(next2);
60856
+ }, [readonly, v3.experiment.type]);
60857
+ const selectEntry = useCallback((c2) => {
60858
+ setCurrentConfigId(c2.id);
60859
+ }, []);
60810
60860
  const onRun = useCallback(() => {
60811
60861
  runAll();
60812
60862
  setStale(false);
@@ -60821,18 +60871,16 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60821
60871
  adjusted: r2.adjusted.type === "some" ? some(r2.adjusted.value.effect) : none$1,
60822
60872
  committed_at: /* @__PURE__ */ new Date(),
60823
60873
  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
60874
+ // Record which question framed this experiment.
60875
+ preset: currentConfigId !== void 0 ? some(currentConfigId) : none$1
60826
60876
  };
60827
60877
  journalBind.mutate([row, ...journalBind.value ?? []]);
60828
60878
  try {
60829
60879
  await journalBind.commit();
60830
- await configBind.commit();
60831
- if (v3.population.type === "some") await populationBind.commit();
60832
60880
  setStale(false);
60833
60881
  } catch {
60834
60882
  }
60835
- }, [config2, experiment.result, journalBind, configBind, populationBind, v3.population.type, currentPreset]);
60883
+ }, [config2, experiment.result, journalBind, currentConfigId]);
60836
60884
  const [tab, setTab] = useState(((_a2 = getSomeorUndefined(v3.defaultTab)) == null ? void 0 : _a2.type) ?? "answer");
60837
60885
  const [guidance, setGuidance] = useState(true);
60838
60886
  const now2 = useMemo(() => /* @__PURE__ */ new Date(), []);
@@ -60847,39 +60895,44 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60847
60895
  }, [ranConfig, config2, meta3]);
60848
60896
  const view = useMemo(() => {
60849
60897
  if (!config2) return null;
60850
- return deriveView(config2, ranConfig ?? config2, columns, experiment.result, journalBind.value, meta3, nRows, now2);
60851
- }, [config2, ranConfig, columns, experiment.result, journalBind.value, meta3, nRows, now2]);
60898
+ return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2);
60899
+ }, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2]);
60852
60900
  const designConfigValue = useMemo(() => ({
60853
60901
  alpha: none$1,
60854
60902
  target_power: none$1,
60855
60903
  materiality: none$1,
60856
60904
  treated_shares: some([0.5, 0.3])
60857
60905
  }), []);
60906
+ const precomputedDesign = getSomeorUndefined(selectedEntry == null ? void 0 : selectedEntry.design) ?? null;
60858
60907
  const designSnapRef = useRef(null);
60859
60908
  useEffect(() => {
60860
60909
  var _a3;
60861
- if (tab !== "validate" || !hasDesign || design.pending) return;
60862
- if (!filteredRows || !config2 || !experiment.result) return;
60863
- if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) === experiment.result) return;
60864
- designSnapRef.current = { result: experiment.result, config: ranConfig ?? config2 };
60865
- design.call(filteredRows, ranConfig ?? config2, experiment.result, designConfigValue);
60866
- }, [tab, hasDesign, filteredRows, config2, ranConfig, experiment.result, design, designConfigValue]);
60867
- const vmDesign = useMemo(
60868
- () => design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3) : null,
60869
- [design.result, meta3]
60870
- );
60871
- const designFresh = design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === experiment.result && !design.pending;
60910
+ if (tab !== "validate" || !hasDesign || design.pending || precomputedDesign !== null) return;
60911
+ if (!filteredRows || !config2 || !shownResult) return;
60912
+ if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) === shownResult) return;
60913
+ designSnapRef.current = { result: shownResult, config: ranConfig ?? config2 };
60914
+ design.call(filteredRows, ranConfig ?? config2, shownResult, designConfigValue);
60915
+ }, [tab, hasDesign, precomputedDesign, filteredRows, config2, ranConfig, shownResult, design, designConfigValue]);
60916
+ const vmDesign = useMemo(() => {
60917
+ if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3);
60918
+ return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3) : null;
60919
+ }, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3]);
60920
+ const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === shownResult && !design.pending;
60872
60921
  if (!config2 || !view) {
60873
60922
  const failed2 = experiment.status === "failed";
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;
60923
+ const noConfigs = !configsBind.error && configs.length === 0;
60924
+ const which = data4.error ? "dataset" : configsBind.error ? "configs" : journalBind.error ? "journal" : null;
60925
+ const bindError = data4.error ?? configsBind.error ?? journalBind.error;
60876
60926
  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: [
60927
+ if (bindMsg) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.danger", children: [
60878
60928
  "Couldn’t load the experiment ",
60879
60929
  which,
60880
60930
  ": ",
60881
60931
  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…" }) });
60932
+ ] }) });
60933
+ if (noConfigs) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", children: "No questions to show — bind a non-empty configs list." }) });
60934
+ if (failed2 && experiment.error) return /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame", p: "6", children: /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) });
60935
+ return /* @__PURE__ */ jsx$1(LoadingSkeleton, {});
60883
60936
  }
60884
60937
  const { spec: vs, answer: a2, refusal: ref, overlap: ov, refute: vr, dose: vd, journal, verdict } = view;
60885
60938
  const higherBetter = getSomeorUndefined((_c2 = meta3 == null ? void 0 : meta3.get(vs.outcome)) == null ? void 0 : _c2.higherIsBetter);
@@ -60889,18 +60942,19 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60889
60942
  /* @__PURE__ */ jsx$1(Box, { css: bs.track, children: /* @__PURE__ */ jsx$1(Box, { css: bs.fill, width: `${Math.round(r2.frac * 100)}%`, bg: toneToken(r2.tone) }) }),
60890
60943
  /* @__PURE__ */ jsx$1(Text, { css: bs.value, children: r2.value })
60891
60944
  ] }, i)) });
60892
- const specStaged = configBind.mode === "staged";
60893
60945
  const hasJournal = v3.journal.type === "some";
60894
- const canRun = !readonly;
60895
- const canCommit = !readonly && specStaged && hasJournal;
60946
+ const canRun = !readonly && hasExperiment;
60947
+ const canCommit = !readonly && hasExperiment && hasJournal;
60896
60948
  const runDisabled = !data4.value || experiment.pending;
60897
60949
  const commitDisabled = experiment.status !== "succeeded" || experiment.pending || stale;
60898
60950
  const failed = experiment.status === "failed" && experiment.error;
60899
- const showResult = experiment.result !== null && !experiment.pending && !failed;
60900
- const tabKeys = [...["answer", "trust", "dose"], ...hasDesign ? ["validate"] : []];
60951
+ const showResult = shownResult !== null && !experiment.pending && !failed;
60952
+ const anyPrecomputedDesign = configs.some((c2) => c2.design.type === "some");
60953
+ const showValidate = hasDesign || anyPrecomputedDesign;
60954
+ const tabKeys = [...["answer", "trust", "dose"], ...showValidate ? ["validate"] : []];
60901
60955
  return /* @__PURE__ */ jsx$1(GuidanceProvider, { on: guidance, vars: helpVars, children: /* @__PURE__ */ jsxs(Box, { layerStyle: "frame", overflow: "visible", children: [
60902
60956
  /* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
60903
- presets.length > 0 && !readonly ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
60957
+ configs.length > 1 ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
60904
60958
  /* @__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
60959
  /* @__PURE__ */ jsxs(Text, { textStyle: "title.card", color: "fg.muted", children: [
60906
60960
  "Does ",
@@ -60911,12 +60965,12 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60911
60965
  ] }),
60912
60966
  /* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.subtle", fontSize: "11px", lineHeight: "1", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown }) })
60913
60967
  ] }) }),
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))
60968
+ /* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { minW: "280px", children: configGroups.map((g2) => /* @__PURE__ */ jsxs(Menu.ItemGroup, { children: [
60969
+ g2.label !== "Questions" && /* @__PURE__ */ jsx$1(Menu.ItemGroupLabel, { textStyle: "caption.eyebrow", fontSize: "9px", children: g2.label }),
60970
+ g2.items.map((c2) => /* @__PURE__ */ jsxs(Menu.Item, { value: c2.id, onClick: () => selectEntry(c2), gap: "2", children: [
60971
+ /* @__PURE__ */ jsx$1(Box, { as: "span", width: "14px", flexShrink: "0", color: "brand.fg", children: c2.id === (selectedEntry == null ? void 0 : selectedEntry.id) && /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faCheck, style: { fontSize: "10px" } }) }),
60972
+ c2.label
60973
+ ] }, c2.id))
60920
60974
  ] }, g2.label)) }) }) })
60921
60975
  ] }) : /* @__PURE__ */ jsx$1(Text, { textStyle: "title.card", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "header", children: [
60922
60976
  "Does ",
@@ -60926,6 +60980,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60926
60980
  "?"
60927
60981
  ] }) }),
60928
60982
  /* @__PURE__ */ jsx$1(Box, { flex: "1" }),
60983
+ readonly && /* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: "View only" }),
60929
60984
  /* @__PURE__ */ jsxs(Box, { as: "span", css: dataStatus.root, children: [
60930
60985
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.indicator }),
60931
60986
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.label, children: stale ? `${nRows} rows` : vs.dataLabel })
@@ -60937,15 +60992,15 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60937
60992
  /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "304px minmax(0,1fr)", alignItems: "start", children: [
60938
60993
  /* @__PURE__ */ jsxs(Box, { borderRightWidth: "1px", borderColor: "border.subtle", children: [
60939
60994
  /* @__PURE__ */ jsxs(Step, { n: 1, title: "What did you change?", help: "step_treatment", children: [
60940
- /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.treatment, kind: vs.treatmentKind, badge, button, choices: columns.filter((c2) => c2.kind === "boolean" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, treatment: c2 }) }),
60995
+ /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.treatment, kind: vs.treatmentKind, badge, button, readonly, choices: columns.filter((c2) => c2.kind === "boolean" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, treatment: c2 }) }),
60941
60996
  /* @__PURE__ */ jsxs(Text, { textStyle: "caption", mt: "1.5", children: [
60942
60997
  "Treated = ",
60943
60998
  /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: vs.comparison })
60944
60999
  ] })
60945
61000
  ] }),
60946
- /* @__PURE__ */ jsx$1(Step, { n: 2, title: "What did you want it to improve?", help: "step_outcome", children: /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.outcome, kind: vs.outcomeKind, badge, button, choices: columns.filter((c2) => c2.kind === "float" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, outcome: c2 }) }) }),
61001
+ /* @__PURE__ */ jsx$1(Step, { n: 2, title: "What did you want it to improve?", help: "step_outcome", children: /* @__PURE__ */ jsx$1(ColumnPick, { column: vs.outcome, kind: vs.outcomeKind, badge, button, readonly, choices: columns.filter((c2) => c2.kind === "float" || c2.kind === "integer").map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, outcome: c2 }) }) }),
60947
61002
  /* @__PURE__ */ jsx$1(Step, { n: 3, title: "What else was different?", help: "step_confounders", children: /* @__PURE__ */ jsxs(Box, { layerStyle: "frame.flat", children: [
60948
- /* @__PURE__ */ jsx$1(Box, { maxH: "216px", overflowY: "auto", children: vs.confounders.map((c2, i) => /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "1fr 78px 16px", gap: "2.5", alignItems: "center", px: "2.5", py: "2.5", borderTopWidth: i ? "1px" : "0", borderColor: "border.subtle", children: [
61003
+ /* @__PURE__ */ jsx$1(Box, { maxH: "216px", overflowY: "auto", children: vs.confounders.map((c2, i) => /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: readonly ? "1fr 78px" : "1fr 78px 16px", gap: "2.5", alignItems: "center", px: "2.5", py: "2.5", borderTopWidth: i ? "1px" : "0", borderColor: "border.subtle", children: [
60949
61004
  /* @__PURE__ */ jsxs(Box, { children: [
60950
61005
  /* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", fontWeight: "semibold", color: "fg.default", children: c2.col }),
60951
61006
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption", lineHeight: "1.35", mt: "px", children: c2.reason })
@@ -60954,14 +61009,14 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60954
61009
  /* @__PURE__ */ jsx$1(Box, { css: bs.track, children: /* @__PURE__ */ jsx$1(Box, { css: bs.fill, width: `${Math.round(c2.imbalance * 100)}%`, bg: toneToken(c2.tone) }) }),
60955
61010
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", fontSize: "9px", textAlign: "center", mt: "1.5", children: /* @__PURE__ */ jsx$1(Help, { id: "confounder_imbalance", children: c2.level }) })
60956
61011
  ] }),
60957
- /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), px: "0", minW: "16px", display: "inline-flex", alignItems: "center", justifyContent: "center", "aria-label": `Remove ${c2.col}`, onClick: () => editConfig({ ...config2, common_causes: config2.common_causes.filter((x2) => x2 !== c2.col), categorical: config2.categorical.type === "some" ? some(config2.categorical.value.filter((x2) => x2 !== c2.col)) : none$1 }), children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faXmark, style: { fontSize: "11px" } }) })
61012
+ !readonly && /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), px: "0", minW: "16px", display: "inline-flex", alignItems: "center", justifyContent: "center", "aria-label": `Remove ${c2.col}`, onClick: () => editConfig({ ...config2, common_causes: config2.common_causes.filter((x2) => x2 !== c2.col), categorical: config2.categorical.type === "some" ? some(config2.categorical.value.filter((x2) => x2 !== c2.col)) : none$1 }), children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faXmark, style: { fontSize: "11px" } }) })
60958
61013
  ] }, i)) }),
60959
- vs.suggestion && /* @__PURE__ */ jsx$1(ColumnMenu, { choices: columns.filter((c2) => !(/* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes])).has(c2.name)).map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, common_causes: [...config2.common_causes, c2] }), children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "ghost", size: "sm" }), justifyContent: "flex-start", width: "100%", color: "brand.fg", fontFamily: "mono", display: "inline-flex", alignItems: "center", gap: "2", children: [
61014
+ !readonly && vs.suggestion && /* @__PURE__ */ jsx$1(ColumnMenu, { choices: columns.filter((c2) => !(/* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes])).has(c2.name)).map((c2) => c2.name), onPick: (c2) => editConfig({ ...config2, common_causes: [...config2.common_causes, c2] }), children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "ghost", size: "sm" }), justifyContent: "flex-start", width: "100%", color: "brand.fg", fontFamily: "mono", display: "inline-flex", alignItems: "center", gap: "2", children: [
60960
61015
  /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faPlus, style: { fontSize: "9px" } }),
60961
61016
  "add another"
60962
61017
  ] }) })
60963
61018
  ] }) }),
60964
- /* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${SUBJECT_MANY}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button }) }),
61019
+ /* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${SUBJECT_MANY}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly }) }),
60965
61020
  /* @__PURE__ */ jsxs(Box, { as: "details", borderTopWidth: "1px", borderColor: "border.subtle", children: [
60966
61021
  /* @__PURE__ */ jsxs(
60967
61022
  Box,
@@ -60994,8 +61049,8 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
60994
61049
  }
60995
61050
  ),
60996
61051
  /* @__PURE__ */ jsxs(Box, { px: "4.5", pb: "3.5", pt: "0.5", children: [
60997
- /* @__PURE__ */ jsx$1(Segmented, { label: "How to compare", help: "adv_method", left: "regression", right: "reweighting", active: vs.method === "reweighting" ? "right" : "left", onPick: (s2) => editConfig({ ...config2, method: some(s2 === "right" ? variant("propensity_score_weighting", { weighting_scheme: none$1 }) : variant("linear_regression", null)) }) }),
60998
- /* @__PURE__ */ jsx$1(Segmented, { label: "Answer for", help: "adv_estimand", left: "all", right: "only treated", active: vs.target === "treated" ? "right" : "left", onPick: (s2) => editConfig({ ...config2, estimand: some(variant(s2 === "right" ? "att" : "ate", null)) }), last: true })
61052
+ /* @__PURE__ */ jsx$1(Segmented, { label: "How to compare", help: "adv_method", left: "regression", right: "reweighting", active: vs.method === "reweighting" ? "right" : "left", readonly, onPick: (s2) => editConfig({ ...config2, method: some(s2 === "right" ? variant("propensity_score_weighting", { weighting_scheme: none$1 }) : variant("linear_regression", null)) }) }),
61053
+ /* @__PURE__ */ jsx$1(Segmented, { label: "Answer for", help: "adv_estimand", left: "all", right: "only treated", active: vs.target === "treated" ? "right" : "left", readonly, onPick: (s2) => editConfig({ ...config2, estimand: some(variant(s2 === "right" ? "att" : "ate", null)) }), last: true })
60999
61054
  ] })
61000
61055
  ] })
61001
61056
  ] }),
@@ -61069,7 +61124,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61069
61124
  ] })
61070
61125
  ] }),
61071
61126
  tab === "answer" && a2 && /* @__PURE__ */ jsx$1(AnswerNumeric, { a: a2, verdict, higherBetter, badge, barList }),
61072
- tab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: ((_d2 = experiment.result) == null ? void 0 : _d2.naive) ?? 0, outcome: vs.outcome }),
61127
+ tab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcome }),
61073
61128
  tab === "trust" && vr && /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
61074
61129
  /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", mb: "3.5", children: /* @__PURE__ */ jsx$1(Help, { id: "trust_intro", children: "Before trusting the answer we tried to break it — colour shows pass / caution." }) }),
61075
61130
  /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame.flat", children: vr.checks.map((c2, i) => {
@@ -61171,7 +61226,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61171
61226
  var _a3;
61172
61227
  const id3 = getSomeorUndefined(r2.preset);
61173
61228
  if (id3 === void 0) return null;
61174
- const label = ((_a3 = presets.find((p2) => p2.id === id3)) == null ? void 0 : _a3.label) ?? id3;
61229
+ const label = ((_a3 = configs.find((c2) => c2.id === id3)) == null ? void 0 : _a3.label) ?? id3;
61175
61230
  return /* @__PURE__ */ jsxs(Fragment, { children: [
61176
61231
  " ",
61177
61232
  /* @__PURE__ */ jsxs(Box, { as: "span", css: chip({ tone: "brand", size: "sm" }), children: [
@@ -61371,11 +61426,17 @@ function ValidatePanel({ vm, barList }) {
61371
61426
  ] }, i)) })
61372
61427
  ] });
61373
61428
  }
61374
- function FilterRail({ fields, population, onChange: onChange2, chip, button }) {
61429
+ function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly }) {
61375
61430
  const [open, setOpen] = useState(null);
61376
61431
  const replaceAt = (i, p2) => onChange2(population.map((f2, j2) => j2 === i ? p2 : f2));
61377
61432
  const removeAt = (i) => onChange2(population.filter((_2, j2) => j2 !== i));
61378
61433
  const done = /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "outline", size: "xs" }), onClick: () => setOpen(null), children: "Done" });
61434
+ if (readonly) {
61435
+ return /* @__PURE__ */ jsx$1(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: population.length === 0 ? /* @__PURE__ */ jsxs(Box, { css: chip({ tone: "plain", numeric: true, shape: "rounded" }), children: [
61436
+ "all ",
61437
+ SUBJECT_MANY
61438
+ ] }) : population.map((pred, i) => /* @__PURE__ */ jsx$1(Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred) }) }, i)) });
61439
+ }
61379
61440
  return /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: [
61380
61441
  population.map((pred, i) => /* @__PURE__ */ jsx$1(
61381
61442
  SliceEditPopover,
@@ -61436,7 +61497,13 @@ function ColumnMenu({ choices, onPick, children: children2 }) {
61436
61497
  /* @__PURE__ */ jsx$1(Portal, { children: /* @__PURE__ */ jsx$1(Menu.Positioner, { children: /* @__PURE__ */ jsx$1(Menu.Content, { children: choices.map((c2) => /* @__PURE__ */ jsx$1(Menu.Item, { value: c2, onClick: () => onPick(c2), children: c2 }, c2)) }) }) })
61437
61498
  ] });
61438
61499
  }
61439
- function ColumnPick({ column: column2, kind, choices, onPick, badge, button }) {
61500
+ function ColumnPick({ column: column2, kind, choices, onPick, badge, button, readonly }) {
61501
+ if (readonly) {
61502
+ return /* @__PURE__ */ jsxs(Box, { css: button({ variant: "outline", size: "sm" }), gap: "1.5", cursor: "default", children: [
61503
+ /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: column2 }),
61504
+ /* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: kind })
61505
+ ] });
61506
+ }
61440
61507
  return /* @__PURE__ */ jsx$1(ColumnMenu, { choices, onPick, children: /* @__PURE__ */ jsxs(Box, { as: "button", css: button({ variant: "outline", size: "sm" }), gap: "1.5", children: [
61441
61508
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: column2 }),
61442
61509
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: kind }),
@@ -61479,10 +61546,14 @@ function SegmentSelect({ options: options2, active, onPick, fill, size: size3 =
61479
61546
  }
61480
61547
  );
61481
61548
  }
61482
- function Segmented({ label, left, right, active, onPick, last: last2, help }) {
61549
+ function SegmentStatic({ value, size: size3 = "xs" }) {
61550
+ const s2 = useSlotRecipe({ key: "segmentGroup" })({ size: size3 });
61551
+ return /* @__PURE__ */ jsx$1(Box, { css: s2.root, alignSelf: "flex-start", children: /* @__PURE__ */ jsx$1(Box, { css: s2.item, "data-state": "checked", children: /* @__PURE__ */ jsx$1(Box, { as: "span", css: s2.itemText, children: value }) }) });
61552
+ }
61553
+ function Segmented({ label, left, right, active, onPick, last: last2, help, readonly }) {
61483
61554
  return /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", alignItems: "stretch", gap: "1.5", py: "2", borderBottomWidth: last2 ? "0" : "1px", borderColor: "border.subtle", children: [
61484
61555
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", textTransform: "none", letterSpacing: "normal", color: "fg.default", children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: label }) : label }),
61485
- /* @__PURE__ */ jsx$1(SegmentSelect, { options: [left, right], active: active === "left" ? 0 : 1, onPick: (i) => onPick(i === 0 ? "left" : "right"), fill: true, size: "xs" })
61556
+ readonly ? /* @__PURE__ */ jsx$1(SegmentStatic, { value: active === "left" ? left : right }) : /* @__PURE__ */ jsx$1(SegmentSelect, { options: [left, right], active: active === "left" ? 0 : 1, onPick: (i) => onPick(i === 0 ? "left" : "right"), fill: true, size: "xs" })
61486
61557
  ] });
61487
61558
  }
61488
61559
  implementUIComponent(Experiment.Component, EastChakraExperiment);