@upstash/react-redis-browser 0.1.11 → 0.2.0

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
@@ -1,13 +1,12 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/components/databrowser/index.tsx
2
2
  var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react); var React3 = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react); var React5 = _interopRequireWildcard(_react); var React6 = _interopRequireWildcard(_react); var React7 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react); var React9 = _interopRequireWildcard(_react); var React10 = _interopRequireWildcard(_react); var React11 = _interopRequireWildcard(_react); var React12 = _interopRequireWildcard(_react);
3
3
 
4
- // src/store.tsx
4
+ // src/redis-context.tsx
5
5
 
6
- var _zustand = require('zustand');
7
6
 
8
7
  // src/lib/clients.ts
9
8
  var _reactquery = require('@tanstack/react-query');
10
- var _redis = require('@upstash/redis');
9
+ var _cloudflare = require('@upstash/redis/cloudflare');
11
10
 
12
11
  // src/components/ui/use-toast.ts
13
12
 
@@ -136,15 +135,16 @@ var redisClient = ({
136
135
  credentials,
137
136
  pipelining
138
137
  }) => {
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;
138
+ const safeProcess = typeof process === "undefined" ? { env: {} } : process;
139
+ const token = _optionalChain([credentials, 'optionalAccess', _2 => _2.token]) || safeProcess.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN;
140
+ const url = _optionalChain([credentials, 'optionalAccess', _3 => _3.url]) || safeProcess.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL;
141
141
  if (!url) {
142
142
  throw new Error("Redis URL is missing!");
143
143
  }
144
144
  if (!token) {
145
145
  throw new Error("Redis TOKEN is missing!");
146
146
  }
147
- const redis = new (0, _redis.Redis)({
147
+ const redis = new (0, _cloudflare.Redis)({
148
148
  url,
149
149
  token,
150
150
  enableAutoPipelining: pipelining,
@@ -180,19 +180,79 @@ var queryClient = new (0, _reactquery.QueryClient)({
180
180
  })
181
181
  });
182
182
 
183
- // src/store.tsx
183
+ // src/redis-context.tsx
184
184
  var _jsxruntime = require('react/jsx-runtime');
185
+ var RedisContext = _react.createContext.call(void 0, void 0);
186
+ var RedisProvider = ({
187
+ children,
188
+ redisCredentials
189
+ }) => {
190
+ const redisInstance = _react.useMemo.call(void 0,
191
+ () => redisClient({ credentials: redisCredentials, pipelining: true }),
192
+ [redisCredentials]
193
+ );
194
+ const redisInstanceNoPipeline = _react.useMemo.call(void 0,
195
+ () => redisClient({ credentials: redisCredentials, pipelining: false }),
196
+ [redisCredentials]
197
+ );
198
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
199
+ RedisContext.Provider,
200
+ {
201
+ value: { redis: redisInstance, redisNoPipeline: redisInstanceNoPipeline },
202
+ children
203
+ }
204
+ );
205
+ };
206
+ var useRedis = () => {
207
+ const context = _react.useContext.call(void 0, RedisContext);
208
+ if (!context) {
209
+ throw new Error("useRedis must be used within a RedisProvider");
210
+ }
211
+ return context;
212
+ };
213
+
214
+ // src/store.tsx
215
+
216
+ var _zustand = require('zustand');
217
+ var _middleware = require('zustand/middleware');
218
+
185
219
  var DatabrowserContext = _react.createContext.call(void 0, void 0);
186
220
  var DatabrowserProvider = ({
187
221
  children,
188
- redisCredentials
222
+ storage
189
223
  }) => {
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 });
224
+ const store = _react.useMemo.call(void 0, () => {
225
+ if (!storage) return _zustand.create.call(void 0, storeCreator);
226
+ return _zustand.create.call(void 0, )(
227
+ _middleware.persist.call(void 0, storeCreator, {
228
+ name: "redis-browser-data",
229
+ storage: {
230
+ getItem: () => {
231
+ const data = storage.get();
232
+ if (!data) return null;
233
+ try {
234
+ return JSON.parse(data);
235
+ } catch (e2) {
236
+ console.error("Error while parsing stored data.");
237
+ return null;
238
+ }
239
+ },
240
+ setItem: (_name, value) => storage.set(JSON.stringify(value)),
241
+ removeItem: () => {
242
+ }
243
+ },
244
+ version: 1,
245
+ // @ts-expect-error Reset the store for < v1
246
+ migrate: (state, version) => {
247
+ if (version === 0) {
248
+ return;
249
+ }
250
+ return state;
251
+ }
252
+ })
253
+ );
254
+ }, []);
255
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserContext.Provider, { value: { store }, children });
196
256
  };
197
257
  var useDatabrowser = () => {
198
258
  const context = _react.useContext.call(void 0, DatabrowserContext);
@@ -205,115 +265,170 @@ var useDatabrowserStore = () => {
205
265
  const { store } = useDatabrowser();
206
266
  return _zustand.useStore.call(void 0, store);
207
267
  };
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 }));
268
+ var storeCreator = (set, get) => ({
269
+ selectedTab: void 0,
270
+ tabs: [],
271
+ addTab: () => {
272
+ const id = crypto.randomUUID();
273
+ const newTabData = {
274
+ selectedKey: void 0,
275
+ search: { key: "", type: void 0 }
276
+ };
277
+ set((old) => ({
278
+ tabs: [...old.tabs, [id, newTabData]],
279
+ selectedTab: id
280
+ }));
212
281
  },
213
- selectedListItem: void 0,
214
- setSelectedListItem: (item) => {
215
- set((old) => ({ ...old, selectedListItem: item }));
282
+ removeTab: (id) => {
283
+ set((old) => {
284
+ const tabIndex = old.tabs.findIndex(([tabId]) => tabId === id);
285
+ if (tabIndex === -1) return old;
286
+ const newTabs = [...old.tabs];
287
+ newTabs.splice(tabIndex, 1);
288
+ let selectedTab = old.selectedTab;
289
+ if (selectedTab === id) {
290
+ const [newId] = _nullishCoalesce(newTabs[tabIndex - 1], () => ( newTabs[tabIndex]));
291
+ selectedTab = newTabs.length > 0 ? newId : void 0;
292
+ }
293
+ return { tabs: newTabs, selectedTab };
294
+ });
216
295
  },
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
-
227
- var _reactresizablepanels = require('react-resizable-panels');
296
+ selectTab: (id) => {
297
+ set({ selectedTab: id });
298
+ },
299
+ getSelectedKey: (tabId) => {
300
+ return _optionalChain([get, 'call', _4 => _4(), 'access', _5 => _5.tabs, 'access', _6 => _6.find, 'call', _7 => _7(([id]) => id === tabId), 'optionalAccess', _8 => _8[1], 'optionalAccess', _9 => _9.selectedKey]);
301
+ },
302
+ setSelectedKey: (tabId, key) => {
303
+ set((old) => {
304
+ const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
305
+ if (tabIndex === -1) return old;
306
+ const newTabs = [...old.tabs];
307
+ const [, tabData] = newTabs[tabIndex];
308
+ newTabs[tabIndex] = [tabId, { ...tabData, selectedKey: key, selectedListItem: void 0 }];
309
+ return { ...old, tabs: newTabs };
310
+ });
311
+ },
312
+ setSelectedListItem: (tabId, item) => {
313
+ set((old) => {
314
+ const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
315
+ if (tabIndex === -1) return old;
316
+ const newTabs = [...old.tabs];
317
+ const [, tabData] = newTabs[tabIndex];
318
+ newTabs[tabIndex] = [tabId, { ...tabData, selectedListItem: item }];
319
+ return { ...old, tabs: newTabs };
320
+ });
321
+ },
322
+ setSearch: (tabId, search) => {
323
+ set((old) => {
324
+ const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
325
+ if (tabIndex === -1) return old;
326
+ const newTabs = [...old.tabs];
327
+ const [, tabData] = newTabs[tabIndex];
328
+ newTabs[tabIndex] = [tabId, { ...tabData, search }];
329
+ return { ...old, tabs: newTabs };
330
+ });
331
+ },
332
+ setSearchKey: (tabId, key) => {
333
+ set((old) => {
334
+ const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
335
+ if (tabIndex === -1) return old;
336
+ const newTabs = [...old.tabs];
337
+ const [, tabData] = newTabs[tabIndex];
338
+ newTabs[tabIndex] = [
339
+ tabId,
340
+ {
341
+ ...tabData,
342
+ search: { ...tabData.search, key }
343
+ }
344
+ ];
345
+ return { ...old, tabs: newTabs };
346
+ });
347
+ },
348
+ setSearchType: (tabId, type) => {
349
+ set((old) => {
350
+ const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
351
+ if (tabIndex === -1) return old;
352
+ const newTabs = [...old.tabs];
353
+ const [, tabData] = newTabs[tabIndex];
354
+ newTabs[tabIndex] = [
355
+ tabId,
356
+ {
357
+ ...tabData,
358
+ search: { ...tabData.search, type }
359
+ }
360
+ ];
361
+ return { ...old, tabs: newTabs };
362
+ });
363
+ },
364
+ searchHistory: [],
365
+ addSearchHistory: (key) => {
366
+ set((old) => ({ ...old, searchHistory: [key, ...old.searchHistory] }));
367
+ }
368
+ });
228
369
 
229
- // src/components/ui/toaster.tsx
230
- var _reactportal = require('@radix-ui/react-portal');
370
+ // src/tab-provider.tsx
231
371
 
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
372
 
243
- // src/components/ui/toast.tsx
373
+ var TabIdContext = _react.createContext.call(void 0, void 0);
374
+ var TabIdProvider = ({ children, value }) => {
375
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdContext.Provider, { value, children });
376
+ };
377
+ var useTabId = () => {
378
+ const tabId = _react.useContext.call(void 0, TabIdContext);
379
+ if (!tabId) {
380
+ throw new Error("useTabId must be used within a TabProvider");
381
+ }
382
+ return tabId;
383
+ };
384
+ var useTab = () => {
385
+ const {
386
+ selectedTab,
387
+ tabs,
388
+ setSelectedKey,
389
+ setSelectedListItem,
390
+ setSearch,
391
+ setSearchKey,
392
+ setSearchType
393
+ } = useDatabrowserStore();
394
+ const tabId = useTabId();
395
+ const tabData = _react.useMemo.call(void 0, () => _optionalChain([tabs, 'access', _10 => _10.find, 'call', _11 => _11(([id]) => id === tabId), 'optionalAccess', _12 => _12[1]]), [tabs, tabId]);
396
+ if (!selectedTab || !tabData) throw new Error("selectedTab is undefined when using useTab()");
397
+ return _react.useMemo.call(void 0,
398
+ () => ({
399
+ active: selectedTab === tabId,
400
+ selectedKey: tabData.selectedKey,
401
+ selectedListItem: tabData.selectedListItem,
402
+ search: tabData.search,
403
+ setSelectedKey: (key) => setSelectedKey(tabId, key),
404
+ setSelectedListItem: (item) => setSelectedListItem(tabId, item),
405
+ setSearch: (search) => setSearch(tabId, search),
406
+ setSearchKey: (key) => setSearchKey(tabId, key),
407
+ setSearchType: (type) => setSearchType(tabId, type)
408
+ }),
409
+ [selectedTab, tabs, tabId]
410
+ );
411
+ };
244
412
 
