@upstash/react-redis-browser 0.1.6 → 0.1.7

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.mjs CHANGED
@@ -2808,7 +2808,7 @@ function formatTime(seconds) {
2808
2808
  if (parts.length === 0) {
2809
2809
  parts.push("0s");
2810
2810
  }
2811
- return parts.slice(0, 2).join(" ");
2811
+ return parts.slice(0, 1).join(" ");
2812
2812
  }
2813
2813
 
2814
2814
  // src/components/ui/toast.tsx
@@ -2923,6 +2923,20 @@ import {
2923
2923
  } from "react";
2924
2924
  import { useInfiniteQuery } from "@tanstack/react-query";
2925
2925
 
2926
+ // src/components/databrowser/hooks/use-fetch-key-type.tsx
2927
+ import { useQuery } from "@tanstack/react-query";
2928
+ var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
2929
+ var useFetchKeyType = (key) => {
2930
+ const { redisNoPipeline: redis } = useDatabrowser();
2931
+ return useQuery({
2932
+ queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key],
2933
+ queryFn: async () => {
2934
+ if (!key) return "none";
2935
+ return await redis.type(key);
2936
+ }
2937
+ });
2938
+ };
2939
+
2926
2940
  // src/components/databrowser/hooks/use-fetch-keys.ts
2927
2941
  import { useCallback, useRef } from "react";
2928
2942
 
@@ -3050,6 +3064,8 @@ var KeysContext = createContext2(void 0);
3050
3064
  var FETCH_KEYS_QUERY_KEY = "use-fetch-keys";
3051
3065
  var KeysProvider = ({ children }) => {
3052
3066
  const { search } = useDatabrowserStore();
3067
+ const cleanSearchKey = search.key.replace("*", "");
3068
+ const { data: exactMatchType } = useFetchKeyType(cleanSearchKey);
3053
3069
  const { fetchKeys, resetCache } = useFetchKeys(search);
3054
3070
  const pageRef = useRef2(0);
3055
3071
  const query = useInfiniteQuery({
@@ -3072,6 +3088,9 @@ var KeysProvider = ({ children }) => {
3072
3088
  }, [query, resetCache]);
3073
3089
  const keys = useMemo2(() => {
3074
3090
  const keys2 = query.data?.pages.flatMap((page) => page.keys) ?? [];
3091
+ if (exactMatchType && exactMatchType !== "none" && (search.type === void 0 || search.type === exactMatchType)) {
3092
+ keys2.push([cleanSearchKey, exactMatchType]);
3093
+ }
3075
3094
  const keysSet = /* @__PURE__ */ new Set();
3076
3095
  const dedupedKeys = [];
3077
3096
  for (const key of keys2) {
@@ -3080,7 +3099,7 @@ var KeysProvider = ({ children }) => {
3080
3099
  dedupedKeys.push(key);
3081
3100
  }
3082
3101
  return dedupedKeys;
3083
- }, [query.data]);
3102
+ }, [query.data, cleanSearchKey, exactMatchType]);
3084
3103
  return /* @__PURE__ */ jsx4(
3085
3104
  KeysContext.Provider,
3086
3105
  {
@@ -3154,7 +3173,7 @@ Button.displayName = "Button";
3154
3173
  import { useMutation } from "@tanstack/react-query";
3155
3174
 
3156
3175
  // src/components/databrowser/components/sidebar/db-size.tsx
3157
- import { useQuery } from "@tanstack/react-query";
3176
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
3158
3177
 
3159
3178
  // src/components/ui/skeleton.tsx
3160
3179
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -3173,7 +3192,7 @@ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
3173
3192
  var FETCH_DB_SIZE_QUERY_KEY = "fetch-db-size";
3174
3193
  var DisplayDbSize = () => {
3175
3194
  const { redis } = useDatabrowser();
3176
- const { data: keyCount } = useQuery({
3195
+ const { data: keyCount } = useQuery2({
3177
3196
  queryKey: [FETCH_DB_SIZE_QUERY_KEY],
3178
3197
  queryFn: async () => {
3179
3198
  return await redis.dbsize();
@@ -3270,76 +3289,6 @@ import { useMutation as useMutation2 } from "@tanstack/react-query";
3270
3289
  // src/components/databrowser/hooks/use-delete-key-cache.ts
3271
3290
  import { useCallback as useCallback3 } from "react";
3272
3291
 
3273
- // src/components/databrowser/hooks/use-fetch-simple-key.tsx
3274
- import { useQuery as useQuery2 } from "@tanstack/react-query";
3275
- var FETCH_SIMPLE_KEY_QUERY_KEY = "fetch-simple-key";
3276
- var useFetchSimpleKey = (dataKey, type) => {
3277
- const { redisNoPipeline: redis } = useDatabrowser();
3278
- const { deleteKeyCache } = useDeleteKeyCache();
3279
- return useQuery2({
3280
- queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey],
3281
- queryFn: async () => {
3282
- let result;
3283
- if (type === "string") result = await redis.get(dataKey);
3284
- else if (type === "json") result = await redis.json.get(dataKey);
3285
- else throw new Error(`Invalid type when fetching simple key: ${type}`);
3286
- if (type === "json" && result !== null)
3287
- result = JSON.stringify(sortObject(JSON.parse(result)));
3288
- if (result === null) deleteKeyCache(dataKey);
3289
- return result;
3290
- }
3291
- });
3292
- };
3293
- var sortObject = (obj) => {
3294
- if (typeof obj !== "object" || obj === null) return obj;
3295
- return Object.fromEntries(
3296
- Object.entries(obj).sort((a, b) => a[0].localeCompare(b[0])).map(
3297
- ([key, value]) => typeof value === "object" && !Array.isArray(value) && value !== null ? [key, sortObject(value)] : [key, value]
3298
- )
3299
- );
3300
- };
3301
-
3302
- // src/components/databrowser/hooks/use-delete-key-cache.ts
3303
- var useDeleteKeyCache = () => {
3304
- const { setSelectedKey } = useDatabrowserStore();
3305
- const { refetch } = useKeys();
3306
- const deleteKeyCache = useCallback3(
3307
- (key) => {
3308
- setSelectedKey(void 0);
3309
- queryClient.invalidateQueries({
3310
- queryKey: [FETCH_KEYS_QUERY_KEY]
3311
- });
3312
- queryClient.invalidateQueries({
3313
- queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, key]
3314
- });
3315
- refetch();
3316
- },
3317
- [setSelectedKey, refetch]
3318
- );
3319
- return { deleteKeyCache };
3320
- };
3321
-
3322
- // src/components/databrowser/hooks/use-delete-key.ts
3323
- var useDeleteKey = () => {
3324
- const { redis } = useDatabrowser();
3325
- const { deleteKeyCache } = useDeleteKeyCache();
3326
- const deleteKey = useMutation2({
3327
- mutationFn: async (key) => {
3328
- return Boolean(await redis.del(key));
3329
- },
3330
- onSuccess: (_, key) => {
3331
- deleteKeyCache(key);
3332
- queryClient.invalidateQueries({
3333
- queryKey: [FETCH_DB_SIZE_QUERY_KEY]
3334
- });
3335
- }
3336
- });
3337
- return deleteKey;
3338
- };
3339
-
3340
- // src/components/databrowser/hooks/use-edit-list-item.tsx
3341
- import { useMutation as useMutation3 } from "@tanstack/react-query";
3342
-
3343
3292
  // src/components/databrowser/hooks/use-fetch-list-items.tsx
3344
3293
  import { useInfiniteQuery as useInfiniteQuery2 } from "@tanstack/react-query";
3345
3294
  var LIST_DISPLAY_PAGE_SIZE = 50;
@@ -3365,13 +3314,15 @@ var useFetchListItems = ({ dataKey, type }) => {
3365
3314
  enabled: type === "zset",
3366
3315
  queryKey: [FETCH_LIST_ITEMS_QUERY_KEY, dataKey, "zset"],
3367
3316
  initialPageParam: 0,
3368
- queryFn: async ({ pageParam: lastIndex }) => {
3369
- const res = await redis.zrange(dataKey, lastIndex, lastIndex + LIST_DISPLAY_PAGE_SIZE - 1, {
3317
+ queryFn: async ({ pageParam: page }) => {
3318
+ const start = page * LIST_DISPLAY_PAGE_SIZE;
3319
+ const end = start + LIST_DISPLAY_PAGE_SIZE - 1;
3320
+ const res = await redis.zrange(dataKey, start, end, {
3370
3321
  withScores: true,
3371
3322
  rev: true
3372
3323
  });
3373
3324
  return {
3374
- cursor: res.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : lastIndex + LIST_DISPLAY_PAGE_SIZE,
3325
+ cursor: res.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : page + 1,
3375
3326
  keys: transformArray(res)
3376
3327
  };
3377
3328
  },
@@ -3396,13 +3347,14 @@ var useFetchListItems = ({ dataKey, type }) => {
3396
3347
  enabled: type === "list",
3397
3348
  queryKey: [FETCH_LIST_ITEMS_QUERY_KEY, dataKey, "list"],
3398
3349
  initialPageParam: 0,
3399
- queryFn: async ({ pageParam }) => {
3400
- const lastIndex = Number(pageParam);
3401
- const values = await redis.lrange(dataKey, lastIndex, lastIndex + LIST_DISPLAY_PAGE_SIZE);
3350
+ queryFn: async ({ pageParam: page }) => {
3351
+ const start = page * LIST_DISPLAY_PAGE_SIZE;
3352
+ const end = start + LIST_DISPLAY_PAGE_SIZE - 1;
3353
+ const values = await redis.lrange(dataKey, start, end);
3402
3354
  return {
3403
- cursor: values.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : lastIndex + LIST_DISPLAY_PAGE_SIZE,
3355
+ cursor: values.length < LIST_DISPLAY_PAGE_SIZE ? void 0 : page + 1,
3404
3356
  keys: values.map((value, i) => ({
3405
- key: (lastIndex + i).toString(),
3357
+ key: (start + i).toString(),
3406
3358
  value
3407
3359
  }))
3408
3360
  };
@@ -3453,7 +3405,81 @@ function transformArray(inputArray) {
3453
3405
  }, []);
3454
3406
  }
3455
3407
 
3408
+ // src/components/databrowser/hooks/use-fetch-simple-key.tsx
3409
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
3410
+ var FETCH_SIMPLE_KEY_QUERY_KEY = "fetch-simple-key";
3411
+ var useFetchSimpleKey = (dataKey, type) => {
3412
+ const { redisNoPipeline: redis } = useDatabrowser();
3413
+ const { deleteKeyCache } = useDeleteKeyCache();
3414
+ return useQuery3({
3415
+ queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey],
3416
+ queryFn: async () => {
3417
+ let result;
3418
+ if (type === "string") result = await redis.get(dataKey);
3419
+ else if (type === "json") result = await redis.json.get(dataKey);
3420
+ else throw new Error(`Invalid type when fetching simple key: ${type}`);
3421
+ if (type === "json" && result !== null)
3422
+ result = JSON.stringify(sortObject(JSON.parse(result)));
3423
+ if (result === null) deleteKeyCache(dataKey);
3424
+ return result;
3425
+ }
3426
+ });
3427
+ };
3428
+ var sortObject = (obj) => {
3429
+ if (typeof obj !== "object" || obj === null) return obj;
3430
+ return Object.fromEntries(
3431
+ Object.entries(obj).sort((a, b) => a[0].localeCompare(b[0])).map(
3432
+ ([key, value]) => typeof value === "object" && !Array.isArray(value) && value !== null ? [key, sortObject(value)] : [key, value]
3433
+ )
3434
+ );
3435
+ };
3436
+
3437
+ // src/components/databrowser/hooks/use-delete-key-cache.ts
3438
+ var useDeleteKeyCache = () => {
3439
+ const { setSelectedKey } = useDatabrowserStore();
3440
+ const { refetch } = useKeys();
3441
+ const deleteKeyCache = useCallback3(
3442
+ (key) => {
3443
+ setSelectedKey(void 0);
3444
+ queryClient.invalidateQueries({
3445
+ queryKey: [FETCH_KEYS_QUERY_KEY]
3446
+ });
3447
+ queryClient.invalidateQueries({
3448
+ queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, key]
3449
+ });
3450
+ queryClient.invalidateQueries({
3451
+ queryKey: [FETCH_LIST_ITEMS_QUERY_KEY, key]
3452
+ });
3453
+ queryClient.invalidateQueries({
3454
+ queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key]
3455
+ });
3456
+ refetch();
3457
+ },
3458
+ [setSelectedKey, refetch]
3459
+ );
3460
+ return { deleteKeyCache };
3461
+ };
3462
+
3463
+ // src/components/databrowser/hooks/use-delete-key.ts
3464
+ var useDeleteKey = () => {
3465
+ const { redis } = useDatabrowser();
3466
+ const { deleteKeyCache } = useDeleteKeyCache();
3467
+ const deleteKey = useMutation2({
3468
+ mutationFn: async (key) => {
3469
+ return Boolean(await redis.del(key));
3470
+ },
3471
+ onSuccess: (_, key) => {
3472
+ deleteKeyCache(key);
3473
+ queryClient.invalidateQueries({
3474
+ queryKey: [FETCH_DB_SIZE_QUERY_KEY]
3475
+ });
3476
+ }
3477
+ });
3478
+ return deleteKey;
3479
+ };
3480
+
3456
3481
  // src/components/databrowser/hooks/use-edit-list-item.tsx
3482
+ import { useMutation as useMutation3 } from "@tanstack/react-query";
3457
3483
  var useEditListItem = () => {
3458
3484
  const { redis } = useDatabrowser();
3459
3485
  return useMutation3({
@@ -3534,914 +3560,940 @@ var useEditListItem = () => {
3534
3560
  };
3535
3561
 
3536
3562
  // src/components/databrowser/hooks/use-fetch-ttl.ts
3537
- import { useEffect as useEffect3 } from "react";
3538
- import { useQuery as useQuery3 } from "@tanstack/react-query";
3539
- var FETCH_TTL_QUERY_KEY = "fetch-ttl";
3540
- var useFetchTTL = (dataKey) => {
3563
+ import { useEffect as useEffect5 } from "react";
3564
+ import { useQuery as useQuery6 } from "@tanstack/react-query";
3565
+
3566
+ // src/components/databrowser/components/display/ttl-badge.tsx
3567
+ import { useEffect as useEffect4, useState as useState5 } from "react";
3568
+ import { IconChevronDown } from "@tabler/icons-react";
3569
+
3570
+ // src/components/databrowser/components/display/header-badges.tsx
3571
+ import bytes from "bytes";
3572
+
3573
+ // src/components/databrowser/hooks/use-fetch-key-length.ts
3574
+ import { useQuery as useQuery4 } from "@tanstack/react-query";
3575
+ var FETCH_KEY_LENGTH_QUERY_KEY = "fetch-key-length";
3576
+ var useFetchKeyLength = ({ dataKey, type }) => {
3541
3577
  const { redis } = useDatabrowser();
3542
- const { isLoading, error, data } = useQuery3({
3543
- queryKey: [FETCH_TTL_QUERY_KEY, dataKey],
3578
+ return useQuery4({
3579
+ queryKey: [FETCH_KEY_LENGTH_QUERY_KEY, dataKey],
3544
3580
  queryFn: async () => {
3545
- return await redis.ttl(dataKey);
3581
+ switch (type) {
3582
+ case "set": {
3583
+ return await redis.scard(dataKey);
3584
+ }
3585
+ case "zset": {
3586
+ return await redis.zcard(dataKey);
3587
+ }
3588
+ case "list": {
3589
+ return await redis.llen(dataKey);
3590
+ }
3591
+ case "hash": {
3592
+ return await redis.hlen(dataKey);
3593
+ }
3594
+ case "stream": {
3595
+ return await redis.xlen(dataKey);
3596
+ }
3597
+ }
3598
+ return null;
3546
3599
  }
3547
3600
  });
3548
- useEffect3(() => {
3549
- if (data === -2) {
3550
- queryClient.invalidateQueries({
3551
- queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
3552
- });
3553
- }
3554
- }, [data === -2]);
3555
- return { isLoading, error, data };
3556
3601
  };
3557
3602
 
3558
- // src/components/databrowser/hooks/use-set-simple-key.tsx
3559
- import { useMutation as useMutation4 } from "@tanstack/react-query";
3560
- var useSetSimpleKey = (dataKey, type) => {
3603
+ // src/components/databrowser/hooks/use-fetch-key-size.ts
3604
+ import { useQuery as useQuery5 } from "@tanstack/react-query";
3605
+ var FETCH_KEY_SIZE_QUERY_KEY = "fetch-key-size";
3606
+ var useFetchKeySize = (dataKey) => {
3561
3607
  const { redis } = useDatabrowser();
3562
- return useMutation4({
3563
- mutationFn: async (value) => {
3564
- if (type === "string") {
3565
- await redis.set(dataKey, value);
3566
- } else if (type === "json") {
3567
- await redis.json.set(dataKey, "$", JSON.parse(value));
3568
- } else {
3569
- throw new Error(`Invalid type when setting simple key: ${type}`);
3570
- }
3571
- },
3572
- onSuccess: (_, value) => {
3573
- queryClient.setQueryData([FETCH_SIMPLE_KEY_QUERY_KEY, dataKey], value);
3574
- queryClient.invalidateQueries({
3575
- queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
3576
- });
3608
+ return useQuery5({
3609
+ queryKey: [FETCH_KEY_SIZE_QUERY_KEY, dataKey],
3610
+ queryFn: async () => {
3611
+ return await redis.eval(`return redis.call("MEMORY", "USAGE", KEYS[1])`, [dataKey], []);
3577
3612
  }
3578
3613
  });
3579
3614
  };
3580
3615
 
3581
- // src/components/databrowser/hooks/use-set-ttl.ts
3582
- import { useMutation as useMutation5 } from "@tanstack/react-query";
3583
- var useSetTTL = () => {
3584
- const { redis } = useDatabrowser();
3585
- const updateTTL = useMutation5({
3586
- mutationFn: async ({ dataKey, ttl }) => {
3587
- await (ttl === void 0 ? redis.persist(dataKey) : redis.expire(dataKey, ttl));
3588
- },
3589
- onSuccess: (_, { dataKey }) => {
3590
- queryClient.invalidateQueries({
3591
- queryKey: [FETCH_TTL_QUERY_KEY, dataKey]
3592
- });
3593
- queryClient.invalidateQueries({
3594
- queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
3595
- });
3616
+ // src/components/databrowser/components/display/header-badges.tsx
3617
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
3618
+ var LengthBadge = ({
3619
+ dataKey,
3620
+ type,
3621
+ content
3622
+ }) => {
3623
+ const { data, isLoading } = useFetchKeyLength({ dataKey, type });
3624
+ const length = content?.length ?? data;
3625
+ return /* @__PURE__ */ jsx8(Badge, { label: "Length:", children: isLoading ? /* @__PURE__ */ jsx8(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : length });
3626
+ };
3627
+ var SizeBadge = ({ dataKey }) => {
3628
+ const { data: size } = useFetchKeySize(dataKey);
3629
+ return /* @__PURE__ */ jsx8(Badge, { label: "Size:", children: size === void 0 || size === null ? /* @__PURE__ */ jsx8(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : bytes(size, {
3630
+ unitSeparator: " "
3631
+ }) });
3632
+ };
3633
+ var HeaderTTLBadge = ({ dataKey }) => {
3634
+ const { data: expireAt } = useFetchKeyExpire(dataKey);
3635
+ const { mutate: setTTL, isPending } = useSetTTL();
3636
+ return /* @__PURE__ */ jsx8(
3637
+ TTLBadge,
3638
+ {
3639
+ expireAt,
3640
+ setTTL: (ttl) => setTTL({ dataKey, ttl }),
3641
+ isPending
3596
3642
  }
3597
- });
3598
- return updateTTL;
3643
+ );
3599
3644
  };
3645
+ var Badge = ({ children, label }) => /* @__PURE__ */ jsxs3("div", { className: "flex h-6 items-center gap-0.5 rounded-md bg-white px-2 text-xs text-zinc-700", children: [
3646
+ /* @__PURE__ */ jsx8("span", { className: "text-zinc-500", children: label }),
3647
+ /* @__PURE__ */ jsx8("span", { className: "font-medium", children })
3648
+ ] });
3600
3649
 
3601
- // src/components/databrowser/components/item-context-menu.tsx
3602
- import { useState as useState4 } from "react";
3603
- import { ContextMenuSeparator as ContextMenuSeparator2 } from "@radix-ui/react-context-menu";
3604
-
3605
- // src/components/ui/context-menu.tsx
3650
+ // src/components/databrowser/components/display/ttl-popover.tsx
3651
+ import { useEffect as useEffect3, useMemo as useMemo3, useState as useState4 } from "react";
3652
+ import { Controller, useForm } from "react-hook-form";
3653
+
3654
+ // src/components/ui/input.tsx
3606
3655
  import * as React4 from "react";
3607
- import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
3608
- import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons";
3609
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
3610
- var ContextMenu = ContextMenuPrimitive.Root;
3611
- var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
3612
- var ContextMenuSubTrigger = React4.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
3613
- ContextMenuPrimitive.SubTrigger,
3614
- {
3615
- ref,
3616
- className: cn(
3617
- "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-50",
3618
- inset && "pl-8",
3619
- className
3620
- ),
3621
- ...props,
3622
- children: [
3623
- children,
3624
- /* @__PURE__ */ jsx8(ChevronRightIcon, { className: "ml-auto h-4 w-4" })
3625
- ]
3626
- }
3627
- ));
3628
- ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
3629
- var ContextMenuSubContent = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
3630
- ContextMenuPrimitive.SubContent,
3631
- {
3632
- ref,
3633
- className: cn(
3634
- "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",
3635
- className
3636
- ),
3637
- ...props
3656
+ import { jsx as jsx9 } from "react/jsx-runtime";
3657
+ var Input = React4.forwardRef(
3658
+ ({ className, type, ...props }, ref) => {
3659
+ return /* @__PURE__ */ jsx9(
3660
+ "input",
3661
+ {
3662
+ type,
3663
+ className: cn(
3664
+ "flex h-8 w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
3665
+ className
3666
+ ),
3667
+ ref,
3668
+ ...props
3669
+ }
3670
+ );
3638
3671
  }
3639
- ));
3640
- ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
3641
- var ContextMenuContent = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(ContextMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx8(
3642
- ContextMenuPrimitive.Content,
3672
+ );
3673
+ Input.displayName = "Input";
3674
+
3675
+ // src/components/ui/popover.tsx
3676
+ import * as React5 from "react";
3677
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
3678
+ import { jsx as jsx10 } from "react/jsx-runtime";
3679
+ var Popover = PopoverPrimitive.Root;
3680
+ var PopoverTrigger = PopoverPrimitive.Trigger;
3681
+ var PopoverContent = React5.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx10(PopoverPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx10(
3682
+ PopoverPrimitive.Content,
3643
3683
  {
3644
3684
  ref,
3685
+ align,
3686
+ sideOffset,
3645
3687
  className: cn(
3646
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md 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",
3688
+ "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 z-50 w-72 rounded-md border border-zinc-200 bg-white p-4 text-zinc-950 shadow-md outline-none dark:border-zinc-800 mt-0.5 dark:bg-zinc-950 dark:text-zinc-50",
3647
3689
  className
3648
3690
  ),
3649
3691
  ...props
3650
3692
  }
3651
3693
  ) }));
3652
- ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
3653
- var ContextMenuItem = React4.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx8(
3654
- ContextMenuPrimitive.Item,
3655
- {
3656
- ref,
3657
- className: cn(
3658
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
3659
- inset && "pl-8",
3660
- className
3661
- ),
3662
- ...props
3663
- }
3664
- ));
3665
- ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
3666
- var ContextMenuCheckboxItem = React4.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs3(
3667
- ContextMenuPrimitive.CheckboxItem,
3694
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3695
+
3696
+ // src/components/ui/select.tsx
3697
+ import * as React6 from "react";
3698
+ import * as SelectPrimitive from "@radix-ui/react-select";
3699
+ import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
3700
+ var Select = SelectPrimitive.Root;
3701
+ var SelectGroup = SelectPrimitive.Group;
3702
+ var SelectValue = SelectPrimitive.Value;
3703
+ var SelectTrigger = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
3704
+ SelectPrimitive.Trigger,
3668
3705
  {
3669
3706
  ref,
3670
3707
  className: cn(
3671
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
3708
+ "relative flex h-8 w-full items-center justify-between rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-zinc-500 focus:ring-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-800 dark:bg-zinc-950 dark:ring-offset-zinc-950 dark:placeholder:text-zinc-400 dark:focus:ring-zinc-300",
3672
3709
  className
3673
3710
  ),
3674
- checked,
3675
3711
  ...props,
3676
3712
  children: [
3677
- /* @__PURE__ */ jsx8("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx8(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx8(CheckIcon, { className: "h-4 w-4" }) }) }),
3678
- children
3713
+ children,
3714
+ /* @__PURE__ */ jsx11(SelectPrimitive.Icon, { asChild: true, className: "absolute right-2", children: /* @__PURE__ */ jsx11(
3715
+ "svg",
3716
+ {
3717
+ width: "16",
3718
+ height: "16",
3719
+ viewBox: "0 0 16 16",
3720
+ fill: "none",
3721
+ xmlns: "http://www.w3.org/2000/svg",
3722
+ children: /* @__PURE__ */ jsx11(
3723
+ "path",
3724
+ {
3725
+ d: "M4 6L8 10L12 6",
3726
+ stroke: "black",
3727
+ strokeOpacity: "0.4",
3728
+ strokeWidth: "1.4",
3729
+ strokeLinecap: "round",
3730
+ strokeLinejoin: "round"
3731
+ }
3732
+ )
3733
+ }
3734
+ ) })
3679
3735
  ]
3680
3736
  }
3681
3737
  ));
3682
- ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
3683
- var ContextMenuRadioItem = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
3684
- ContextMenuPrimitive.RadioItem,
3738
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
3739
+ var SelectContent = React6.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx11(SelectPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx11(
3740
+ SelectPrimitive.Content,
3685
3741
  {
3686
3742
  ref,
3687
3743
  className: cn(
3688
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
3744
+ "relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-200 bg-white text-zinc-950 shadow-md 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-zinc-800 dark:bg-zinc-950 dark:text-neutral-50",
3745
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
3689
3746
  className
3690
3747
  ),
3748
+ position,
3691
3749
  ...props,
3692
- children: [
3693
- /* @__PURE__ */ jsx8("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx8(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx8(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
3694
- children
3695
- ]
3750
+ children: /* @__PURE__ */ jsx11(
3751
+ SelectPrimitive.Viewport,
3752
+ {
3753
+ className: cn(
3754
+ "p-1",
3755
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
3756
+ ),
3757
+ children
3758
+ }
3759
+ )
3696
3760
  }
3697
- ));
3698
- ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
3699
- var ContextMenuLabel = React4.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx8(
3700
- ContextMenuPrimitive.Label,
3761
+ ) }));
3762
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
3763
+ var SelectLabel = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
3764
+ SelectPrimitive.Label,
3701
3765
  {
3702
3766
  ref,
3703
- className: cn(
3704
- "px-2 py-1.5 text-sm font-semibold text-neutral-950 dark:text-neutral-50",
3705
- inset && "pl-8",
3706
- className
3707
- ),
3767
+ className: cn("px-2 py-1.5 text-sm font-semibold", className),
3708
3768
  ...props
3709
3769
  }
3710
3770
  ));
3711
- ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
3712
- var ContextMenuSeparator = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
3713
- ContextMenuPrimitive.Separator,
3771
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
3772
+ var SelectItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
3773
+ SelectPrimitive.Item,
3714
3774
  {
3715
3775
  ref,
3716
- className: cn("-mx-1 my-1 h-px bg-neutral-200 dark:bg-neutral-800", className),
3717
- ...props
3718
- }
3719
- ));
3720
- ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
3721
- var ContextMenuShortcut = ({ className, ...props }) => {
3722
- return /* @__PURE__ */ jsx8(
3723
- "span",
3724
- {
3725
- className: cn(
3726
- "ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400",
3727
- className
3728
- ),
3729
- ...props
3730
- }
3731
- );
3732
- };
3733
- ContextMenuShortcut.displayName = "ContextMenuShortcut";
3734
-
3735
- // src/components/ui/alert-dialog.tsx
3736
- import * as React5 from "react";
3737
- import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
3738
- import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
3739
- var AlertDialog = AlertDialogPrimitive.Root;
3740
- var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
3741
- var AlertDialogPortal = ({ ...props }) => /* @__PURE__ */ jsx9(AlertDialogPrimitive.Portal, { container: portalRoot, ...props });
3742
- AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName;
3743
- var AlertDialogOverlay = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
3744
- AlertDialogPrimitive.Overlay,
3745
- {
3746
3776
  className: cn(
3747
- "fixed inset-0 z-50 bg-white/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 dark:bg-zinc-950/80",
3777
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
3748
3778
  className
3749
3779
  ),
3750
3780
  ...props,
3751
- ref
3752
- }
3753
- ));
3754
- AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
3755
- var AlertDialogContent = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs4(AlertDialogPortal, { children: [
3756
- /* @__PURE__ */ jsx9(AlertDialogOverlay, {}),
3757
- /* @__PURE__ */ jsx9(
3758
- AlertDialogPrimitive.Content,
3759
- {
3760
- ref,
3761
- className: cn(
3762
- "antialiased data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-zinc-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] dark:border-zinc-800 dark:bg-zinc-950 sm:rounded-lg md:w-full",
3763
- className
3764
- ),
3765
- ...props
3766
- }
3767
- )
3768
- ] }));
3769
- AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
3770
- var AlertDialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx9("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props });
3771
- AlertDialogHeader.displayName = "AlertDialogHeader";
3772
- var AlertDialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx9(
3773
- "div",
3774
- {
3775
- className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
3776
- ...props
3777
- }
3778
- );
3779
- AlertDialogFooter.displayName = "AlertDialogFooter";
3780
- var AlertDialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
3781
- AlertDialogPrimitive.Title,
3782
- {
3783
- ref,
3784
- className: cn("text-lg font-semibold", className),
3785
- ...props
3786
- }
3787
- ));
3788
- AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
3789
- var AlertDialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
3790
- AlertDialogPrimitive.Description,
3791
- {
3792
- ref,
3793
- className: cn("text-sm text-zinc-500 dark:text-zinc-400", className),
3794
- ...props
3781
+ children: [
3782
+ /* @__PURE__ */ jsx11("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx11(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx11(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx11(
3783
+ "svg",
3784
+ {
3785
+ width: "15",
3786
+ height: "15",
3787
+ viewBox: "0 0 15 15",
3788
+ fill: "none",
3789
+ xmlns: "http://www.w3.org/2000/svg",
3790
+ className: "h-4 w-4",
3791
+ children: /* @__PURE__ */ jsx11(
3792
+ "path",
3793
+ {
3794
+ d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
3795
+ fill: "currentColor",
3796
+ fillRule: "evenodd",
3797
+ clipRule: "evenodd"
3798
+ }
3799
+ )
3800
+ }
3801
+ ) }) }) }),
3802
+ /* @__PURE__ */ jsx11(SelectPrimitive.ItemText, { children })
3803
+ ]
3795
3804
  }
3796
3805
  ));
3797
- AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
3798
- var AlertDialogAction = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(AlertDialogPrimitive.Action, { ref, className: cn(buttonVariants(), className), ...props }));
3799
- AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
3800
- var AlertDialogCancel = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
3801
- AlertDialogPrimitive.Cancel,
3806
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
3807
+ var SelectSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
3808
+ SelectPrimitive.Separator,
3802
3809
  {
3803
3810
  ref,
3804
- className: cn(buttonVariants({ variant: "outline" }), "mt-2 sm:!mt-0", className),
3811
+ className: cn("-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-800", className),
3805
3812
  ...props
3806
3813
  }
