@upstash/react-redis-browser 0.1.10 → 0.1.11-canary-2

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
@@ -4,9 +4,97 @@ var _react = require('react'); var React = _interopRequireWildcard(_react); var
4
4
  // src/store.tsx
5
5
 
6
6
  var _zustand = require('zustand');
7
+ var _jsxruntime = require('react/jsx-runtime');
8
+ var DatabrowserContext = _react.createContext.call(void 0, void 0);
9
+ var DatabrowserProvider = ({ children }) => {
10
+ const store = _react.useMemo.call(void 0, () => createDatabrowserStore(), []);
11
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserContext.Provider, { value: { store }, children });
12
+ };
13
+ var useDatabrowser = () => {
14
+ const context = _react.useContext.call(void 0, DatabrowserContext);
15
+ if (!context) {
16
+ throw new Error("useDatabrowser must be used within a DatabrowserProvider");
17
+ }
18
+ return context;
19
+ };
20
+ var useDatabrowserStore = () => {
21
+ const { store } = useDatabrowser();
22
+ return _zustand.useStore.call(void 0, store);
23
+ };
24
+ var createDatabrowserStore = () => _zustand.create.call(void 0, (set, get) => ({
25
+ selectedTab: void 0,
26
+ tabs: {},
27
+ addTab: () => {
28
+ const id = crypto.randomUUID();
29
+ const newTabData = {
30
+ selectedKey: void 0,
31
+ search: { key: "", type: void 0 }
32
+ };
33
+ set((old) => ({
34
+ tabs: { ...old.tabs, [id]: newTabData },
35
+ selectedTab: old.selectedTab === void 0 ? id : old.selectedTab
36
+ }));
37
+ },
38
+ removeTab: (id) => {
39
+ set((old) => {
40
+ const newTabs = { ...old.tabs };
41
+ delete newTabs[id];
42
+ let selectedTab = old.selectedTab;
43
+ if (selectedTab === id) {
44
+ const tabIds = Object.keys(newTabs);
45
+ selectedTab = tabIds.length > 0 ? tabIds[0] : void 0;
46
+ }
47
+ return { tabs: newTabs, selectedTab };
48
+ });
49
+ },
50
+ selectTab: (id) => {
51
+ set({ selectedTab: id });
52
+ },
53
+ getSelectedKey: (tabId) => {
54
+ return _optionalChain([get, 'call', _2 => _2(), 'access', _3 => _3.tabs, 'access', _4 => _4[tabId], 'optionalAccess', _5 => _5.selectedKey]);
55
+ },
56
+ setSelectedKey: (tabId, key) => {
57
+ set((old) => ({
58
+ ...old,
59
+ tabs: {
60
+ ...old.tabs,
61
+ [tabId]: { ...old.tabs[tabId], selectedKey: key, selectedListItem: void 0 }
62
+ }
63
+ }));
64
+ },
65
+ setSelectedListItem: (tabId, item) => {
66
+ set((old) => ({
67
+ ...old,
68
+ tabs: { ...old.tabs, [tabId]: { ...old.tabs[tabId], selectedListItem: item } }
69
+ }));
70
+ },
71
+ setSearch: (tabId, search) => set((old) => ({ ...old, tabs: { ...old.tabs, [tabId]: { ...old.tabs[tabId], search } } })),
72
+ setSearchKey: (tabId, key) => set((old) => ({
73
+ ...old,
74
+ tabs: {
75
+ ...old.tabs,
76
+ [tabId]: { ...old.tabs[tabId], search: { ...old.tabs[tabId].search, key } }
77
+ }
78
+ })),
79
+ setSearchType: (tabId, type) => set((old) => ({
80
+ ...old,
81
+ tabs: {
82
+ ...old.tabs,
83
+ [tabId]: { ...old.tabs[tabId], search: { ...old.tabs[tabId].search, type } }
84
+ }
85
+ })),
86
+ searchHistory: [],
87
+ addSearchHistory: (key) => {
88
+ set((old) => ({ ...old, searchHistory: [key, ...old.searchHistory] }));
89
+ }
90
+ }));
7
91
 
8
- // src/lib/clients.ts
92
+ // src/components/databrowser/index.tsx
93
+ var _reacttooltip = require('@radix-ui/react-tooltip'); var TooltipPrimitive = _interopRequireWildcard(_reacttooltip);
9
94
  var _reactquery = require('@tanstack/react-query');
95
+
96
+ // src/lib/clients.ts
97
+
10
98
  var _redis = require('@upstash/redis');
11
99
 
12
100
  // src/components/ui/use-toast.ts
@@ -136,8 +224,8 @@ var redisClient = ({
136
224
  credentials,
137
225
  pipelining
138
226
  }) => {
139
- const token = _optionalChain([credentials, 'optionalAccess', _2 => _2.token]) || process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN;
140
- const url = _optionalChain([credentials, 'optionalAccess', _3 => _3.url]) || process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL;
227
+ const token = _optionalChain([credentials, 'optionalAccess', _6 => _6.token]) || process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN;
228
+ const url = _optionalChain([credentials, 'optionalAccess', _7 => _7.url]) || process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL;
141
229
  if (!url) {
142
230
  throw new Error("Redis URL is missing!");
143
231
  }
@@ -180,140 +268,53 @@ var queryClient = new (0, _reactquery.QueryClient)({
180
268
  })
181
269
  });
182
270
 
183
- // src/store.tsx
184
- var _jsxruntime = require('react/jsx-runtime');
185
- var DatabrowserContext = _react.createContext.call(void 0, void 0);
186
- var DatabrowserProvider = ({
271
+ // src/redis-context.tsx
272
+
273
+
274
+ var RedisContext = _react.createContext.call(void 0, void 0);
275
+ var RedisProvider = ({
187
276
  children,
188
277
  redisCredentials
189
278
  }) => {
190
- const redisInstance = _react.useMemo.call(void 0, () => redisClient({ credentials: redisCredentials, pipelining: true }), [redisCredentials]);
191
- const redisInstanceNoPipeline = _react.useMemo.call(void 0, () => redisClient({ credentials: redisCredentials, pipelining: false }), [redisCredentials]);
192
- const [store] = _react.useState.call(void 0, () => {
193
- return createDatabrowserStore();
194
- });
195
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserContext.Provider, { value: { redis: redisInstance, redisNoPipeline: redisInstanceNoPipeline, store }, children });
279
+ const redisInstance = _react.useMemo.call(void 0,
280
+ () => redisClient({ credentials: redisCredentials, pipelining: true }),
281
+ [redisCredentials]
282
+ );
283
+ const redisInstanceNoPipeline = _react.useMemo.call(void 0,
284
+ () => redisClient({ credentials: redisCredentials, pipelining: false }),
285
+ [redisCredentials]
286
+ );
287
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
288
+ RedisContext.Provider,
289
+ {
290
+ value: { redis: redisInstance, redisNoPipeline: redisInstanceNoPipeline },
291
+ children
292
+ }
293
+ );
196
294
  };
