@elaraai/e3-ui-components 1.0.61 → 1.0.63

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.d.ts CHANGED
@@ -13,6 +13,7 @@ export { TaskPreview, type TaskPreviewProps } from './components/TaskPreview.js'
13
13
  export { UITaskPreview, type UITaskPreviewProps } from './components/UITaskPreview.js';
14
14
  export { DataTaskPreview, type DataTaskPreviewProps } from './components/DataTaskPreview.js';
15
15
  export { DatasetPreview, type DatasetPreviewProps } from './components/DatasetPreview.js';
16
+ export { DatasetKeySearch, type DatasetKeySearchProps, type DatasetKeyMatchRange } from './components/DatasetKeySearch.js';
16
17
  export { StatusDisplay, type StatusDisplayProps } from './components/StatusDisplay.js';
17
18
  export { EastValueViewer, type EastValueViewerProps } from './components/EastValueViewer.js';
18
19
  export { VirtualizedLogViewer, type VirtualizedLogViewerProps } from './components/VirtualizedLogViewer.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,4BAA4B,CAAC;AACpC,OAAO,4BAA4B,CAAC;AACpC,OAAO,iBAAiB,CAAC;AACzB,OAAO,qBAAqB,CAAC;AAC7B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,uBAAuB,CAAC;AAG/B,cAAc,qBAAqB,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1D,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3E,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAG7F,OAAO,EAAE,uBAAuB,EAAE,KAAK,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,yBAAyB,EAAE,KAAK,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvG,OAAO,EAAE,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGzH,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,4BAA4B,CAAC;AACpC,OAAO,4BAA4B,CAAC;AACpC,OAAO,iBAAiB,CAAC;AACzB,OAAO,qBAAqB,CAAC;AAC7B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,uBAAuB,CAAC;AAG/B,cAAc,qBAAqB,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1D,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3E,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAG7F,OAAO,EAAE,uBAAuB,EAAE,KAAK,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,yBAAyB,EAAE,KAAK,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvG,OAAO,EAAE,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGzH,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAC3H,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC"}
package/dist/index.js CHANGED
@@ -18,17 +18,17 @@ var __privateWrapper = (obj, member, setter, getter) => ({
18
18
  }
19
19
  });
20
20
  var _focused, _cleanup, _setup, _a, _provider, _providerCalled, _b, _online, _cleanup2, _setup2, _c, _gcTimeout, _d, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _e, _client2, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _f, _mutations, _scopes, _mutationId, _g, _queries, _h, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _i, _j;
21
- import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, StructType, StringType, walkPatch, pathToString, pathDisplay, printFor, isVariant, prunePatchFor, detectConflictsFor, mergeWithResolutionsFor, validatePatchFor, isEastSet, isEastDict, ArrayType } from "@elaraai/east";
21
+ import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, StructType, StringType, walkPatch, pathToString, pathDisplay, printFor, isVariant, prunePatchFor, detectConflictsFor, mergeWithResolutionsFor, validatePatchFor, isEastSet, isEastDict, ArrayType, parseFor } from "@elaraai/east";
22
22
  import { EastTypeType } from "@elaraai/east/internal";
23
23
  import { DataBindModeType, DataBindPrimitives, bindPlatformFn, FuncBindPrimitives, FuncErrorType, FuncStatusType, funcBindPlatformFn, RecordBindPrimitives, recordBindPlatformFn, Diff, Ontology, FuncBindHandleType, Experiment, decisionBindPlatformFn, DecisionBindPrimitives, DecisionConstraintType, DiffBindingType, CommitStateType, VerdictType, AnswerType, judgementInputType, DecisionType, DecisionQueue, DecisionJournal, decodeManifest } from "@elaraai/e3-ui/internal";
24
24
  import { registerReactiveTracker, registerPlatformImplementation, StateRuntime, getRegisteredPlatformImplementations, boundSliceConfig } from "@elaraai/east-ui-components/platform";
25
25
  import { TreePathType, DatasetStatusType } from "@elaraai/e3-types";