3807
3814
  ));
3808
- AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
3815
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
3809
3816
 
3810
- // src/components/databrowser/components/display/delete-alert-dialog.tsx
3811
- import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
3812
- function DeleteAlertDialog({
3813
- children,
3814
- onDeleteConfirm,
3815
- open,
3816
- onOpenChange,
3817
- deletionType
3818
- }) {
3819
- return /* @__PURE__ */ jsxs5(AlertDialog, { open, onOpenChange, children: [
3820
- children && /* @__PURE__ */ jsx10(AlertDialogTrigger, { asChild: true, children }),
3821
- /* @__PURE__ */ jsxs5(AlertDialogContent, { children: [
3822
- /* @__PURE__ */ jsxs5(AlertDialogHeader, { children: [
3823
- /* @__PURE__ */ jsx10(AlertDialogTitle, { children: deletionType === "item" ? "Delete Item" : "Delete Key" }),
3824
- /* @__PURE__ */ jsxs5(AlertDialogDescription, { className: "mt-5", children: [
3825
- "Are you sure you want to delete this ",
3826
- deletionType,
3827
- "?",
3828
- /* @__PURE__ */ jsx10("br", {}),
3829
- "This action cannot be undone."
3830
- ] })
3831
- ] }),
3832
- /* @__PURE__ */ jsxs5(AlertDialogFooter, { children: [
3833
- /* @__PURE__ */ jsx10(AlertDialogCancel, { type: "button", children: "Cancel" }),
3834
- /* @__PURE__ */ jsx10(
3835
- AlertDialogAction,
3836
- {
3837
- className: "bg-red-500 text-gray-50 hover:bg-red-600",
3838
- onClick: onDeleteConfirm,
3839
- children: "Yes, Delete"
3840
- }
3841
- )
3842
- ] })
3843
- ] })
3844
- ] });
3845
- }
3846
-
3847
- // src/components/databrowser/components/item-context-menu.tsx
3848
- import { Fragment, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
3849
- var ItemContextMenu = ({
3850
- children,
3851
- dataKey,
3852
- type
3817
+ // src/components/ui/spinner.tsx
3818
+ import { Fragment, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
3819
+ var Spinner = ({
3820
+ isLoading,
3821
+ className,
3822
+ isLoadingText,
3823
+ children
3853
3824
  }) => {
3854
- const { mutate: editItem } = useEditListItem();
3855
- const [isAlertOpen, setAlertOpen] = useState4(false);
3856
- const [data, setData] = useState4();
3857
- return /* @__PURE__ */ jsxs6(Fragment, { children: [
3858
- /* @__PURE__ */ jsx11(
3859
- DeleteAlertDialog,
3860
- {
3861
- deletionType: "item",
3862
- open: isAlertOpen,
3863
- onOpenChange: setAlertOpen,
3864
- onDeleteConfirm: (e) => {
3865
- e.stopPropagation();
3866
- if (data) {
3867
- editItem({
3868
- type,
3869
- dataKey,
3870
- itemKey: data?.key,
3871
- // For deletion
3872
- newKey: void 0
3873
- });
3874
- }
3875
- setAlertOpen(false);
3876
- }
3877
- }
3878
- ),
3879
- /* @__PURE__ */ jsxs6(ContextMenu, { children: [
3880
- /* @__PURE__ */ jsx11(
3881
- ContextMenuTrigger,
3882
- {
3883
- asChild: true,
3884
- onContextMenu: (e) => {
3885
- const el = e.target;
3886
- const item = el.closest("[data-item-key]");
3887
- if (item && item instanceof HTMLElement && item.dataset.itemKey !== void 0) {
3888
- setData({
3889
- key: item.dataset.itemKey,
3890
- value: item.dataset.itemValue
3891
- });
3892
- } else {
3893
- throw new Error("Key not found");
3894
- }
3895
- },
3896
- children
3897
- }
3898
- ),
3899
- /* @__PURE__ */ jsxs6(ContextMenuContent, { children: [
3900
- /* @__PURE__ */ jsx11(
3901
- ContextMenuItem,
3902
- {
3903
- onClick: () => {
3904
- if (!data) return;
3905
- navigator.clipboard.writeText(data?.key);
3906
- toast({
3907
- description: "Key copied to clipboard"
3908
- });
3909
- },
3910
- children: "Copy key"
3911
- }
3912
- ),
3913
- data?.value && /* @__PURE__ */ jsx11(
3914
- ContextMenuItem,
3915
- {
3916
- onClick: () => {
3917
- navigator.clipboard.writeText(data?.value ?? "");
3918
- toast({
3919
- description: "Value copied to clipboard"
3920
- });
3921
- },
3922
- children: "Copy value"
3923
- }
3924
- ),
3925
- /* @__PURE__ */ jsx11(ContextMenuSeparator2, {}),
3926
- /* @__PURE__ */ jsx11(ContextMenuItem, { disabled: type === "stream", onClick: () => setAlertOpen(true), children: "Delete item" })
3927
- ] })
3928
- ] })
3929
- ] });
3930
- };
3931
-
3932
- // src/components/databrowser/components/sidebar/infinite-scroll.tsx
3933
- import { IconLoader2 } from "@tabler/icons-react";
3934
-
3935
- // src/components/ui/scroll-area.tsx
3936
- import * as React6 from "react";
3937
- import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
3938
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
3939
- var ScrollArea = React6.forwardRef(({ className, children, onScroll, ...props }, ref) => /* @__PURE__ */ jsxs7(
3940
- ScrollAreaPrimitive.Root,
3941
- {
3942
- ref,
3943
- className: cn("relative overflow-hidden", className),
3944
- ...props,
3945
- children: [
3946
- /* @__PURE__ */ jsx12(
3947
- ScrollAreaPrimitive.Viewport,
3948
- {
3949
- onScroll,
3950
- className: "h-full w-full rounded-[inherit] [&>div]:!block",
3951
- children
3952
- }
3953
- ),
3954
- /* @__PURE__ */ jsx12(ScrollBar, {}),
3955
- /* @__PURE__ */ jsx12(ScrollAreaPrimitive.Corner, {})
3956
- ]
3957
- }
3958
- ));
3959
- ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
3960
- var ScrollBar = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
3961
- ScrollAreaPrimitive.ScrollAreaScrollbar,
3962
- {
3963
- ref,
3964
- orientation: "vertical",
3965
- className: cn("flex h-full w-2 touch-none select-none transition-colors", className),
3966
- ...props,
3967
- children: /* @__PURE__ */ jsx12(
3968
- ScrollAreaPrimitive.ScrollAreaThumb,
3825
+ return /* @__PURE__ */ jsx12("div", { className: className ?? "flex items-center", children: isLoading ? /* @__PURE__ */ jsxs5(Fragment, { children: [
3826
+ isLoadingText,
3827
+ /* @__PURE__ */ jsx12(
3828
+ "svg",
3969
3829
  {
3970
- className: cn("relative flex-1 rounded-full bg-neutral-200/70 dark:bg-neutral-800")
3830
+ xmlns: "http://www.w3.org/2000/svg",
3831
+ width: "24",
3832
+ height: "24",
3833
+ viewBox: "0 0 24 24",
3834
+ fill: "none",
3835
+ stroke: "currentColor",
3836
+ strokeWidth: "2",
3837
+ strokeLinecap: "round",
3838
+ strokeLinejoin: "round",
3839
+ className: cn("h-4 w-4 animate-spin", isLoadingText ? "ml-2" : ""),
3840
+ children: /* @__PURE__ */ jsx12("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3971
3841
  }
3972
3842
  )
3973
- }
3974
- ));
3975
- ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
3843
+ ] }) : children });
3844
+ };
3976
3845
 
3977
- // src/components/databrowser/components/sidebar/infinite-scroll.tsx
3978
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
3979
- var InfiniteScroll = ({
3980
- query,
3981
- children
3982
- }) => {
3983
- const handleScroll = (e) => {
3984
- const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;
3985
- if (scrollTop + clientHeight > scrollHeight - 100) {
3986
- if (query.isFetching || !query.hasNextPage) {
3987
- return;
3988
- }
3989
- query.fetchNextPage();
3990
- }
3846
+ // src/components/databrowser/components/display/ttl-popover.tsx
3847
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
3848
+ var timeUnits = [
3849
+ { label: "Seconds", value: 1 },
3850
+ { label: "Minutes", value: 60 },
3851
+ { label: "Hours", value: 60 * 60 },
3852
+ { label: "Days", value: 60 * 60 * 24 }
3853
+ ];
3854
+ function TTLPopover({
3855
+ children,
3856
+ ttl,
3857
+ setTTL,
3858
+ isPending
3859
+ }) {
3860
+ const [open, setOpen] = useState4(false);
3861
+ const defaultValues = useMemo3(() => {
3862
+ return { type: "Seconds", value: ttl };
3863
+ }, [ttl]);
3864
+ const { control, handleSubmit, formState, reset } = useForm({
3865
+ defaultValues
3866
+ });
3867
+ useEffect3(() => {
3868
+ reset(defaultValues, {
3869
+ keepValues: true
3870
+ });
3871
+ }, [defaultValues]);
3872
+ const onSubmit = handleSubmit(async ({ value, type }) => {
3873
+ await setTTL(value * timeUnits.find((unit) => unit.label === type).value);
3874
+ setOpen(false);
3875
+ });
3876
+ const handlePersist = async () => {
3877
+ await setTTL(TTL_INFINITE);
3878
+ setOpen(false);
3991
3879
  };
3992
- return /* @__PURE__ */ jsxs8(
3993
- ScrollArea,
3880
+ return /* @__PURE__ */ jsxs6(
3881
+ Popover,
3994
3882
  {
3995
- type: "always",
3996
- className: "block h-full w-full transition-all",
3997
- onScroll: handleScroll,
3883
+ open,
3884
+ onOpenChange: (isOpen) => {
3885
+ if (isOpen) reset();
3886
+ setOpen(isOpen);
3887
+ },
3998
3888
  children: [
3999
- children,
4000
- /* @__PURE__ */ jsx13("div", { className: "flex h-[100px] justify-center py-2 text-zinc-300", children: query.isFetching && /* @__PURE__ */ jsx13(IconLoader2, { className: "animate-spin", size: 16 }) })
3889
+ /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx13("button", { children }) }),
3890
+ /* @__PURE__ */ jsx13(PopoverContent, { className: "w-[300px]", align: "end", children: /* @__PURE__ */ jsxs6(
3891
+ "form",
3892
+ {
3893
+ className: "space-y-4",
3894
+ onSubmit: (e) => {
3895
+ onSubmit(e);
3896
+ e.stopPropagation();
3897
+ },
3898
+ children: [
3899
+ /* @__PURE__ */ jsx13("h4", { className: "font-medium leading-none", children: "Expiration" }),
3900
+ /* @__PURE__ */ jsxs6("div", { children: [
3901
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center", children: [
3902
+ /* @__PURE__ */ jsx13(
3903
+ Controller,
3904
+ {
3905
+ rules: {
3906
+ required: "Please enter an expiration time",
3907
+ min: { value: -1, message: "TTL can't be lower than -1" }
3908
+ },
3909
+ control,
3910
+ name: "value",
3911
+ render: ({ field }) => /* @__PURE__ */ jsx13(Input, { min: "-1", ...field, className: "grow rounded-r-none" })
3912
+ }
3913
+ ),
3914
+ /* @__PURE__ */ jsx13(
3915
+ Controller,
3916
+ {
3917
+ control,
3918
+ name: "type",
3919
+ render: ({ field }) => /* @__PURE__ */ jsxs6(Select, { value: field.value, onValueChange: field.onChange, children: [
3920
+ /* @__PURE__ */ jsx13(SelectTrigger, { className: "w-auto rounded-l-none border-l-0 pr-8", children: /* @__PURE__ */ jsx13(SelectValue, {}) }),
3921
+ /* @__PURE__ */ jsx13(SelectContent, { children: timeUnits.map((unit) => /* @__PURE__ */ jsx13(SelectItem, { value: unit.label, children: unit.label }, unit.label)) })
3922
+ ] })
3923
+ }
3924
+ )
3925
+ ] }),
3926
+ formState.errors.value && /* @__PURE__ */ jsx13("p", { className: "mt-2 text-xs text-red-500", children: formState.errors.value.message }),
3927
+ /* @__PURE__ */ jsx13("p", { className: "mt-2 text-xs text-zinc-500", children: "TTL sets a timer to automatically delete keys after a defined period." })
3928
+ ] }),
3929
+ /* @__PURE__ */ jsxs6("div", { className: "flex justify-between", children: [
3930
+ /* @__PURE__ */ jsx13(
3931
+ Button,
3932
+ {
3933
+ type: "button",
3934
+ variant: "outline",
3935
+ disabled: ttl === TTL_INFINITE,
3936
+ onClick: handlePersist,
3937
+ children: "Persist"
3938
+ }
3939
+ ),
3940
+ /* @__PURE__ */ jsxs6("div", { className: "flex gap-2", children: [
3941
+ /* @__PURE__ */ jsx13(Button, { variant: "outline", onClick: () => setOpen(false), type: "button", children: "Cancel" }),
3942
+ /* @__PURE__ */ jsx13(Button, { variant: "primary", type: "submit", children: /* @__PURE__ */ jsx13(Spinner, { isLoading: isPending, isLoadingText: "Saving", children: "Save" }) })
3943
+ ] })
3944
+ ] })
3945
+ ]
3946
+ }
3947
+ ) })
4001
3948
  ]
4002
3949
  }
4003
3950
  );
4004
- };
4005
-
4006
- // src/components/databrowser/components/display/display-header.tsx
4007
- import { IconPlus } from "@tabler/icons-react";
4008
-
4009
- // src/components/databrowser/components/type-tag.tsx
4010
- import {
4011
- IconArrowsSort,
4012
- IconCodeDots,
4013
- IconHash,
4014
- IconLayersIntersect,
4015
- IconList,
4016
- IconQuote
4017
- } from "@tabler/icons-react";
4018
- import { jsx as jsx14 } from "react/jsx-runtime";
4019
- var iconsMap = {
4020
- string: /* @__PURE__ */ jsx14(IconQuote, { size: 15, stroke: 1.3 }),
4021
- set: /* @__PURE__ */ jsx14(IconLayersIntersect, { size: 15, stroke: 1.3 }),
4022
- hash: /* @__PURE__ */ jsx14(IconHash, { size: 15, stroke: 1.3 }),
4023
- json: /* @__PURE__ */ jsx14(IconCodeDots, { size: 15, stroke: 1.3 }),
4024
- zset: /* @__PURE__ */ jsx14(IconArrowsSort, { size: 15, stroke: 1.3 }),
4025
- list: /* @__PURE__ */ jsx14(IconList, { size: 15, stroke: 1.3 }),
4026
- stream: /* @__PURE__ */ jsx14(IconList, { size: 15, stroke: 1.3 })
4027
- };
4028
- var tagVariants = cva("inline-flex shrink-0 items-center rounded-md justify-center", {
4029
- variants: {
4030
- variant: {
4031
- string: "bg-sky-200 text-sky-800",
4032
- hash: "bg-amber-200 text-amber-800",
4033
- set: "bg-indigo-200 text-indigo-800",
4034
- zset: "bg-pink-200 text-pink-800",
4035
- json: "bg-purple-200 text-purple-800",
4036
- list: "bg-orange-200 text-orange-800",
4037
- stream: "bg-green-200 text-green-800"
4038
- },
4039
- type: {
4040
- icon: "size-5",
4041
- badge: "h-6 px-2 uppercase whitespace-nowrap text-xs font-medium leading-none tracking-wide"
4042
- }
4043
- },
4044
- defaultVariants: {
4045
- variant: "string",
4046
- type: "icon"
4047
- }
4048
- });
4049
- function TypeTag({ className, variant, type }) {
4050
- return /* @__PURE__ */ jsx14("span", { className: cn(tagVariants({ variant, type, className })), children: type === "icon" ? iconsMap[variant] : DATA_TYPE_NAMES[variant] });
4051
3951
  }
4052
3952
 
4053
- // src/components/databrowser/components/display/header-badges.tsx
4054
- import { useEffect as useEffect5 } from "react";
4055
- import { IconChevronDown } from "@tabler/icons-react";
4056
- import bytes from "bytes";
3953
+ // src/components/databrowser/components/display/ttl-badge.tsx
3954
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
3955
+ var TTL_INFINITE = -1;
3956
+ var TTL_NOT_FOUND = -2;
3957
+ var calculateTTL = (expireAt) => {
3958
+ if (!expireAt) return;
3959
+ if (expireAt === TTL_INFINITE) return TTL_INFINITE;
3960
+ return Math.max(0, Math.floor((expireAt - Date.now()) / 1e3));
3961
+ };
3962
+ var TTLBadge = ({
3963
+ label = "TTL:",
3964
+ expireAt,
3965
+ setTTL,
3966
+ isPending
3967
+ }) => {
3968
+ const [ttl, setTTLLabel] = useState5(() => calculateTTL(expireAt));
3969
+ useEffect4(() => {
3970
+ setTTLLabel(calculateTTL(expireAt));
3971
+ const interval = setInterval(() => {
3972
+ setTTLLabel(calculateTTL(expireAt));
3973
+ }, 1e3);
3974
+ return () => clearInterval(interval);
3975
+ }, [expireAt]);
3976
+ return /* @__PURE__ */ jsx14(Badge, { label, children: ttl === void 0 ? /* @__PURE__ */ jsx14(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : /* @__PURE__ */ jsx14(TTLPopover, { ttl, setTTL, isPending, children: /* @__PURE__ */ jsxs7("div", { className: "flex gap-[2px]", children: [
3977
+ ttl === TTL_INFINITE ? "Forever" : formatTime(ttl),
3978
+ /* @__PURE__ */ jsx14(IconChevronDown, { className: "mt-[1px] text-zinc-400", size: 12 })
3979
+ ] }) }) });
3980
+ };
4057
3981
 
4058
- // src/components/databrowser/hooks/use-fetch-key-length.ts
4059
- import { useQuery as useQuery4 } from "@tanstack/react-query";
4060
- var FETCH_KEY_LENGTH_QUERY_KEY = "fetch-key-length";
4061
- var useFetchKeyLength = ({ dataKey, type }) => {
3982
+ // src/components/databrowser/hooks/use-fetch-ttl.ts
3983
+ var FETCH_TTL_QUERY_KEY = "fetch-ttl";
3984
+ var useFetchKeyExpire = (dataKey) => {
4062
3985
  const { redis } = useDatabrowser();
4063
- return useQuery4({
4064
- queryKey: [FETCH_KEY_LENGTH_QUERY_KEY, dataKey],
3986
+ const { isLoading, error, data } = useQuery6({
3987
+ queryKey: [FETCH_TTL_QUERY_KEY, dataKey],
4065
3988
  queryFn: async () => {
4066
- switch (type) {
4067
- case "set": {
4068
- return await redis.scard(dataKey);
4069
- }
4070
- case "zset": {
4071
- return await redis.zcard(dataKey);
4072
- }
4073
- case "list": {
4074
- return await redis.llen(dataKey);
4075
- }
4076
- case "hash": {
4077
- return await redis.hlen(dataKey);
4078
- }
4079
- case "stream": {
4080
- return await redis.xlen(dataKey);
4081
- }
3989
+ const ttl = await redis.ttl(dataKey);
3990
+ return ttl === TTL_INFINITE || ttl === TTL_NOT_FOUND ? ttl : Date.now() + ttl * 1e3;
3991
+ }
3992
+ });
3993
+ useEffect5(() => {
3994
+ if (data === TTL_NOT_FOUND) {
3995
+ queryClient.invalidateQueries({
3996
+ queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
3997
+ });
3998
+ }
3999
+ }, [data === TTL_NOT_FOUND]);
4000
+ return { isLoading, error, data };
4001
+ };
4002
+
4003
+ // src/components/databrowser/hooks/use-set-simple-key.tsx
4004
+ import { useMutation as useMutation4 } from "@tanstack/react-query";
4005
+ var useSetSimpleKey = (dataKey, type) => {
4006
+ const { redis } = useDatabrowser();
4007
+ return useMutation4({
4008
+ mutationFn: async (value) => {
4009
+ if (type === "string") {
4010
+ await redis.set(dataKey, value);
4011
+ } else if (type === "json") {
4012
+ await redis.json.set(dataKey, "$", JSON.parse(value));
4013
+ } else {
4014
+ throw new Error(`Invalid type when setting simple key: ${type}`);
4082
4015
  }
4083
- return null;
4016
+ },
4017
+ onSuccess: (_, value) => {
4018
+ queryClient.setQueryData([FETCH_SIMPLE_KEY_QUERY_KEY, dataKey], value);
4019
+ queryClient.invalidateQueries({
4020
+ queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
4021
+ });
4084
4022
  }
4085
4023
  });
4086
4024
  };
4087
4025
 
4088
- // src/components/databrowser/hooks/use-fetch-key-size.ts
4089
- import { useQuery as useQuery5 } from "@tanstack/react-query";
4090
- var FETCH_KEY_SIZE_QUERY_KEY = "fetch-key-size";
4091
- var useFetchKeySize = (dataKey) => {
4026
+ // src/components/databrowser/hooks/use-set-ttl.ts
4027
+ import { useMutation as useMutation5 } from "@tanstack/react-query";
4028
+ var useSetTTL = () => {
4092
4029
  const { redis } = useDatabrowser();
4093
- return useQuery5({
4094
- queryKey: [FETCH_KEY_SIZE_QUERY_KEY, dataKey],
4095
- queryFn: async () => {
4096
- return await redis.eval(`return redis.call("MEMORY", "USAGE", KEYS[1])`, [dataKey], []);
4030
+ const updateTTL = useMutation5({
4031
+ mutationFn: async ({ dataKey, ttl }) => {
4032
+ await (ttl === void 0 || ttl === TTL_INFINITE ? redis.persist(dataKey) : redis.expire(dataKey, ttl));
4033
+ },
4034
+ onSuccess: (_, { dataKey }) => {
4035
+ queryClient.removeQueries({
4036
+ queryKey: [FETCH_TTL_QUERY_KEY, dataKey]
4037
+ });
4038
+ queryClient.invalidateQueries({
4039
+ queryKey: [FETCH_SIMPLE_KEY_QUERY_KEY, dataKey]
4040
+ });
4097
4041
  }
4098
4042
  });
4043
+ return updateTTL;
4099
4044
  };
4100
4045
 
4101
- // src/components/databrowser/components/display/ttl-popover.tsx
4102
- import { useEffect as useEffect4, useMemo as useMemo3, useState as useState5 } from "react";
4103
- import { Controller, useForm } from "react-hook-form";
4046
+ // src/components/databrowser/components/item-context-menu.tsx
4047
+ import { useState as useState6 } from "react";
4048
+ import { ContextMenuSeparator as ContextMenuSeparator2 } from "@radix-ui/react-context-menu";
4104
4049
 
4105
- // src/components/ui/input.tsx
4050
+ // src/components/ui/context-menu.tsx
4106
4051
  import * as React7 from "react";
4107
- import { jsx as jsx15 } from "react/jsx-runtime";
4108
- var Input = React7.forwardRef(
4109
- ({ className, type, ...props }, ref) => {
4110
- return /* @__PURE__ */ jsx15(
4111
- "input",
4112
- {
4113
- type,
4114
- className: cn(
4115
- "flex h-8 w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
4116
- className
4117
- ),
4118
- ref,
4119
- ...props
4120
- }
4121
- );
4052
+ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
4053
+ import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons";
4054
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
4055
+ var ContextMenu = ContextMenuPrimitive.Root;
4056
+ var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
4057
+ var ContextMenuSubTrigger = React7.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs8(
4058
+ ContextMenuPrimitive.SubTrigger,
4059
+ {
4060
+ ref,
4061
+ className: cn(
4062
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-900 dark:focus:bg-neutral-800 dark:focus:text-neutral-50 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-50",
4063
+ inset && "pl-8",
4064
+ className
4065
+ ),
4066
+ ...props,
4067
+ children: [
4068
+ children,
4069
+ /* @__PURE__ */ jsx15(ChevronRightIcon, { className: "ml-auto h-4 w-4" })
4070
+ ]
4122
4071
  }
4123
- );
4124
- Input.displayName = "Input";
4125
-
4126
- // src/components/ui/popover.tsx
4127
- import * as React8 from "react";
4128
- import * as PopoverPrimitive from "@radix-ui/react-popover";
4129
- import { jsx as jsx16 } from "react/jsx-runtime";
4130
- var Popover = PopoverPrimitive.Root;
4131
- var PopoverTrigger = PopoverPrimitive.Trigger;
4132
- var PopoverContent = React8.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx16(PopoverPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx16(
4133
- PopoverPrimitive.Content,
4072
+ ));
4073
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
4074
+ var ContextMenuSubContent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx15(
4075
+ ContextMenuPrimitive.SubContent,
4134
4076
  {
4135
4077
  ref,
4136
- align,
4137
- sideOffset,
4138
4078
  className: cn(
4139
- "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 z-50 w-72 rounded-md border border-zinc-200 bg-white p-4 text-zinc-950 shadow-md outline-none dark:border-zinc-800 mt-0.5 dark:bg-zinc-950 dark:text-zinc-50",
4079
+ "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",
4080
+ className
4081
+ ),
4082
+ ...props
4083
+ }
4084
+ ));
4085
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
4086
+ var ContextMenuContent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx15(ContextMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx15(
4087
+ ContextMenuPrimitive.Content,
4088
+ {
4089
+ ref,
4090
+ className: cn(
4091
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md 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",
4140
4092
  className
4141
4093
  ),
4142
4094
  ...props
4143
4095
  }
4144
4096
  ) }));
4145
- PopoverContent.displayName = PopoverPrimitive.Content.displayName;
4097
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
4098
+ var ContextMenuItem = React7.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx15(
4099
+ ContextMenuPrimitive.Item,
4100
+ {
4101
+ ref,
4102
+ className: cn(
4103
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
4104
+ inset && "pl-8",
4105
+ className
4106
+ ),
4107
+ ...props
4108
+ }
4109
+ ));
4110
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
4111
+ var ContextMenuCheckboxItem = React7.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs8(
4112
+ ContextMenuPrimitive.CheckboxItem,
4113
+ {
4114
+ ref,
4115
+ className: cn(
4116
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
4117
+ className
4118
+ ),
4119
+ checked,
4120
+ ...props,
4121
+ children: [
4122
+ /* @__PURE__ */ jsx15("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx15(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx15(CheckIcon, { className: "h-4 w-4" }) }) }),
4123
+ children
4124
+ ]
4125
+ }
4126
+ ));
4127
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
4128
+ var ContextMenuRadioItem = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs8(
4129
+ ContextMenuPrimitive.RadioItem,
4130
+ {
4131
+ ref,
4132
+ className: cn(
4133
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
4134
+ className
4135
+ ),
4136
+ ...props,
4137
+ children: [
4138
+ /* @__PURE__ */ jsx15("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx15(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx15(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
4139
+ children
4140
+ ]
4141
+ }
4142
+ ));
4143
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
4144
+ var ContextMenuLabel = React7.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx15(
4145
+ ContextMenuPrimitive.Label,
4146
+ {
4147
+ ref,
4148
+ className: cn(
4149
+ "px-2 py-1.5 text-sm font-semibold text-neutral-950 dark:text-neutral-50",
4150
+ inset && "pl-8",
4151
+ className
4152
+ ),
4153
+ ...props
4154
+ }
4155
+ ));
4156
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
4157
+ var ContextMenuSeparator = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx15(
4158
+ ContextMenuPrimitive.Separator,
4159
+ {
4160
+ ref,
4161
+ className: cn("-mx-1 my-1 h-px bg-neutral-200 dark:bg-neutral-800", className),
4162
+ ...props
4163
+ }
4164
+ ));
4165
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
4166
+ var ContextMenuShortcut = ({ className, ...props }) => {
4167
+ return /* @__PURE__ */ jsx15(
4168
+ "span",
4169
+ {
4170
+ className: cn(
4171
+ "ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400",
4172
+ className
4173
+ ),
4174
+ ...props
4175
+ }
4176
+ );
4177
+ };
4178
+ ContextMenuShortcut.displayName = "ContextMenuShortcut";
4146
4179
 
4147
- // src/components/ui/select.tsx
4148
- import * as React9 from "react";
4149
- import * as SelectPrimitive from "@radix-ui/react-select";
4150
- import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
4151
- var Select = SelectPrimitive.Root;
4152
- var SelectGroup = SelectPrimitive.Group;
4153
- var SelectValue = SelectPrimitive.Value;
4154
- var SelectTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs9(
4155
- SelectPrimitive.Trigger,
4180
+ // src/components/ui/alert-dialog.tsx
4181
+ import * as React8 from "react";
4182
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
4183
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
4184
+ var AlertDialog = AlertDialogPrimitive.Root;
4185
+ var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
4186
+ var AlertDialogPortal = ({ ...props }) => /* @__PURE__ */ jsx16(AlertDialogPrimitive.Portal, { container: portalRoot, ...props });
4187
+ AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName;
4188
+ var AlertDialogOverlay = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx16(
4189
+ AlertDialogPrimitive.Overlay,
4156
4190
  {
4157
- ref,
4158
4191
  className: cn(
4159
- "relative flex h-8 w-full items-center justify-between rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-zinc-500 focus:ring-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-800 dark:bg-zinc-950 dark:ring-offset-zinc-950 dark:placeholder:text-zinc-400 dark:focus:ring-zinc-300",
4192
+ "fixed inset-0 z-50 bg-white/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 dark:bg-zinc-950/80",
4160
4193
  className
4161
4194
  ),
4162
4195
  ...props,
4163
- children: [
4164
- children,
4165
- /* @__PURE__ */ jsx17(SelectPrimitive.Icon, { asChild: true, className: "absolute right-2", children: /* @__PURE__ */ jsx17(
4166
- "svg",
4167
- {
4168
- width: "16",
4169
- height: "16",
4170
- viewBox: "0 0 16 16",
4171
- fill: "none",
4172
- xmlns: "http://www.w3.org/2000/svg",
4173
- children: /* @__PURE__ */ jsx17(
4174
- "path",
4175
- {
4176
- d: "M4 6L8 10L12 6",
4177
- stroke: "black",
4178
- strokeOpacity: "0.4",
4179
- strokeWidth: "1.4",
4180
- strokeLinecap: "round",
4181
- strokeLinejoin: "round"
4182
- }
4183
- )
4184
- }
4185
- ) })
4186
- ]
4196
+ ref
4187
4197
  }
4188
4198
  ));
4189
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
4190
- var SelectContent = React9.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx17(SelectPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx17(
4191
- SelectPrimitive.Content,
4199
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
4200
+ var AlertDialogContent = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs9(AlertDialogPortal, { children: [
4201
+ /* @__PURE__ */ jsx16(AlertDialogOverlay, {}),
4202
+ /* @__PURE__ */ jsx16(
4203
+ AlertDialogPrimitive.Content,
4204
+ {
4205
+ ref,
4206
+ className: cn(
4207
+ "antialiased data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-zinc-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] dark:border-zinc-800 dark:bg-zinc-950 sm:rounded-lg md:w-full",
4208
+ className
4209
+ ),
4210
+ ...props
4211
+ }
4212
+ )
4213
+ ] }));
4214
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
4215
+ var AlertDialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx16("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props });
4216
+ AlertDialogHeader.displayName = "AlertDialogHeader";
4217
+ var AlertDialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx16(
4218
+ "div",
4219
+ {
4220
+ className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
4221
+ ...props
4222
+ }
4223
+ );
4224
+ AlertDialogFooter.displayName = "AlertDialogFooter";
4225
+ var AlertDialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx16(
4226
+ AlertDialogPrimitive.Title,
4192
4227
  {
4193
4228
  ref,
4194
- className: cn(
4195
- "relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-200 bg-white text-zinc-950 shadow-md 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-zinc-800 dark:bg-zinc-950 dark:text-neutral-50",
4196
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
4197
- className
4198
- ),
4199
- position,
4200
- ...props,
4201
- children: /* @__PURE__ */ jsx17(
4202
- SelectPrimitive.Viewport,
4203
- {
4204
- className: cn(
4205
- "p-1",
4206
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
4207
- ),
4208
- children
4209
- }
4210
- )
4229
+ className: cn("text-lg font-semibold", className),
4230
+ ...props
4211
4231
  }
4212
- ) }));
4213
- SelectContent.displayName = SelectPrimitive.Content.displayName;
4214
- var SelectLabel = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
4215
- SelectPrimitive.Label,
4232
+ ));
4233
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
4234
+ var AlertDialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx16(
4235
+ AlertDialogPrimitive.Description,
4216
4236
  {
4217
4237
  ref,
4218
- className: cn("px-2 py-1.5 text-sm font-semibold", className),
4238
+ className: cn("text-sm text-zinc-500 dark:text-zinc-400", className),
4219
4239
  ...props
4220
4240
  }
4221
4241
  ));
4222
- SelectLabel.displayName = SelectPrimitive.Label.displayName;
4223
- var SelectItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs9(
4224
- SelectPrimitive.Item,
4242
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
4243
+ var AlertDialogAction = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx16(AlertDialogPrimitive.Action, { ref, className: cn(buttonVariants(), className), ...props }));
4244
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
4245
+ var AlertDialogCancel = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx16(
4246
+ AlertDialogPrimitive.Cancel,
4225
4247
  {
4226
4248
  ref,
4227
- className: cn(
4228
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50",
4229
- className
4249
+ className: cn(buttonVariants({ variant: "outline" }), "mt-2 sm:!mt-0", className),
4250
+ ...props
4251
+ }
4252
+ ));
4253
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
4254
+
4255
+ // src/components/databrowser/components/display/delete-alert-dialog.tsx
4256
+ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
4257
+ function DeleteAlertDialog({
4258
+ children,
4259
+ onDeleteConfirm,
4260
+ open,
4261
+ onOpenChange,
4262
+ deletionType
4263
+ }) {
4264
+ return /* @__PURE__ */ jsxs10(AlertDialog, { open, onOpenChange, children: [
4265
+ children && /* @__PURE__ */ jsx17(AlertDialogTrigger, { asChild: true, children }),
4266
+ /* @__PURE__ */ jsxs10(AlertDialogContent, { children: [
4267
+ /* @__PURE__ */ jsxs10(AlertDialogHeader, { children: [
4268
+ /* @__PURE__ */ jsx17(AlertDialogTitle, { children: deletionType === "item" ? "Delete Item" : "Delete Key" }),
4269
+ /* @__PURE__ */ jsxs10(AlertDialogDescription, { className: "mt-5", children: [
4270
+ "Are you sure you want to delete this ",
4271
+ deletionType,
4272
+ "?",
4273
+ /* @__PURE__ */ jsx17("br", {}),
4274
+ "This action cannot be undone."
4275
+ ] })
4276
+ ] }),
4277
+ /* @__PURE__ */ jsxs10(AlertDialogFooter, { children: [
4278
+ /* @__PURE__ */ jsx17(AlertDialogCancel, { type: "button", children: "Cancel" }),
4279
+ /* @__PURE__ */ jsx17(
4280
+ AlertDialogAction,
4281
+ {
4282
+ className: "bg-red-500 text-gray-50 hover:bg-red-600",
4283
+ onClick: onDeleteConfirm,
4284
+ children: "Yes, Delete"
4285
+ }
4286
+ )
4287
+ ] })
4288
+ ] })
4289
+ ] });
4290
+ }
4291
+
4292
+ // src/components/databrowser/components/item-context-menu.tsx
4293
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
4294
+ var ItemContextMenu = ({
4295
+ children,
4296
+ dataKey,
4297
+ type
4298
+ }) => {
4299
+ const { mutate: editItem } = useEditListItem();
4300
+ const [isAlertOpen, setAlertOpen] = useState6(false);
4301
+ const [data, setData] = useState6();
4302
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
4303
+ /* @__PURE__ */ jsx18(
4304
+ DeleteAlertDialog,
4305
+ {
4306
+ deletionType: "item",
4307
+ open: isAlertOpen,
4308
+ onOpenChange: setAlertOpen,
4309
+ onDeleteConfirm: (e) => {
4310
+ e.stopPropagation();
4311
+ if (data) {
4312
+ editItem({
4313
+ type,
4314
+ dataKey,
4315
+ itemKey: data?.key,
4316
+ // For deletion
4317
+ newKey: void 0
4318
+ });
4319
+ }
4320
+ setAlertOpen(false);
4321
+ }
4322
+ }
4230
4323
  ),
4324
+ /* @__PURE__ */ jsxs11(ContextMenu, { children: [
4325
+ /* @__PURE__ */ jsx18(
4326
+ ContextMenuTrigger,
4327
+ {
4328
+ asChild: true,
4329
+ onContextMenu: (e) => {
4330
+ const el = e.target;
4331
+ const item = el.closest("[data-item-key]");
4332
+ if (item && item instanceof HTMLElement && item.dataset.itemKey !== void 0) {
4333
+ setData({
4334
+ key: item.dataset.itemKey,
4335
+ value: item.dataset.itemValue
4336
+ });
4337
+ } else {
4338
+ throw new Error("Key not found");
4339
+ }
4340
+ },
4341
+ children
4342
+ }
4343
+ ),
4344
+ /* @__PURE__ */ jsxs11(ContextMenuContent, { children: [
4345
+ /* @__PURE__ */ jsx18(
4346
+ ContextMenuItem,
4347
+ {
4348
+ onClick: () => {
4349
+ if (!data) return;
4350
+ navigator.clipboard.writeText(data?.key);
4351
+ toast({
4352
+ description: "Key copied to clipboard"
4353
+ });
4354
+ },
4355
+ children: "Copy key"
4356
+ }
4357
+ ),
4358
+ data?.value && /* @__PURE__ */ jsx18(
4359
+ ContextMenuItem,
4360
+ {
4361
+ onClick: () => {
4362
+ navigator.clipboard.writeText(data?.value ?? "");
4363
+ toast({
4364
+ description: "Value copied to clipboard"
4365
+ });
4366
+ },
4367
+ children: "Copy value"
4368
+ }
4369
+ ),
4370
+ /* @__PURE__ */ jsx18(ContextMenuSeparator2, {}),
4371
+ /* @__PURE__ */ jsx18(ContextMenuItem, { disabled: type === "stream", onClick: () => setAlertOpen(true), children: "Delete item" })
4372
+ ] })
4373
+ ] })
4374
+ ] });
4375
+ };
4376
+
4377
+ // src/components/databrowser/components/sidebar/infinite-scroll.tsx
4378
+ import { IconLoader2 } from "@tabler/icons-react";
4379
+
4380
+ // src/components/ui/scroll-area.tsx
4381
+ import * as React9 from "react";
4382
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
4383
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
4384
+ var ScrollArea = React9.forwardRef(({ className, children, onScroll, ...props }, ref) => /* @__PURE__ */ jsxs12(
4385
+ ScrollAreaPrimitive.Root,
4386
+ {
4387
+ ref,
4388
+ className: cn("relative overflow-hidden", className),
4231
4389
  ...props,
4232
4390
  children: [
4233
- /* @__PURE__ */ jsx17("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx17(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx17(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx17(
4234
- "svg",
4391
+ /* @__PURE__ */ jsx19(
4392
+ ScrollAreaPrimitive.Viewport,
4235
4393
  {
4236
- width: "15",
4237
- height: "15",
4238
- viewBox: "0 0 15 15",
4239
- fill: "none",
4240
- xmlns: "http://www.w3.org/2000/svg",
4241
- className: "h-4 w-4",
4242
- children: /* @__PURE__ */ jsx17(
4243
- "path",
4244
- {
4245
- d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
4246
- fill: "currentColor",
4247
- fillRule: "evenodd",
4248
- clipRule: "evenodd"
4249
- }
4250
- )
4394
+ onScroll,
4395
+ className: "h-full w-full rounded-[inherit] [&>div]:!block",
4396
+ children
4251
4397
  }
4252
- ) }) }) }),
4253
- /* @__PURE__ */ jsx17(SelectPrimitive.ItemText, { children })
4398
+ ),
4399
+ /* @__PURE__ */ jsx19(ScrollBar, {}),
4400
+ /* @__PURE__ */ jsx19(ScrollAreaPrimitive.Corner, {})
4254
4401
  ]