197
- var useDatabrowser = () => {
198
- const context = _react.useContext.call(void 0, DatabrowserContext);
295
+ var useRedis = () => {
296
+ const context = _react.useContext.call(void 0, RedisContext);
199
297
  if (!context) {
200
- throw new Error("useDatabrowser must be used within a DatabrowserProvider");
298
+ throw new Error("useRedis must be used within a RedisProvider");
201
299
  }
202
300
  return context;
203
301
  };
204
- var useDatabrowserStore = () => {
205
- const { store } = useDatabrowser();
206
- return _zustand.useStore.call(void 0, store);
207
- };
208
- var createDatabrowserStore = () => _zustand.create.call(void 0, (set) => ({
209
- selectedKey: void 0,
210
- setSelectedKey: (key) => {
211
- set((old) => ({ ...old, selectedKey: key, selectedListItem: void 0 }));
212
- },
213
- selectedListItem: void 0,
214
- setSelectedListItem: (item) => {
215
- set((old) => ({ ...old, selectedListItem: item }));
216
- },
217
- search: { key: "", type: void 0 },
218
- setSearch: (search) => set({ search }),
219
- setSearchKey: (key) => set((state) => ({ search: { ...state.search, key } })),
220
- setSearchType: (type) => set((state) => ({ search: { ...state.search, type } }))
221
- }));
222
-
223
- // src/components/databrowser/index.tsx
224
- var _reacttooltip = require('@radix-ui/react-tooltip'); var TooltipPrimitive = _interopRequireWildcard(_reacttooltip);
225
- var _iconsreact = require('@tabler/icons-react');
226
302
 
303
+ // src/components/databrowser/components/databrowser-instance.tsx
227
304
  var _reactresizablepanels = require('react-resizable-panels');
228
305
 
229
- // src/components/ui/toaster.tsx
230
- var _reactportal = require('@radix-ui/react-portal');
231
-
232
- // src/lib/portal-root.ts
233
- var root;
234
- if (typeof document !== "undefined") {
235
- const id = "react-redis-browser-portal-root";
236
- root = _nullishCoalesce(document.querySelector(`#${id}`), () => ( document.createElement("div")));
237
- root.classList.add("ups-db");
238
- root.id = "react-redis-browser-portal-root";
239
- document.body.append(root);
240
- }
241
- var portalRoot = root;
242
-
243
- // src/components/ui/toast.tsx
244
-
245
- var _reacticons = require('@radix-ui/react-icons');
246
- var _reacttoast = require('@radix-ui/react-toast'); var ToastPrimitives = _interopRequireWildcard(_reacttoast);
247
-
248
- // node_modules/class-variance-authority/node_modules/clsx/dist/clsx.mjs
249
- function r(e) {
250
- var t, f, n = "";
251
- if ("string" == typeof e || "number" == typeof e) n += e;
252
- else if ("object" == typeof e) if (Array.isArray(e)) for (t = 0; t < e.length; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
253
- else for (t in e) e[t] && (n && (n += " "), n += t);
254
- return n;
255
- }
256
- function clsx() {
257
- for (var e, t, f = 0, n = ""; f < arguments.length; ) (e = arguments[f++]) && (t = r(e)) && (n && (n += " "), n += t);
258
- return n;
259
- }
260
-
261
- // node_modules/class-variance-authority/dist/index.mjs
262
- var falsyToString = (value) => typeof value === "boolean" ? "".concat(value) : value === 0 ? "0" : value;
263
- var cx = clsx;
264
- var cva = (base, config) => {
265
- return (props) => {
266
- var ref;
267
- if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
268
- const { variants, defaultVariants } = config;
269
- const getVariantClassNames = Object.keys(variants).map((variant) => {
270
- const variantProp = props === null || props === void 0 ? void 0 : props[variant];
271
- const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
272
- if (variantProp === null) return null;
273
- const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
274
- return variants[variant][variantKey];
275
- });
276
- const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
277
- let [key, value] = param;
278
- if (value === void 0) {
279
- return acc;
280
- }
281
- acc[key] = value;
282
- return acc;
283
- }, {});
284
- const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (ref = config.compoundVariants) === null || ref === void 0 ? void 0 : ref.reduce((acc, param1) => {
285
- let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param1;
286
- return Object.entries(compoundVariantOptions).every((param) => {
287
- let [key, value] = param;
288
- return Array.isArray(value) ? value.includes({
289
- ...defaultVariants,
290
- ...propsWithoutUndefined
291
- }[key]) : {
292
- ...defaultVariants,
293
- ...propsWithoutUndefined
294
- }[key] === value;
295
- }) ? [
296
- ...acc,
297
- cvClass,
298
- cvClassName
299
- ] : acc;
300
- }, []);
301
- return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
302
- };
303
- };
304
-
305
306
  // node_modules/clsx/dist/clsx.mjs
306
- function r2(e) {
307
+ function r(e) {
307
308
  var t, f, n = "";
308
309
  if ("string" == typeof e || "number" == typeof e) n += e;
309
310
  else if ("object" == typeof e) if (Array.isArray(e)) {
310
311
  var o = e.length;
311
- for (t = 0; t < o; t++) e[t] && (f = r2(e[t])) && (n && (n += " "), n += f);
312
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
312
313
  } else for (f in e) e[f] && (n && (n += " "), n += f);
313
314
  return n;
314
315
  }
315
- function clsx2() {
316
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r2(e)) && (n && (n += " "), n += t);
316
+ function clsx() {
317
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
317
318
  return n;
318
319
  }
319
320
 
@@ -358,15 +359,15 @@ var getGroupRecursive = (classParts, classPartObject) => {
358
359
  return void 0;
359
360
  }
360
361
  const classRest = classParts.join(CLASS_PART_SEPARATOR);
361
- return _optionalChain([classPartObject, 'access', _4 => _4.validators, 'access', _5 => _5.find, 'call', _6 => _6(({
362
+ return _optionalChain([classPartObject, 'access', _8 => _8.validators, 'access', _9 => _9.find, 'call', _10 => _10(({
362
363
  validator
363
- }) => validator(classRest)), 'optionalAccess', _7 => _7.classGroupId]);
364
+ }) => validator(classRest)), 'optionalAccess', _11 => _11.classGroupId]);
364
365
  };
365
366
  var arbitraryPropertyRegex = /^\[(.+)\]$/;
366
367
  var getGroupIdForArbitraryProperty = (className) => {
367
368
  if (arbitraryPropertyRegex.test(className)) {
368
369
  const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)[1];
369
- const property = _optionalChain([arbitraryPropertyClassName, 'optionalAccess', _8 => _8.substring, 'call', _9 => _9(0, arbitraryPropertyClassName.indexOf(":"))]);
370
+ const property = _optionalChain([arbitraryPropertyClassName, 'optionalAccess', _12 => _12.substring, 'call', _13 => _13(0, arbitraryPropertyClassName.indexOf(":"))]);
370
371
  if (property) {
371
372
  return "arbitrary.." + property;
372
373
  }
@@ -2779,7 +2780,7 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
2779
2780
 
2780
2781
  // src/lib/utils.ts
2781
2782
  function cn(...inputs) {
2782
- return twMerge(clsx2(inputs));
2783
+ return twMerge(clsx(inputs));
2783
2784
  }
2784
2785
  function formatNumber(value) {
2785
2786
  const intl = new Intl.NumberFormat("en-US");
@@ -2811,6 +2812,82 @@ function formatTime(seconds) {
2811
2812
  return parts.slice(0, 1).join(" ");
2812
2813
  }
2813
2814
 
2815
+ // src/components/ui/toaster.tsx
2816
+ var _reactportal = require('@radix-ui/react-portal');
2817
+
2818
+ // src/lib/portal-root.ts
2819
+ var root;
2820
+ if (typeof document !== "undefined") {
2821
+ const id = "react-redis-browser-portal-root";
2822
+ root = _nullishCoalesce(document.querySelector(`#${id}`), () => ( document.createElement("div")));
2823
+ root.classList.add("ups-db");
2824
+ root.id = "react-redis-browser-portal-root";
2825
+ document.body.append(root);
2826
+ }
2827
+ var portalRoot = root;
2828
+
2829
+ // src/components/ui/toast.tsx
2830
+
2831
+ var _reacticons = require('@radix-ui/react-icons');
2832
+ var _reacttoast = require('@radix-ui/react-toast'); var ToastPrimitives = _interopRequireWildcard(_reacttoast);
2833
+
2834
+ // node_modules/class-variance-authority/node_modules/clsx/dist/clsx.mjs
2835
+ function r2(e) {
2836
+ var t, f, n = "";
2837
+ if ("string" == typeof e || "number" == typeof e) n += e;
2838
+ else if ("object" == typeof e) if (Array.isArray(e)) for (t = 0; t < e.length; t++) e[t] && (f = r2(e[t])) && (n && (n += " "), n += f);
2839
+ else for (t in e) e[t] && (n && (n += " "), n += t);
2840
+ return n;
2841
+ }
2842
+ function clsx2() {
2843
+ for (var e, t, f = 0, n = ""; f < arguments.length; ) (e = arguments[f++]) && (t = r2(e)) && (n && (n += " "), n += t);
2844
+ return n;
2845
+ }
2846
+
2847
+ // node_modules/class-variance-authority/dist/index.mjs
2848
+ var falsyToString = (value) => typeof value === "boolean" ? "".concat(value) : value === 0 ? "0" : value;
2849
+ var cx = clsx2;
2850
+ var cva = (base, config) => {
2851
+ return (props) => {
2852
+ var ref;
2853
+ if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
2854
+ const { variants, defaultVariants } = config;
2855
+ const getVariantClassNames = Object.keys(variants).map((variant) => {
2856
+ const variantProp = props === null || props === void 0 ? void 0 : props[variant];
2857
+ const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
2858
+ if (variantProp === null) return null;
2859
+ const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
2860
+ return variants[variant][variantKey];
2861
+ });
2862
+ const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
2863
+ let [key, value] = param;
2864
+ if (value === void 0) {
2865
+ return acc;
2866
+ }
2867
+ acc[key] = value;
2868
+ return acc;
2869
+ }, {});
2870
+ const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (ref = config.compoundVariants) === null || ref === void 0 ? void 0 : ref.reduce((acc, param1) => {
2871
+ let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param1;
2872
+ return Object.entries(compoundVariantOptions).every((param) => {
2873
+ let [key, value] = param;
2874
+ return Array.isArray(value) ? value.includes({
2875
+ ...defaultVariants,
2876
+ ...propsWithoutUndefined
2877
+ }[key]) : {
2878
+ ...defaultVariants,
2879
+ ...propsWithoutUndefined
2880
+ }[key] === value;
2881
+ }) ? [
2882
+ ...acc,
2883
+ cvClass,
2884
+ cvClassName
2885
+ ] : acc;
2886
+ }, []);
2887
+ return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
2888
+ };
2889
+ };
2890
+
2814
2891
  // src/components/ui/toast.tsx