245
- var _reacticons = require('@radix-ui/react-icons');
246
- var _reacttoast = require('@radix-ui/react-toast'); var ToastPrimitives = _interopRequireWildcard(_reacttoast);
413
+ // src/components/databrowser/index.tsx
414
+ var _reacttooltip = require('@radix-ui/react-tooltip'); var TooltipPrimitive = _interopRequireWildcard(_reacttooltip);
247
415
 
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
416
 
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
- };
417
+ // src/components/databrowser/components/databrowser-instance.tsx
418
+ var _reactresizablepanels = require('react-resizable-panels');
304
419
 
305
420
  // node_modules/clsx/dist/clsx.mjs
306
- function r2(e) {
421
+ function r(e) {
307
422
  var t, f, n = "";
308
423
  if ("string" == typeof e || "number" == typeof e) n += e;
309
424
  else if ("object" == typeof e) if (Array.isArray(e)) {
310
425
  var o = e.length;
311
- for (t = 0; t < o; t++) e[t] && (f = r2(e[t])) && (n && (n += " "), n += f);
426
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
312
427
  } else for (f in e) e[f] && (n && (n += " "), n += f);
313
428
  return n;
314
429
  }
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);
430
+ function clsx() {
431
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
317
432
  return n;
318
433
  }
319
434
 
@@ -358,15 +473,15 @@ var getGroupRecursive = (classParts, classPartObject) => {
358
473
  return void 0;
359
474
  }
360
475
  const classRest = classParts.join(CLASS_PART_SEPARATOR);
361
- return _optionalChain([classPartObject, 'access', _4 => _4.validators, 'access', _5 => _5.find, 'call', _6 => _6(({
476
+ return _optionalChain([classPartObject, 'access', _13 => _13.validators, 'access', _14 => _14.find, 'call', _15 => _15(({
362
477
  validator
363
- }) => validator(classRest)), 'optionalAccess', _7 => _7.classGroupId]);
478
+ }) => validator(classRest)), 'optionalAccess', _16 => _16.classGroupId]);
364
479
  };
365
480
  var arbitraryPropertyRegex = /^\[(.+)\]$/;
366
481
  var getGroupIdForArbitraryProperty = (className) => {
367
482
  if (arbitraryPropertyRegex.test(className)) {
368
483
  const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)[1];
369
- const property = _optionalChain([arbitraryPropertyClassName, 'optionalAccess', _8 => _8.substring, 'call', _9 => _9(0, arbitraryPropertyClassName.indexOf(":"))]);
484
+ const property = _optionalChain([arbitraryPropertyClassName, 'optionalAccess', _17 => _17.substring, 'call', _18 => _18(0, arbitraryPropertyClassName.indexOf(":"))]);
370
485
  if (property) {
371
486
  return "arbitrary.." + property;
372
487
  }
@@ -2779,7 +2894,7 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
2779
2894
 
2780
2895
  // src/lib/utils.ts
2781
2896
  function cn(...inputs) {
2782
- return twMerge(clsx2(inputs));
2897
+ return twMerge(clsx(inputs));
2783
2898
  }
2784
2899
  function formatNumber(value) {
2785
2900
  const intl = new Intl.NumberFormat("en-US");
@@ -2810,6 +2925,83 @@ function formatTime(seconds) {
2810
2925
  }
2811
2926
  return parts.slice(0, 1).join(" ");
2812
2927
  }
2928
+ var isTest = typeof window !== "undefined" && window.__PLAYWRIGHT__ === true;
2929
+
2930
+ // src/components/ui/toaster.tsx
2931
+ var _reactportal = require('@radix-ui/react-portal');
2932
+
2933
+ // src/lib/portal-root.ts
2934
+ var root;
2935
+ if (typeof document !== "undefined") {
2936
+ const id = "react-redis-browser-portal-root";
2937
+ root = _nullishCoalesce(document.querySelector(`#${id}`), () => ( document.createElement("div")));
2938
+ root.classList.add("ups-db");
2939
+ root.id = "react-redis-browser-portal-root";
2940
+ document.body.append(root);
2941
+ }
2942
+ var portalRoot = root;
2943
+
2944
+ // src/components/ui/toast.tsx
2945
+
2946
+ var _reacticons = require('@radix-ui/react-icons');
2947
+ var _reacttoast = require('@radix-ui/react-toast'); var ToastPrimitives = _interopRequireWildcard(_reacttoast);
2948
+
2949
+ // node_modules/class-variance-authority/node_modules/clsx/dist/clsx.mjs
2950
+ function r2(e) {
2951
+ var t, f, n = "";
2952
+ if ("string" == typeof e || "number" == typeof e) n += e;
2953
+ 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);
2954
+ else for (t in e) e[t] && (n && (n += " "), n += t);
2955
+ return n;
2956
+ }
2957
+ function clsx2() {
2958
+ for (var e, t, f = 0, n = ""; f < arguments.length; ) (e = arguments[f++]) && (t = r2(e)) && (n && (n += " "), n += t);
2959
+ return n;
2960
+ }
2961
+
2962
+ // node_modules/class-variance-authority/dist/index.mjs
2963
+ var falsyToString = (value) => typeof value === "boolean" ? "".concat(value) : value === 0 ? "0" : value;
2964
+ var cx = clsx2;
2965
+ var cva = (base, config) => {
2966
+ return (props) => {
2967
+ var ref;
2968
+ 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);
2969
+ const { variants, defaultVariants } = config;
2970
+ const getVariantClassNames = Object.keys(variants).map((variant) => {
2971
+ const variantProp = props === null || props === void 0 ? void 0 : props[variant];
2972
+ const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
2973
+ if (variantProp === null) return null;
2974
+ const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
2975
+ return variants[variant][variantKey];
2976
+ });
2977
+ const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
2978
+ let [key, value] = param;
2979
+ if (value === void 0) {
2980
+ return acc;
2981
+ }
2982
+ acc[key] = value;
2983
+ return acc;
2984
+ }, {});
2985
+ const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (ref = config.compoundVariants) === null || ref === void 0 ? void 0 : ref.reduce((acc, param1) => {
2986
+ let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param1;
2987
+ return Object.entries(compoundVariantOptions).every((param) => {
2988
+ let [key, value] = param;
2989
+ return Array.isArray(value) ? value.includes({
2990
+ ...defaultVariants,
2991
+ ...propsWithoutUndefined
2992
+ }[key]) : {
2993
+ ...defaultVariants,
2994
+ ...propsWithoutUndefined
2995
+ }[key] === value;
2996
+ }) ? [
2997
+ ...acc,
2998
+ cvClass,
2999
+ cvClassName
3000
+ ] : acc;
3001
+ }, []);
3002
+ return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
3003
+ };
3004
+ };
2813
3005
 
2814
3006
  // src/components/ui/toast.tsx
2815
3007
 
@@ -2917,26 +3109,58 @@ function Toaster() {
2917
3109
 
2918
3110
 
2919
3111
 
3112
+ // src/components/databrowser/hooks/use-fetch-key-type.ts
3113
+
3114
+ var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
3115
+ var useFetchKeyType = (key) => {
3116
+ const { redis } = useRedis();
3117
+ return _reactquery.useQuery.call(void 0, {
3118
+ queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key],
3119
+ queryFn: async () => {
3120
+ if (!key) return "none";
3121
+ return await redis.type(key);
3122
+ }
3123
+ });
3124
+ };
3125
+
3126
+ // src/components/databrowser/hooks/use-keys.tsx
3127
+
2920
3128
  var KeysContext = _react.createContext.call(void 0, void 0);