4255
4402
  }
4256
4403
  ));
4257
- SelectItem.displayName = SelectPrimitive.Item.displayName;
4258
- var SelectSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
4259
- SelectPrimitive.Separator,
4404
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
4405
+ var ScrollBar = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
4406
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
4260
4407
  {
4261
4408
  ref,
4262
- className: cn("-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-800", className),
4263
- ...props
4264
- }
4265
- ));
4266
- SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
4267
-
4268
- // src/components/ui/spinner.tsx
4269
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
4270
- var Spinner = ({
4271
- isLoading,
4272
- className,
4273
- isLoadingText,
4274
- children
4275
- }) => {
4276
- return /* @__PURE__ */ jsx18("div", { className: className ?? "flex items-center", children: isLoading ? /* @__PURE__ */ jsxs10(Fragment2, { children: [
4277
- isLoadingText,
4278
- /* @__PURE__ */ jsx18(
4279
- "svg",
4409
+ orientation: "vertical",
4410
+ className: cn("flex h-full w-2 touch-none select-none transition-colors", className),
4411
+ ...props,
4412
+ children: /* @__PURE__ */ jsx19(
4413
+ ScrollAreaPrimitive.ScrollAreaThumb,
4280
4414
  {
4281
- xmlns: "http://www.w3.org/2000/svg",
4282
- width: "24",
4283
- height: "24",
4284
- viewBox: "0 0 24 24",
4285
- fill: "none",
4286
- stroke: "currentColor",
4287
- strokeWidth: "2",
4288
- strokeLinecap: "round",
4289
- strokeLinejoin: "round",
4290
- className: cn("h-4 w-4 animate-spin", isLoadingText ? "ml-2" : ""),
4291
- children: /* @__PURE__ */ jsx18("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
4415
+ className: cn("relative flex-1 rounded-full bg-neutral-200/70 dark:bg-neutral-800")
4292
4416
  }
4293
4417
  )
4294
- ] }) : children });
4295
- };
4418
+ }
4419
+ ));
4420
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
4296
4421
 