2815
2892
 
2816
2893
  var ToastProvider = ToastPrimitives.Provider;
@@ -2917,12 +2994,61 @@ function Toaster() {
2917
2994
 
2918
2995
 
2919
2996
 
2997
+ // src/tab-provider.tsx
2998
+
2999
+
3000
+ var TabIdContext = _react.createContext.call(void 0, void 0);
3001
+ var TabIdProvider = ({ children, value }) => {
3002
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdContext.Provider, { value, children });
3003
+ };
3004
+ var useTab = () => {
3005
+ const {
3006
+ selectedTab,
3007
+ tabs,
3008
+ setSelectedKey,
3009
+ setSelectedListItem,
3010
+ setSearch,
3011
+ setSearchKey,
3012
+ setSearchType
3013
+ } = useDatabrowserStore();
3014
+ if (!selectedTab) throw new Error("selectedTab is undefined when using useTab()");
3015
+ return _react.useMemo.call(void 0,
3016
+ () => ({
3017
+ selectedKey: _optionalChain([tabs, 'access', _14 => _14[selectedTab], 'optionalAccess', _15 => _15.selectedKey]),
3018
+ selectedListItem: _optionalChain([tabs, 'access', _16 => _16[selectedTab], 'optionalAccess', _17 => _17.selectedListItem]),
3019
+ search: _optionalChain([tabs, 'access', _18 => _18[selectedTab], 'optionalAccess', _19 => _19.search]),
3020
+ setSelectedKey: (key) => setSelectedKey(selectedTab, key),
3021
+ setSelectedListItem: (item) => setSelectedListItem(selectedTab, item),
3022
+ setSearch: (search) => setSearch(selectedTab, search),
3023
+ setSearchKey: (key) => setSearchKey(selectedTab, key),
3024
+ setSearchType: (type) => setSearchType(selectedTab, type)
3025
+ }),
3026
+ [selectedTab, tabs]
3027
+ );
3028
+ };
3029
+
3030
+ // src/components/databrowser/hooks/use-fetch-key-type.ts
3031
+
3032
+ var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
3033
+ var useFetchKeyType = (key) => {
3034
+ const { redis } = useRedis();
3035
+ return _reactquery.useQuery.call(void 0, {
3036
+ queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key],
3037
+ queryFn: async () => {
3038
+ if (!key) return "none";
3039
+ return await redis.type(key);
3040
+ }
3041
+ });
3042
+ };
3043
+
3044
+ // src/components/databrowser/hooks/use-keys.tsx
3045
+
2920
3046
  var KeysContext = _react.createContext.call(void 0, void 0);
2921
3047
  var FETCH_KEYS_QUERY_KEY = "use-fetch-keys";
2922
3048
  var SCAN_COUNT = 100;