26
- import { workspaceStatus, datasetListAt, datasetList, dataflowExecuteLaunch, datasetSet, datasetGet, ApiError, workspaceFunctionCall, workspaceFunctionList, workspaceRecordHistory, workspaceRecordMutate, workspaceRecordDescribe, repoCreate, repoGc, repoGcStart, repoGcStatus, repoList, repoRemove, repoStatus, packageExport, packageGet, packageImport, packageList, packageRemove, workspaceCreate, workspaceDeploy, workspaceExport, workspaceGet, workspaceList, workspaceRemove, datasetGetStatus, datasetListRecursive, datasetListRecursivePaths, datasetListWithStatus, taskExecutionList, taskGet, taskList, dataflowCancel, dataflowExecute, dataflowExecutePoll, dataflowGraph, taskLogs, datasetGetPage } from "@elaraai/e3-api-client";
26
+ import { workspaceStatus, datasetListAt, datasetList, dataflowExecuteLaunch, datasetSet, datasetGet, ApiError, workspaceFunctionCall, workspaceFunctionList, workspaceRecordHistory, workspaceRecordMutate, workspaceRecordDescribe, repoCreate, repoGc, repoGcStart, repoGcStatus, repoList, repoRemove, repoStatus, packageExport, packageGet, packageImport, packageList, packageRemove, workspaceCreate, workspaceDeploy, workspaceExport, workspaceGet, workspaceList, workspaceRemove, datasetGetStatus, datasetListRecursive, datasetListRecursivePaths, datasetListWithStatus, taskExecutionList, taskGet, taskList, dataflowCancel, dataflowExecute, dataflowExecutePoll, dataflowGraph, taskLogs, datasetGetPage, datasetFindKey } from "@elaraai/e3-api-client";
27
27
  import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
28
28
  import * as React from "react";
29
29
  import React__default, { useId, useMemo, useContext, createContext, useRef, useEffect, useState, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
30
30
  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, Button, Tabs, Badge, useTabs } from "@chakra-ui/react";
31
- import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, useContainerBelow, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, LoadingIcon, EastChakraValueTree, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
31
+ import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, useContainerBelow, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, LoadingIcon, EastChakraCombobox, EastChakraValueTree, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
32
32
  import { createPortal } from "react-dom";
33
33
  import { sliceMatches } from "@elaraai/east-ui/internal";
34
34
  import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery, keepPreviousData, useQueryClient } from "@tanstack/react-query";
@@ -63988,6 +63988,271 @@ class ErrorBoundary extends Component {
63988
63988
  return this.props.children;
63989
63989
  }
63990
63990
  }