4297
- // src/components/databrowser/components/display/ttl-popover.tsx
4298
- import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
4299
- var PERSISTED_KEY = -1;
4300
- var timeUnits = [
4301
- { label: "Seconds", value: 1 },
4302
- { label: "Minutes", value: 60 },
4303
- { label: "Hours", value: 60 * 60 },
4304
- { label: "Days", value: 60 * 60 * 24 }
4305
- ];
4306
- function TTLPopover({
4307
- children,
4308
- ttl,
4309
- dataKey
4310
- }) {
4311
- const [open, setOpen] = useState5(false);
4312
- const { mutateAsync: setTTL, isPending } = useSetTTL();
4313
- const defaultValues = useMemo3(() => {
4314
- return { type: "Seconds", value: ttl };
4315
- }, [ttl]);
4316
- const { control, handleSubmit, formState, reset } = useForm({
4317
- defaultValues
4318
- });
4319
- useEffect4(() => {
4320
- reset(defaultValues, {
4321
- keepValues: true
4322
- });
4323
- }, [defaultValues]);
4324
- const onSubmit = handleSubmit(async ({ value, type }) => {
4325
- await setTTL({
4326
- dataKey,
4327
- ttl: value * timeUnits.find((unit) => unit.label === type).value
4328
- });
4329
- setOpen(false);
4330
- });
4331
- const handlePersist = async () => {
4332
- await setTTL({
4333
- dataKey,
4334
- ttl: void 0
4335
- });
4336
- setOpen(false);
4422
+ // src/components/databrowser/components/sidebar/infinite-scroll.tsx
4423
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
4424
+ var InfiniteScroll = ({
4425
+ query,
4426
+ children
4427
+ }) => {
4428
+ const handleScroll = (e) => {
4429
+ const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;
4430
+ if (scrollTop + clientHeight > scrollHeight - 100) {
4431
+ if (query.isFetching || !query.hasNextPage) {
4432
+ return;
4433
+ }
4434
+ query.fetchNextPage();
4435
+ }
4337
4436
  };
4338
- return /* @__PURE__ */ jsxs11(
4339
- Popover,
4437
+ return /* @__PURE__ */ jsxs13(
4438
+ ScrollArea,
4340
4439
  {
4341
- open,
4342
- onOpenChange: (isOpen) => {
4343
- if (isOpen) reset();
4344
- setOpen(isOpen);
4345
- },
4440
+ type: "always",
4441
+ className: "block h-full w-full transition-all",
4442
+ onScroll: handleScroll,
4346
4443
  children: [
4347
- /* @__PURE__ */ jsx19(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx19("button", { children }) }),
4348
- /* @__PURE__ */ jsx19(PopoverContent, { className: "w-[300px]", align: "end", children: /* @__PURE__ */ jsxs11("form", { className: "space-y-4", onSubmit, children: [
4349
- /* @__PURE__ */ jsx19("h4", { className: "font-medium leading-none", children: "Expiration" }),
4350
- /* @__PURE__ */ jsxs11("div", { children: [
4351
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center", children: [
4352
- /* @__PURE__ */ jsx19(
4353
- Controller,
4354
- {
4355
- rules: {
4356
- required: "Please enter an expiration time",
4357
- min: { value: -1, message: "TTL can't be lower than -1" }
4358
- },
4359
- control,
4360
- name: "value",
4361
- render: ({ field }) => /* @__PURE__ */ jsx19(Input, { min: "-1", ...field, className: "grow rounded-r-none" })
4362
- }
4363
- ),
4364
- /* @__PURE__ */ jsx19(
4365
- Controller,
4366
- {
4367
- control,
4368
- name: "type",
4369
- render: ({ field }) => /* @__PURE__ */ jsxs11(Select, { value: field.value, onValueChange: field.onChange, children: [
4370
- /* @__PURE__ */ jsx19(SelectTrigger, { className: "w-auto rounded-l-none border-l-0 pr-8", children: /* @__PURE__ */ jsx19(SelectValue, {}) }),
4371
- /* @__PURE__ */ jsx19(SelectContent, { children: timeUnits.map((unit) => /* @__PURE__ */ jsx19(SelectItem, { value: unit.label, children: unit.label }, unit.label)) })
4372
- ] })
4373
- }
4374
- )
4375
- ] }),
4376
- formState.errors.value && /* @__PURE__ */ jsx19("p", { className: "mt-2 text-xs text-red-500", children: formState.errors.value.message }),
4377
- /* @__PURE__ */ jsx19("p", { className: "mt-2 text-xs text-zinc-500", children: "TTL sets a timer to automatically delete keys after a defined period." })
4378
- ] }),
4379
- /* @__PURE__ */ jsxs11("div", { className: "flex justify-between", children: [
4380
- /* @__PURE__ */ jsx19(
4381
- Button,
4382
- {
4383
- type: "button",
4384
- variant: "outline",
4385
- disabled: ttl === PERSISTED_KEY,
4386
- onClick: handlePersist,
4387
- children: "Persist"
4388
- }
4389
- ),
4390
- /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
4391
- /* @__PURE__ */ jsx19(Button, { variant: "outline", onClick: () => setOpen(false), type: "button", children: "Cancel" }),
4392
- /* @__PURE__ */ jsx19(Button, { variant: "primary", type: "submit", children: /* @__PURE__ */ jsx19(Spinner, { isLoading: isPending, isLoadingText: "Saving", children: "Save" }) })
4393
- ] })
4394
- ] })
4395
- ] }) })
4444
+ children,
4445
+ /* @__PURE__ */ jsx20("div", { className: "flex h-[100px] justify-center py-2 text-zinc-300", children: query.isFetching && /* @__PURE__ */ jsx20(IconLoader2, { className: "animate-spin", size: 16 }) })
4396
4446
  ]
4397
4447
  }
4398
4448
  );