2923
3049
  var KeysProvider = ({ children }) => {
2924
- const { search } = useDatabrowserStore();
2925
- const { redisNoPipeline: redis } = useDatabrowser();
3050
+ const { search } = useTab();
3051
+ const { redisNoPipeline: redis } = useRedis();
2926
3052
  const query = _reactquery.useInfiniteQuery.call(void 0, {
2927
3053
  queryKey: [FETCH_KEYS_QUERY_KEY, search],
2928
3054
  initialPageParam: "0",
@@ -2950,6 +3076,9 @@ var KeysProvider = ({ children }) => {
2950
3076
  index += 2;
2951
3077
  }
2952
3078
  }
3079
+ for (const [key, type] of keys2) {
3080
+ queryClient.setQueryData([FETCH_KEY_TYPE_QUERY_KEY, key], type);
3081
+ }
2953
3082
  return {
2954
3083
  cursor: cursor === "0" ? void 0 : cursor,
2955
3084
  keys: keys2,
@@ -2961,7 +3090,7 @@ var KeysProvider = ({ children }) => {
2961
3090
  refetchOnMount: false
2962
3091
  });
2963
3092
  const keys = _react.useMemo.call(void 0, () => {
2964
- const keys2 = _nullishCoalesce(_optionalChain([query, 'access', _10 => _10.data, 'optionalAccess', _11 => _11.pages, 'access', _12 => _12.flatMap, 'call', _13 => _13((page) => page.keys)]), () => ( []));
3093
+ const keys2 = _nullishCoalesce(_optionalChain([query, 'access', _20 => _20.data, 'optionalAccess', _21 => _21.pages, 'access', _22 => _22.flatMap, 'call', _23 => _23((page) => page.keys)]), () => ( []));
2965
3094
  const keysSet = /* @__PURE__ */ new Set();
2966
3095
  const dedupedKeys = [];
2967
3096
  for (const key of keys2) {
@@ -2992,19 +3121,19 @@ var useKeys = () => {
2992
3121
  var useKeyType = (key) => {
2993
3122
  const { keys } = useKeys();
2994
3123
  const keyTuple = _react.useMemo.call(void 0, () => keys.find(([k, _]) => k === key), [keys, key]);
2995
- return _optionalChain([keyTuple, 'optionalAccess', _14 => _14[1]]);
3124
+ return _optionalChain([keyTuple, 'optionalAccess', _24 => _24[1]]);
2996
3125
  };
2997
3126
 
2998
3127
  // src/components/databrowser/components/display/display-list.tsx
2999
3128
 
3000
-
3129
+ var _iconsreact = require('@tabler/icons-react');
3001
3130
 
3002
3131
  // src/components/ui/button.tsx
3003
3132
 
3004
3133
  var _reactslot = require('@radix-ui/react-slot');
3005
3134
 
3006
3135
  var buttonVariants = cva(
3007
- "inline-flex items-center justify-center rounded-md text-sm ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300",
3136
+ "inline-flex items-center justify-center rounded-md text-sm ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300",
3008
3137
  {
3009
3138
  variants: {
3010
3139
  variant: {
@@ -3061,7 +3190,7 @@ function Skeleton({ className, ...props }) {
3061
3190
 
3062
3191
  var FETCH_DB_SIZE_QUERY_KEY = "fetch-db-size";
3063
3192
  var DisplayDbSize = () => {
3064
- const { redis } = useDatabrowser();
3193
+ const { redis } = useRedis();
3065
3194
  const { data: keyCount } = _reactquery.useQuery.call(void 0, {
3066
3195
  queryKey: [FETCH_DB_SIZE_QUERY_KEY],
3067
3196
  queryFn: async () => {
@@ -3079,7 +3208,7 @@ var DisplayDbSize = () => {
3079
3208
 
3080
3209
  // src/components/databrowser/hooks/use-add-key.ts
3081
3210
  var useAddKey = () => {
3082
- const { redis } = useDatabrowser();
3211
+ const { redis } = useRedis();
3083
3212
  const mutation = _reactquery.useMutation.call(void 0, {
3084
3213
  mutationFn: async ({ key, type }) => {
3085
3214
  if (await redis.exists(key)) throw new Error(`Key "${key}" already exists`);
@@ -3159,16 +3288,12 @@ var useAddKey = () => {
3159
3288
  // src/components/databrowser/hooks/use-delete-key-cache.ts
3160
3289
 
3161
3290
 
3162
- // src/components/databrowser/hooks/use-fetch-key-type.tsx
3163
-
3164
- var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
3165
-
3166
3291
  // src/components/databrowser/hooks/use-fetch-list-items.tsx
3167
3292
 
3168
3293
  var LIST_DISPLAY_PAGE_SIZE = 50;
3169
3294
  var FETCH_LIST_ITEMS_QUERY_KEY = "use-fetch-list-items";
3170
3295
  var useFetchListItems = ({ dataKey, type }) => {
3171
- const { redisNoPipeline: redis } = useDatabrowser();
3296
+ const { redisNoPipeline: redis } = useRedis();
3172
3297
  const setQuery = _reactquery.useInfiniteQuery.call(void 0, {
3173
3298
  enabled: type === "set",
3174
3299
  queryKey: [FETCH_LIST_ITEMS_QUERY_KEY, dataKey, "set"],
@@ -3247,7 +3372,7 @@ var useFetchListItems = ({ dataKey, type }) => {
3247
3372
  // +1 since first message is the last one
3248
3373
  LIST_DISPLAY_PAGE_SIZE + 1
3249
3374
  );
3250
- const lastMessageId = messages.length > 0 ? _optionalChain([messages, 'access', _15 => _15.at, 'call', _16 => _16(-1), 'optionalAccess', _17 => _17[0]]) : void 0;
3375
+ const lastMessageId = messages.length > 0 ? _optionalChain([messages, 'access', _25 => _25.at, 'call', _26 => _26(-1), 'optionalAccess', _27 => _27[0]]) : void 0;
3251
3376
  return {
3252
3377
  cursor: messages.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : lastMessageId,
3253
3378
  keys: messages.map(([id, fields]) => ({
@@ -3283,7 +3408,7 @@ function transformArray(inputArray) {
3283
3408
 
3284
3409
  var FETCH_SIMPLE_KEY_QUERY_KEY = "fetch-simple-key";
3285
3410
  var useFetchSimpleKey = (dataKey, type) => {
3286
- const { redisNoPipeline: redis } = useDatabrowser();
3411
+ const { redisNoPipeline: redis } = useRedis();
3287
3412
  const { deleteKeyCache } = useDeleteKeyCache();
3288
3413
  return _reactquery.useQuery.call(void 0, {
3289
3414
  queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey],
@@ -3310,7 +3435,7 @@ var sortObject = (obj) => {
3310
3435
 
3311
3436
  // src/components/databrowser/hooks/use-delete-key-cache.ts
3312
3437
  var useDeleteKeyCache = () => {
3313
- const { setSelectedKey } = useDatabrowserStore();
3438
+ const { setSelectedKey } = useTab();
3314
3439
  const deleteKeyCache = _react.useCallback.call(void 0,
3315
3440
  (key) => {
3316
3441
  setSelectedKey(void 0);
@@ -3334,7 +3459,7 @@ var useDeleteKeyCache = () => {
3334
3459
 
3335
3460
  // src/components/databrowser/hooks/use-delete-key.ts
3336
3461
  var useDeleteKey = () => {
3337
- const { redis } = useDatabrowser();
3462
+ const { redis } = useRedis();
3338
3463
  const { deleteKeyCache } = useDeleteKeyCache();
3339
3464
  const deleteKey = _reactquery.useMutation.call(void 0, {
3340
3465
  mutationFn: async (key) => {
@@ -3353,7 +3478,7 @@ var useDeleteKey = () => {
3353
3478
  // src/components/databrowser/hooks/use-edit-list-item.tsx
3354
3479
 
3355
3480
  var useEditListItem = () => {
3356
- const { redis } = useDatabrowser();
3481
+ const { redis } = useRedis();
3357
3482
  return _reactquery.useMutation.call(void 0, {
3358
3483
  mutationFn: async ({
3359
3484
  type,
@@ -3411,7 +3536,7 @@ var useEditListItem = () => {
3411
3536
  }
3412
3537
  case "stream": {
3413
3538
  if (!isNew || !newKey) throw new Error("Stream data type is not mutable");
3414
- const opts = transformArray(_nullishCoalesce(_optionalChain([newValue, 'optionalAccess', _18 => _18.split, 'call', _19 => _19("\n")]), () => ( []))).map(
3539
+ const opts = transformArray(_nullishCoalesce(_optionalChain([newValue, 'optionalAccess', _28 => _28.split, 'call', _29 => _29("\n")]), () => ( []))).map(
3415
3540
  ({ key, value }) => [key, value]
3416
3541
  );
3417
3542
  pipe.xadd(dataKey, newKey, Object.fromEntries(opts));
@@ -3446,7 +3571,7 @@ var _bytes = require('bytes'); var _bytes2 = _interopRequireDefault(_bytes);
3446
3571
 
3447
3572
  var FETCH_KEY_LENGTH_QUERY_KEY = "fetch-key-length";
3448
3573
  var useFetchKeyLength = ({ dataKey, type }) => {
3449
- const { redis } = useDatabrowser();
3574
+ const { redis } = useRedis();
3450
3575
  return _reactquery.useQuery.call(void 0, {
3451
3576
  queryKey: [FETCH_KEY_LENGTH_QUERY_KEY, dataKey],
3452
3577
  queryFn: async () => {
@@ -3476,7 +3601,7 @@ var useFetchKeyLength = ({ dataKey, type }) => {
3476
3601
 
3477
3602
  var FETCH_KEY_SIZE_QUERY_KEY = "fetch-key-size";
3478
3603
  var useFetchKeySize = (dataKey) => {
3479
- const { redis } = useDatabrowser();
3604
+ const { redis } = useRedis();
3480
3605
  return _reactquery.useQuery.call(void 0, {
3481
3606
  queryKey: [FETCH_KEY_SIZE_QUERY_KEY, dataKey],
3482
3607
  queryFn: async () => {
@@ -3493,7 +3618,7 @@ var LengthBadge = ({
3493
3618
  content
3494
3619
  }) => {
3495
3620
  const { data, isLoading } = useFetchKeyLength({ dataKey, type });
3496
- const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _20 => _20.length]), () => ( data));
3621
+ const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _30 => _30.length]), () => ( data));
3497
3622
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Badge, { label: "Length:", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : length });
3498
3623
  };
3499
3624
  var SizeBadge = ({ dataKey }) => {
@@ -3503,7 +3628,7 @@ var SizeBadge = ({ dataKey }) => {
3503
3628
  }) });
3504
3629
  };
3505
3630
  var HeaderTTLBadge = ({ dataKey }) => {
3506
- const { data: expireAt } = useFetchKeyExpire(dataKey);
3631
+ const { data: expireAt } = useFetchTTL(dataKey);
3507
3632
  const { mutate: setTTL, isPending } = useSetTTL();
3508
3633
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3509
3634
  TTLBadge,
@@ -3853,8 +3978,8 @@ var TTLBadge = ({
3853
3978
 
3854
3979
  // src/components/databrowser/hooks/use-fetch-ttl.ts
3855
3980
  var FETCH_TTL_QUERY_KEY = "fetch-ttl";
3856
- var useFetchKeyExpire = (dataKey) => {
3857
- const { redis } = useDatabrowser();
3981
+ var useFetchTTL = (dataKey) => {
3982
+ const { redis } = useRedis();
3858
3983
  const { isLoading, error, data } = _reactquery.useQuery.call(void 0, {
3859
3984
  queryKey: [FETCH_TTL_QUERY_KEY, dataKey],
3860
3985
  queryFn: async () => {
@@ -3875,7 +4000,7 @@ var useFetchKeyExpire = (dataKey) => {
3875
4000
  // src/components/databrowser/hooks/use-set-simple-key.tsx
3876
4001
 
3877
4002
  var useSetSimpleKey = (dataKey, type) => {
3878
- const { redis } = useDatabrowser();
4003
+ const { redis } = useRedis();
3879
4004
  return _reactquery.useMutation.call(void 0, {
3880
4005
  mutationFn: async (value) => {
3881
4006
  if (type === "string") {
@@ -3898,7 +4023,7 @@ var useSetSimpleKey = (dataKey, type) => {
3898
4023
  // src/components/databrowser/hooks/use-set-ttl.ts
3899
4024
 
3900
4025
  var useSetTTL = () => {
3901
- const { redis } = useDatabrowser();
4026
+ const { redis } = useRedis();
3902
4027
  const updateTTL = _reactquery.useMutation.call(void 0, {
3903
4028
  mutationFn: async ({ dataKey, ttl }) => {
3904
4029
  await (ttl === void 0 || ttl === TTL_INFINITE ? redis.persist(dataKey) : redis.expire(dataKey, ttl));
@@ -4184,7 +4309,7 @@ var ItemContextMenu = ({
4184
4309
  editItem({
4185
4310
  type,
4186
4311
  dataKey,
4187
- itemKey: _optionalChain([data, 'optionalAccess', _21 => _21.key]),
4312
+ itemKey: _optionalChain([data, 'optionalAccess', _31 => _31.key]),
4188
4313
  // For deletion
4189
4314
  newKey: void 0
4190
4315
  });
@@ -4219,7 +4344,7 @@ var ItemContextMenu = ({
4219
4344
  {
4220
4345
  onClick: () => {
4221
4346
  if (!data) return;
4222
- navigator.clipboard.writeText(_optionalChain([data, 'optionalAccess', _22 => _22.key]));
4347
+ navigator.clipboard.writeText(_optionalChain([data, 'optionalAccess', _32 => _32.key]));
4223
4348
  toast({
4224
4349
  description: "Key copied to clipboard"
4225
4350
  });
@@ -4227,11 +4352,11 @@ var ItemContextMenu = ({
4227
4352
  children: "Copy key"
4228
4353
  }
4229
4354
  ),
4230
- _optionalChain([data, 'optionalAccess', _23 => _23.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4355
+ _optionalChain([data, 'optionalAccess', _33 => _33.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4231
4356
  ContextMenuItem,
4232
4357
  {
4233
4358
  onClick: () => {
4234
- navigator.clipboard.writeText(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _24 => _24.value]), () => ( "")));
4359
+ navigator.clipboard.writeText(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _34 => _34.value]), () => ( "")));
4235
4360
  toast({
4236
4361
  description: "Value copied to clipboard"
4237
4362
  });
@@ -4253,7 +4378,7 @@ var ItemContextMenu = ({
4253
4378
 
4254
4379
  var _reactscrollarea = require('@radix-ui/react-scroll-area'); var ScrollAreaPrimitive = _interopRequireWildcard(_reactscrollarea);
4255
4380
 
4256
- var ScrollArea = React9.forwardRef(({ className, children, onScroll, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4381
+ var ScrollArea = React9.forwardRef(({ className, children, onScroll, disableRoundedInherit = false, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4257
4382
  ScrollAreaPrimitive.Root,
4258
4383
  {
4259
4384
  ref,
@@ -4264,7 +4389,7 @@ var ScrollArea = React9.forwardRef(({ className, children, onScroll, ...props },
4264
4389
  ScrollAreaPrimitive.Viewport,
4265
4390
  {
4266
4391
  onScroll,
4267
- className: "h-full w-full rounded-[inherit] [&>div]:!block",
4392
+ className: cn("h-full w-full [&>div]:!block", !disableRoundedInherit && "rounded-[inherit]"),
4268
4393
  children
4269
4394
  }
4270
4395
  ),
@@ -4295,7 +4420,8 @@ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
4295
4420
 
4296
4421
  var InfiniteScroll = ({
4297
4422
  query,
4298
- children
4423
+ children,
4424
+ ...props
4299
4425
  }) => {
4300
4426
  const handleScroll = (e) => {
4301
4427
  const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;
@@ -4310,8 +4436,12 @@ var InfiniteScroll = ({
4310
4436
  ScrollArea,
4311
4437
  {
4312
4438
  type: "always",
4313
- className: "block h-full w-full transition-all",
4314
4439
  onScroll: handleScroll,
4440
+ ...props,
4441
+ className: cn(
4442
+ "block h-full w-full overflow-visible rounded-lg border border-zinc-200 bg-white p-1 pr-3 transition-all",
4443
+ props.className
4444
+ ),
4315
4445
  children: [
4316
4446
  children,
4317
4447
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-[100px] justify-center py-2 text-zinc-300", children: query.isFetching && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconLoader2, { className: "animate-spin", size: 16 }) })
@@ -4394,14 +4524,14 @@ var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, .
4394
4524
  {
4395
4525
  ref,
4396
4526
  className: cn(
4397
- "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-zinc-100 data-[state=open]:bg-zinc-100 dark:focus:bg-zinc-800 dark:data-[state=open]:bg-zinc-800",
4527
+ "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 data-[state=open]:bg-neutral-100 dark:focus:bg-neutral-800 dark:data-[state=open]:bg-neutral-800 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
4398
4528
  inset && "pl-8",
4399
4529
  className
4400
4530
  ),
4401
4531
  ...props,
4402
4532
  children: [
4403
4533
  children,
4404
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.ChevronRightIcon, { className: "ml-auto size-4" })
4534
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.ChevronRightIcon, { className: "ml-auto" })
4405
4535
  ]
4406
4536
  }
4407
4537
  ));
@@ -4411,7 +4541,7 @@ var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) =
4411
4541
  {
4412
4542
  ref,
4413
4543
  className: cn(
4414
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
4544
+ "z-50 min-w-[8rem] origin-[--radix-dropdown-menu-content-transform-origin] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
4415
4545
  className
4416
4546
  ),
4417
4547
  ...props
@@ -4424,8 +4554,8 @@ var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...pr
4424
4554
  ref,
4425
4555
  sideOffset,
4426
4556
  className: cn(
4427
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
4428
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4557
+ "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
4558
+ "origin-[--radix-dropdown-menu-content-transform-origin] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4429
4559
  className
4430
4560
  ),
4431
4561
  ...props
@@ -4456,7 +4586,7 @@ var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checke
4456
4586
  checked,
4457
4587
  ...props,
4458
4588
  children: [
4459
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.CheckIcon, { className: "size-4" }) }) }),
4589
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.CheckIcon, { className: "h-4 w-4" }) }) }),
4460
4590
  children
4461
4591
  ]
4462
4592
  }
@@ -4472,7 +4602,7 @@ var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props
4472
4602
  ),
4473
4603
  ...props,
4474
4604
  children: [
4475
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.DotFilledIcon, { className: "size-4 fill-current" }) }) }),
4605
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.DotFilledIcon, { className: "h-2 w-2 fill-current" }) }) }),
4476
4606
  children
4477
4607
  ]
4478
4608
  }
@@ -4539,11 +4669,11 @@ var DisplayHeader = ({
4539
4669
  type,
4540
4670
  content
4541
4671
  }) => {
4542
- const { setSelectedListItem } = useDatabrowserStore();
4672
+ const { setSelectedListItem } = useTab();
4543
4673
  const handleAddItem = () => {
4544
4674
  setSelectedListItem({ key: type === "stream" ? "*" : "", isNew: true });
4545
4675
  };
4546
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
4676
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100", children: [
4547
4677
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-h-10 items-center justify-between gap-4", children: [
4548
4678
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "grow truncate text-base", children: dataKey.trim() === "" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "ml-1 text-zinc-500", children: "(Empty Key)" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-semibold", children: dataKey }) }),
4549
4679
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1", children: [
@@ -4600,7 +4730,7 @@ var useFetchHashFieldExpires = ({
4600
4730
  dataKey,
4601
4731
  fields
4602
4732
  }) => {
4603
- const { redis } = useDatabrowser();
4733
+ const { redis } = useRedis();
4604
4734
  return _reactquery.useQuery.call(void 0, {
4605
4735
  queryKey: [FETCH_HASH_FIELD_TTLS_QUERY_KEY, dataKey, fields],
4606
4736
  queryFn: async () => {
@@ -4631,7 +4761,7 @@ var useFetchHashFieldExpires = ({
4631
4761
  // src/components/databrowser/hooks/use-set-hash-ttl.ts
4632
4762
 
4633
4763
  var useSetHashTTL = () => {
4634
- const { redis } = useDatabrowser();
4764
+ const { redis } = useRedis();
4635
4765
  return _reactquery.useMutation.call(void 0, {
4636
4766
  mutationFn: async ({
4637
4767
  dataKey,
@@ -4653,7 +4783,7 @@ var useSetHashTTL = () => {
4653
4783
  var HashFieldTTLBadge = ({ dataKey, field }) => {
4654
4784
  const { data } = useFetchHashFieldExpires({ dataKey, fields: [field] });
4655
4785
  const { mutate: setTTL, isPending } = useSetHashTTL();
4656
- const expireAt = _optionalChain([data, 'optionalAccess', _25 => _25[field]]);
4786
+ const expireAt = _optionalChain([data, 'optionalAccess', _35 => _35[field]]);
4657
4787
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4658
4788
  TTLBadge,
4659
4789
  {
@@ -4742,7 +4872,7 @@ var CustomEditor = ({
4742
4872
  if (!monaco || !editorRef.current) {
4743
4873
  return;
4744
4874
  }
4745
- _optionalChain([monaco, 'optionalAccess', _26 => _26.editor, 'access', _27 => _27.setModelLanguage, 'call', _28 => _28(editorRef.current.getModel(), language)]);
4875
+ _optionalChain([monaco, 'optionalAccess', _36 => _36.editor, 'access', _37 => _37.setModelLanguage, 'call', _38 => _38(editorRef.current.getModel(), language)]);
4746
4876
  }, [monaco, language]);
4747
4877
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4748
4878
  "div",
@@ -4877,7 +5007,7 @@ var ListEditDisplay = ({
4877
5007
  type,
4878
5008
  item
4879
5009
  }) => {
4880
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grow rounded-md bg-zinc-100 p-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListEditForm, { item, type, dataKey }, item.key) });
5010
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grow rounded-md bg-zinc-100", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListEditForm, { item, type, dataKey }, item.key) });
4881
5011
  };
4882
5012
  var ListEditForm = ({
4883
5013
  type,
@@ -4889,7 +5019,7 @@ var ListEditForm = ({
4889
5019
  dataKey
4890
5020
  });
4891
5021
  const findValue = () => {
4892
- for (const page of _nullishCoalesce(_optionalChain([query, 'access', _29 => _29.data, 'optionalAccess', _30 => _30.pages]), () => ( []))) {
5022
+ for (const page of _nullishCoalesce(_optionalChain([query, 'access', _39 => _39.data, 'optionalAccess', _40 => _40.pages]), () => ( []))) {
4893
5023
  const item = page.keys.find((item2) => item2.key === itemKey);
4894
5024
  if (item && "value" in item) return item.value;
4895
5025
  }
@@ -4903,7 +5033,7 @@ var ListEditForm = ({
4903
5033
  }
4904
5034
  });
4905
5035
  const { mutateAsync: editItem, isPending } = useEditListItem();
4906
- const { setSelectedListItem } = useDatabrowserStore();
5036
+ const { setSelectedListItem } = useTab();
4907
5037
  const [keyLabel, valueLabel] = headerLabels[type];
4908
5038
  const onSubmit = form.handleSubmit(async ({ key, value }) => {
4909
5039
  await editItem({
@@ -5035,7 +5165,7 @@ var HashFieldTTLInfo = ({
5035
5165
  fields
5036
5166
  }) => {
5037
5167
  const { data } = useFetchHashFieldExpires({ dataKey, fields });
5038
- const expireAt = _optionalChain([data, 'optionalAccess', _31 => _31[field]]);
5168
+ const expireAt = _optionalChain([data, 'optionalAccess', _41 => _41[field]]);
5039
5169
  const [ttl, setTTL] = _react.useState.call(void 0, () => calculateTTL(expireAt));
5040
5170
  _react.useEffect.call(void 0, () => {
5041
5171
  setTTL(calculateTTL(expireAt));
@@ -5058,12 +5188,12 @@ var headerLabels = {
5058
5188
  set: ["Value", ""]
5059
5189
  };
5060
5190
  var ListDisplay = ({ dataKey, type }) => {
5061
- const { selectedListItem } = useDatabrowserStore();
5191
+ const { selectedListItem } = useTab();
5062
5192
  const query = useFetchListItems({ dataKey, type });
5063
5193
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2", children: [
5064
5194
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayHeader, { dataKey, type }),
5065
5195
  selectedListItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListEditDisplay, { dataKey, type, item: selectedListItem }),
5066
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", { className: "w-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListItems, { dataKey, type, query }) }) }) }) }) }) })
5196
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", { className: "w-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListItems, { dataKey, type, query }) }) }) }) }) })
5067
5197
  ] });
5068
5198
  };
5069
5199
  var ListItems = ({
@@ -5071,8 +5201,8 @@ var ListItems = ({
5071
5201
  type,
5072
5202
  dataKey
5073
5203
  }) => {
5074
- const { setSelectedListItem } = useDatabrowserStore();
5075
- const keys = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([query, 'access', _32 => _32.data, 'optionalAccess', _33 => _33.pages, 'access', _34 => _34.flatMap, 'call', _35 => _35((page) => page.keys)]), () => ( [])), [query.data]);
5204
+ const { setSelectedListItem } = useTab();
5205
+ const keys = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([query, 'access', _42 => _42.data, 'optionalAccess', _43 => _43.pages, 'access', _44 => _44.flatMap, 'call', _45 => _45((page) => page.keys)]), () => ( [])), [query.data]);
5076
5206
  const fields = _react.useMemo.call(void 0, () => keys.map((key) => key.key), [keys]);
5077
5207
  const { mutate: editItem } = useEditListItem();
5078
5208
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -5083,7 +5213,7 @@ var ListItems = ({
5083
5213
  onClick: () => {
5084
5214
  setSelectedListItem({ key });
5085
5215
  },
5086
- className: cn("h-10 border-b border-b-zinc-100 hover:bg-zinc-100 "),
5216
+ className: cn("h-10 border-b border-b-zinc-100 transition-colors hover:bg-zinc-100"),
5087
5217
  children: [
5088
5218
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5089
5219
  "td",
@@ -5154,13 +5284,7 @@ var EditorDisplay = ({ dataKey, type }) => {
5154
5284
  const { data } = useFetchSimpleKey(dataKey, type);
5155
5285
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full w-full flex-col gap-2", children: [
5156
5286
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayHeader, { dataKey, type, content: _nullishCoalesce(data, () => ( void 0)) }),
5157
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5158
- "div",
5159
- {
5160
- className: "flex h-full grow flex-col gap-2\n rounded-md bg-zinc-100 p-3",
5161
- children: data === void 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Spinner, { isLoadingText: "", isLoading: true }) : data === null ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplayForm, { dataKey, type, data }, dataKey)
5162
- }
5163
- )
5287
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full grow flex-col gap-2 rounded-md bg-zinc-100", children: data === void 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Spinner, { isLoadingText: "", isLoading: true }) : data === null ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplayForm, { dataKey, type, data }, dataKey) })
5164
5288
  ] });
5165
5289
  };
5166
5290
  var EditorDisplayForm = ({
@@ -5204,10 +5328,10 @@ var EditorDisplayForm = ({
5204
5328
  // src/components/databrowser/components/display/index.tsx
5205
5329
 
5206
5330
  var DataDisplay = () => {
5207
- const { selectedKey } = useDatabrowserStore();
5331
+ const { selectedKey } = useTab();
5208
5332
  const { query } = useKeys();
5209
5333
  const type = useKeyType(selectedKey);
5210
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full rounded-xl border bg-white p-1", children: !selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : !type ? query.isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: type === "string" || type === "json" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListDisplay, { dataKey: selectedKey, type }) }) });
5334
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full p-4", children: !selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : !type ? query.isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: type === "string" || type === "json" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListDisplay, { dataKey: selectedKey, type }) }) });
5211
5335
  };
5212
5336
 
5213
5337
  // src/components/databrowser/components/sidebar/index.tsx
@@ -5323,7 +5447,7 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
5323
5447
  // src/components/databrowser/components/add-key-modal.tsx
5324
5448
 
5325
5449
  function AddKeyModal() {
5326
- const { setSelectedKey } = useDatabrowserStore();
5450
+ const { setSelectedKey } = useTab();
5327
5451
  const [open, setOpen] = _react.useState.call(void 0, false);
5328
5452
  const { mutateAsync: addKey, isPending } = useAddKey();
5329
5453
  const { control, handleSubmit, formState, reset } = _reacthookform.useForm.call(void 0, {
@@ -5337,7 +5461,7 @@ function AddKeyModal() {
5337
5461
  setSelectedKey(key);
5338
5462
  setOpen(false);
5339
5463
  setTimeout(() => {
5340
- _optionalChain([window, 'access', _36 => _36.document, 'access', _37 => _37.querySelector, 'call', _38 => _38(`[data-key="${key}"]`), 'optionalAccess', _39 => _39.scrollIntoView, 'call', _40 => _40({
5464
+ _optionalChain([window, 'access', _46 => _46.document, 'access', _47 => _47.querySelector, 'call', _48 => _48(`[data-key="${key}"]`), 'optionalAccess', _49 => _49.scrollIntoView, 'call', _50 => _50({
5341
5465
  behavior: "smooth",
5342
5466
  block: "start",
5343
5467
  inline: "nearest"
@@ -5382,7 +5506,7 @@ function AddKeyModal() {
5382
5506
  }
5383
5507
  )
5384
5508
  ] }),
5385
- formState.errors.key && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-3 mt-2 text-xs text-red-500", children: _optionalChain([formState, 'access', _41 => _41.errors, 'access', _42 => _42.key, 'optionalAccess', _43 => _43.message]) }),
5509
+ formState.errors.key && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-3 mt-2 text-xs text-red-500", children: _optionalChain([formState, 'access', _51 => _51.errors, 'access', _52 => _52.key, 'optionalAccess', _53 => _53.message]) }),
5386
5510
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mt-2 text-xs text-zinc-500", children: "After creating the key, you can edit the value" }),
5387
5511
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-6 flex justify-end gap-2", children: [
5388
5512
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -5476,7 +5600,7 @@ var SidebarContextMenu = ({ children }) => {
5476
5600
 
5477
5601
  var KeysList = () => {
5478
5602
  const { keys } = useKeys();
5479
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyItem, { nextKey: _nullishCoalesce(_optionalChain([keys, 'access', _44 => _44.at, 'call', _45 => _45(i + 1), 'optionalAccess', _46 => _46[0]]), () => ( "")), data }, data[0])) }) }) });
5603
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyItem, { nextKey: _nullishCoalesce(_optionalChain([keys, 'access', _54 => _54.at, 'call', _55 => _55(i + 1), 'optionalAccess', _56 => _56[0]]), () => ( "")), data }, data[0])) }) });
5480
5604
  };
5481
5605
  var keyStyles = {
5482
5606
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5488,7 +5612,7 @@ var keyStyles = {
5488
5612
  stream: "border-green-400 !bg-green-50 text-green-900"
5489
5613
  };
5490
5614
  var KeyItem = ({ data, nextKey }) => {
5491
- const { selectedKey, setSelectedKey } = useDatabrowserStore();
5615
+ const { selectedKey, setSelectedKey } = useTab();
5492
5616
  const [dataKey, dataType] = data;
5493
5617
  const isKeySelected = selectedKey === dataKey;
5494
5618
  const isNextKeySelected = selectedKey === nextKey;
@@ -5498,7 +5622,7 @@ var KeyItem = ({ data, nextKey }) => {
5498
5622
  "data-key": dataKey,
5499
5623
  variant: isKeySelected ? "default" : "ghost",
5500
5624
  className: cn(
5501
- "relative flex h-10 w-full items-center justify-start gap-2 px-3 py-0 ",
5625
+ "relative flex h-10 w-full items-center justify-start gap-2 px-3 py-0 !ring-0 focus-visible:bg-zinc-50",
5502
5626
  "select-none border border-transparent text-left",
5503
5627
  isKeySelected && "shadow-sm",
5504
5628
  isKeySelected && keyStyles[dataType]
@@ -5517,30 +5641,106 @@ var KeyItem = ({ data, nextKey }) => {
5517
5641
 
5518
5642
 
5519
5643
 
5644
+ var dedupeSearchHistory = (history) => {
5645
+ const seen = /* @__PURE__ */ new Set();
5646
+ return history.filter((item) => {
5647
+ if (!item || seen.has(item)) return false;
5648
+ seen.add(item);
5649
+ return true;
5650
+ });
5651
+ };
5520
5652
  var SearchInput = () => {
5521
- const { setSearchKey, search } = useDatabrowserStore();
5653
+ const { setSearchKey, search } = useTab();
5654
+ const { searchHistory, addSearchHistory } = useDatabrowserStore();
5522
5655
  const [state, setState] = _react.useState.call(void 0, search.key);
5523
- const submit = (value) => {
5656
+ const [isFocus, setIsFocus] = _react.useState.call(void 0, false);
5657
+ const [focusedIndex, setFocusedIndex] = _react.useState.call(void 0, -1);
5658
+ const inputRef = _react.useRef.call(void 0, null);
5659
+ const historyItemRefs = _react.useRef.call(void 0, []);
5660
+ const handleSubmit = (value) => {
5524
5661
  if (value.trim() !== "" && !value.includes("*")) value = `${value}*`;
5662
+ addSearchHistory(value);
5525
5663
  setSearchKey(value);
5526
5664
  setState(value);
5527
5665
  };
5528
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative grow", children: [
5529
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5530
- Input,
5531
- {
5532
- placeholder: "Search",
5533
- className: "rounded-l-none border-zinc-300 font-normal",
5534
- onKeyDown: (e) => {
5535
- if (e.key === "Enter") submit(e.currentTarget.value);
5536
- },
5537
- onChange: (e) => {
5538
- setState(e.currentTarget.value);
5539
- if (e.currentTarget.value.trim() === "") submit("");
5540
- },
5541
- value: state
5666
+ const filteredHistory = dedupeSearchHistory(
5667
+ searchHistory.filter((item) => item.includes(state) && item !== state)
5668
+ ).slice(0, 5).map((item) => item.endsWith("*") ? item.slice(0, -1) : item);
5669
+ _react.useEffect.call(void 0, () => {
5670
+ setFocusedIndex(-1);
5671
+ }, [filteredHistory.length]);
5672
+ const handleKeyDown = (e) => {
5673
+ if (e.key === "Enter") {
5674
+ const text = focusedIndex >= 0 && focusedIndex < filteredHistory.length ? filteredHistory[focusedIndex] : e.currentTarget.value;
5675
+ handleSubmit(text);
5676
+ } else if (e.key === "Escape") {
5677
+ setState("");
5678
+ setFocusedIndex(-1);
5679
+ _optionalChain([inputRef, 'access', _57 => _57.current, 'optionalAccess', _58 => _58.blur, 'call', _59 => _59()]);
5680
+ } else if (e.key === "ArrowDown" || e.key === "Tab" && !e.shiftKey) {
5681
+ e.preventDefault();
5682
+ if (focusedIndex < filteredHistory.length - 1) {
5683
+ setFocusedIndex(focusedIndex + 1);
5684
+ } else if (filteredHistory.length > 0) {
5685
+ setFocusedIndex(0);
5542
5686
  }
5543
- ),
5687
+ } else if (e.key === "ArrowUp" || e.key === "Tab" && e.shiftKey) {
5688
+ e.preventDefault();
5689
+ if (focusedIndex > 0) {
5690
+ setFocusedIndex(focusedIndex - 1);
5691
+ } else if (filteredHistory.length > 0 && focusedIndex === 0) {
5692
+ setFocusedIndex(-1);
5693
+ _optionalChain([inputRef, 'access', _60 => _60.current, 'optionalAccess', _61 => _61.focus, 'call', _62 => _62()]);
5694
+ } else if (filteredHistory.length > 0) {
5695
+ setFocusedIndex(filteredHistory.length - 1);
5696
+ }
5697
+ }
5698
+ };
5699
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative grow", children: [
5700
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Popover, { open: isFocus && filteredHistory.length > 0, children: [
5701
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5702
+ Input,
5703
+ {
5704
+ ref: inputRef,
5705
+ placeholder: "Search",
5706
+ className: "rounded-l-none border-zinc-300 font-normal",
5707
+ onKeyDown: handleKeyDown,
5708
+ onChange: (e) => {
5709
+ setState(e.currentTarget.value);
5710
+ if (e.currentTarget.value.trim() === "") handleSubmit("");
5711
+ },
5712
+ value: state,
5713
+ onFocus: () => {
5714
+ setIsFocus(true);
5715
+ setFocusedIndex(-1);
5716
+ },
5717
+ onBlur: () => setIsFocus(false)
5718
+ }
5719
+ ) }) }),
5720
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5721
+ PopoverContent,
5722
+ {
5723
+ className: "w-[--radix-popover-trigger-width] divide-y px-3 py-2 text-[13px] text-zinc-900",
5724
+ autoFocus: false,
5725
+ onOpenAutoFocus: (e) => {
5726
+ e.preventDefault();
5727
+ e.stopPropagation();
5728
+ },
5729
+ children: filteredHistory.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full py-[3px]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5730
+ "button",
5731
+ {
5732
+ ref: (el) => {
5733
+ historyItemRefs.current[index] = el;
5734
+ },
5735
+ onClick: () => handleSubmit(item),
5736
+ onMouseEnter: () => setFocusedIndex(index),
5737
+ className: `block w-full rounded-sm p-1 text-left transition-colors ${focusedIndex === index ? "bg-zinc-100" : "hover:bg-zinc-100"}`,
5738
+ children: item
5739
+ }
5740
+ ) }, item))
5741
+ }
5742
+ )
5743
+ ] }),
5544
5744
  state && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5545
5745
  Button,
5546
5746
  {
@@ -5557,7 +5757,8 @@ var SearchInput = () => {
5557
5757
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", children: "Clear" })
5558
5758
  ]
5559
5759
  }
5560
- )
5760
+ ),
5761
+ " "
5561
5762
  ] });
5562
5763
  };
5563
5764
 
@@ -5573,7 +5774,7 @@ var LoadingSkeleton = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div",
5573
5774
 
5574
5775
  var ALL_TYPES_KEY = "all";
5575
5776
  function DataTypeSelector() {
5576
- const { search, setSearchType } = useDatabrowserStore();
5777
+ const { search, setSearchType } = useTab();
5577
5778
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5578
5779
  Select,
5579
5780
  {
@@ -5599,8 +5800,8 @@ function DataTypeSelector() {
5599
5800
 
5600
5801
  function Sidebar() {
5601
5802
  const { keys, query } = useKeys();
5602
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5603
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5803
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 p-4", children: [
5804
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100", children: [
5604
5805
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center justify-between pl-1", children: [
5605
5806
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayDbSize, {}),
5606
5807
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-1", children: [
@@ -5638,19 +5839,15 @@ function Sidebar() {
5638
5839
  ] }),
5639
5840
  query.isLoading && keys.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingSkeleton, {}) : keys.length > 0 ? (
5640
5841
  // Infinite scroll already has a loader at the bottom
5641
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysList, {}) })
5842
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, disableRoundedInherit: true, className: "min-h-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysList, {}) })
5642
5843
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Empty, {})
5643
5844
  ] });
5644
5845
  }
5645
5846
 
5646
- // src/components/databrowser/index.tsx
5847
+ // src/components/databrowser/components/databrowser-instance.tsx
5647
5848
 
5648
- var RedisBrowser = ({ token, url }) => {
5649
- const credentials = _react.useMemo.call(void 0, () => ({ token, url }), [token, url]);
5650
- _react.useEffect.call(void 0, () => {
5651
- queryClient.resetQueries();
5652
- }, [credentials.url]);
5653
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacttooltip.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserProvider, { redisCredentials: credentials, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "ups-db", style: { height: "100%" }, children: [
5849
+ var DatabrowserInstance = ({ hidden }) => {
5850
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: cn("min-h-0 grow rounded-md bg-zinc-100", hidden && "hidden"), children: [
5654
5851
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5655
5852
  _reactresizablepanels.PanelGroup,
5656
5853
  {
@@ -5659,20 +5856,109 @@ var RedisBrowser = ({ token, url }) => {
5659
5856
  className: "h-full w-full gap-0.5 text-sm antialiased",
5660
5857
  children: [
5661
5858
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.Panel, { defaultSize: 30, minSize: 30, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Sidebar, {}) }),
5662
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.PanelResizeHandle, { className: "h-fullm flex w-1.5 items-center justify-center rounded-full hover:bg-zinc-300/20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5663
- _iconsreact.IconDotsVertical,
5664
- {
5665
- size: 16,
5666
- stroke: 1,
5667
- className: "pointer-events-none shrink-0 opacity-20"
5668
- }
5669
- ) }),
5859
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.PanelResizeHandle, { className: "group flex h-full w-1.5 justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full border-r border-dashed border-zinc-200 transition-colors group-hover:border-zinc-300" }) }),
5670
5860
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.Panel, { minSize: 40, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DataDisplay, {}) })
5671
5861
  ]
5672
5862
  }
5673
5863
  ),
5674
5864
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Toaster, {})
5675
- ] }) }) }) }) });
5865
+ ] }) });
5866
+ };
5867
+
5868
+ // src/components/databrowser/components/databrowser-tabs.tsx
5869
+
5870
+
5871
+ // src/components/databrowser/components/tab-type-icon.tsx
5872
+
5873
+ function TabTypeIcon({ selectedKey }) {
5874
+ const { data: keyType, isLoading } = useFetchKeyType(selectedKey);
5875
+ if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "h-5 w-5 rounded" });
5876
+ if (!keyType || keyType === "none") return;
5877
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TypeTag, { variant: keyType, type: "icon" });
5878
+ }
5879
+
5880
+ // src/components/databrowser/components/databrowser-tabs.tsx
5881
+
5882
+ var Tab = ({ id }) => {
5883
+ const { selectTab, selectedTab, tabs, removeTab } = useDatabrowserStore();
5884
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5885
+ "div",
5886
+ {
5887
+ onClick: () => selectTab(id),
5888
+ className: cn(
5889
+ "flex h-9 cursor-pointer items-center gap-2 rounded-t-lg border border-zinc-200 px-3 text-[13px] transition-colors",
5890
+ id === selectedTab ? "border-b-white bg-white text-zinc-900" : "bg-zinc-100 hover:bg-zinc-50"
5891
+ ),
5892
+ children: [
5893
+ tabs[id].selectedKey ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
5894
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabTypeIcon, { selectedKey: tabs[id].selectedKey }),
5895
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "max-w-32 truncate whitespace-nowrap", children: tabs[id].selectedKey })
5896
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "whitespace-nowrap", children: "New Tab" }),
5897
+ Object.keys(tabs).length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5898
+ "button",
5899
+ {
5900
+ onClick: (e) => {
5901
+ e.stopPropagation();
5902
+ removeTab(id);
5903
+ },
5904
+ className: "p-1 text-zinc-300 transition-colors hover:text-zinc-500",
5905
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconX, { size: 16 })
5906
+ }
5907
+ )
5908
+ ]
5909
+ }
5910
+ );
5911
+ };
5912
+ var DatabrowserTabs = () => {
5913
+ const { tabs, addTab } = useDatabrowserStore();
5914
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative mb-2 shrink-0", children: [
5915
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute bottom-0 left-0 right-0 -z-10 h-[1px] w-full bg-zinc-200" }),
5916
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "scrollbar-hide flex translate-y-[1px] items-center gap-1 overflow-x-scroll pb-[1px] [&::-webkit-scrollbar]:hidden", children: [
5917
+ Object.keys(tabs).map((id) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tab, { id }, id)),
5918
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5919
+ Button,
5920
+ {
5921
+ variant: "secondary",
5922
+ size: "icon-sm",
5923
+ onClick: addTab,
5924
+ className: "mr-1 flex-shrink-0",
5925
+ title: "Add new tab",
5926
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500", size: 16 })
5927
+ }
5928
+ )
5929
+ ] })
5930
+ ] });
5931
+ };
5932
+
5933
+ // src/components/databrowser/index.tsx
5934
+
5935
+ var RedisBrowser = ({
5936
+ token,
5937
+ url,
5938
+ hideTabs
5939
+ }) => {
5940
+ const credentials = _react.useMemo.call(void 0, () => ({ token, url }), [token, url]);
5941
+ _react.useEffect.call(void 0, () => {
5942
+ queryClient.resetQueries();
5943
+ }, [credentials.url]);
5944
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RedisProvider, { redisCredentials: credentials, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserProvider, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacttooltip.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5945
+ "div",
5946
+ {
5947
+ className: "ups-db",
5948
+ style: { height: "100%", display: "flex", flexDirection: "column" },
5949
+ children: [
5950
+ !hideTabs && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserTabs, {}),
5951
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserInstances, {})
5952
+ ]
5953
+ }
5954
+ ) }) }) }) });
5955
+ };
5956
+ var DatabrowserInstances = () => {
5957
+ const { tabs, selectedTab, addTab } = useDatabrowserStore();
5958
+ _react.useEffect.call(void 0, () => {
5959
+ if (Object.keys(tabs).length === 0) addTab();
5960
+ }, [tabs]);
5961
+ return Object.entries(tabs).map(([id]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdProvider, { value: id, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserInstance, { hidden: id !== selectedTab }) }, id));
5676
5962
  };
5677
5963
 
5678
5964