2921
3129
  var FETCH_KEYS_QUERY_KEY = "use-fetch-keys";
2922
- var SCAN_COUNT = 100;
3130
+ var SCAN_COUNTS = [100, 300, 500];
2923
3131
  var KeysProvider = ({ children }) => {
2924
- const { search } = useDatabrowserStore();
2925
- const { redisNoPipeline: redis } = useDatabrowser();
3132
+ const { active, search } = useTab();
3133
+ const { redisNoPipeline: redis } = useRedis();
3134
+ const performScan = async (count2, cursor) => {
3135
+ const args = [cursor];
3136
+ if (search.key) {
3137
+ args.push("MATCH", search.key);
3138
+ }
3139
+ if (search.type) {
3140
+ args.push("TYPE", search.type);
3141
+ }
3142
+ args.push("COUNT", count2.toString());
3143
+ if (!search.type) args.push("WITHTYPE");
3144
+ return await redis.exec(["SCAN", ...args]);
3145
+ };
3146
+ const scanUntilAvailable = async (cursor) => {
3147
+ let i = 0;
3148
+ while (true) {
3149
+ const [newCursor, values] = await performScan(_nullishCoalesce(SCAN_COUNTS[i], () => ( SCAN_COUNTS.at(-1))), cursor);
3150
+ cursor = newCursor;
3151
+ i++;
3152
+ if (values.length > 0 || cursor === "0") {
3153
+ return [cursor, values];
3154
+ }
3155
+ }
3156
+ };
2926
3157
  const query = _reactquery.useInfiniteQuery.call(void 0, {
2927
3158
  queryKey: [FETCH_KEYS_QUERY_KEY, search],
3159
+ // Only fetch when tab is active
3160
+ enabled: active,
2928
3161
  initialPageParam: "0",
2929
3162
  queryFn: async ({ pageParam: lastCursor }) => {
2930
- const args = [lastCursor];
2931
- if (search.key) {
2932
- args.push("MATCH", search.key);
2933
- }
2934
- if (search.type) {
2935
- args.push("TYPE", search.type);
2936
- }
2937
- args.push("COUNT", SCAN_COUNT.toString());
2938
- if (!search.type) args.push("WITHTYPE");
2939
- const [cursor, values] = await redis.exec(["SCAN", ...args]);
3163
+ const [cursor, values] = await scanUntilAvailable(lastCursor);
2940
3164
  const keys2 = [];
2941
3165
  let index = 0;
2942
3166
  while (true) {
@@ -2950,6 +3174,9 @@ var KeysProvider = ({ children }) => {
2950
3174
  index += 2;
2951
3175
  }
2952
3176
  }
3177
+ for (const [key, type] of keys2) {
3178
+ queryClient.setQueryData([FETCH_KEY_TYPE_QUERY_KEY, key], type);
3179
+ }
2953
3180
  return {
2954
3181
  cursor: cursor === "0" ? void 0 : cursor,
2955
3182
  keys: keys2,
@@ -2961,7 +3188,7 @@ var KeysProvider = ({ children }) => {
2961
3188
  refetchOnMount: false
2962
3189
  });
2963
3190
  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)]), () => ( []));
3191
+ const keys2 = _nullishCoalesce(_optionalChain([query, 'access', _19 => _19.data, 'optionalAccess', _20 => _20.pages, 'access', _21 => _21.flatMap, 'call', _22 => _22((page) => page.keys)]), () => ( []));
2965
3192
  const keysSet = /* @__PURE__ */ new Set();
2966
3193
  const dedupedKeys = [];