4399
- }
4400
-
4401
- // src/components/databrowser/components/display/header-badges.tsx
4402
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
4403
- var LengthBadge = ({
4404
- dataKey,
4405
- type,
4406
- content
4407
- }) => {
4408
- const { data, isLoading } = useFetchKeyLength({ dataKey, type });
4409
- const length = content?.length ?? data;
4410
- return /* @__PURE__ */ jsx20(Badge, { label: "Length:", children: isLoading ? /* @__PURE__ */ jsx20(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : length });
4411
- };
4412
- var SizeBadge = ({ dataKey }) => {
4413
- const { data: size } = useFetchKeySize(dataKey);
4414
- return /* @__PURE__ */ jsx20(Badge, { label: "Size:", children: size === void 0 || size === null ? /* @__PURE__ */ jsx20(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : bytes(size, {
4415
- unitSeparator: " "
4416
- }) });
4417
4449
  };
4418
- var TTL_INFINITE = -1;
4419
- var TTL_NOT_FOUND = -2;
4420
- var TTLBadge = ({ dataKey }) => {
4421
- const { data: ttl } = useFetchTTL(dataKey);
4422
- const { deleteKeyCache } = useDeleteKeyCache();
4423
- useEffect5(() => {
4424
- const interval = setInterval(() => {
4425
- queryClient.setQueryData([FETCH_TTL_QUERY_KEY, dataKey], (ttl2) => {
4426
- if (ttl2 === void 0 || ttl2 === TTL_INFINITE) return ttl2;
4427
- if (ttl2 <= 1) {
4428
- deleteKeyCache(dataKey);
4429
- return TTL_NOT_FOUND;
4430
- }
4431
- return ttl2 - 1;
4432
- });
4433
- }, 1e3);
4434
- return () => clearInterval(interval);
4435
- }, []);
4436
- return /* @__PURE__ */ jsx20(Badge, { label: "TTL:", children: ttl === void 0 ? /* @__PURE__ */ jsx20(Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : /* @__PURE__ */ jsx20(TTLPopover, { dataKey, ttl, children: /* @__PURE__ */ jsxs12("div", { className: "flex gap-[2px]", children: [
4437
- ttl === TTL_INFINITE ? "Forever" : formatTime(ttl),
4438
- /* @__PURE__ */ jsx20(IconChevronDown, { className: "mt-[1px] text-zinc-400", size: 12 })
4439
- ] }) }) });
4450
+
4451
+ // src/components/databrowser/components/display/display-header.tsx
4452
+ import { IconPlus } from "@tabler/icons-react";
4453
+
4454
+ // src/components/databrowser/components/type-tag.tsx
4455
+ import {
4456
+ IconArrowsSort,
4457
+ IconCodeDots,
4458
+ IconHash,
4459
+ IconLayersIntersect,
4460
+ IconList,
4461
+ IconQuote
4462
+ } from "@tabler/icons-react";
4463
+ import { jsx as jsx21 } from "react/jsx-runtime";
4464
+ var iconsMap = {
4465
+ string: /* @__PURE__ */ jsx21(IconQuote, { size: 15, stroke: 1.3 }),
4466
+ set: /* @__PURE__ */ jsx21(IconLayersIntersect, { size: 15, stroke: 1.3 }),
4467
+ hash: /* @__PURE__ */ jsx21(IconHash, { size: 15, stroke: 1.3 }),
4468
+ json: /* @__PURE__ */ jsx21(IconCodeDots, { size: 15, stroke: 1.3 }),
4469
+ zset: /* @__PURE__ */ jsx21(IconArrowsSort, { size: 15, stroke: 1.3 }),
4470
+ list: /* @__PURE__ */ jsx21(IconList, { size: 15, stroke: 1.3 }),
4471
+ stream: /* @__PURE__ */ jsx21(IconList, { size: 15, stroke: 1.3 })
4440
4472
  };
4441
- var Badge = ({ children, label }) => /* @__PURE__ */ jsxs12("div", { className: "flex h-6 items-center gap-0.5 rounded-md bg-white px-2 text-xs text-zinc-700", children: [
4442
- /* @__PURE__ */ jsx20("span", { className: "text-zinc-500", children: label }),
4443
- /* @__PURE__ */ jsx20("span", { className: "font-medium", children })
4444
- ] });
4473
+ var tagVariants = cva("inline-flex shrink-0 items-center rounded-md justify-center", {
4474
+ variants: {
4475
+ variant: {
4476
+ string: "bg-sky-200 text-sky-800",
4477
+ hash: "bg-amber-200 text-amber-800",
4478
+ set: "bg-indigo-200 text-indigo-800",
4479
+ zset: "bg-pink-200 text-pink-800",
4480
+ json: "bg-purple-200 text-purple-800",
4481
+ list: "bg-orange-200 text-orange-800",
4482
+ stream: "bg-green-200 text-green-800"
4483
+ },
4484
+ type: {
4485
+ icon: "size-5",
4486
+ badge: "h-6 px-2 uppercase whitespace-nowrap text-xs font-medium leading-none tracking-wide"
4487
+ }
4488
+ },
4489
+ defaultVariants: {
4490
+ variant: "string",
4491
+ type: "icon"
4492
+ }
4493
+ });
4494
+ function TypeTag({ className, variant, type }) {
4495
+ return /* @__PURE__ */ jsx21("span", { className: cn(tagVariants({ variant, type, className })), children: type === "icon" ? iconsMap[variant] : DATA_TYPE_NAMES[variant] });
4496
+ }
4445
4497
 
4446
4498
  // src/components/databrowser/components/display/key-actions.tsx
4447
4499
  import { IconDotsVertical } from "@tabler/icons-react";
@@ -4450,10 +4502,10 @@ import { IconDotsVertical } from "@tabler/icons-react";
4450
4502
  import * as React10 from "react";
4451
4503
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
4452
4504
  import { CheckIcon as CheckIcon2, ChevronRightIcon as ChevronRightIcon2, DotFilledIcon as DotFilledIcon2 } from "@radix-ui/react-icons";
4453
- import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
4505
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
4454
4506
  var DropdownMenu = DropdownMenuPrimitive.Root;
4455
4507
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
4456
- var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs13(
4508
+ var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
4457
4509
  DropdownMenuPrimitive.SubTrigger,
4458
4510
  {
4459
4511
  ref,
@@ -4465,12 +4517,12 @@ var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, .
4465
4517
  ...props,
4466
4518
  children: [
4467
4519
  children,
4468
- /* @__PURE__ */ jsx21(ChevronRightIcon2, { className: "ml-auto size-4" })
4520
+ /* @__PURE__ */ jsx22(ChevronRightIcon2, { className: "ml-auto size-4" })
4469
4521
  ]
4470
4522
  }
4471
4523
  ));
4472
4524
  DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
4473
- var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx21(
4525
+ var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
4474
4526
  DropdownMenuPrimitive.SubContent,
4475
4527
  {
4476
4528
  ref,
@@ -4482,7 +4534,7 @@ var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) =
4482
4534
  }
4483
4535
  ));
4484
4536
  DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
4485
- var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx21(DropdownMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx21(
4537
+ var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx22(DropdownMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ jsx22(
4486
4538
  DropdownMenuPrimitive.Content,
4487
4539
  {
4488
4540
  ref,
@@ -4496,7 +4548,7 @@ var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...pr
4496
4548
  }
4497
4549
  ) }));
4498
4550
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
4499
- var DropdownMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx21(
4551
+ var DropdownMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx22(
4500
4552
  DropdownMenuPrimitive.Item,
4501
4553
  {
4502
4554
  ref,
@@ -4509,7 +4561,7 @@ var DropdownMenuItem = React10.forwardRef(({ className, inset, ...props }, ref)
4509
4561
  }
4510
4562
  ));
4511
4563
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
4512
- var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs13(
4564
+ var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs14(
4513
4565
  DropdownMenuPrimitive.CheckboxItem,
4514
4566
  {
4515
4567
  ref,
@@ -4520,13 +4572,13 @@ var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checke
4520
4572
  checked,
4521
4573
  ...props,
4522
4574
  children: [
4523
- /* @__PURE__ */ jsx21("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx21(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx21(CheckIcon2, { className: "size-4" }) }) }),
4575
+ /* @__PURE__ */ jsx22("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx22(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx22(CheckIcon2, { className: "size-4" }) }) }),
4524
4576
  children
4525
4577
  ]
4526
4578
  }
4527
4579
  ));
4528
4580
  DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
4529
- var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs13(
4581
+ var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
4530
4582
  DropdownMenuPrimitive.RadioItem,
4531
4583
  {
4532
4584
  ref,
@@ -4536,13 +4588,13 @@ var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props
4536
4588
  ),
4537
4589
  ...props,
4538
4590
  children: [
4539
- /* @__PURE__ */ jsx21("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx21(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx21(DotFilledIcon2, { className: "size-4 fill-current" }) }) }),
4591
+ /* @__PURE__ */ jsx22("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx22(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx22(DotFilledIcon2, { className: "size-4 fill-current" }) }) }),
4540
4592
  children
4541
4593
  ]
4542
4594
  }
4543
4595
  ));
4544
4596
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
4545
- var DropdownMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx21(
4597
+ var DropdownMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx22(
4546
4598
  DropdownMenuPrimitive.Label,
4547
4599
  {
4548
4600
  ref,
@@ -4551,7 +4603,7 @@ var DropdownMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref)
4551
4603
  }
4552
4604
  ));
4553
4605
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
4554
- var DropdownMenuSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx21(
4606
+ var DropdownMenuSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
4555
4607
  DropdownMenuPrimitive.Separator,
4556
4608
  {
4557
4609
  ref,
@@ -4561,18 +4613,18 @@ var DropdownMenuSeparator = React10.forwardRef(({ className, ...props }, ref) =>
4561
4613
  ));
4562
4614
  DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
4563
4615
  var DropdownMenuShortcut = ({ className, ...props }) => {
4564
- return /* @__PURE__ */ jsx21("span", { className: cn("ml-auto text-xs tracking-widest opacity-60", className), ...props });
4616
+ return /* @__PURE__ */ jsx22("span", { className: cn("ml-auto text-xs tracking-widest opacity-60", className), ...props });
4565
4617
  };
4566
4618
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
4567
4619
 
4568
4620
  // src/components/databrowser/components/display/key-actions.tsx
4569
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
4621
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
4570
4622
  function KeyActions({ dataKey, content }) {
4571
4623
  const { mutateAsync: deleteKey } = useDeleteKey();
4572
- return /* @__PURE__ */ jsxs14(DropdownMenu, { children: [
4573
- /* @__PURE__ */ jsx22(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(Button, { size: "icon-sm", children: /* @__PURE__ */ jsx22(IconDotsVertical, { className: "size-4 text-zinc-500" }) }) }),
4574
- /* @__PURE__ */ jsxs14(DropdownMenuContent, { className: "", align: "end", children: [
4575
- content && /* @__PURE__ */ jsx22(
4624
+ return /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
4625
+ /* @__PURE__ */ jsx23(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(Button, { size: "icon-sm", children: /* @__PURE__ */ jsx23(IconDotsVertical, { className: "size-4 text-zinc-500" }) }) }),
4626
+ /* @__PURE__ */ jsxs15(DropdownMenuContent, { className: "", align: "end", children: [
4627
+ content && /* @__PURE__ */ jsx23(
4576
4628
  DropdownMenuItem,
4577
4629
  {
4578
4630
  onClick: () => {
@@ -4584,12 +4636,12 @@ function KeyActions({ dataKey, content }) {
4584
4636
  children: "Copy content"
4585
4637
  }
4586
4638
  ),
4587
- /* @__PURE__ */ jsx22(
4639
+ /* @__PURE__ */ jsx23(
4588
4640
  DeleteAlertDialog,
4589
4641
  {
4590
4642
  deletionType: "key",
4591
4643
  onDeleteConfirm: async () => await deleteKey(dataKey),
4592
- children: /* @__PURE__ */ jsx22(DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" })
4644
+ children: /* @__PURE__ */ jsx23(DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" })
4593
4645
  }
4594
4646
  )
4595
4647
  ] })
@@ -4597,7 +4649,7 @@ function KeyActions({ dataKey, content }) {
4597
4649
  }
4598
4650
 
4599
4651
  // src/components/databrowser/components/display/display-header.tsx
4600
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
4652
+ import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
4601
4653
  var DisplayHeader = ({
4602
4654
  dataKey,
4603
4655
  type,
@@ -4607,34 +4659,33 @@ var DisplayHeader = ({
4607
4659
  const handleAddItem = () => {
4608
4660
  setSelectedListItem({ key: type === "stream" ? "*" : "", isNew: true });
4609
4661
  };
4610
- return /* @__PURE__ */ jsxs15("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
4611
- /* @__PURE__ */ jsxs15("div", { className: "flex min-h-10 items-center justify-between gap-4", children: [
4612
- /* @__PURE__ */ jsx23("h2", { className: "grow truncate text-base", children: dataKey.trim() === "" ? /* @__PURE__ */ jsx23("span", { className: "ml-1 text-zinc-500", children: "(Empty Key)" }) : /* @__PURE__ */ jsx23("span", { className: "font-semibold", children: dataKey }) }),
4613
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1", children: [
4614
- type !== "string" && type !== "json" && /* @__PURE__ */ jsx23(Button, { onClick: handleAddItem, size: "icon-sm", children: /* @__PURE__ */ jsx23(IconPlus, { className: "size-4 text-zinc-500" }) }),
4615
- /* @__PURE__ */ jsx23(KeyActions, { dataKey, content })
4662
+ return /* @__PURE__ */ jsxs16("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
4663
+ /* @__PURE__ */ jsxs16("div", { className: "flex min-h-10 items-center justify-between gap-4", children: [
4664
+ /* @__PURE__ */ jsx24("h2", { className: "grow truncate text-base", children: dataKey.trim() === "" ? /* @__PURE__ */ jsx24("span", { className: "ml-1 text-zinc-500", children: "(Empty Key)" }) : /* @__PURE__ */ jsx24("span", { className: "font-semibold", children: dataKey }) }),
4665
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-1", children: [
4666
+ type !== "string" && type !== "json" && /* @__PURE__ */ jsx24(Button, { onClick: handleAddItem, size: "icon-sm", children: /* @__PURE__ */ jsx24(IconPlus, { className: "size-4 text-zinc-500" }) }),
4667
+ /* @__PURE__ */ jsx24(KeyActions, { dataKey, content })
4616
4668
  ] })
4617
4669
  ] }),
4618
- /* @__PURE__ */ jsxs15("div", { className: "flex h-10 flex-wrap items-center gap-1.5", children: [
4619
- /* @__PURE__ */ jsx23(TypeTag, { variant: type, type: "badge" }),
4620
- /* @__PURE__ */ jsx23(SizeBadge, { dataKey }),
4621
- /* @__PURE__ */ jsx23(LengthBadge, { dataKey, type, content }),
4622
- /* @__PURE__ */ jsx23(TTLBadge, { dataKey })
4670
+ /* @__PURE__ */ jsxs16("div", { className: "flex h-10 flex-wrap items-center gap-1.5", children: [
4671
+ /* @__PURE__ */ jsx24(TypeTag, { variant: type, type: "badge" }),
4672
+ /* @__PURE__ */ jsx24(SizeBadge, { dataKey }),
4673
+ /* @__PURE__ */ jsx24(LengthBadge, { dataKey, type, content }),
4674
+ /* @__PURE__ */ jsx24(HeaderTTLBadge, { dataKey })
4623
4675
  ] })
4624
4676
  ] });
4625
4677
  };
4626
4678
 
4627
4679
  // src/components/databrowser/components/display/display-list-edit.tsx
4628
- import { useEffect as useEffect8 } from "react";
4629
4680
  import { Controller as Controller2, FormProvider, useForm as useForm2, useFormContext } from "react-hook-form";
4630
4681
 
4631
4682
  // src/components/ui/tooltip.tsx
4632
4683
  import * as React11 from "react";
4633
4684
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
4634
- import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
4685
+ import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
4635
4686
  var Tooltip = TooltipPrimitive.Root;
4636
4687
  var TooltipTrigger = TooltipPrimitive.Trigger;
4637
- var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx24(
4688
+ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx25(
4638
4689
  TooltipPrimitive.Content,
4639
4690
  {
4640
4691
  ref,
@@ -4651,31 +4702,103 @@ var SimpleTooltip = ({
4651
4702
  content,
4652
4703
  children
4653
4704
  }) => {
4654
- if (!content) return /* @__PURE__ */ jsx24(Fragment3, { children });
4655
- return /* @__PURE__ */ jsxs16(Tooltip, { delayDuration: 400, children: [
4656
- /* @__PURE__ */ jsx24(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx24("div", { children }) }),
4657
- /* @__PURE__ */ jsx24(TooltipContent, { children: content })
4705
+ if (!content) return /* @__PURE__ */ jsx25(Fragment3, { children });
4706
+ return /* @__PURE__ */ jsxs17(Tooltip, { delayDuration: 400, children: [
4707
+ /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25("div", { children }) }),
4708
+ /* @__PURE__ */ jsx25(TooltipContent, { children: content })
4658
4709
  ] });
4659
4710
  };
4660
4711
 
4712
+ // src/components/databrowser/hooks/use-fetch-hash-ttl.ts
4713
+ import { useQuery as useQuery7 } from "@tanstack/react-query";
4714
+ var FETCH_HASH_FIELD_TTLS_QUERY_KEY = "fetch-hash-field-ttls";
4715
+ var useFetchHashFieldExpires = ({
4716
+ dataKey,
4717
+ fields
4718
+ }) => {
4719
+ const { redis } = useDatabrowser();
4720
+ return useQuery7({
4721
+ queryKey: [FETCH_HASH_FIELD_TTLS_QUERY_KEY, dataKey, fields],
4722
+ queryFn: async () => {
4723
+ const cachedExpires = /* @__PURE__ */ new Map();
4724
+ for (const field of fields) {
4725
+ const expireAt = queryClient.getQueryData([
4726
+ FETCH_HASH_FIELD_TTLS_QUERY_KEY,
4727
+ dataKey,
4728
+ field
4729
+ ]);
4730
+ if (expireAt !== void 0) cachedExpires.set(field, expireAt);
4731
+ }
4732
+ const filteredFields = fields.filter((field) => !cachedExpires.has(field));
4733
+ if (filteredFields.length === 0) return Object.fromEntries(cachedExpires.entries());
4734
+ const res = await redis.httl(dataKey, filteredFields);
4735
+ const expireAts = res.map(
4736
+ (ttl) => ttl === TTL_INFINITE || ttl === TTL_NOT_FOUND ? ttl : Date.now() + ttl * 1e3
4737
+ );
4738
+ for (const [i, field] of filteredFields.entries()) {
4739
+ queryClient.setQueryData([FETCH_HASH_FIELD_TTLS_QUERY_KEY, dataKey, field], expireAts[i]);
4740
+ }
4741
+ const newExpiresArray = expireAts.map((expireAt, i) => [filteredFields[i], expireAt]);
4742
+ return Object.fromEntries([...cachedExpires.entries(), ...newExpiresArray]);
4743
+ }
4744
+ });
4745
+ };
4746
+
4747
+ // src/components/databrowser/hooks/use-set-hash-ttl.ts
4748
+ import { useMutation as useMutation6 } from "@tanstack/react-query";
4749
+ var useSetHashTTL = () => {
4750
+ const { redis } = useDatabrowser();
4751
+ return useMutation6({
4752
+ mutationFn: async ({
4753
+ dataKey,
4754
+ field,
4755
+ ttl
4756
+ }) => {
4757
+ await (ttl === void 0 || ttl === TTL_INFINITE ? redis.hpersist(dataKey, field) : redis.hexpire(dataKey, field, ttl));
4758
+ },
4759
+ onSuccess: (_, { dataKey }) => {
4760
+ queryClient.removeQueries({
4761
+ queryKey: [FETCH_HASH_FIELD_TTLS_QUERY_KEY, dataKey]
4762
+ });
4763
+ }
4764
+ });
4765
+ };
4766
+
4767
+ // src/components/databrowser/components/display/hash/hash-field-ttl-badge.tsx
4768
+ import { jsx as jsx26 } from "react/jsx-runtime";
4769
+ var HashFieldTTLBadge = ({ dataKey, field }) => {
4770
+ const { data } = useFetchHashFieldExpires({ dataKey, fields: [field] });
4771
+ const { mutate: setTTL, isPending } = useSetHashTTL();
4772
+ const expireAt = data?.[field];
4773
+ return /* @__PURE__ */ jsx26(
4774
+ TTLBadge,
4775
+ {
4776
+ label: "Field TTL:",
4777
+ expireAt,
4778
+ setTTL: (ttl) => setTTL({ dataKey, field, ttl }),
4779
+ isPending
4780
+ }
4781
+ );
4782
+ };
4783
+
4661
4784
  // src/components/databrowser/components/display/input/use-field.tsx
4662
- import { useEffect as useEffect7, useState as useState7 } from "react";
4785
+ import { useEffect as useEffect7, useState as useState8 } from "react";
4663
4786
  import { useController } from "react-hook-form";
4664
4787
 
4665
4788
  // src/components/databrowser/components/display/input/content-type-select.tsx
4666
4789
  import { useMemo as useMemo4 } from "react";
4667
- import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
4790
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
4668
4791
  var ContentTypeSelect = ({
4669
4792
  value,
4670
4793
  onChange,
4671
4794
  data
4672
4795
  }) => {
4673
4796
  const isValidJSON = useMemo4(() => checkIsValidJSON(data), [data]);
4674
- return /* @__PURE__ */ jsxs17(Select, { value, onValueChange: onChange, children: [
4675
- /* @__PURE__ */ jsx25(SelectTrigger, { className: "h-6 w-auto border-none bg-transparent pl-0 pr-6 text-xs text-zinc-500", children: /* @__PURE__ */ jsx25(SelectValue, { placeholder: "Text" }) }),
4676
- /* @__PURE__ */ jsx25(SelectContent, { children: /* @__PURE__ */ jsxs17(SelectGroup, { children: [
4677
- /* @__PURE__ */ jsx25(SelectItem, { value: "Text", children: "Text" }),
4678
- /* @__PURE__ */ jsx25(SelectItem, { disabled: !isValidJSON, value: "JSON", children: "JSON" })
4797
+ return /* @__PURE__ */ jsxs18(Select, { value, onValueChange: onChange, children: [
4798
+ /* @__PURE__ */ jsx27(SelectTrigger, { className: "h-6 w-auto border-none bg-transparent pl-0 pr-6 text-xs text-zinc-500", children: /* @__PURE__ */ jsx27(SelectValue, { placeholder: "Text" }) }),
4799
+ /* @__PURE__ */ jsx27(SelectContent, { children: /* @__PURE__ */ jsxs18(SelectGroup, { children: [
4800
+ /* @__PURE__ */ jsx27(SelectItem, { value: "Text", children: "Text" }),
4801
+ /* @__PURE__ */ jsx27(SelectItem, { disabled: !isValidJSON, value: "JSON", children: "JSON" })
4679
4802
  ] }) })
4680
4803
  ] });
4681
4804
  };
@@ -4685,12 +4808,12 @@ import { useEffect as useEffect6, useRef as useRef3 } from "react";
4685
4808
  import { Editor, useMonaco } from "@monaco-editor/react";
4686
4809
 
4687
4810
  // src/components/databrowser/copy-button.tsx
4688
- import { useState as useState6 } from "react";
4811
+ import { useState as useState7 } from "react";
4689
4812
  import { IconCheck, IconCopy } from "@tabler/icons-react";
4690
- import { jsx as jsx26 } from "react/jsx-runtime";
4813
+ import { jsx as jsx28 } from "react/jsx-runtime";
4691
4814
  function CopyButton({ value, ...props }) {
4692
- const [copied, setCopied] = useState6(false);
4693
- return /* @__PURE__ */ jsx26(
4815
+ const [copied, setCopied] = useState7(false);
4816
+ return /* @__PURE__ */ jsx28(
4694
4817
  Button,
4695
4818
  {
4696
4819
  onClick: (e) => {
@@ -4707,7 +4830,7 @@ function CopyButton({ value, ...props }) {
4707
4830
  variant: "secondary",
4708
4831
  size: "icon-sm",
4709
4832
  ...props,
4710
- children: copied ? /* @__PURE__ */ jsx26(IconCheck, { className: "size-4 text-green-500" }) : /* @__PURE__ */ jsx26(IconCopy, { className: "size-4 text-zinc-500" })
4833
+ children: copied ? /* @__PURE__ */ jsx28(IconCheck, { className: "size-4 text-green-500" }) : /* @__PURE__ */ jsx28(IconCopy, { className: "size-4 text-zinc-500" })
4711
4834
  }
4712
4835
  );
4713
4836
  }
@@ -4720,7 +4843,7 @@ var handleCopyClick = async (textToCopy) => {
4720
4843
  };
4721
4844
 
4722
4845
  // src/components/databrowser/components/display/input/custom-editor.tsx
4723
- import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
4846
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
4724
4847
  var CustomEditor = ({
4725
4848
  language,
4726
4849
  value,
@@ -4737,7 +4860,7 @@ var CustomEditor = ({
4737
4860
  }
4738
4861
  monaco?.editor.setModelLanguage(editorRef.current.getModel(), language);
4739
4862
  }, [monaco, language]);
4740
- return /* @__PURE__ */ jsxs18(
4863
+ return /* @__PURE__ */ jsxs19(
4741
4864
  "div",
4742
4865
  {
4743
4866
  className: cn("group/editor relative", height === void 0 && "h-full p-2"),
@@ -4745,7 +4868,7 @@ var CustomEditor = ({
4745
4868
  height
4746
4869
  },
4747
4870
  children: [
4748
- /* @__PURE__ */ jsx27(
4871
+ /* @__PURE__ */ jsx29(
4749
4872
  Editor,
4750
4873
  {
4751
4874
  loading: void 0,
@@ -4786,7 +4909,7 @@ var CustomEditor = ({
4786
4909
  }
4787
4910
  }
4788
4911
  ),
4789
- showCopyButton && /* @__PURE__ */ jsx27(
4912
+ showCopyButton && /* @__PURE__ */ jsx29(
4790
4913
  CopyButton,
4791
4914
  {
4792
4915
  value,
@@ -4799,7 +4922,7 @@ var CustomEditor = ({
4799
4922
  };
4800
4923
 
4801
4924
  // src/components/databrowser/components/display/input/use-field.tsx
4802
- import { Fragment as Fragment4, jsx as jsx28 } from "react/jsx-runtime";
4925
+ import { Fragment as Fragment4, jsx as jsx30 } from "react/jsx-runtime";
4803
4926
  var useField = ({
4804
4927
  name,
4805
4928
  form,
@@ -4812,16 +4935,19 @@ var useField = ({
4812
4935
  name,
4813
4936
  control: form.control
4814
4937
  });
4815
- const [contentType, setContentType] = useState7(
4938
+ const [contentType, setContentType] = useState8(
4816
4939
  () => checkIsValidJSON(field.value) ? "JSON" : "Text"
4817
4940
  );
4818
4941
  useEffect7(() => {
4819
- if (!checkIsValidJSON(data)) {
4820
- return;
4942
+ if (contentType === "JSON" && checkIsValidJSON(data)) {
4943
+ form.setValue(name, formatJSON(data), {
4944
+ shouldDirty: false
4945
+ });
4946
+ } else {
4947
+ form.setValue(name, data, {
4948
+ shouldDirty: false
4949
+ });
4821
4950
  }
4822
- form.setValue(name, formatJSON(data), {
4823
- shouldDirty: false
4824
- });
4825
4951
  }, [data]);
4826
4952
  const handleTypeChange = (type) => {
4827
4953
  setContentType(type);
@@ -4836,8 +4962,8 @@ var useField = ({
4836
4962
  }
4837
4963
  };
4838
4964
  return {
4839
- selector: /* @__PURE__ */ jsx28(ContentTypeSelect, { value: contentType, onChange: handleTypeChange, data: field.value }),
4840
- editor: /* @__PURE__ */ jsx28(Fragment4, { children: /* @__PURE__ */ jsx28(
4965
+ selector: /* @__PURE__ */ jsx30(ContentTypeSelect, { value: contentType, onChange: handleTypeChange, data: field.value }),
4966
+ editor: /* @__PURE__ */ jsx30(Fragment4, { children: /* @__PURE__ */ jsx30(
4841
4967
  CustomEditor,
4842
4968
  {
4843
4969
  language: contentType === "JSON" ? "json" : "plaintext",
@@ -4861,13 +4987,13 @@ var checkIsValidJSON = (value) => {
4861
4987
  };
4862
4988
 
4863
4989
  // src/components/databrowser/components/display/display-list-edit.tsx
4864
- import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
4990
+ import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
4865
4991
  var ListEditDisplay = ({
4866
4992
  dataKey,
4867
4993
  type,
4868
4994
  item
4869
4995
  }) => {
4870
- return /* @__PURE__ */ jsx29("div", { className: "grow rounded-md bg-zinc-100 p-3", children: /* @__PURE__ */ jsx29(ListEditForm, { item, type, dataKey }, item.key) });
4996
+ return /* @__PURE__ */ jsx31("div", { className: "grow rounded-md bg-zinc-100 p-3", children: /* @__PURE__ */ jsx31(ListEditForm, { item, type, dataKey }, item.key) });
4871
4997
  };
4872
4998
  var ListEditForm = ({
4873
4999
  type,
@@ -4892,12 +5018,6 @@ var ListEditForm = ({
4892
5018
  value: itemValue
4893
5019
  }
4894
5020
  });
4895
- useEffect8(() => {
4896
- form.reset({
4897
- key: itemKey,
4898
- value: itemValue
4899
- });
4900
- }, [itemKey, itemValue]);
4901
5021
  const { mutateAsync: editItem, isPending } = useEditListItem();
4902
5022
  const { setSelectedListItem } = useDatabrowserStore();
4903
5023
  const [keyLabel, valueLabel] = headerLabels[type];
@@ -4912,9 +5032,9 @@ var ListEditForm = ({
4912
5032
  });
4913
5033
  setSelectedListItem(void 0);
4914
5034
  });
4915
- return /* @__PURE__ */ jsx29(FormProvider, { ...form, children: /* @__PURE__ */ jsxs19("form", { onSubmit, className: "flex flex-col gap-2", children: [
4916
- /* @__PURE__ */ jsxs19("div", { className: "flex grow flex-col gap-2", children: [
4917
- type !== "list" && /* @__PURE__ */ jsx29(
5035
+ return /* @__PURE__ */ jsx31(FormProvider, { ...form, children: /* @__PURE__ */ jsxs20("form", { onSubmit, className: "flex flex-col gap-2", children: [
5036
+ /* @__PURE__ */ jsxs20("div", { className: "flex grow flex-col gap-2", children: [
5037
+ type !== "list" && /* @__PURE__ */ jsx31(
4918
5038
  FormItem,
4919
5039
  {
4920
5040
  readOnly: type === "stream",
@@ -4924,7 +5044,7 @@ var ListEditForm = ({
4924
5044
  data: itemKey
4925
5045
  }
4926
5046
  ),
4927
- type === "zset" ? /* @__PURE__ */ jsx29(NumberFormItem, { name: "value", label: valueLabel }) : type !== "set" && /* @__PURE__ */ jsx29(
5047
+ type === "zset" ? /* @__PURE__ */ jsx31(NumberFormItem, { name: "value", label: valueLabel }) : type !== "set" && /* @__PURE__ */ jsx31(
4928
5048
  FormItem,
4929
5049
  {
4930
5050
  readOnly: type === "stream",
@@ -4935,43 +5055,55 @@ var ListEditForm = ({
4935
5055
  }
4936
5056
  )
4937
5057
  ] }),
4938
- /* @__PURE__ */ jsxs19("div", { className: "flex justify-end gap-2", children: [
4939
- /* @__PURE__ */ jsx29(
4940
- Button,
4941
- {
4942
- type: "button",
4943
- onClick: () => {
4944
- setSelectedListItem(void 0);
4945
- },
4946
- children: "Cancel"
4947
- }
4948
- ),
4949
- /* @__PURE__ */ jsx29(
4950
- SimpleTooltip,
4951
- {
4952
- content: type === "stream" && !isNew ? "Streams are not mutable" : void 0,
4953
- children: /* @__PURE__ */ jsx29(
4954
- Button,
4955
- {
4956
- variant: "primary",
4957
- type: "submit",
4958
- disabled: !form.formState.isValid || !form.formState.isDirty || type === "stream" && !isNew,
4959
- children: /* @__PURE__ */ jsx29(Spinner, { isLoading: isPending, isLoadingText: "Saving", children: "Save" })
4960
- }
4961
- )
4962
- }
4963
- )
4964
- ] })
5058
+ /* @__PURE__ */ jsxs20(
5059
+ "div",
5060
+ {
5061
+ className: cn(
5062
+ "flex items-center",
5063
+ type === "hash" && itemKey !== "" ? "justify-between" : "justify-end"
5064
+ ),
5065
+ children: [
5066
+ type === "hash" && itemKey !== "" && /* @__PURE__ */ jsx31(HashFieldTTLBadge, { dataKey, field: itemKey }),
5067
+ /* @__PURE__ */ jsxs20("div", { className: "flex gap-2", children: [
5068
+ /* @__PURE__ */ jsx31(
5069
+ Button,
5070
+ {
5071
+ type: "button",
5072
+ onClick: () => {
5073
+ setSelectedListItem(void 0);
5074
+ },
5075
+ children: "Cancel"
5076
+ }
5077
+ ),
5078
+ /* @__PURE__ */ jsx31(
5079
+ SimpleTooltip,
5080
+ {
5081
+ content: type === "stream" && !isNew ? "Streams are not mutable" : void 0,
5082
+ children: /* @__PURE__ */ jsx31(
5083
+ Button,
5084
+ {
5085
+ variant: "primary",
5086
+ type: "submit",
5087
+ disabled: !form.formState.isValid || !form.formState.isDirty || type === "stream" && !isNew,
5088
+ children: /* @__PURE__ */ jsx31(Spinner, { isLoading: isPending, isLoadingText: "Saving", children: "Save" })
5089
+ }
5090
+ )
5091
+ }
5092
+ )
5093
+ ] })
5094
+ ]
5095
+ }
5096
+ )
4965
5097
  ] }) });
4966
5098
  };
4967
5099
  var NumberFormItem = ({ name, label }) => {
4968
- return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
4969
- /* @__PURE__ */ jsx29("div", { className: "flex", children: /* @__PURE__ */ jsx29("span", { className: "text-xs font-medium text-zinc-700", children: label }) }),
4970
- /* @__PURE__ */ jsx29(
5100
+ return /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
5101
+ /* @__PURE__ */ jsx31("div", { className: "flex", children: /* @__PURE__ */ jsx31("span", { className: "text-xs font-medium text-zinc-700", children: label }) }),
5102
+ /* @__PURE__ */ jsx31(
4971
5103
  Controller2,
4972
5104
  {
4973
5105
  name,
4974
- render: ({ field }) => /* @__PURE__ */ jsx29(
5106
+ render: ({ field }) => /* @__PURE__ */ jsx31(
4975
5107
  "input",
4976
5108
  {
4977
5109
  className: "plain-input rounded-md border border-zinc-300 px-3 py-1 shadow-sm",
@@ -4999,19 +5131,41 @@ var FormItem = ({
4999
5131
  readOnly,
5000
5132
  data
5001
5133
  });
5002
- return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
5003
- /* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-1 text-xs", children: [
5004
- /* @__PURE__ */ jsx29("span", { className: "font-medium text-zinc-700", children: label }),
5134
+ return /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
5135
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-1 text-xs", children: [
5136
+ /* @__PURE__ */ jsx31("span", { className: "font-medium text-zinc-700", children: label }),
5005
5137
  " ",
5006
- /* @__PURE__ */ jsx29("span", { className: "text-zinc-300", children: "/" }),
5138
+ /* @__PURE__ */ jsx31("span", { className: "text-zinc-300", children: "/" }),
5007
5139
  selector
5008
5140
  ] }),
5009
- /* @__PURE__ */ jsx29("div", { className: "overflow-hidden rounded-md border border-zinc-300 bg-white p-2 shadow-sm", children: editor })
5141
+ /* @__PURE__ */ jsx31("div", { className: "overflow-hidden rounded-md border border-zinc-300 bg-white p-2 shadow-sm", children: editor })
5010
5142
  ] });
5011
5143
  };
5012
5144
 
5145
+ // src/components/databrowser/components/display/hash/hash-field-ttl-info.tsx
5146
+ import { useEffect as useEffect8, useState as useState9 } from "react";
5147
+ import { jsx as jsx32 } from "react/jsx-runtime";
5148
+ var HashFieldTTLInfo = ({
5149
+ dataKey,
5150
+ field,
5151
+ fields
5152
+ }) => {
5153
+ const { data } = useFetchHashFieldExpires({ dataKey, fields });
5154
+ const expireAt = data?.[field];
5155
+ const [ttl, setTTL] = useState9(() => calculateTTL(expireAt));
5156
+ useEffect8(() => {
5157
+ setTTL(calculateTTL(expireAt));
5158
+ const interval = setInterval(() => {
5159
+ setTTL(calculateTTL(expireAt));
5160
+ }, 1e3);
5161
+ return () => clearInterval(interval);
5162
+ }, [expireAt]);
5163
+ if (!expireAt || expireAt === TTL_NOT_FOUND || expireAt === TTL_INFINITE) return;
5164
+ return /* @__PURE__ */ jsx32("span", { className: "block min-w-[30px] whitespace-nowrap text-right text-red-600", children: formatTime(ttl ?? 0) });
5165
+ };
5166
+
5013
5167
  // src/components/databrowser/components/display/display-list.tsx
5014
- import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
5168
+ import { Fragment as Fragment5, jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
5015
5169
  var headerLabels = {
5016
5170
  list: ["Index", "Content"],
5017
5171
  hash: ["Field", "Value"],
@@ -5022,10 +5176,10 @@ var headerLabels = {
5022
5176
  var ListDisplay = ({ dataKey, type }) => {
5023
5177
  const { selectedListItem } = useDatabrowserStore();
5024
5178
  const query = useFetchListItems({ dataKey, type });
5025
- return /* @__PURE__ */ jsxs20("div", { className: "flex h-full flex-col gap-2", children: [
5026
- /* @__PURE__ */ jsx30(DisplayHeader, { dataKey, type }),
5027
- selectedListItem && /* @__PURE__ */ jsx30(ListEditDisplay, { dataKey, type, item: selectedListItem }),
5028
- /* @__PURE__ */ jsx30("div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ jsx30(InfiniteScroll, { query, children: /* @__PURE__ */ jsx30("div", { className: "pr-3", children: /* @__PURE__ */ jsx30("table", { className: "w-full", children: /* @__PURE__ */ jsx30(ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ jsx30("tbody", { children: /* @__PURE__ */ jsx30(ListItems, { dataKey, type, query }) }) }) }) }) }) })
5179
+ return /* @__PURE__ */ jsxs21("div", { className: "flex h-full flex-col gap-2", children: [
5180
+ /* @__PURE__ */ jsx33(DisplayHeader, { dataKey, type }),
5181
+ selectedListItem && /* @__PURE__ */ jsx33(ListEditDisplay, { dataKey, type, item: selectedListItem }),
5182
+ /* @__PURE__ */ jsx33("div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ jsx33(InfiniteScroll, { query, children: /* @__PURE__ */ jsx33("div", { className: "pr-3", children: /* @__PURE__ */ jsx33("table", { className: "w-full", children: /* @__PURE__ */ jsx33(ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ jsx33("tbody", { children: /* @__PURE__ */ jsx33(ListItems, { dataKey, type, query }) }) }) }) }) }) })
5029
5183
  ] });
5030
5184
  };
5031
5185
  var ListItems = ({
@@ -5035,8 +5189,9 @@ var ListItems = ({
5035
5189
  }) => {
5036
5190
  const { setSelectedListItem } = useDatabrowserStore();
5037
5191
  const keys = useMemo5(() => query.data?.pages.flatMap((page) => page.keys) ?? [], [query.data]);
5192
+ const fields = useMemo5(() => keys.map((key) => key.key), [keys]);
5038
5193
  const { mutate: editItem } = useEditListItem();
5039
- return /* @__PURE__ */ jsx30(Fragment5, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ jsxs20(
5194
+ return /* @__PURE__ */ jsx33(Fragment5, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ jsxs21(
5040
5195
  "tr",
5041
5196
  {
5042
5197
  "data-item-key": key,
@@ -5044,9 +5199,9 @@ var ListItems = ({
5044
5199
  onClick: () => {
5045
5200
  setSelectedListItem({ key });
5046
5201
  },
5047
- className: "h-10 border-b border-b-zinc-100 hover:bg-zinc-50",
5202
+ className: cn("h-10 border-b border-b-zinc-100 hover:bg-zinc-100 "),
5048
5203
  children: [
5049
- /* @__PURE__ */ jsx30(
5204
+ /* @__PURE__ */ jsx33(
5050
5205
  "td",
5051
5206
  {
5052
5207
  className: cn(
@@ -5056,38 +5211,49 @@ var ListItems = ({
5056
5211
  children: key
5057
5212
  }
5058
5213
  ),
5059
- value !== void 0 && /* @__PURE__ */ jsx30(
5214
+ value !== void 0 && /* @__PURE__ */ jsx33(
5060
5215
  "td",
5061
5216
  {
5062
5217
  className: cn("cursor-pointer truncate px-3", type === "zset" ? "w-24" : "max-w-0"),
5063
5218
  children: value
5064
5219
  }
5065
5220
  ),
5066
- type !== "stream" && /* @__PURE__ */ jsx30(
5221
+ type !== "stream" && /* @__PURE__ */ jsx33(
5067
5222
  "td",
5068
5223
  {
5069
- width: 20,
5070
- className: "px-3",
5224
+ className: "w-0 min-w-0 p-0",
5071
5225
  onClick: (e) => {
5072
5226
  e.stopPropagation();
5073
5227
  },
5074
- children: /* @__PURE__ */ jsx30(
5075
- DeleteAlertDialog,
5076
- {
5077
- deletionType: "item",
5078
- onDeleteConfirm: (e) => {
5079
- e.stopPropagation();
5080
- editItem({
5081
- type,
5082
- dataKey,
5083
- itemKey: key,
5084
- // For deletion
5085
- newKey: void 0
5086
- });
5087
- },
5088
- children: /* @__PURE__ */ jsx30(Button, { size: "icon-sm", variant: "secondary", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx30(IconTrash, { className: "size-4 text-zinc-500" }) })
5089
- }
5090
- )
5228
+ children: /* @__PURE__ */ jsxs21("div", { className: "flex items-center justify-end gap-2", children: [
5229
+ type === "hash" && /* @__PURE__ */ jsx33(HashFieldTTLInfo, { dataKey, field: key, fields }),
5230
+ /* @__PURE__ */ jsx33(
5231
+ DeleteAlertDialog,
5232
+ {
5233
+ deletionType: "item",
5234
+ onDeleteConfirm: (e) => {
5235
+ e.stopPropagation();
5236
+ editItem({
5237
+ type,
5238
+ dataKey,
5239
+ itemKey: key,
5240
+ // For deletion
5241
+ newKey: void 0
5242
+ });
5243
+ },
5244
+ children: /* @__PURE__ */ jsx33(
5245
+ Button,
5246
+ {
5247
+ className: "",
5248
+ size: "icon-sm",
5249
+ variant: "secondary",
5250
+ onClick: (e) => e.stopPropagation(),
5251
+ children: /* @__PURE__ */ jsx33(IconTrash, { className: "size-4 text-zinc-500" })
5252
+ }
5253
+ )
5254
+ }
5255
+ )
5256
+ ] })
5091
5257
  }
5092
5258
  )
5093
5259
  ]
@@ -5099,16 +5265,16 @@ var ListItems = ({
5099
5265
  // src/components/databrowser/components/display/display-simple.tsx
5100
5266
  import { useEffect as useEffect9 } from "react";
5101
5267
  import { useForm as useForm3 } from "react-hook-form";
5102
- import { Fragment as Fragment6, jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
5268
+ import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
5103
5269
  var EditorDisplay = ({ dataKey, type }) => {
5104
5270
  const { data } = useFetchSimpleKey(dataKey, type);
5105
- return /* @__PURE__ */ jsxs21("div", { className: "flex h-full w-full flex-col gap-2", children: [
5106
- /* @__PURE__ */ jsx31(DisplayHeader, { dataKey, type, content: data ?? void 0 }),
5107
- /* @__PURE__ */ jsx31(
5271
+ return /* @__PURE__ */ jsxs22("div", { className: "flex h-full w-full flex-col gap-2", children: [
5272
+ /* @__PURE__ */ jsx34(DisplayHeader, { dataKey, type, content: data ?? void 0 }),
5273
+ /* @__PURE__ */ jsx34(
5108
5274
  "div",
5109
5275
  {
5110
5276
  className: "flex h-full grow flex-col gap-2\n rounded-md bg-zinc-100 p-3",
5111
- children: data === void 0 ? /* @__PURE__ */ jsx31(Spinner, { isLoadingText: "", isLoading: true }) : data === null ? /* @__PURE__ */ jsx31(Fragment6, {}) : /* @__PURE__ */ jsx31(EditorDisplayForm, { dataKey, type, data }, dataKey)
5277
+ children: data === void 0 ? /* @__PURE__ */ jsx34(Spinner, { isLoadingText: "", isLoading: true }) : data === null ? /* @__PURE__ */ jsx34(Fragment6, {}) : /* @__PURE__ */ jsx34(EditorDisplayForm, { dataKey, type, data }, dataKey)
5112
5278
  }
5113
5279
  )
5114
5280
  ] });
@@ -5122,26 +5288,21 @@ var EditorDisplayForm = ({
5122
5288
  defaultValues: { value: data }
5123
5289
  });
5124
5290
  useEffect9(() => {
5125
- form.reset(
5126
- { value: data },
5127
- {
5128
- keepValues: false
5129
- }
5130
- );
5291
+ form.reset({ value: data });
5131
5292
  }, [data]);
5132
5293
  const { editor, selector } = useField({ name: "value", form, data });
5133
5294
  const { mutateAsync: setKey, isPending: isSettingKey } = useSetSimpleKey(dataKey, type);
5134
5295
  const handleCancel = () => {
5135
- form.reset();
5296
+ form.reset({ value: data });
5136
5297
  };
5137
- return /* @__PURE__ */ jsxs21(Fragment6, { children: [
5138
- /* @__PURE__ */ jsxs21("div", { className: "flex grow flex-col gap-1", children: [
5139
- /* @__PURE__ */ jsx31("div", { className: "flex shrink-0 items-center gap-2", children: type === "json" ? /* @__PURE__ */ jsx31("div", {}) : selector }),
5140
- /* @__PURE__ */ jsx31("div", { className: "grow rounded-md border border-zinc-300 bg-white p-1", children: editor })
5298
+ return /* @__PURE__ */ jsxs22(Fragment6, { children: [
5299
+ /* @__PURE__ */ jsxs22("div", { className: "flex grow flex-col gap-1", children: [
5300
+ /* @__PURE__ */ jsx34("div", { className: "flex shrink-0 items-center gap-2", children: type === "json" ? /* @__PURE__ */ jsx34("div", {}) : selector }),
5301
+ /* @__PURE__ */ jsx34("div", { className: "grow rounded-md border border-zinc-300 bg-white p-1", children: editor })
5141
5302
  ] }),
5142
- /* @__PURE__ */ jsx31("div", { className: "flex shrink-0 items-center gap-2", children: /* @__PURE__ */ jsxs21("div", { className: "ml-auto flex gap-2", children: [
5143
- form.formState.isDirty && /* @__PURE__ */ jsx31(Button, { onClick: handleCancel, children: "Cancel" }),
5144
- /* @__PURE__ */ jsx31(
5303
+ /* @__PURE__ */ jsx34("div", { className: "flex shrink-0 items-center gap-2", children: /* @__PURE__ */ jsxs22("div", { className: "ml-auto flex gap-2", children: [
5304
+ form.formState.isDirty && /* @__PURE__ */ jsx34(Button, { onClick: handleCancel, children: "Cancel" }),
5305
+ /* @__PURE__ */ jsx34(
5145
5306
  Button,
5146
5307
  {
5147
5308
  variant: "primary",
@@ -5149,7 +5310,7 @@ var EditorDisplayForm = ({
5149
5310
  await setKey(value);
5150
5311
  }),
5151
5312
  disabled: !form.formState.isValid || !form.formState.isDirty,
5152
- children: /* @__PURE__ */ jsx31(Spinner, { isLoading: isSettingKey, isLoadingText: "Saving", children: "Save" })
5313
+ children: /* @__PURE__ */ jsx34(Spinner, { isLoading: isSettingKey, isLoadingText: "Saving", children: "Save" })
5153
5314
  }
5154
5315
  )
5155
5316
  ] }) })
@@ -5157,19 +5318,19 @@ var EditorDisplayForm = ({
5157
5318
  };
5158
5319
 
5159
5320
  // src/components/databrowser/components/display/index.tsx
5160
- import { Fragment as Fragment7, jsx as jsx32 } from "react/jsx-runtime";
5321
+ import { Fragment as Fragment7, jsx as jsx35 } from "react/jsx-runtime";
5161
5322
  var DataDisplay = () => {
5162
5323
  const { selectedKey } = useDatabrowserStore();
5163
5324
  const { query } = useKeys();
5164
5325
  const type = useKeyType(selectedKey);
5165
- return /* @__PURE__ */ jsx32("div", { className: "h-full rounded-xl border bg-white p-1", children: !selectedKey ? /* @__PURE__ */ jsx32("div", {}) : !type ? query.isLoading ? /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32("span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ jsx32("div", {}) : /* @__PURE__ */ jsx32(Fragment7, { children: type === "string" || type === "json" ? /* @__PURE__ */ jsx32(EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ jsx32(ListDisplay, { dataKey: selectedKey, type }) }) });
5326
+ return /* @__PURE__ */ jsx35("div", { className: "h-full rounded-xl border bg-white p-1", children: !selectedKey ? /* @__PURE__ */ jsx35("div", {}) : !type ? query.isLoading ? /* @__PURE__ */ jsx35("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx35("span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ jsx35("div", {}) : /* @__PURE__ */ jsx35(Fragment7, { children: type === "string" || type === "json" ? /* @__PURE__ */ jsx35(EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ jsx35(ListDisplay, { dataKey: selectedKey, type }) }) });
5166
5327
  };
5167
5328
 
5168
5329
  // src/components/databrowser/components/sidebar/index.tsx
5169
5330
  import { IconRefresh } from "@tabler/icons-react";
5170
5331
 
5171
5332
  // src/components/databrowser/components/add-key-modal.tsx
5172
- import { useState as useState8 } from "react";
5333
+ import { useState as useState10 } from "react";
5173
5334
  import { DialogDescription as DialogDescription2 } from "@radix-ui/react-dialog";
5174
5335
  import { PlusIcon } from "@radix-ui/react-icons";
5175
5336
  import { Controller as Controller3, useForm as useForm4 } from "react-hook-form";
@@ -5177,12 +5338,12 @@ import { Controller as Controller3, useForm as useForm4 } from "react-hook-form"
5177
5338
  // src/components/ui/dialog.tsx
5178
5339
  import * as React12 from "react";
5179
5340
  import * as DialogPrimitive from "@radix-ui/react-dialog";
5180
- import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
5341
+ import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
5181
5342
  var Dialog = DialogPrimitive.Root;
5182
5343
  var DialogTrigger = DialogPrimitive.Trigger;
5183
- var DialogPortal = (props) => /* @__PURE__ */ jsx33(DialogPrimitive.Portal, { container: portalRoot, ...props });
5344
+ var DialogPortal = (props) => /* @__PURE__ */ jsx36(DialogPrimitive.Portal, { container: portalRoot, ...props });
5184
5345
  DialogPortal.displayName = DialogPrimitive.Portal.displayName;
5185
- var DialogOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx33(
5346
+ var DialogOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx36(
5186
5347
  DialogPrimitive.Overlay,
5187
5348
  {
5188
5349
  ref,
@@ -5196,9 +5357,9 @@ var DialogOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__P
5196
5357
  }
5197
5358
  ));
5198
5359
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
5199
- var DialogContent = React12.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs22(DialogPortal, { children: [
5200
- /* @__PURE__ */ jsx33(DialogOverlay, {}),
5201
- /* @__PURE__ */ jsxs22(
5360
+ var DialogContent = React12.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs23(DialogPortal, { children: [
5361
+ /* @__PURE__ */ jsx36(DialogOverlay, {}),
5362
+ /* @__PURE__ */ jsxs23(
5202
5363
  DialogPrimitive.Content,
5203
5364
  {
5204
5365
  ref,
@@ -5218,8 +5379,8 @@ var DialogContent = React12.forwardRef(({ className, children, ...props }, ref)
5218
5379
  ...props,
5219
5380
  children: [
5220
5381
  children,
5221
- /* @__PURE__ */ jsxs22(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-zinc-100 data-[state=open]:text-zinc-500 dark:ring-offset-zinc-950 dark:focus:ring-zinc-300 dark:data-[state=open]:bg-zinc-800 dark:data-[state=open]:text-zinc-400", children: [
5222
- /* @__PURE__ */ jsx33(
5382
+ /* @__PURE__ */ jsxs23(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-zinc-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-zinc-100 data-[state=open]:text-zinc-500 dark:ring-offset-zinc-950 dark:focus:ring-zinc-300 dark:data-[state=open]:bg-zinc-800 dark:data-[state=open]:text-zinc-400", children: [
5383
+ /* @__PURE__ */ jsx36(
5223
5384
  "svg",
5224
5385
  {
5225
5386
  width: "15",
@@ -5228,7 +5389,7 @@ var DialogContent = React12.forwardRef(({ className, children, ...props }, ref)
5228
5389
  fill: "none",
5229
5390
  xmlns: "http://www.w3.org/2000/svg",
5230
5391
  className: "h-4 w-4",
5231
- children: /* @__PURE__ */ jsx33(
5392
+ children: /* @__PURE__ */ jsx36(
5232
5393
  "path",
5233
5394
  {
5234
5395
  d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z",
@@ -5239,16 +5400,16 @@ var DialogContent = React12.forwardRef(({ className, children, ...props }, ref)
5239
5400
  )
5240
5401
  }
5241
5402
  ),
5242
- /* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Close" })
5403
+ /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "Close" })
5243
5404
  ] })
5244
5405
  ]
5245
5406
  }
5246
5407
  )
5247
5408
  ] }));
5248
5409
  DialogContent.displayName = DialogPrimitive.Content.displayName;
5249
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx33("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
5410
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx36("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
5250
5411
  DialogHeader.displayName = "DialogHeader";
5251
- var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx33(
5412
+ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx36(
5252
5413
  "div",
5253
5414
  {
5254
5415
  className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
@@ -5256,7 +5417,7 @@ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx33(
5256
5417
  }
5257
5418
  );
5258
5419
  DialogFooter.displayName = "DialogFooter";
5259
- var DialogTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx33(
5420
+ var DialogTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx36(
5260
5421
  DialogPrimitive.Title,
5261
5422
  {
5262
5423
  ref,
@@ -5265,7 +5426,7 @@ var DialogTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PUR
5265
5426
  }
5266
5427
  ));
5267
5428
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5268
- var DialogDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx33(
5429
+ var DialogDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx36(
5269
5430
  DialogPrimitive.Description,
5270
5431
  {
5271
5432
  ref,
@@ -5276,10 +5437,10 @@ var DialogDescription = React12.forwardRef(({ className, ...props }, ref) => /*
5276
5437
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
5277
5438
 
5278
5439
  // src/components/databrowser/components/add-key-modal.tsx
5279
- import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
5440
+ import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
5280
5441
  function AddKeyModal() {
5281
5442
  const { setSelectedKey } = useDatabrowserStore();
5282
- const [open, setOpen] = useState8(false);
5443
+ const [open, setOpen] = useState10(false);
5283
5444
  const { mutateAsync: addKey, isPending } = useAddKey();
5284
5445
  const { control, handleSubmit, formState, reset } = useForm4({
5285
5446
  defaultValues: {
@@ -5299,7 +5460,7 @@ function AddKeyModal() {
5299
5460
  });
5300
5461
  }, 100);
5301
5462
  });
5302
- return /* @__PURE__ */ jsxs23(
5463
+ return /* @__PURE__ */ jsxs24(
5303
5464
  Dialog,
5304
5465
  {
5305
5466
  open,
@@ -5308,24 +5469,24 @@ function AddKeyModal() {
5308
5469
  setOpen(open2);
5309
5470
  },
5310
5471
  children: [
5311
- /* @__PURE__ */ jsx34(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(Button, { variant: "primary", size: "icon-sm", children: /* @__PURE__ */ jsx34(PlusIcon, { className: "size-4" }) }) }),
5312
- /* @__PURE__ */ jsxs23(DialogContent, { className: "max-w-[400px]", children: [
5313
- /* @__PURE__ */ jsx34(DialogHeader, { children: /* @__PURE__ */ jsx34(DialogTitle, { children: "Create new key" }) }),
5314
- /* @__PURE__ */ jsx34("div", { className: "sr-only", children: /* @__PURE__ */ jsx34(DialogDescription2, { children: "Create new key" }) }),
5315
- /* @__PURE__ */ jsxs23("form", { className: "mt-4", onSubmit, children: [
5316
- /* @__PURE__ */ jsxs23("div", { className: "flex gap-1", children: [
5317
- /* @__PURE__ */ jsx34(
5472
+ /* @__PURE__ */ jsx37(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(Button, { variant: "primary", size: "icon-sm", children: /* @__PURE__ */ jsx37(PlusIcon, { className: "size-4" }) }) }),
5473
+ /* @__PURE__ */ jsxs24(DialogContent, { className: "max-w-[400px]", children: [
5474
+ /* @__PURE__ */ jsx37(DialogHeader, { children: /* @__PURE__ */ jsx37(DialogTitle, { children: "Create new key" }) }),
5475
+ /* @__PURE__ */ jsx37("div", { className: "sr-only", children: /* @__PURE__ */ jsx37(DialogDescription2, { children: "Create new key" }) }),
5476
+ /* @__PURE__ */ jsxs24("form", { className: "mt-4", onSubmit, children: [
5477
+ /* @__PURE__ */ jsxs24("div", { className: "flex gap-1", children: [
5478
+ /* @__PURE__ */ jsx37(
5318
5479
  Controller3,
5319
5480
  {
5320
5481
  control,
5321
5482
  name: "type",
5322
- render: ({ field }) => /* @__PURE__ */ jsxs23(Select, { value: field.value, onValueChange: field.onChange, children: [
5323
- /* @__PURE__ */ jsx34(SelectTrigger, { className: "h-8 w-auto pl-[3px] pr-8", children: /* @__PURE__ */ jsx34(SelectValue, {}) }),
5324
- /* @__PURE__ */ jsx34(SelectContent, { children: /* @__PURE__ */ jsx34(SelectGroup, { children: DATA_TYPES.map((type) => /* @__PURE__ */ jsx34(SelectItem, { value: type, children: /* @__PURE__ */ jsx34(TypeTag, { variant: type, type: "badge" }) }, type)) }) })
5483
+ render: ({ field }) => /* @__PURE__ */ jsxs24(Select, { value: field.value, onValueChange: field.onChange, children: [
5484
+ /* @__PURE__ */ jsx37(SelectTrigger, { className: "h-8 w-auto pl-[3px] pr-8", children: /* @__PURE__ */ jsx37(SelectValue, {}) }),
5485
+ /* @__PURE__ */ jsx37(SelectContent, { children: /* @__PURE__ */ jsx37(SelectGroup, { children: DATA_TYPES.map((type) => /* @__PURE__ */ jsx37(SelectItem, { value: type, children: /* @__PURE__ */ jsx37(TypeTag, { variant: type, type: "badge" }) }, type)) }) })
5325
5486
  ] })
5326
5487
  }
5327
5488
  ),
5328
- /* @__PURE__ */ jsx34(
5489
+ /* @__PURE__ */ jsx37(
5329
5490
  Controller3,
5330
5491
  {
5331
5492
  rules: {
@@ -5333,14 +5494,14 @@ function AddKeyModal() {
5333
5494
  },
5334
5495
  control,
5335
5496
  name: "key",
5336
- render: ({ field }) => /* @__PURE__ */ jsx34(Input, { placeholder: "mykey", ...field, className: "h-8 grow" })
5497
+ render: ({ field }) => /* @__PURE__ */ jsx37(Input, { placeholder: "mykey", ...field, className: "h-8 grow" })
5337
5498
  }
5338
5499
  )
5339
5500
  ] }),
5340
- formState.errors.key && /* @__PURE__ */ jsx34("p", { className: "mb-3 mt-2 text-xs text-red-500", children: formState.errors.key?.message }),
5341
- /* @__PURE__ */ jsx34("p", { className: "mt-2 text-xs text-zinc-500", children: "After creating the key, you can edit the value" }),
5342
- /* @__PURE__ */ jsxs23("div", { className: "mt-6 flex justify-end gap-2", children: [
5343
- /* @__PURE__ */ jsx34(
5501
+ formState.errors.key && /* @__PURE__ */ jsx37("p", { className: "mb-3 mt-2 text-xs text-red-500", children: formState.errors.key?.message }),
5502
+ /* @__PURE__ */ jsx37("p", { className: "mt-2 text-xs text-zinc-500", children: "After creating the key, you can edit the value" }),
5503
+ /* @__PURE__ */ jsxs24("div", { className: "mt-6 flex justify-end gap-2", children: [
5504
+ /* @__PURE__ */ jsx37(
5344
5505
  Button,
5345
5506
  {
5346
5507
  type: "button",
@@ -5351,7 +5512,7 @@ function AddKeyModal() {
5351
5512
  children: "Cancel"
5352
5513
  }
5353
5514
  ),
5354
- /* @__PURE__ */ jsx34(Button, { variant: "primary", type: "submit", children: /* @__PURE__ */ jsx34(Spinner, { isLoading: isPending, isLoadingText: "Creating", children: "Create" }) })
5515
+ /* @__PURE__ */ jsx37(Button, { variant: "primary", type: "submit", children: /* @__PURE__ */ jsx37(Spinner, { isLoading: isPending, isLoadingText: "Creating", children: "Create" }) })
5355
5516
  ] })
5356
5517
  ] })
5357
5518
  ] })
@@ -5361,24 +5522,24 @@ function AddKeyModal() {
5361
5522
  }
5362
5523
 
5363
5524
  // src/components/databrowser/components/sidebar/empty.tsx
5364
- import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
5525
+ import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
5365
5526
  var Empty = () => {
5366
- return /* @__PURE__ */ jsx35("div", { className: "flex h-full w-full items-center justify-center rounded-md border border-dashed px-4 py-6 text-center", children: /* @__PURE__ */ jsxs24("div", { className: "space-y-5", children: [
5367
- /* @__PURE__ */ jsx35("p", { className: "text-md font-medium", children: "Data on a break" }),
5368
- /* @__PURE__ */ jsx35("p", { className: "text-balance text-center", children: '"Quick, lure it back with some CLI magic!"' })
5527
+ return /* @__PURE__ */ jsx38("div", { className: "flex h-full w-full items-center justify-center rounded-md border border-dashed px-4 py-6 text-center", children: /* @__PURE__ */ jsxs25("div", { className: "space-y-5", children: [
5528
+ /* @__PURE__ */ jsx38("p", { className: "text-md font-medium", children: "Data on a break" }),
5529
+ /* @__PURE__ */ jsx38("p", { className: "text-balance text-center", children: '"Quick, lure it back with some CLI magic!"' })
5369
5530
  ] }) });
5370
5531
  };
5371
5532
 
5372
5533
  // src/components/databrowser/components/sidebar-context-menu.tsx
5373
- import { useState as useState9 } from "react";
5534
+ import { useState as useState11 } from "react";
5374
5535
  import { ContextMenuSeparator as ContextMenuSeparator3 } from "@radix-ui/react-context-menu";
5375
- import { Fragment as Fragment8, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
5536
+ import { Fragment as Fragment8, jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
5376
5537
  var SidebarContextMenu = ({ children }) => {
5377
5538
  const { mutate: deleteKey } = useDeleteKey();
5378
- const [isAlertOpen, setAlertOpen] = useState9(false);
5379
- const [dataKey, setDataKey] = useState9("");
5380
- return /* @__PURE__ */ jsxs25(Fragment8, { children: [
5381
- /* @__PURE__ */ jsx36(
5539
+ const [isAlertOpen, setAlertOpen] = useState11(false);
5540
+ const [dataKey, setDataKey] = useState11("");
5541
+ return /* @__PURE__ */ jsxs26(Fragment8, { children: [
5542
+ /* @__PURE__ */ jsx39(
5382
5543
  DeleteAlertDialog,
5383
5544
  {
5384
5545
  deletionType: "key",
@@ -5391,8 +5552,8 @@ var SidebarContextMenu = ({ children }) => {
5391
5552
  }
5392
5553
  }
5393
5554
  ),
5394
- /* @__PURE__ */ jsxs25(ContextMenu, { children: [
5395
- /* @__PURE__ */ jsx36(
5555
+ /* @__PURE__ */ jsxs26(ContextMenu, { children: [
5556
+ /* @__PURE__ */ jsx39(
5396
5557
  ContextMenuTrigger,
5397
5558
  {
5398
5559
  onContextMenu: (e) => {
@@ -5407,8 +5568,8 @@ var SidebarContextMenu = ({ children }) => {
5407
5568
  children
5408
5569
  }
5409
5570
  ),
5410
- /* @__PURE__ */ jsxs25(ContextMenuContent, { children: [
5411
- /* @__PURE__ */ jsx36(
5571
+ /* @__PURE__ */ jsxs26(ContextMenuContent, { children: [
5572
+ /* @__PURE__ */ jsx39(
5412
5573
  ContextMenuItem,
5413
5574
  {
5414
5575
  onClick: () => {
@@ -5420,18 +5581,18 @@ var SidebarContextMenu = ({ children }) => {
5420
5581
  children: "Copy key"
5421
5582
  }
5422
5583
  ),
5423
- /* @__PURE__ */ jsx36(ContextMenuSeparator3, {}),
5424
- /* @__PURE__ */ jsx36(ContextMenuItem, { onClick: () => setAlertOpen(true), children: "Delete key" })
5584
+ /* @__PURE__ */ jsx39(ContextMenuSeparator3, {}),
5585
+ /* @__PURE__ */ jsx39(ContextMenuItem, { onClick: () => setAlertOpen(true), children: "Delete key" })
5425
5586
  ] })
5426
5587
  ] })
5427
5588
  ] });
5428
5589
  };
5429
5590
 
5430
5591
  // src/components/databrowser/components/sidebar/keys-list.tsx
5431
- import { Fragment as Fragment9, jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
5592
+ import { Fragment as Fragment9, jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
5432
5593
  var KeysList = () => {
5433
5594
  const { keys } = useKeys();
5434
- return /* @__PURE__ */ jsx37("div", { className: "pr-3", children: /* @__PURE__ */ jsx37(SidebarContextMenu, { children: /* @__PURE__ */ jsx37(Fragment9, { children: keys.map((data, i) => /* @__PURE__ */ jsx37(KeyItem, { nextKey: keys.at(i + 1)?.[0] ?? "", data }, data[0])) }) }) });
5595
+ return /* @__PURE__ */ jsx40("div", { className: "pr-3", children: /* @__PURE__ */ jsx40(SidebarContextMenu, { children: /* @__PURE__ */ jsx40(Fragment9, { children: keys.map((data, i) => /* @__PURE__ */ jsx40(KeyItem, { nextKey: keys.at(i + 1)?.[0] ?? "", data }, data[0])) }) }) });
5435
5596
  };
5436
5597
  var keyStyles = {
5437
5598
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5447,7 +5608,7 @@ var KeyItem = ({ data, nextKey }) => {
5447
5608
  const [dataKey, dataType] = data;
5448
5609
  const isKeySelected = selectedKey === dataKey;
5449
5610
  const isNextKeySelected = selectedKey === nextKey;
5450
- return /* @__PURE__ */ jsxs26(
5611
+ return /* @__PURE__ */ jsxs27(
5451
5612
  Button,
5452
5613
  {
5453
5614
  "data-key": dataKey,
@@ -5460,28 +5621,28 @@ var KeyItem = ({ data, nextKey }) => {
5460
5621
  ),
5461
5622
  onClick: () => setSelectedKey(dataKey),
5462
5623
  children: [
5463
- /* @__PURE__ */ jsx37(TypeTag, { variant: dataType, type: "icon" }),
5464
- /* @__PURE__ */ jsx37("p", { className: "truncate whitespace-nowrap", children: dataKey }),
5465
- !isKeySelected && !isNextKeySelected && /* @__PURE__ */ jsx37("span", { className: "absolute -bottom-px left-3 right-3 h-px bg-zinc-100" })
5624
+ /* @__PURE__ */ jsx40(TypeTag, { variant: dataType, type: "icon" }),
5625
+ /* @__PURE__ */ jsx40("p", { className: "truncate whitespace-nowrap", children: dataKey }),
5626
+ !isKeySelected && !isNextKeySelected && /* @__PURE__ */ jsx40("span", { className: "absolute -bottom-px left-3 right-3 h-px bg-zinc-100" })
5466
5627
  ]
5467
5628
  }
5468
5629
  );
5469
5630
  };
5470
5631
 
5471
5632
  // src/components/databrowser/components/sidebar/search-input.tsx
5472
- import { useState as useState10 } from "react";
5633
+ import { useState as useState12 } from "react";
5473
5634
  import { IconX } from "@tabler/icons-react";
5474
- import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
5635
+ import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
5475
5636
  var SearchInput = () => {
5476
5637
  const { setSearchKey, search } = useDatabrowserStore();
5477
- const [state, setState] = useState10(search.key);
5638
+ const [state, setState] = useState12(search.key);
5478
5639
  const submit = (value) => {
5479
5640
  if (value.trim() !== "" && !value.includes("*")) value = `${value}*`;
5480
5641
  setSearchKey(value);
5481
5642
  setState(value);
5482
5643
  };
5483
- return /* @__PURE__ */ jsxs27("div", { className: "relative grow", children: [
5484
- /* @__PURE__ */ jsx38(
5644
+ return /* @__PURE__ */ jsxs28("div", { className: "relative grow", children: [
5645
+ /* @__PURE__ */ jsx41(
5485
5646
  Input,
5486
5647
  {
5487
5648
  placeholder: "Search",
@@ -5496,7 +5657,7 @@ var SearchInput = () => {
5496
5657
  value: state
5497
5658
  }
5498
5659
  ),
5499
- search.key && /* @__PURE__ */ jsxs27(
5660
+ state && /* @__PURE__ */ jsxs28(
5500
5661
  Button,
5501
5662
  {
5502
5663
  type: "button",
@@ -5505,10 +5666,11 @@ var SearchInput = () => {
5505
5666
  className: "absolute right-1 top-1/2 h-5 w-5 -translate-y-1/2 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100",
5506
5667
  onClick: () => {
5507
5668
  setSearchKey("");
5669
+ setState("");
5508
5670
  },
5509
5671
  children: [
5510
- /* @__PURE__ */ jsx38(IconX, { size: 16 }),
5511
- /* @__PURE__ */ jsx38("span", { className: "sr-only", children: "Clear" })
5672
+ /* @__PURE__ */ jsx41(IconX, { size: 16 }),
5673
+ /* @__PURE__ */ jsx41("span", { className: "sr-only", children: "Clear" })
5512
5674
  ]
5513
5675
  }
5514
5676
  )
@@ -5516,19 +5678,19 @@ var SearchInput = () => {
5516
5678
  };
5517
5679
 
5518
5680
  // src/components/databrowser/components/sidebar/skeleton-buttons.tsx
5519
- import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
5681
+ import { jsx as jsx42, jsxs as jsxs29 } from "react/jsx-runtime";
5520
5682
  var DEFAULT_SKELETON_COUNT = 6;
5521
- var LoadingSkeleton = () => /* @__PURE__ */ jsx39("div", { className: "grid", children: Array.from({ length: DEFAULT_SKELETON_COUNT }).fill(0).map((_, idx) => /* @__PURE__ */ jsxs28("div", { className: "flex h-10 items-center gap-2 px-3", children: [
5522
- /* @__PURE__ */ jsx39(Skeleton, { className: "size-5 shrink-0 rounded" }),
5523
- /* @__PURE__ */ jsx39(Skeleton, { className: "h-4 grow rounded" })
5683
+ var LoadingSkeleton = () => /* @__PURE__ */ jsx42("div", { className: "grid", children: Array.from({ length: DEFAULT_SKELETON_COUNT }).fill(0).map((_, idx) => /* @__PURE__ */ jsxs29("div", { className: "flex h-10 items-center gap-2 px-3", children: [
5684
+ /* @__PURE__ */ jsx42(Skeleton, { className: "size-5 shrink-0 rounded" }),
5685
+ /* @__PURE__ */ jsx42(Skeleton, { className: "h-4 grow rounded" })
5524
5686
  ] }, idx)) });
5525
5687
 
5526
5688
  // src/components/databrowser/components/sidebar/type-selector.tsx
5527
- import { jsx as jsx40, jsxs as jsxs29 } from "react/jsx-runtime";
5689
+ import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
5528
5690
  var ALL_TYPES_KEY = "all";
5529
5691
  function DataTypeSelector() {
5530
5692
  const { search, setSearchType } = useDatabrowserStore();
5531
- return /* @__PURE__ */ jsxs29(
5693
+ return /* @__PURE__ */ jsxs30(
5532
5694
  Select,
5533
5695
  {
5534
5696
  onValueChange: (type) => {
@@ -5540,9 +5702,9 @@ function DataTypeSelector() {
5540
5702
  },
5541
5703
  value: search.type === void 0 ? ALL_TYPES_KEY : search.type,
5542
5704
  children: [
5543
- /* @__PURE__ */ jsx40(SelectTrigger, { className: "!w-auto select-none whitespace-nowrap rounded-r-none border-r-0 border-zinc-300 pr-8", children: /* @__PURE__ */ jsx40(SelectValue, {}) }),
5544
- /* @__PURE__ */ jsx40(SelectContent, { children: /* @__PURE__ */ jsx40(SelectGroup, { children: [[ALL_TYPES_KEY, "All Types"], ...Object.entries(DATA_TYPE_NAMES)].map(
5545
- ([key, value]) => /* @__PURE__ */ jsx40(SelectItem, { value: key, children: value }, key)
5705
+ /* @__PURE__ */ jsx43(SelectTrigger, { className: "!w-auto select-none whitespace-nowrap rounded-r-none border-r-0 border-zinc-300 pr-8", children: /* @__PURE__ */ jsx43(SelectValue, {}) }),
5706
+ /* @__PURE__ */ jsx43(SelectContent, { children: /* @__PURE__ */ jsx43(SelectGroup, { children: [[ALL_TYPES_KEY, "All Types"], ...Object.entries(DATA_TYPE_NAMES)].map(
5707
+ ([key, value]) => /* @__PURE__ */ jsx43(SelectItem, { value: key, children: value }, key)
5546
5708
  ) }) })
5547
5709
  ]
5548
5710
  }
@@ -5550,15 +5712,15 @@ function DataTypeSelector() {
5550
5712
  }
5551
5713
 
5552
5714
  // src/components/databrowser/components/sidebar/index.tsx
5553
- import { jsx as jsx41, jsxs as jsxs30 } from "react/jsx-runtime";
5715
+ import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
5554
5716
  function Sidebar() {
5555
5717
  const { keys, query, refetch } = useKeys();
5556
- return /* @__PURE__ */ jsxs30("div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5557
- /* @__PURE__ */ jsxs30("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5558
- /* @__PURE__ */ jsxs30("div", { className: "flex h-10 items-center justify-between pl-1", children: [
5559
- /* @__PURE__ */ jsx41(DisplayDbSize, {}),
5560
- /* @__PURE__ */ jsxs30("div", { className: "flex gap-1", children: [
5561
- /* @__PURE__ */ jsx41(
5718
+ return /* @__PURE__ */ jsxs31("div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5719
+ /* @__PURE__ */ jsxs31("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5720
+ /* @__PURE__ */ jsxs31("div", { className: "flex h-10 items-center justify-between pl-1", children: [
5721
+ /* @__PURE__ */ jsx44(DisplayDbSize, {}),
5722
+ /* @__PURE__ */ jsxs31("div", { className: "flex gap-1", children: [
5723
+ /* @__PURE__ */ jsx44(
5562
5724
  Button,
5563
5725
  {
5564
5726
  className: "h-7 w-7 px-0",
@@ -5573,39 +5735,45 @@ function Sidebar() {
5573
5735
  queryClient.invalidateQueries({
5574
5736
  queryKey: [FETCH_DB_SIZE_QUERY_KEY]
5575
5737
  });
5738
+ queryClient.invalidateQueries({
5739
+ queryKey: [FETCH_KEY_TYPE_QUERY_KEY]
5740
+ });
5576
5741
  },
5577
- children: /* @__PURE__ */ jsx41(Spinner, { isLoading: query.isFetching, children: /* @__PURE__ */ jsx41(IconRefresh, { size: 16 }) })
5742
+ children: /* @__PURE__ */ jsx44(Spinner, { isLoading: query.isFetching, children: /* @__PURE__ */ jsx44(IconRefresh, { size: 16 }) })
5578
5743
  }
5579
5744
  ),
5580
- /* @__PURE__ */ jsx41(AddKeyModal, {})
5745
+ /* @__PURE__ */ jsx44(AddKeyModal, {})
5581
5746
  ] })
5582
5747
  ] }),
5583
- /* @__PURE__ */ jsxs30("div", { className: "flex h-10 items-center", children: [
5584
- /* @__PURE__ */ jsx41(DataTypeSelector, {}),
5585
- /* @__PURE__ */ jsx41(SearchInput, {})
5748
+ /* @__PURE__ */ jsxs31("div", { className: "flex h-10 items-center", children: [
5749
+ /* @__PURE__ */ jsx44(DataTypeSelector, {}),
5750
+ /* @__PURE__ */ jsx44(SearchInput, {})
5586
5751
  ] })
5587
5752
  ] }),
5588
- query.isLoading ? /* @__PURE__ */ jsx41(LoadingSkeleton, {}) : keys.length > 0 ? /* @__PURE__ */ jsx41(InfiniteScroll, { query, children: /* @__PURE__ */ jsx41(KeysList, {}) }) : /* @__PURE__ */ jsx41(Empty, {})
5753
+ query.isLoading && keys.length === 0 ? /* @__PURE__ */ jsx44(LoadingSkeleton, {}) : keys.length > 0 ? (
5754
+ // Infinite scroll already has a loader at the bottom
5755
+ /* @__PURE__ */ jsx44(InfiniteScroll, { query, children: /* @__PURE__ */ jsx44(KeysList, {}) })
5756
+ ) : /* @__PURE__ */ jsx44(Empty, {})
5589
5757
  ] });
5590
5758
  }
5591
5759
 
5592
5760
  // src/components/databrowser/index.tsx
5593
- import { jsx as jsx42, jsxs as jsxs31 } from "react/jsx-runtime";
5761
+ import { jsx as jsx45, jsxs as jsxs32 } from "react/jsx-runtime";
5594
5762
  var RedisBrowser = ({ token, url }) => {
5595
5763
  const credentials = useMemo6(() => ({ token, url }), [token, url]);
5596
5764
  useEffect10(() => {
5597
5765
  queryClient.resetQueries();
5598
5766
  }, [credentials.url]);
5599
- return /* @__PURE__ */ jsx42(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx42(TooltipProvider, { children: /* @__PURE__ */ jsx42(DatabrowserProvider, { redisCredentials: credentials, children: /* @__PURE__ */ jsx42(KeysProvider, { children: /* @__PURE__ */ jsxs31("div", { className: "ups-db", style: { height: "100%" }, children: [
5600
- /* @__PURE__ */ jsxs31(
5767
+ return /* @__PURE__ */ jsx45(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx45(TooltipProvider, { children: /* @__PURE__ */ jsx45(DatabrowserProvider, { redisCredentials: credentials, children: /* @__PURE__ */ jsx45(KeysProvider, { children: /* @__PURE__ */ jsxs32("div", { className: "ups-db", style: { height: "100%" }, children: [
5768
+ /* @__PURE__ */ jsxs32(
5601
5769
  PanelGroup,
5602
5770
  {
5603
5771
  autoSaveId: "persistence",
5604
5772
  direction: "horizontal",
5605
5773
  className: "h-full w-full gap-0.5 text-sm antialiased",
5606
5774
  children: [
5607
- /* @__PURE__ */ jsx42(Panel, { defaultSize: 30, minSize: 30, children: /* @__PURE__ */ jsx42(Sidebar, {}) }),
5608
- /* @__PURE__ */ jsx42(PanelResizeHandle, { className: "h-fullm flex w-1.5 items-center justify-center rounded-full hover:bg-zinc-300/20", children: /* @__PURE__ */ jsx42(
5775
+ /* @__PURE__ */ jsx45(Panel, { defaultSize: 30, minSize: 30, children: /* @__PURE__ */ jsx45(Sidebar, {}) }),
5776
+ /* @__PURE__ */ jsx45(PanelResizeHandle, { className: "h-fullm flex w-1.5 items-center justify-center rounded-full hover:bg-zinc-300/20", children: /* @__PURE__ */ jsx45(
5609
5777
  IconDotsVertical2,
5610
5778
  {
5611
5779
  size: 16,
@@ -5613,11 +5781,11 @@ var RedisBrowser = ({ token, url }) => {
5613
5781
  className: "pointer-events-none shrink-0 opacity-20"
5614
5782
  }
5615
5783
  ) }),
5616
- /* @__PURE__ */ jsx42(Panel, { minSize: 40, children: /* @__PURE__ */ jsx42(DataDisplay, {}) })
5784
+ /* @__PURE__ */ jsx45(Panel, { minSize: 40, children: /* @__PURE__ */ jsx45(DataDisplay, {}) })
5617
5785
  ]
5618
5786
  }
5619
5787
  ),
5620
- /* @__PURE__ */ jsx42(Toaster, {})
5788
+ /* @__PURE__ */ jsx45(Toaster, {})
5621
5789
  ] }) }) }) }) });
5622
5790
  };
5623
5791
  export {