63991
+ const FIND_DEBOUNCE_MS = 250;
63992
+ const POPUP_LIMIT = 20;
63993
+ function structFields(keyType) {
63994
+ if (keyType.type !== "Struct") return null;
63995
+ const fields = keyType.value;
63996
+ return fields.length > 0 ? fields : null;
63997
+ }
63998
+ function splitTopLevel(text) {
63999
+ const parts = [];
64000
+ let current = "";
64001
+ let inString = false;
64002
+ let depth = 0;
64003
+ for (let i = 0; i < text.length; i++) {
64004
+ const ch = text[i];
64005
+ if (inString) {
64006
+ current += ch;
64007
+ if (ch === "\\" && i + 1 < text.length) {
64008
+ current += text[i + 1];
64009
+ i++;
64010
+ } else if (ch === '"') {
64011
+ inString = false;
64012
+ }
64013
+ continue;
64014
+ }
64015
+ if (ch === '"') {
64016
+ inString = true;
64017
+ current += ch;
64018
+ } else if (ch === "(" || ch === "[" || ch === "{") {
64019
+ depth++;
64020
+ current += ch;
64021
+ } else if (ch === ")" || ch === "]" || ch === "}") {
64022
+ depth--;
64023
+ current += ch;
64024
+ } else if (ch === "," && depth === 0) {
64025
+ parts.push(current);
64026
+ current = "";
64027
+ } else {
64028
+ current += ch;
64029
+ }
64030
+ }
64031
+ parts.push(current);
64032
+ return parts;
64033
+ }
64034
+ function keySignature(keyType) {
64035
+ const fields = structFields(keyType);
64036
+ if (fields === null) return keyType.type;
64037
+ return `(${fields.map((f2) => `${f2.name}: ${f2.type.type}`).join(", ")})`;
64038
+ }
64039
+ function parseKeyInput(keyType, text) {
64040
+ const fields = structFields(keyType);
64041
+ if (fields === null) {
64042
+ if (keyType.type === "String") return { kind: "query", query: { prefix: text } };
64043
+ const parsed = parseFor(keyType)(text);
64044
+ if (!parsed.success) return { kind: "hint", hint: `Key is ${keyType.type}` };
64045
+ return { kind: "query", query: { key: printFor(keyType)(parsed.value) } };
64046
+ }
64047
+ if (text.trimStart().startsWith("(")) {
64048
+ const parsed = parseFor(keyType)(text);
64049
+ if (!parsed.success) return { kind: "hint", hint: `Key is ${keySignature(keyType)}` };
64050
+ return { kind: "query", query: { key: printFor(keyType)(parsed.value) } };
64051
+ }
64052
+ const segments = splitTopLevel(text);
64053
+ if (segments.length > fields.length) {
64054
+ return { kind: "hint", hint: `Key is ${keySignature(keyType)}` };
64055
+ }
64056
+ const exact = [];
64057
+ for (let i = 0; i < segments.length; i++) {
64058
+ const field = fields[i];
64059
+ const raw = segments[i].trim();
64060
+ const isLast = i === segments.length - 1;
64061
+ if (isLast && raw === "" && i > 0) {
64062
+ return { kind: "query", query: { fields: exact } };
64063
+ }
64064
+ if (field.type.type === "String" && !raw.startsWith('"')) {
64065
+ if (isLast) {
64066
+ return exact.length === 0 ? { kind: "query", query: { prefix: raw } } : { kind: "query", query: { fields: exact, prefix: raw } };
64067
+ }
64068
+ exact.push(printFor(StringType)(raw));
64069
+ continue;
64070
+ }
64071
+ const parsed = parseFor(field.type)(raw);
64072
+ if (!parsed.success) {
64073
+ return { kind: "hint", hint: `${field.name} is ${field.type.type} — key is ${keySignature(keyType)}` };
64074
+ }
64075
+ exact.push(printFor(field.type)(parsed.value));
64076
+ }
64077
+ return { kind: "query", query: { fields: exact } };
64078
+ }
64079
+ const MATCH_NOTHING = { lower: () => false, upper: () => false };
64080
+ function keyRangePredicates(keyType, query) {
64081
+ if ("key" in query) return null;
64082
+ if (keyType.type === "Struct") {
64083
+ const meta3 = keyType.value;
64084
+ const literals = "fields" in query ? query.fields : [];
64085
+ if (literals.length > meta3.length) return MATCH_NOTHING;
64086
+ const values = [];
64087
+ for (let j2 = 0; j2 < literals.length; j2++) {
64088
+ const parsed = parseFor(meta3[j2].type)(literals[j2]);
64089
+ if (!parsed.success) return MATCH_NOTHING;
64090
+ values.push(parsed.value);
64091
+ }
64092
+ const cmps = meta3.map((f2) => compareFor(f2.type));
64093
+ const lead = (k2) => {
64094
+ for (let j2 = 0; j2 < values.length; j2++) {
64095
+ const c2 = cmps[j2](k2[meta3[j2].name], values[j2]);
64096
+ if (c2 !== 0) return c2;
64097
+ }
64098
+ return 0;
64099
+ };
64100
+ const prefix22 = query.prefix;
64101
+ if (prefix22 === void 0) {
64102
+ return { lower: (k2) => lead(k2) >= 0, upper: (k2) => lead(k2) > 0 };
64103
+ }
64104
+ const prefixIdx = values.length;
64105
+ if (prefixIdx >= meta3.length || meta3[prefixIdx].type.type !== "String") return MATCH_NOTHING;
64106
+ const prefixName = meta3[prefixIdx].name;
64107
+ const prefixCmp = cmps[prefixIdx];
64108
+ return {
64109
+ lower: (k2) => {
64110
+ const c2 = lead(k2);
64111
+ return c2 !== 0 ? c2 > 0 : prefixCmp(k2[prefixName], prefix22) >= 0;
64112
+ },
64113
+ upper: (k2) => {
64114
+ const c2 = lead(k2);
64115
+ if (c2 !== 0) return c2 > 0;
64116
+ const field = k2[prefixName];
64117
+ return prefixCmp(field, prefix22) > 0 && !field.startsWith(prefix22);
64118
+ }
64119
+ };
64120
+ }
64121
+ if (!("prefix" in query) || query.prefix === void 0 || keyType.type !== "String") return MATCH_NOTHING;
64122
+ const prefix2 = query.prefix;
64123
+ const cmp = compareFor(keyType);
64124
+ return {
64125
+ lower: (k2) => cmp(k2, prefix2) >= 0,
64126
+ upper: (k2) => cmp(k2, prefix2) > 0 && !k2.startsWith(prefix2)
64127
+ };
64128
+ }
64129
+ const DatasetKeySearch = memo(function DatasetKeySearch2({ keyType, onFind, onListRange, onJump, onClear }) {
64130
+ const [range, setRange] = useState(null);
64131
+ const [items, setItems] = useState([]);
64132
+ const [activeIdx, setActiveIdx] = useState(-1);
64133
+ const [hint, setHint] = useState(null);
64134
+ const [resetSeq, setResetSeq] = useState(0);
64135
+ const debounceRef = useRef(void 0);
64136
+ const findSeqRef = useRef(0);
64137
+ useEffect(() => () => clearTimeout(debounceRef.current), []);
64138
+ const runFind = useCallback((query) => {
64139
+ const seq = ++findSeqRef.current;
64140
+ void (async () => {
64141
+ try {
64142
+ const result = await onFind(query);
64143
+ if (seq !== findSeqRef.current) return;
64144
+ setRange(result);
64145
+ setActiveIdx(-1);
64146
+ if (result.found) {
64147
+ const labels = await onListRange(result.row, Math.min(POPUP_LIMIT, result.count));
64148
+ if (seq !== findSeqRef.current) return;
64149
+ setItems(labels.map((label, i) => ({ row: result.row + i, label })));
64150
+ } else {
64151
+ setItems([]);
64152
+ }
64153
+ } catch {
64154
+ if (seq !== findSeqRef.current) return;
64155
+ setRange(null);
64156
+ setItems([]);
64157
+ }
64158
+ })();
64159
+ }, [onFind, onListRange]);
64160
+ const resetQueryState = useCallback(() => {
64161
+ clearTimeout(debounceRef.current);
64162
+ findSeqRef.current++;
64163
+ setRange(null);
64164
+ setItems([]);
64165
+ setActiveIdx(-1);
64166
+ setHint(null);
64167
+ }, []);
64168
+ const handleInput = useCallback((text) => {
64169
+ clearTimeout(debounceRef.current);
64170
+ if (text === "") {
64171
+ resetQueryState();
64172
+ onClear == null ? void 0 : onClear();
64173
+ return;
64174
+ }
64175
+ const parsed = parseKeyInput(keyType, text);
64176
+ if (parsed.kind === "hint") {
64177
+ findSeqRef.current++;
64178
+ setRange(null);
64179
+ setItems([]);
64180
+ setActiveIdx(-1);
64181
+ setHint(parsed.hint);
64182
+ return;
64183
+ }
64184
+ setHint(null);
64185
+ debounceRef.current = setTimeout(() => runFind(parsed.query), FIND_DEBOUNCE_MS);
64186
+ }, [keyType, runFind, resetQueryState, onClear]);
64187
+ const clearSearch = useCallback(() => {
64188
+ resetQueryState();
64189
+ setResetSeq((s2) => s2 + 1);
64190
+ onClear == null ? void 0 : onClear();
64191
+ }, [resetQueryState, onClear]);
64192
+ const commit = useCallback((row) => {
64193
+ onJump(row);
64194
+ if (range !== null) setActiveIdx(row - range.row);
64195
+ }, [onJump, range]);
64196
+ const step3 = useCallback((delta) => {
64197
+ if (range === null || !range.found) return;
64198
+ const next2 = Math.max(0, Math.min(range.count - 1, (activeIdx === -1 ? 0 : activeIdx) + delta));
64199
+ commit(range.row + next2);
64200
+ }, [range, activeIdx, commit]);
64201
+ const onKeyDownCapture = useCallback((e3) => {
64202
+ if (e3.key !== "Enter" || range === null || !range.found) return;
64203
+ if (document.querySelector('[data-scope="combobox"][data-part="content"] [data-highlighted]') !== null) return;
64204
+ commit(range.row + Math.max(0, activeIdx));
64205
+ }, [range, activeIdx, commit]);
64206
+ const placeholder = useMemo(() => {
64207
+ const fields = structFields(keyType);
64208
+ if (fields !== null) return `Search keys (${fields.map((f2) => f2.name).join(", ")})`;
64209
+ return keyType.type === "String" ? "Search keys" : `Find key (${keyType.type})`;
64210
+ }, [keyType]);
64211
+ const payload = useMemo(() => ({
64212
+ value: none$1,
64213
+ items: items.map((it) => ({ value: String(it.row), label: it.label, disabled: none$1 })),
64214
+ placeholder: some(placeholder),
64215
+ multiple: none$1,
64216
+ disabled: none$1,
64217
+ allowCustomValue: some(true),
64218
+ onChange: some((v3) => commit(Number(v3))),
64219
+ onChangeMultiple: none$1,
64220
+ onInputValueChange: some(handleInput),
64221
+ onOpenChange: none$1,
64222
+ style: some({ size: some(variant("xs", null)), color: none$1, background: none$1, borderColor: none$1 })
64223
+ }), [items, placeholder, commit, handleInput]);
64224
+ const status = hint !== null ? hint : range === null ? null : !range.found ? "No matches" : activeIdx === -1 ? `${range.count.toLocaleString()} ${range.count === 1 ? "match" : "matches"}` : `${(activeIdx + 1).toLocaleString()} of ${range.count.toLocaleString()}`;
64225
+ const canStep = range !== null && range.found && range.count > 1;
64226
+ return /* @__PURE__ */ jsxs(Flex, { gap: 1, align: "center", minW: "0", onKeyDownCapture, "data-part": "dataset-key-search", children: [
64227
+ /* @__PURE__ */ jsx$1(Flex, { width: `min(${placeholder.length + 10}ch, 40rem)`, minW: "12rem", flexShrink: 1, children: /* @__PURE__ */ jsx$1(EastChakraCombobox, { value: payload, selectionBehavior: "preserve" }, resetSeq) }),
64228
+ status !== null && /* @__PURE__ */ jsx$1(Text, { fontSize: "xs", color: "fg.muted", whiteSpace: "nowrap", children: status }),
64229
+ canStep && /* @__PURE__ */ jsxs(Fragment, { children: [
64230
+ /* @__PURE__ */ jsx$1(
64231
+ IconButton,
64232
+ {
64233
+ "aria-label": "Previous match",
64234
+ size: "2xs",
64235
+ variant: "ghost",
64236
+ disabled: activeIdx <= 0,
64237
+ onClick: () => step3(-1),
64238
+ children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronUp })
64239
+ }
64240
+ ),
64241
+ /* @__PURE__ */ jsx$1(
64242
+ IconButton,
64243
+ {
64244
+ "aria-label": "Next match",
64245
+ size: "2xs",
64246
+ variant: "ghost",
64247
+ disabled: activeIdx >= range.count - 1,
64248
+ onClick: () => step3(1),
64249
+ children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown })
64250
+ }
64251
+ )
64252
+ ] }),
64253
+ (range !== null || hint !== null) && /* @__PURE__ */ jsx$1(IconButton, { "aria-label": "Clear search", size: "2xs", variant: "ghost", onClick: clearSearch, children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faXmark }) })
64254
+ ] });
64255
+ });
63991
64256
  function pagingDebug(...args) {
63992
64257
  try {
63993
64258
  if (typeof localStorage === "undefined") return;
@@ -63999,6 +64264,17 @@ function pagingDebug(...args) {
63999
64264
  console.info("[e3-paging]", ...args);
64000
64265
  }
64001
64266
  const PAGE_SIZE = 500;
64267
+ const MAX_RETAINED_PAGES = 8;
64268
+ function pruneRetainedPages(pages, firstPage, lastPage, max5) {
64269
+ if (pages.size <= max5) return pages;
64270
+ const distance2 = (p2) => p2 < firstPage ? firstPage - p2 : p2 > lastPage ? p2 - lastPage : 0;
64271
+ const keep = [...pages.keys()].sort((a2, b2) => distance2(a2) - distance2(b2) || a2 - b2).slice(0, max5);
64272
+ const kept = /* @__PURE__ */ new Map();
64273
+ for (const p2 of keep.sort((a2, b2) => a2 - b2)) {
64274
+ kept.set(p2, pages.get(p2));
64275
+ }
64276
+ return kept;
64277
+ }
64002
64278
  function pageRows(type, decoded, offset) {
64003
64279
  if (type.type === "Array") {
64004
64280
  const elemType2 = type.value;
@@ -64042,12 +64318,14 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64042
64318
  const [totals, setTotals] = useState(null);
64043
64319
  const [loadingCount, setLoadingCount] = useState(0);
64044
64320
  const [error3, setError] = useState(null);
64321
+ const [jumpRow, setJumpRow] = useState(void 0);
64045
64322
  const inflightRef = useRef(/* @__PURE__ */ new Set());
64046
64323
  useEffect(() => {
64047
64324
  pagingDebug(`reset (path=${path2}, hash=${hash2.slice(0, 8)})`);
64048
64325
  setPages(/* @__PURE__ */ new Map());
64049
64326
  setTotals(null);
64050
64327
  setError(null);
64328
+ setJumpRow(void 0);
64051
64329
  inflightRef.current.clear();
64052
64330
  }, [path2, hash2]);
64053
64331
  const loadPage = useCallback((pageIdx) => {
@@ -64055,13 +64333,13 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64055
64333
  inflightRef.current.add(pageIdx);
64056
64334
  setLoadingCount((n2) => n2 + 1);
64057
64335
  pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * PAGE_SIZE}, limit=${PAGE_SIZE}, hash=${hash2.slice(0, 8)})`);
64058
- const pathParts = path2.split(".").filter(Boolean).map((v3) => variant("field", v3));
64336
+ const pathParts2 = path2.split(".").filter(Boolean).map((v3) => variant("field", v3));
64059
64337
  const reqOpts = requestOptions ?? { token: null };
64060
64338
  queryClient.fetchQuery({
64061
64339
  queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `p${pageIdx}`],
64062
64340
  // Hash-pinned: the URL is a pure function of the bytes, so any
64063
64341
  // HTTP cache between here and the server can hold it immutably.
64064
- queryFn: () => datasetGetPage(apiUrl, repo, workspace, pathParts, { offset: pageIdx * PAGE_SIZE, limit: PAGE_SIZE, hash: hash2 }, reqOpts),
64342
+ queryFn: () => datasetGetPage(apiUrl, repo, workspace, pathParts2, { offset: pageIdx * PAGE_SIZE, limit: PAGE_SIZE, hash: hash2 }, reqOpts),
64065
64343
  staleTime: Infinity
64066
64344
  // pages of one content hash are immutable
64067
64345
  }).then((page) => {
@@ -64098,8 +64376,35 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64098
64376
  if (!pages.has(p2)) missing.push(p2);
64099
64377
  }
64100
64378
  pagingDebug(`need rows [${startRow}, ${endRow}) → pages ${first2}..${last2}, missing=[${missing.join(",")}], inflight=[${[...inflightRef.current].join(",")}]`);
64379
+ setPages((prev2) => pruneRetainedPages(prev2, first2, last2, MAX_RETAINED_PAGES));
64101
64380
  for (const p2 of missing) loadPage(p2);
64102
64381
  }, [pages, loadPage]);
64382
+ const keyType = useMemo(() => type.type === "Dict" ? type.value.key : type.type === "Set" ? type.value : null, [type]);
64383
+ const pathParts = useMemo(() => path2.split(".").filter(Boolean).map((v3) => variant("field", v3)), [path2]);
64384
+ const onFindKey = useCallback(async (query) => {
64385
+ const reqOpts = requestOptions ?? { token: null };
64386
+ const queryTag = JSON.stringify(query);
64387
+ const result = await queryClient.fetchQuery({
64388
+ queryKey: ["datasetFind", apiUrl, repo, workspace, path2, hash2, queryTag],
64389
+ queryFn: () => datasetFindKey(apiUrl, repo, workspace, pathParts, { ...query, hash: hash2 }, reqOpts),
64390
+ staleTime: Infinity
64391
+ // hash-pinned: one content hash, one answer
64392
+ });
64393
+ pagingDebug(`find ${queryTag}: found=${result.found} row=${result.row} count=${result.count}`);
64394
+ return result;
64395
+ }, [queryClient, apiUrl, repo, workspace, path2, hash2, pathParts, requestOptions]);
64396
+ const onListRange = useCallback(async (row, limit2) => {
64397
+ const reqOpts = requestOptions ?? { token: null };
64398
+ const page = await queryClient.fetchQuery({
64399
+ queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `w${row}:${limit2}`],
64400
+ queryFn: () => datasetGetPage(apiUrl, repo, workspace, pathParts, { offset: row, limit: limit2, hash: hash2 }, reqOpts),
64401
+ staleTime: Infinity
64402
+ });
64403
+ const decoded = decodeBeast2For(type)(page.data);
64404
+ const stringKeys = keyType !== null && keyType.type === "String";
64405
+ const keys = type.type === "Dict" ? [...decoded.keys()] : [...decoded.values()];
64406
+ return keys.map((k2) => stringKeys ? k2 : ValueTree.keyLabel(keyType, k2));
64407
+ }, [queryClient, apiUrl, repo, workspace, path2, hash2, pathParts, requestOptions, type, keyType]);
64103
64408
  const treeValue = useMemo(() => ({
64104
64409
  root: ValueTree.materialize(type, emptyOf(type)),
64105
64410
  onEdit: none$1,
@@ -64112,8 +64417,9 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64112
64417
  totalRows: totals.elements,
64113
64418
  pageSize: PAGE_SIZE,
64114
64419
  pages,
64115
- onNeedRows
64116
- }, [totals, pages, onNeedRows]);
64420
+ onNeedRows,
64421
+ scrollToRow: jumpRow
64422
+ }, [totals, pages, onNeedRows, jumpRow]);
64117
64423
  if (error3 !== null) {
64118
64424
  if (error3 instanceof ApiError && error3.code === "dataset_too_large") {
64119
64425
  return /* @__PURE__ */ jsxs(Flex, { height: "100%", direction: "column", align: "center", justify: "center", gap: 3, p: 6, children: [
@@ -64138,6 +64444,16 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64138
64444
  formatSize(totals.bytes > 0 ? totals.bytes : sizeBytes)
64139
64445
  ] }),
64140
64446
  loadingCount > 0 && /* @__PURE__ */ jsx$1(Text, { fontSize: "xs", color: "fg.muted", children: "Loading…" }),
64447
+ keyType !== null && /* @__PURE__ */ jsx$1(
64448
+ DatasetKeySearch,
64449
+ {
64450
+ keyType,
64451
+ onFind: onFindKey,
64452
+ onListRange,
64453
+ onJump: setJumpRow,
64454
+ onClear: () => setJumpRow(void 0)
64455
+ }
64456
+ ),
64141
64457
  /* @__PURE__ */ jsx$1(Flex, { flex: 1, justify: "flex-end", children: /* @__PURE__ */ jsx$1(DownloadButton, { onClick: onDownload }) })
64142
64458
  ] }),
64143
64459
  /* @__PURE__ */ jsx$1(Box, { flex: 1, minHeight: 0, overflow: "hidden", children: /* @__PURE__ */ jsx$1(EastChakraValueTree, { value: treeValue, storageKey: `${path2}:page`, paging }) })
@@ -64209,6 +64525,37 @@ const DatasetPreview = memo(function DatasetPreview2({
64209
64525
  await setMutation.mutateAsync({ path: treePath, data: data4 });
64210
64526
  await queryClient.invalidateQueries({ queryKey: ["datasetStatus", apiUrl, repo, workspace, path2] });
64211
64527
  }, [apiUrl, repo, workspace, path2, type, setMutation, queryClient]);
64528
+ const keyType = useMemo(() => type === void 0 ? null : type.type === "Dict" ? type.value.key : type.type === "Set" ? type.value : null, [type]);
64529
+ const inlineKeys = useMemo(() => decoded === void 0 || type === void 0 ? null : type.type === "Dict" ? [...decoded.keys()] : type.type === "Set" ? [...decoded.values()] : null, [type, decoded]);
64530
+ const [jumpRow, setJumpRow] = useState(void 0);
64531
+ useEffect(() => {
64532
+ setJumpRow(void 0);
64533
+ }, [decoded]);
64534
+ const onFindInline = useCallback(async (query) => {
64535
+ if (inlineKeys === null || keyType === null) return { found: false, row: 0, count: 0 };
64536
+ const range = keyRangePredicates(keyType, query);
64537
+ if (range === null) {
64538
+ const parsed = parseFor(keyType)(query.key);
64539
+ if (!parsed.success) return { found: false, row: 0, count: 0 };
64540
+ const cmp = compareFor(keyType);
64541
+ for (let i = 0; i < inlineKeys.length; i++) {
64542
+ const order = cmp(inlineKeys[i], parsed.value);
64543
+ if (order === 0) return { found: true, row: i, count: 1 };
64544
+ if (order > 0) return { found: false, row: i, count: 0 };
64545
+ }
64546
+ return { found: false, row: inlineKeys.length, count: 0 };
64547
+ }
64548
+ let row = inlineKeys.findIndex(range.lower);
64549
+ if (row === -1) row = inlineKeys.length;
64550
+ let count2 = 0;
64551
+ while (row + count2 < inlineKeys.length && !range.upper(inlineKeys[row + count2])) count2++;
64552
+ return { found: count2 > 0, row, count: count2 };
64553
+ }, [inlineKeys, keyType]);
64554
+ const onListInline = useCallback(async (row, limit2) => {
64555
+ if (inlineKeys === null || keyType === null) return [];
64556
+ const stringKeys = keyType.type === "String";
64557
+ return inlineKeys.slice(row, row + limit2).map((k2) => stringKeys ? k2 : ValueTree.keyLabel(keyType, k2));
64558
+ }, [inlineKeys, keyType]);
64212
64559
  const treeValue = useMemo(() => {
64213
64560
  if (type === void 0 || decoded === void 0) return null;
64214
64561
  const root2 = ValueTree.materialize(type, decoded);
@@ -64263,14 +64610,26 @@ const DatasetPreview = memo(function DatasetPreview2({
64263
64610
  const count = type === void 0 || decoded === void 0 ? null : type.type === "Array" ? decoded.length : type.type === "Set" || type.type === "Dict" ? decoded.size : null;
64264
64611
  const countText = count === null ? "" : `${count.toLocaleString()} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
64265
64612
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
64266
- /* @__PURE__ */ jsxs(Flex, { px: 4, py: 2, justify: "flex-end", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
64267
- /* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "fg.muted", mr: 2, alignSelf: "center", children: [
64268
- countText,
64269
- formatSize(sizeBytes)
64270
- ] }),
64271
- /* @__PURE__ */ jsx$1(DownloadButton, { onClick: download })
64613
+ /* @__PURE__ */ jsxs(Flex, { px: 4, py: 2, gap: 2, align: "center", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
64614
+ keyType !== null && inlineKeys !== null && /* @__PURE__ */ jsx$1(
64615
+ DatasetKeySearch,
64616
+ {
64617
+ keyType,
64618
+ onFind: onFindInline,
64619
+ onListRange: onListInline,
64620
+ onJump: setJumpRow,
64621
+ onClear: () => setJumpRow(void 0)
64622
+ }
64623
+ ),
64624
+ /* @__PURE__ */ jsxs(Flex, { flex: 1, justify: "flex-end", align: "center", gap: 2, children: [
64625
+ /* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "fg.muted", children: [
64626
+ countText,
64627
+ formatSize(sizeBytes)
64628
+ ] }),
64629
+ /* @__PURE__ */ jsx$1(DownloadButton, { onClick: download })
64630
+ ] })
64272
64631
  ] }),
64273
- /* @__PURE__ */ jsx$1(Box, { flex: 1, minHeight: 0, overflow: "hidden", children: treeValue !== null && /* @__PURE__ */ jsx$1(EastChakraValueTree, { value: treeValue, storageKey: path2 ?? "value" }) })
64632
+ /* @__PURE__ */ jsx$1(Box, { flex: 1, minHeight: 0, overflow: "hidden", children: treeValue !== null && /* @__PURE__ */ jsx$1(EastChakraValueTree, { value: treeValue, storageKey: path2 ?? "value", scrollToRow: jumpRow }) })
64274
64633
  ] });
64275
64634
  });
64276
64635
  const InputPreview = memo(function InputPreview2({
@@ -65262,6 +65621,7 @@ export {
65262
65621
  BindPlatform,
65263
65622
  BindRuntime,
65264
65623
  DataTaskPreview,
65624
+ DatasetKeySearch,
65265
65625
  DatasetPreview,
65266
65626
  E3Provider,
65267
65627
  EastChakraDecisionJournal,