2967
3194
  for (const key of keys2) {
@@ -2992,19 +3219,19 @@ var useKeys = () => {
2992
3219
  var useKeyType = (key) => {
2993
3220
  const { keys } = useKeys();
2994
3221
  const keyTuple = _react.useMemo.call(void 0, () => keys.find(([k, _]) => k === key), [keys, key]);
2995
- return _optionalChain([keyTuple, 'optionalAccess', _14 => _14[1]]);
3222
+ return _optionalChain([keyTuple, 'optionalAccess', _23 => _23[1]]);
2996
3223
  };
2997
3224
 
2998
3225
  // src/components/databrowser/components/display/display-list.tsx
2999
3226
 
3000
-
3227
+ var _iconsreact = require('@tabler/icons-react');
3001
3228
 
3002
3229
  // src/components/ui/button.tsx
3003
3230
 
3004
3231
  var _reactslot = require('@radix-ui/react-slot');
3005
3232
 
3006
3233
  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",
3234
+ "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
3235
  {
3009
3236
  variants: {
3010
3237
  variant: {
@@ -3061,7 +3288,7 @@ function Skeleton({ className, ...props }) {
3061
3288
 
3062
3289
  var FETCH_DB_SIZE_QUERY_KEY = "fetch-db-size";
3063
3290
  var DisplayDbSize = () => {
3064
- const { redis } = useDatabrowser();
3291
+ const { redis } = useRedis();
3065
3292
  const { data: keyCount } = _reactquery.useQuery.call(void 0, {
3066
3293
  queryKey: [FETCH_DB_SIZE_QUERY_KEY],
3067
3294
  queryFn: async () => {
@@ -3079,7 +3306,7 @@ var DisplayDbSize = () => {
3079
3306
 
3080
3307
  // src/components/databrowser/hooks/use-add-key.ts
3081
3308
  var useAddKey = () => {
3082
- const { redis } = useDatabrowser();
3309
+ const { redis } = useRedis();
3083
3310
  const mutation = _reactquery.useMutation.call(void 0, {
3084
3311
  mutationFn: async ({ key, type }) => {
3085
3312
  if (await redis.exists(key)) throw new Error(`Key "${key}" already exists`);
@@ -3136,7 +3363,7 @@ var useAddKey = () => {
3136
3363
  queryKey: [FETCH_KEYS_QUERY_KEY]
3137
3364
  },
3138
3365
  (data) => {
3139
- if (!data) throw new Error("Data is undefined");
3366
+ if (!data) return;
3140
3367
  return {
3141
3368
  ...data,
3142
3369
  pages: data.pages.map(
@@ -3159,16 +3386,12 @@ var useAddKey = () => {
3159
3386
  // src/components/databrowser/hooks/use-delete-key-cache.ts
3160
3387
 
3161
3388
 
3162
- // src/components/databrowser/hooks/use-fetch-key-type.tsx
3163
-
3164
- var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
3165
-
3166
3389
  // src/components/databrowser/hooks/use-fetch-list-items.tsx
3167
3390
 
3168
3391
  var LIST_DISPLAY_PAGE_SIZE = 50;
3169
3392
  var FETCH_LIST_ITEMS_QUERY_KEY = "use-fetch-list-items";
3170
3393
  var useFetchListItems = ({ dataKey, type }) => {
3171
- const { redisNoPipeline: redis } = useDatabrowser();
3394
+ const { redisNoPipeline: redis } = useRedis();
3172
3395
  const setQuery = _reactquery.useInfiniteQuery.call(void 0, {
3173
3396
  enabled: type === "set",
3174
3397
  queryKey: [FETCH_LIST_ITEMS_QUERY_KEY, dataKey, "set"],
@@ -3247,7 +3470,7 @@ var useFetchListItems = ({ dataKey, type }) => {
3247
3470
  // +1 since first message is the last one
3248
3471
  LIST_DISPLAY_PAGE_SIZE + 1
3249
3472
  );
3250
- const lastMessageId = messages.length > 0 ? _optionalChain([messages, 'access', _15 => _15.at, 'call', _16 => _16(-1), 'optionalAccess', _17 => _17[0]]) : void 0;
3473
+ const lastMessageId = messages.length > 0 ? _optionalChain([messages, 'access', _24 => _24.at, 'call', _25 => _25(-1), 'optionalAccess', _26 => _26[0]]) : void 0;
3251
3474
  return {
3252
3475
  cursor: messages.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : lastMessageId,
3253
3476
  keys: messages.map(([id, fields]) => ({
@@ -3283,7 +3506,7 @@ function transformArray(inputArray) {
3283
3506
 
3284
3507
  var FETCH_SIMPLE_KEY_QUERY_KEY = "fetch-simple-key";
3285
3508
  var useFetchSimpleKey = (dataKey, type) => {
3286
- const { redisNoPipeline: redis } = useDatabrowser();
3509
+ const { redisNoPipeline: redis } = useRedis();
3287
3510
  const { deleteKeyCache } = useDeleteKeyCache();
3288
3511
  return _reactquery.useQuery.call(void 0, {
3289
3512
  queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey],
@@ -3310,7 +3533,7 @@ var sortObject = (obj) => {
3310
3533
 
3311
3534
  // src/components/databrowser/hooks/use-delete-key-cache.ts
3312
3535
  var useDeleteKeyCache = () => {
3313
- const { setSelectedKey } = useDatabrowserStore();
3536
+ const { setSelectedKey } = useTab();
3314
3537
  const deleteKeyCache = _react.useCallback.call(void 0,
3315
3538
  (key) => {
3316
3539
  setSelectedKey(void 0);
@@ -3334,7 +3557,7 @@ var useDeleteKeyCache = () => {
3334
3557
 
3335
3558
  // src/components/databrowser/hooks/use-delete-key.ts
3336
3559
  var useDeleteKey = () => {
3337
- const { redis } = useDatabrowser();
3560
+ const { redis } = useRedis();
3338
3561
  const { deleteKeyCache } = useDeleteKeyCache();
3339
3562
  const deleteKey = _reactquery.useMutation.call(void 0, {
3340
3563
  mutationFn: async (key) => {
@@ -3353,7 +3576,7 @@ var useDeleteKey = () => {
3353
3576
  // src/components/databrowser/hooks/use-edit-list-item.tsx
3354
3577
 
3355
3578
  var useEditListItem = () => {
3356
- const { redis } = useDatabrowser();
3579
+ const { redis } = useRedis();
3357
3580
  return _reactquery.useMutation.call(void 0, {
3358
3581
  mutationFn: async ({
3359
3582
  type,
@@ -3411,7 +3634,7 @@ var useEditListItem = () => {
3411
3634
  }
3412
3635
  case "stream": {
3413
3636
  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(
3637
+ const opts = transformArray(_nullishCoalesce(_optionalChain([newValue, 'optionalAccess', _27 => _27.split, 'call', _28 => _28("\n")]), () => ( []))).map(
3415
3638
  ({ key, value }) => [key, value]
3416
3639
  );
3417
3640
  pipe.xadd(dataKey, newKey, Object.fromEntries(opts));
@@ -3446,7 +3669,7 @@ var _bytes = require('bytes'); var _bytes2 = _interopRequireDefault(_bytes);
3446
3669
 
3447
3670
  var FETCH_KEY_LENGTH_QUERY_KEY = "fetch-key-length";
3448
3671
  var useFetchKeyLength = ({ dataKey, type }) => {
3449
- const { redis } = useDatabrowser();
3672
+ const { redis } = useRedis();
3450
3673
  return _reactquery.useQuery.call(void 0, {
3451
3674
  queryKey: [FETCH_KEY_LENGTH_QUERY_KEY, dataKey],
3452
3675
  queryFn: async () => {
@@ -3476,7 +3699,7 @@ var useFetchKeyLength = ({ dataKey, type }) => {
3476
3699
 
3477
3700
  var FETCH_KEY_SIZE_QUERY_KEY = "fetch-key-size";
3478
3701
  var useFetchKeySize = (dataKey) => {
3479
- const { redis } = useDatabrowser();
3702
+ const { redis } = useRedis();
3480
3703
  return _reactquery.useQuery.call(void 0, {
3481
3704
  queryKey: [FETCH_KEY_SIZE_QUERY_KEY, dataKey],
3482
3705
  queryFn: async () => {
@@ -3493,7 +3716,7 @@ var LengthBadge = ({
3493
3716
  content
3494
3717
  }) => {
3495
3718
  const { data, isLoading } = useFetchKeyLength({ dataKey, type });
3496
- const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _20 => _20.length]), () => ( data));
3719
+ const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _29 => _29.length]), () => ( data));
3497
3720
  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
3721
  };
3499
3722
  var SizeBadge = ({ dataKey }) => {
@@ -3503,7 +3726,7 @@ var SizeBadge = ({ dataKey }) => {
3503
3726
  }) });
3504
3727
  };
3505
3728
  var HeaderTTLBadge = ({ dataKey }) => {
3506
- const { data: expireAt } = useFetchKeyExpire(dataKey);
3729
+ const { data: expireAt } = useFetchTTL(dataKey);
3507
3730
  const { mutate: setTTL, isPending } = useSetTTL();
3508
3731
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3509
3732
  TTLBadge,
@@ -3853,8 +4076,8 @@ var TTLBadge = ({
3853
4076
 
3854
4077
  // src/components/databrowser/hooks/use-fetch-ttl.ts
3855
4078
  var FETCH_TTL_QUERY_KEY = "fetch-ttl";
3856
- var useFetchKeyExpire = (dataKey) => {
3857
- const { redis } = useDatabrowser();
4079
+ var useFetchTTL = (dataKey) => {
4080
+ const { redis } = useRedis();
3858
4081
  const { isLoading, error, data } = _reactquery.useQuery.call(void 0, {
3859
4082
  queryKey: [FETCH_TTL_QUERY_KEY, dataKey],
3860
4083
  queryFn: async () => {
@@ -3875,7 +4098,7 @@ var useFetchKeyExpire = (dataKey) => {
3875
4098
  // src/components/databrowser/hooks/use-set-simple-key.tsx
3876
4099
 
3877
4100
  var useSetSimpleKey = (dataKey, type) => {
3878
- const { redis } = useDatabrowser();
4101
+ const { redis } = useRedis();
3879
4102
  return _reactquery.useMutation.call(void 0, {
3880
4103
  mutationFn: async (value) => {
3881
4104
  if (type === "string") {
@@ -3898,7 +4121,7 @@ var useSetSimpleKey = (dataKey, type) => {
3898
4121
  // src/components/databrowser/hooks/use-set-ttl.ts
3899
4122
 
3900
4123
  var useSetTTL = () => {
3901
- const { redis } = useDatabrowser();
4124
+ const { redis } = useRedis();
3902
4125
  const updateTTL = _reactquery.useMutation.call(void 0, {
3903
4126
  mutationFn: async ({ dataKey, ttl }) => {
3904
4127
  await (ttl === void 0 || ttl === TTL_INFINITE ? redis.persist(dataKey) : redis.expire(dataKey, ttl));
@@ -4184,7 +4407,7 @@ var ItemContextMenu = ({
4184
4407
  editItem({
4185
4408
  type,
4186
4409
  dataKey,
4187
- itemKey: _optionalChain([data, 'optionalAccess', _21 => _21.key]),
4410
+ itemKey: _optionalChain([data, 'optionalAccess', _30 => _30.key]),
4188
4411
  // For deletion
4189
4412
  newKey: void 0
4190
4413
  });
@@ -4219,7 +4442,7 @@ var ItemContextMenu = ({
4219
4442
  {
4220
4443
  onClick: () => {
4221
4444
  if (!data) return;
4222
- navigator.clipboard.writeText(_optionalChain([data, 'optionalAccess', _22 => _22.key]));
4445
+ navigator.clipboard.writeText(_optionalChain([data, 'optionalAccess', _31 => _31.key]));
4223
4446
  toast({
4224
4447
  description: "Key copied to clipboard"
4225
4448
  });
@@ -4227,11 +4450,11 @@ var ItemContextMenu = ({
4227
4450
  children: "Copy key"
4228
4451
  }
4229
4452
  ),
4230
- _optionalChain([data, 'optionalAccess', _23 => _23.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4453
+ _optionalChain([data, 'optionalAccess', _32 => _32.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4231
4454
  ContextMenuItem,
4232
4455
  {
4233
4456
  onClick: () => {
4234
- navigator.clipboard.writeText(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _24 => _24.value]), () => ( "")));
4457
+ navigator.clipboard.writeText(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _33 => _33.value]), () => ( "")));
4235
4458
  toast({
4236
4459
  description: "Value copied to clipboard"
4237
4460
  });
@@ -4254,7 +4477,7 @@ var ItemContextMenu = ({
4254
4477
 
4255
4478
  var _reactscrollarea = require('@radix-ui/react-scroll-area'); var ScrollAreaPrimitive = _interopRequireWildcard(_reactscrollarea);
4256
4479
 
4257
- var ScrollArea = React9.forwardRef(({ className, children, onScroll, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4480
+ var ScrollArea = React9.forwardRef(({ className, children, onScroll, disableRoundedInherit = false, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4258
4481
  ScrollAreaPrimitive.Root,
4259
4482
  {
4260
4483
  ref,
@@ -4265,7 +4488,7 @@ var ScrollArea = React9.forwardRef(({ className, children, onScroll, ...props },
4265
4488
  ScrollAreaPrimitive.Viewport,
4266
4489
  {
4267
4490
  onScroll,
4268
- className: "h-full w-full rounded-[inherit] [&>div]:!block",
4491
+ className: cn("h-full w-full [&>div]:!block", !disableRoundedInherit && "rounded-[inherit]"),
4269
4492
  children
4270
4493
  }
4271
4494
  ),
@@ -4296,8 +4519,10 @@ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
4296
4519
 
4297
4520
  var InfiniteScroll = ({
4298
4521
  query,
4299
- children
4522
+ children,
4523
+ ...props
4300
4524
  }) => {
4525
+ const { active } = useTab();
4301
4526
  const scrollRef = _react.useRef.call(void 0, null);
4302
4527
  const contentRef = _react.useRef.call(void 0, null);
4303
4528
  const handleScroll = (e) => {
@@ -4319,15 +4544,20 @@ var InfiniteScroll = ({
4319
4544
  }
4320
4545
  };
4321
4546
  _react.useEffect.call(void 0, () => {
4547
+ if (!active) return;
4322
4548
  const timer = setTimeout(checkAndFetchMore, 100);
4323
4549
  return () => clearTimeout(timer);
4324
- }, [query.data]);
4550
+ }, [active, query.data]);
4325
4551
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4326
4552
  ScrollArea,
4327
4553
  {
4328
4554
  type: "always",
4329
- className: "block h-full w-full transition-all",
4330
4555
  onScroll: handleScroll,
4556
+ ...props,
4557
+ className: cn(
4558
+ "block h-full w-full overflow-visible rounded-lg border border-zinc-200 bg-white p-1 pr-3 transition-all",
4559
+ props.className
4560
+ ),
4331
4561
  ref: scrollRef,
4332
4562
  children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: contentRef, children: [
4333
4563
  children,
@@ -4411,14 +4641,14 @@ var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, .
4411
4641
  {
4412
4642
  ref,
4413
4643
  className: cn(
4414
- "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",
4644
+ "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",
4415
4645
  inset && "pl-8",
4416
4646
  className
4417
4647
  ),
4418
4648
  ...props,
4419
4649
  children: [
4420
4650
  children,
4421
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.ChevronRightIcon, { className: "ml-auto size-4" })
4651
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.ChevronRightIcon, { className: "ml-auto" })
4422
4652
  ]
4423
4653
  }
4424
4654
  ));
@@ -4428,7 +4658,7 @@ var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) =
4428
4658
  {
4429
4659
  ref,
4430
4660
  className: cn(
4431
- "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",
4661
+ "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",
4432
4662
  className
4433
4663
  ),
4434
4664
  ...props
@@ -4441,8 +4671,8 @@ var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...pr
4441
4671
  ref,
4442
4672
  sideOffset,
4443
4673
  className: cn(
4444
- "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",
4445
- "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",
4674
+ "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",
4675
+ "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",
4446
4676
  className
4447
4677
  ),
4448
4678
  ...props
@@ -4473,7 +4703,7 @@ var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checke
4473
4703
  checked,
4474
4704
  ...props,
4475
4705
  children: [
4476
- /* @__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" }) }) }),
4706
+ /* @__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" }) }) }),
4477
4707
  children
4478
4708
  ]
4479
4709
  }
@@ -4489,7 +4719,7 @@ var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props
4489
4719
  ),
4490
4720
  ...props,
4491
4721
  children: [
4492
- /* @__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" }) }) }),
4722
+ /* @__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" }) }) }),
4493
4723
  children
4494
4724
  ]
4495
4725
  }
@@ -4522,8 +4752,8 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
4522
4752
 
4523
4753
  function KeyActions({ dataKey, content }) {
4524
4754
  const { mutateAsync: deleteKey } = useDeleteKey();
4525
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DropdownMenu, { children: [
4526
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconDotsVertical, { className: "size-4 text-zinc-500" }) }) }),
4755
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DropdownMenu, { modal: false, children: [
4756
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", "aria-label": "Key actions", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconDotsVertical, { className: "size-4 text-zinc-500" }) }) }),
4527
4757
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DropdownMenuContent, { className: "", align: "end", children: [
4528
4758
  content && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4529
4759
  DropdownMenuItem,
@@ -4537,12 +4767,28 @@ function KeyActions({ dataKey, content }) {
4537
4767
  children: "Copy content"
4538
4768
  }
4539
4769
  ),
4770
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4771
+ DropdownMenuItem,
4772
+ {
4773
+ onClick: () => {
4774
+ navigator.clipboard.writeText(dataKey);
4775
+ },
4776
+ children: "Copy key"
4777
+ }
4778
+ ),
4540
4779
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4541
4780
  DeleteAlertDialog,
4542
4781
  {
4543
4782
  deletionType: "key",
4544
4783
  onDeleteConfirm: async () => await deleteKey(dataKey),
4545
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" })
4784
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4785
+ DropdownMenuItem,
4786
+ {
4787
+ className: "text-red-500 focus:bg-red-500 focus:text-white",
4788
+ onSelect: (e) => e.preventDefault(),
4789
+ children: "Delete key"
4790
+ }
4791
+ )
4546
4792
  }
4547
4793
  )
4548
4794
  ] })
@@ -4556,15 +4802,15 @@ var DisplayHeader = ({
4556
4802
  type,
4557
4803
  content
4558
4804
  }) => {
4559
- const { setSelectedListItem } = useDatabrowserStore();
4805
+ const { setSelectedListItem } = useTab();
4560
4806
  const handleAddItem = () => {
4561
4807
  setSelectedListItem({ key: type === "stream" ? "*" : "", isNew: true });
4562
4808
  };
4563
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
4809
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100", children: [
4564
4810
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-h-10 items-center justify-between gap-4", children: [
4565
4811
  /* @__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 }) }),
4566
4812
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1", children: [
4567
- type !== "string" && type !== "json" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { onClick: handleAddItem, size: "icon-sm", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "size-4 text-zinc-500" }) }),
4813
+ type !== "string" && type !== "json" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { onClick: handleAddItem, size: "icon-sm", "aria-label": "Add item", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "size-4 text-zinc-500" }) }),
4568
4814
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyActions, { dataKey, content })
4569
4815
  ] })
4570
4816
  ] }),
@@ -4586,7 +4832,7 @@ var DisplayHeader = ({
4586
4832
 
4587
4833
  var Tooltip = TooltipPrimitive.Root;
4588
4834
  var TooltipTrigger = TooltipPrimitive.Trigger;
4589
- var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4835
+ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4590
4836
  TooltipPrimitive.Content,
4591
4837
  {
4592
4838
  ref,
@@ -4597,7 +4843,7 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
4597
4843
  ),
4598
4844
  ...props
4599
4845
  }
4600
- ));
4846
+ ) }));
4601
4847
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
4602
4848
  var SimpleTooltip = ({
4603
4849
  content,
@@ -4606,7 +4852,7 @@ var SimpleTooltip = ({
4606
4852
  if (!content) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children });
4607
4853
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tooltip, { delayDuration: 400, children: [
4608
4854
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children }) }),
4609
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipContent, { children: content })
4855
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipContent, { side: "top", children: content })
4610
4856
  ] });
4611
4857
  };
4612
4858
 
@@ -4617,7 +4863,7 @@ var useFetchHashFieldExpires = ({
4617
4863
  dataKey,
4618
4864
  fields
4619
4865
  }) => {
4620
- const { redis } = useDatabrowser();
4866
+ const { redis } = useRedis();
4621
4867
  return _reactquery.useQuery.call(void 0, {
4622
4868
  queryKey: [FETCH_HASH_FIELD_TTLS_QUERY_KEY, dataKey, fields],
4623
4869
  queryFn: async () => {
@@ -4648,7 +4894,7 @@ var useFetchHashFieldExpires = ({
4648
4894
  // src/components/databrowser/hooks/use-set-hash-ttl.ts
4649
4895
 
4650
4896
  var useSetHashTTL = () => {
4651
- const { redis } = useDatabrowser();
4897
+ const { redis } = useRedis();
4652
4898
  return _reactquery.useMutation.call(void 0, {
4653
4899
  mutationFn: async ({
4654
4900
  dataKey,
@@ -4670,7 +4916,7 @@ var useSetHashTTL = () => {
4670
4916
  var HashFieldTTLBadge = ({ dataKey, field }) => {
4671
4917
  const { data } = useFetchHashFieldExpires({ dataKey, fields: [field] });
4672
4918
  const { mutate: setTTL, isPending } = useSetHashTTL();
4673
- const expireAt = _optionalChain([data, 'optionalAccess', _25 => _25[field]]);
4919
+ const expireAt = _optionalChain([data, 'optionalAccess', _34 => _34[field]]);
4674
4920
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4675
4921
  TTLBadge,
4676
4922
  {
@@ -4753,63 +4999,59 @@ var CustomEditor = ({
4753
4999
  showCopyButton,
4754
5000
  readOnly
4755
5001
  }) => {
5002
+ const { active } = useTab();
4756
5003
  const monaco = _react2.useMonaco.call(void 0, );
4757
5004
  const editorRef = _react.useRef.call(void 0, );
4758
5005
  _react.useEffect.call(void 0, () => {
4759
- if (!monaco || !editorRef.current) {
5006
+ if (!active || !monaco || !editorRef.current) {
4760
5007
  return;
4761
5008
  }
4762
- _optionalChain([monaco, 'optionalAccess', _26 => _26.editor, 'access', _27 => _27.setModelLanguage, 'call', _28 => _28(editorRef.current.getModel(), language)]);
4763
- }, [monaco, language]);
5009
+ _optionalChain([monaco, 'optionalAccess', _35 => _35.editor, 'access', _36 => _36.setModelLanguage, 'call', _37 => _37(editorRef.current.getModel(), language)]);
5010
+ }, [monaco, language, active]);
5011
+ const editor = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5012
+ _react2.Editor,
5013
+ {
5014
+ loading: void 0,
5015
+ onMount: (editor2) => {
5016
+ editorRef.current = editor2;
5017
+ },
5018
+ value,
5019
+ onChange: (value2) => {
5020
+ onChange(_nullishCoalesce(value2, () => ( "")));
5021
+ },
5022
+ defaultLanguage: language,
5023
+ options: {
5024
+ readOnly,
5025
+ wordWrap: "on",
5026
+ overviewRulerBorder: false,
5027
+ overviewRulerLanes: 0,
5028
+ formatOnPaste: true,
5029
+ formatOnType: true,
5030
+ renderWhitespace: "none",
5031
+ smoothScrolling: true,
5032
+ autoIndent: "full",
5033
+ guides: { indentation: false },
5034
+ fontSize: 13,
5035
+ cursorBlinking: "smooth",
5036
+ minimap: { enabled: false },
5037
+ folding: false,
5038
+ glyphMargin: false,
5039
+ lineNumbers: "off",
5040
+ parameterHints: { enabled: false },
5041
+ lineDecorationsWidth: 0,
5042
+ automaticLayout: true,
5043
+ scrollBeyondLastLine: false,
5044
+ renderLineHighlight: "none"
5045
+ }
5046
+ }
5047
+ );
4764
5048
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4765
5049
  "div",
4766
5050
  {
4767
5051
  className: cn("group/editor relative", height === void 0 && "h-full p-2"),
4768
- style: {
4769
- height
4770
- },
5052
+ style: { height },
4771
5053
  children: [
4772
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4773
- _react2.Editor,
4774
- {
4775
- loading: void 0,
4776
- onMount: (editor) => {
4777
- editorRef.current = editor;
4778
- },
4779
- value,
4780
- onChange: (value2) => {
4781
- onChange(_nullishCoalesce(value2, () => ( "")));
4782
- },
4783
- defaultLanguage: language,
4784
- options: {
4785
- readOnly,
4786
- wordWrap: "on",
4787
- overviewRulerBorder: false,
4788
- overviewRulerLanes: 0,
4789
- formatOnPaste: true,
4790
- formatOnType: true,
4791
- renderWhitespace: "none",
4792
- smoothScrolling: true,
4793
- autoIndent: "full",
4794
- guides: {
4795
- indentation: false
4796
- },
4797
- fontSize: 13,
4798
- cursorBlinking: "smooth",
4799
- minimap: {
4800
- enabled: false
4801
- },
4802
- folding: false,
4803
- glyphMargin: false,
4804
- lineNumbers: "off",
4805
- parameterHints: { enabled: false },
4806
- lineDecorationsWidth: 0,
4807
- automaticLayout: true,
4808
- scrollBeyondLastLine: false,
4809
- renderLineHighlight: "none"
4810
- }
4811
- }
4812
- ),
5054
+ isTest ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { "aria-label": "editor", value, onChange: (e) => onChange(e.target.value) }) : editor,
4813
5055
  showCopyButton && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4814
5056
  CopyButton,
4815
5057
  {
@@ -4882,7 +5124,7 @@ var checkIsValidJSON = (value) => {
4882
5124
  try {
4883
5125
  JSON.parse(value);
4884
5126
  return true;
4885
- } catch (e2) {
5127
+ } catch (e3) {
4886
5128
  return false;
4887
5129
  }
4888
5130
  };
@@ -4894,7 +5136,7 @@ var ListEditDisplay = ({
4894
5136
  type,
4895
5137
  item
4896
5138
  }) => {
4897
- 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) });
5139
+ 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) });
4898
5140
  };
4899
5141
  var ListEditForm = ({
4900
5142
  type,
@@ -4906,7 +5148,7 @@ var ListEditForm = ({
4906
5148
  dataKey
4907
5149
  });
4908
5150
  const findValue = () => {
4909
- for (const page of _nullishCoalesce(_optionalChain([query, 'access', _29 => _29.data, 'optionalAccess', _30 => _30.pages]), () => ( []))) {
5151
+ for (const page of _nullishCoalesce(_optionalChain([query, 'access', _38 => _38.data, 'optionalAccess', _39 => _39.pages]), () => ( []))) {
4910
5152
  const item = page.keys.find((item2) => item2.key === itemKey);
4911
5153
  if (item && "value" in item) return item.value;
4912
5154
  }
@@ -4920,7 +5162,7 @@ var ListEditForm = ({
4920
5162
  }
4921
5163
  });
4922
5164
  const { mutateAsync: editItem, isPending } = useEditListItem();
4923
- const { setSelectedListItem } = useDatabrowserStore();
5165
+ const { setSelectedListItem } = useTab();
4924
5166
  const [keyLabel, valueLabel] = headerLabels[type];
4925
5167
  const onSubmit = form.handleSubmit(async ({ key, value }) => {
4926
5168
  await editItem({
@@ -5052,7 +5294,7 @@ var HashFieldTTLInfo = ({
5052
5294
  fields
5053
5295
  }) => {
5054
5296
  const { data } = useFetchHashFieldExpires({ dataKey, fields });
5055
- const expireAt = _optionalChain([data, 'optionalAccess', _31 => _31[field]]);
5297
+ const expireAt = _optionalChain([data, 'optionalAccess', _40 => _40[field]]);
5056
5298
  const [ttl, setTTL] = _react.useState.call(void 0, () => calculateTTL(expireAt));
5057
5299
  _react.useEffect.call(void 0, () => {
5058
5300
  setTTL(calculateTTL(expireAt));
@@ -5075,12 +5317,12 @@ var headerLabels = {
5075
5317
  set: ["Value", ""]
5076
5318
  };
5077
5319
  var ListDisplay = ({ dataKey, type }) => {
5078
- const { selectedListItem } = useDatabrowserStore();
5320
+ const { selectedListItem } = useTab();
5079
5321
  const query = useFetchListItems({ dataKey, type });
5080
5322
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2", children: [
5081
5323
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayHeader, { dataKey, type }),
5082
5324
  selectedListItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListEditDisplay, { dataKey, type, item: selectedListItem }),
5083
- /* @__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 }) }) }) }) }) }) })
5325
+ /* @__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 }) }) }) }) }) })
5084
5326
  ] });
5085
5327
  };
5086
5328
  var ListItems = ({
@@ -5088,8 +5330,8 @@ var ListItems = ({
5088
5330
  type,
5089
5331
  dataKey
5090
5332
  }) => {
5091
- const { setSelectedListItem } = useDatabrowserStore();
5092
- 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]);
5333
+ const { setSelectedListItem } = useTab();
5334
+ const keys = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([query, 'access', _41 => _41.data, 'optionalAccess', _42 => _42.pages, 'access', _43 => _43.flatMap, 'call', _44 => _44((page) => page.keys)]), () => ( [])), [query.data]);
5093
5335
  const fields = _react.useMemo.call(void 0, () => keys.map((key) => key.key), [keys]);
5094
5336
  const { mutate: editItem } = useEditListItem();
5095
5337
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -5100,7 +5342,7 @@ var ListItems = ({
5100
5342
  onClick: () => {
5101
5343
  setSelectedListItem({ key });
5102
5344
  },
5103
- className: cn("h-10 border-b border-b-zinc-100 hover:bg-zinc-100 "),
5345
+ className: cn("h-10 border-b border-b-zinc-100 transition-colors hover:bg-zinc-100"),
5104
5346
  children: [
5105
5347
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5106
5348
  "td",
@@ -5171,13 +5413,7 @@ var EditorDisplay = ({ dataKey, type }) => {
5171
5413
  const { data } = useFetchSimpleKey(dataKey, type);
5172
5414
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full w-full flex-col gap-2", children: [
5173
5415
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayHeader, { dataKey, type, content: _nullishCoalesce(data, () => ( void 0)) }),
5174
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5175
- "div",
5176
- {
5177
- className: "flex h-full grow flex-col gap-2\n rounded-md bg-zinc-100 p-3",
5178
- 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)
5179
- }
5180
- )
5416
+ /* @__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) })
5181
5417
  ] });
5182
5418
  };
5183
5419
  var EditorDisplayForm = ({
@@ -5221,10 +5457,10 @@ var EditorDisplayForm = ({
5221
5457
  // src/components/databrowser/components/display/index.tsx
5222
5458
 
5223
5459
  var DataDisplay = () => {
5224
- const { selectedKey } = useDatabrowserStore();
5460
+ const { selectedKey } = useTab();
5225
5461
  const { query } = useKeys();
5226
5462
  const type = useKeyType(selectedKey);
5227
- 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 }) }) });
5463
+ 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 }) }) });
5228
5464
  };
5229
5465
 
5230
5466
  // src/components/databrowser/components/sidebar/index.tsx
@@ -5340,7 +5576,7 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
5340
5576
  // src/components/databrowser/components/add-key-modal.tsx
5341
5577
 
5342
5578
  function AddKeyModal() {
5343
- const { setSelectedKey } = useDatabrowserStore();
5579
+ const { setSelectedKey } = useTab();
5344
5580
  const [open, setOpen] = _react.useState.call(void 0, false);
5345
5581
  const { mutateAsync: addKey, isPending } = useAddKey();
5346
5582
  const { control, handleSubmit, formState, reset } = _reacthookform.useForm.call(void 0, {
@@ -5354,7 +5590,7 @@ function AddKeyModal() {
5354
5590
  setSelectedKey(key);
5355
5591
  setOpen(false);
5356
5592
  setTimeout(() => {
5357
- _optionalChain([window, 'access', _36 => _36.document, 'access', _37 => _37.querySelector, 'call', _38 => _38(`[data-key="${key}"]`), 'optionalAccess', _39 => _39.scrollIntoView, 'call', _40 => _40({
5593
+ _optionalChain([window, 'access', _45 => _45.document, 'access', _46 => _46.querySelector, 'call', _47 => _47(`[data-key="${key}"]`), 'optionalAccess', _48 => _48.scrollIntoView, 'call', _49 => _49({
5358
5594
  behavior: "smooth",
5359
5595
  block: "start",
5360
5596
  inline: "nearest"
@@ -5370,7 +5606,7 @@ function AddKeyModal() {
5370
5606
  setOpen(open2);
5371
5607
  },
5372
5608
  children: [
5373
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "primary", size: "icon-sm", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.PlusIcon, { className: "size-4" }) }) }),
5609
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "primary", size: "icon-sm", "aria-label": "Add key", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.PlusIcon, { className: "size-4" }) }) }),
5374
5610
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DialogContent, { className: "max-w-[400px]", children: [
5375
5611
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTitle, { children: "Create new key" }) }),
5376
5612
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "sr-only", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactdialog.DialogDescription, { children: "Create new key" }) }),
@@ -5399,7 +5635,7 @@ function AddKeyModal() {
5399
5635
  }
5400
5636
  )
5401
5637
  ] }),
5402
- 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]) }),
5638
+ formState.errors.key && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-3 mt-2 text-xs text-red-500", children: _optionalChain([formState, 'access', _50 => _50.errors, 'access', _51 => _51.key, 'optionalAccess', _52 => _52.message]) }),
5403
5639
  /* @__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" }),
5404
5640
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-6 flex justify-end gap-2", children: [
5405
5641
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -5425,7 +5661,7 @@ function AddKeyModal() {
5425
5661
  // src/components/databrowser/components/sidebar/empty.tsx
5426
5662
 
5427
5663
  var Empty = () => {
5428
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center rounded-md border border-dashed px-4 py-6 text-center", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-5", children: [
5664
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center rounded-md border bg-white px-4 py-6 text-center", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-5", children: [
5429
5665
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-md font-medium", children: "Data on a break" }),
5430
5666
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-balance text-center", children: '"Quick, lure it back with some CLI magic!"' })
5431
5667
  ] }) });
@@ -5493,7 +5729,7 @@ var SidebarContextMenu = ({ children }) => {
5493
5729
 
5494
5730
  var KeysList = () => {
5495
5731
  const { keys } = useKeys();
5496
- 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])) }) }) });
5732
+ 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', _53 => _53.at, 'call', _54 => _54(i + 1), 'optionalAccess', _55 => _55[0]]), () => ( "")), data }, data[0])) }) });
5497
5733
  };
5498
5734
  var keyStyles = {
5499
5735
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5505,7 +5741,7 @@ var keyStyles = {
5505
5741
  stream: "border-green-400 !bg-green-50 text-green-900"
5506
5742
  };
5507
5743
  var KeyItem = ({ data, nextKey }) => {
5508
- const { selectedKey, setSelectedKey } = useDatabrowserStore();
5744
+ const { selectedKey, setSelectedKey } = useTab();
5509
5745
  const [dataKey, dataType] = data;
5510
5746
  const isKeySelected = selectedKey === dataKey;
5511
5747
  const isNextKeySelected = selectedKey === nextKey;
@@ -5515,7 +5751,7 @@ var KeyItem = ({ data, nextKey }) => {
5515
5751
  "data-key": dataKey,
5516
5752
  variant: isKeySelected ? "default" : "ghost",
5517
5753
  className: cn(
5518
- "relative flex h-10 w-full items-center justify-start gap-2 px-3 py-0 ",
5754
+ "relative flex h-10 w-full items-center justify-start gap-2 px-3 py-0 !ring-0 focus-visible:bg-zinc-50",
5519
5755
  "select-none border border-transparent text-left",
5520
5756
  isKeySelected && "shadow-sm",
5521
5757
  isKeySelected && keyStyles[dataType]
@@ -5534,30 +5770,106 @@ var KeyItem = ({ data, nextKey }) => {
5534
5770
 
5535
5771
 
5536
5772
 
5773
+ var dedupeSearchHistory = (history) => {
5774
+ const seen = /* @__PURE__ */ new Set();
5775
+ return history.filter((item) => {
5776
+ if (!item || seen.has(item)) return false;
5777
+ seen.add(item);
5778
+ return true;
5779
+ });
5780
+ };
5537
5781
  var SearchInput = () => {
5538
- const { setSearchKey, search } = useDatabrowserStore();
5782
+ const { setSearchKey, search } = useTab();
5783
+ const { searchHistory, addSearchHistory } = useDatabrowserStore();
5539
5784
  const [state, setState] = _react.useState.call(void 0, search.key);
5540
- const submit = (value) => {
5785
+ const [isFocus, setIsFocus] = _react.useState.call(void 0, false);
5786
+ const [focusedIndex, setFocusedIndex] = _react.useState.call(void 0, -1);
5787
+ const inputRef = _react.useRef.call(void 0, null);
5788
+ const historyItemRefs = _react.useRef.call(void 0, []);
5789
+ const handleSubmit = (value) => {
5541
5790
  if (value.trim() !== "" && !value.includes("*")) value = `${value}*`;
5791
+ addSearchHistory(value);
5542
5792
  setSearchKey(value);
5543
5793
  setState(value);
5544
5794
  };
5545
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative grow", children: [
5546
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5547
- Input,
5548
- {
5549
- placeholder: "Search",
5550
- className: "rounded-l-none border-zinc-300 font-normal",
5551
- onKeyDown: (e) => {
5552
- if (e.key === "Enter") submit(e.currentTarget.value);
5553
- },
5554
- onChange: (e) => {
5555
- setState(e.currentTarget.value);
5556
- if (e.currentTarget.value.trim() === "") submit("");
5557
- },
5558
- value: state
5795
+ const filteredHistory = dedupeSearchHistory(
5796
+ searchHistory.filter((item) => item.includes(state) && item !== state)
5797
+ ).slice(0, 5).map((item) => item.endsWith("*") ? item.slice(0, -1) : item);
5798
+ _react.useEffect.call(void 0, () => {
5799
+ setFocusedIndex(-1);
5800
+ }, [filteredHistory.length]);
5801
+ const handleKeyDown = (e) => {
5802
+ if (e.key === "Enter") {
5803
+ const text = focusedIndex >= 0 && focusedIndex < filteredHistory.length ? filteredHistory[focusedIndex] : e.currentTarget.value;
5804
+ handleSubmit(text);
5805
+ } else if (e.key === "Escape") {
5806
+ setState("");
5807
+ setFocusedIndex(-1);
5808
+ _optionalChain([inputRef, 'access', _56 => _56.current, 'optionalAccess', _57 => _57.blur, 'call', _58 => _58()]);
5809
+ } else if (e.key === "ArrowDown" || e.key === "Tab" && !e.shiftKey) {
5810
+ e.preventDefault();
5811
+ if (focusedIndex < filteredHistory.length - 1) {
5812
+ setFocusedIndex(focusedIndex + 1);
5813
+ } else if (filteredHistory.length > 0) {
5814
+ setFocusedIndex(0);
5559
5815
  }
5560
- ),
5816
+ } else if (e.key === "ArrowUp" || e.key === "Tab" && e.shiftKey) {
5817
+ e.preventDefault();
5818
+ if (focusedIndex > 0) {
5819
+ setFocusedIndex(focusedIndex - 1);
5820
+ } else if (filteredHistory.length > 0 && focusedIndex === 0) {
5821
+ setFocusedIndex(-1);
5822
+ _optionalChain([inputRef, 'access', _59 => _59.current, 'optionalAccess', _60 => _60.focus, 'call', _61 => _61()]);
5823
+ } else if (filteredHistory.length > 0) {
5824
+ setFocusedIndex(filteredHistory.length - 1);
5825
+ }
5826
+ }
5827
+ };
5828
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative grow", children: [
5829
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Popover, { open: isFocus && filteredHistory.length > 0, children: [
5830
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5831
+ Input,
5832
+ {
5833
+ ref: inputRef,
5834
+ placeholder: "Search",
5835
+ className: "rounded-l-none border-zinc-300 font-normal",
5836
+ onKeyDown: handleKeyDown,
5837
+ onChange: (e) => {
5838
+ setState(e.currentTarget.value);
5839
+ if (e.currentTarget.value.trim() === "") handleSubmit("");
5840
+ },
5841
+ value: state,
5842
+ onFocus: () => {
5843
+ setIsFocus(true);
5844
+ setFocusedIndex(-1);
5845
+ },
5846
+ onBlur: () => setIsFocus(false)
5847
+ }
5848
+ ) }) }),
5849
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5850
+ PopoverContent,
5851
+ {
5852
+ className: "w-[--radix-popover-trigger-width] divide-y px-3 py-2 text-[13px] text-zinc-900",
5853
+ autoFocus: false,
5854
+ onOpenAutoFocus: (e) => {
5855
+ e.preventDefault();
5856
+ e.stopPropagation();
5857
+ },
5858
+ children: filteredHistory.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full py-[3px]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5859
+ "button",
5860
+ {
5861
+ ref: (el) => {
5862
+ historyItemRefs.current[index] = el;
5863
+ },
5864
+ onClick: () => handleSubmit(item),
5865
+ onMouseEnter: () => setFocusedIndex(index),
5866
+ className: `block w-full truncate rounded-sm p-1 text-left transition-colors ${focusedIndex === index ? "bg-zinc-100" : "hover:bg-zinc-100"}`,
5867
+ children: item
5868
+ }
5869
+ ) }, item))
5870
+ }
5871
+ )
5872
+ ] }),
5561
5873
  state && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5562
5874
  Button,
5563
5875
  {
@@ -5574,14 +5886,15 @@ var SearchInput = () => {
5574
5886
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", children: "Clear" })
5575
5887
  ]
5576
5888
  }
5577
- )
5889
+ ),
5890
+ " "
5578
5891
  ] });
5579
5892
  };
5580
5893
 
5581
5894
  // src/components/databrowser/components/sidebar/skeleton-buttons.tsx
5582
5895
 
5583
5896
  var DEFAULT_SKELETON_COUNT = 6;
5584
- var LoadingSkeleton = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grid", children: Array.from({ length: DEFAULT_SKELETON_COUNT }).fill(0).map((_, idx) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center gap-2 px-3", children: [
5897
+ var LoadingSkeleton = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "block h-full w-full rounded-lg border border-zinc-200 bg-white p-1 pr-3 transition-all", children: Array.from({ length: DEFAULT_SKELETON_COUNT }).fill(0).map((_, idx) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center gap-2 px-3", children: [
5585
5898
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "size-5 shrink-0 rounded" }),
5586
5899
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "h-4 grow rounded" })
5587
5900
  ] }, idx)) });
@@ -5590,7 +5903,7 @@ var LoadingSkeleton = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div",
5590
5903
 
5591
5904
  var ALL_TYPES_KEY = "all";
5592
5905
  function DataTypeSelector() {
5593
- const { search, setSearchType } = useDatabrowserStore();
5906
+ const { search, setSearchType } = useTab();
5594
5907
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5595
5908
  Select,
5596
5909
  {
@@ -5616,14 +5929,15 @@ function DataTypeSelector() {
5616
5929
 
5617
5930
  function Sidebar() {
5618
5931
  const { keys, query } = useKeys();
5619
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5620
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5932
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 p-4", children: [
5933
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100", children: [
5621
5934
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center justify-between pl-1", children: [
5622
5935
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayDbSize, {}),
5623
5936
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-1", children: [
5624
5937
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5625
5938
  Button,
5626
5939
  {
5940
+ "aria-label": "Refresh",
5627
5941
  className: "h-7 w-7 px-0",
5628
5942
  onClick: () => {
5629
5943
  queryClient.invalidateQueries({
@@ -5655,19 +5969,15 @@ function Sidebar() {
5655
5969
  ] }),
5656
5970
  query.isLoading && keys.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingSkeleton, {}) : keys.length > 0 ? (
5657
5971
  // Infinite scroll already has a loader at the bottom
5658
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysList, {}) })
5972
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, disableRoundedInherit: true, className: "min-h-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeysList, {}) })
5659
5973
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Empty, {})
5660
5974
  ] });
5661
5975
  }
5662
5976
 
5663
- // src/components/databrowser/index.tsx
5977
+ // src/components/databrowser/components/databrowser-instance.tsx
5664
5978
 
5665
- var RedisBrowser = ({ token, url }) => {
5666
- const credentials = _react.useMemo.call(void 0, () => ({ token, url }), [token, url]);
5667
- _react.useEffect.call(void 0, () => {
5668
- queryClient.resetQueries();
5669
- }, [credentials.url]);
5670
- 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: [
5979
+ var DatabrowserInstance = ({ hidden }) => {
5980
+ 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: [
5671
5981
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5672
5982
  _reactresizablepanels.PanelGroup,
5673
5983
  {
@@ -5676,20 +5986,145 @@ var RedisBrowser = ({ token, url }) => {
5676
5986
  className: "h-full w-full gap-0.5 text-sm antialiased",
5677
5987
  children: [
5678
5988
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.Panel, { defaultSize: 30, minSize: 30, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Sidebar, {}) }),
5679
- /* @__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,
5680
- _iconsreact.IconDotsVertical,
5681
- {
5682
- size: 16,
5683
- stroke: 1,
5684
- className: "pointer-events-none shrink-0 opacity-20"
5685
- }
5686
- ) }),
5989
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.PanelResizeHandle, { className: "group flex h-full w-3 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-500" }) }),
5687
5990
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactresizablepanels.Panel, { minSize: 40, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DataDisplay, {}) })
5688
5991
  ]
5689
5992
  }
5690
5993
  ),
5691
5994
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Toaster, {})
5692
- ] }) }) }) }) });
5995
+ ] }) });
5996
+ };
5997
+
5998
+ // src/components/databrowser/components/databrowser-tabs.tsx
5999
+
6000
+
6001
+ // src/components/databrowser/components/tab.tsx
6002
+
6003
+
6004
+ // src/components/databrowser/components/tab-type-icon.tsx
6005
+
6006
+ function TabTypeIcon({ selectedKey }) {
6007
+ const { data: keyType, isLoading } = useFetchKeyType(selectedKey);
6008
+ if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "h-5 w-5 rounded" });
6009
+ if (!keyType || keyType === "none") return;
6010
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TypeTag, { variant: keyType, type: "icon" });
6011
+ }
6012
+
6013
+ // src/hooks/use-overflow.ts
6014
+
6015
+ var useOverflow = () => {
6016
+ const [isOverflow, setIsOverflow] = _react.useState.call(void 0, false);
6017
+ const observerRef = _react.useRef.call(void 0, null);
6018
+ const ref = _react.useCallback.call(void 0, (node) => {
6019
+ if (observerRef.current) {
6020
+ observerRef.current.disconnect();
6021
+ observerRef.current = null;
6022
+ }
6023
+ if (!node) return;
6024
+ observerRef.current = new ResizeObserver((entries) => {
6025
+ const el = _optionalChain([entries, 'access', _62 => _62.at, 'call', _63 => _63(0), 'optionalAccess', _64 => _64.target]);
6026
+ if (!el) return;
6027
+ setIsOverflow(el.scrollWidth > el.clientWidth);
6028
+ });
6029
+ observerRef.current.observe(node);
6030
+ }, []);
6031
+ _react.useEffect.call(void 0, () => {
6032
+ return () => {
6033
+ _optionalChain([observerRef, 'access', _65 => _65.current, 'optionalAccess', _66 => _66.disconnect, 'call', _67 => _67()]);
6034
+ };
6035
+ }, []);
6036
+ return { ref, isOverflow };
6037
+ };
6038
+
6039
+ // src/components/databrowser/components/tab.tsx
6040
+
6041
+ var Tab = ({ id }) => {
6042
+ const { active, search, selectedKey } = useTab();
6043
+ const { selectTab, removeTab, tabs } = useDatabrowserStore();
6044
+ const { ref, isOverflow } = useOverflow();
6045
+ const label = search.key || selectedKey;
6046
+ const iconNode = search.key ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconSearch, { size: 15 }) : selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabTypeIcon, { selectedKey }) : void 0;
6047
+ const tabNode = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6048
+ "div",
6049
+ {
6050
+ onClick: () => selectTab(id),
6051
+ className: cn(
6052
+ "flex h-9 cursor-pointer items-center gap-2 rounded-t-lg border border-zinc-200 px-3 text-[13px] transition-colors",
6053
+ active ? "border-b-white bg-white text-zinc-900" : "bg-zinc-100 hover:bg-zinc-50"
6054
+ ),
6055
+ children: [
6056
+ iconNode,
6057
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { ref, className: "max-w-32 truncate whitespace-nowrap", children: label || "New Tab" }),
6058
+ tabs.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6059
+ "button",
6060
+ {
6061
+ onClick: (e) => {
6062
+ e.stopPropagation();
6063
+ removeTab(id);
6064
+ },
6065
+ className: "p-1 text-zinc-300 transition-colors hover:text-zinc-500",
6066
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconX, { size: 16 })
6067
+ }
6068
+ )
6069
+ ]
6070
+ }
6071
+ );
6072
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: isOverflow ? label : void 0, children: tabNode });
6073
+ };
6074
+
6075
+ // src/components/databrowser/components/databrowser-tabs.tsx
6076
+
6077
+ var DatabrowserTabs = () => {
6078
+ const { tabs, addTab } = useDatabrowserStore();
6079
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative mb-2 shrink-0", children: [
6080
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute bottom-0 left-0 right-0 -z-10 h-[1px] w-full bg-zinc-200" }),
6081
+ /* @__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: [
6082
+ tabs.map(([id]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdProvider, { value: id, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tab, { id }) }, id)),
6083
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6084
+ Button,
6085
+ {
6086
+ variant: "secondary",
6087
+ size: "icon-sm",
6088
+ onClick: addTab,
6089
+ className: "mr-1 flex-shrink-0",
6090
+ title: "Add new tab",
6091
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500", size: 16 })
6092
+ }
6093
+ )
6094
+ ] })
6095
+ ] });
6096
+ };
6097
+
6098
+ // src/components/databrowser/index.tsx
6099
+
6100
+ var RedisBrowser = ({
6101
+ token,
6102
+ url,
6103
+ hideTabs,
6104
+ storage
6105
+ }) => {
6106
+ const credentials = _react.useMemo.call(void 0, () => ({ token, url }), [token, url]);
6107
+ _react.useEffect.call(void 0, () => {
6108
+ queryClient.resetQueries();
6109
+ }, [credentials.url]);
6110
+ 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, { storage, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacttooltip.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6111
+ "div",
6112
+ {
6113
+ className: "ups-db",
6114
+ style: { height: "100%", display: "flex", flexDirection: "column" },
6115
+ children: [
6116
+ !hideTabs && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserTabs, {}),
6117
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserInstances, {})
6118
+ ]
6119
+ }
6120
+ ) }) }) }) });
6121
+ };
6122
+ var DatabrowserInstances = () => {
6123
+ const { tabs, selectedTab, addTab } = useDatabrowserStore();
6124
+ _react.useEffect.call(void 0, () => {
6125
+ if (tabs.length === 0) addTab();
6126
+ }, [tabs]);
6127
+ return tabs.map(([id]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdProvider, { value: id, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserInstance, { hidden: id !== selectedTab }) }, id));
5693
6128
  };
5694
6129
 
5695
6130