@upstash/react-redis-browser 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -260,7 +260,7 @@ var DatabrowserProvider = ({
260
260
  removeItem: () => {
261
261
  }
262
262
  },
263
- version: 2,
263
+ version: 3,
264
264
  // @ts-expect-error Reset the store for < v1
265
265
  migrate: (originalState, version) => {
266
266
  const state = originalState;
@@ -273,6 +273,21 @@ var DatabrowserProvider = ({
273
273
  tabs: state.tabs.map(([id, data]) => [id, { ...data, id }])
274
274
  };
275
275
  }
276
+ if (version === 2) {
277
+ return {
278
+ ...state,
279
+ tabs: state.tabs.map(([id, data]) => {
280
+ const oldData = data;
281
+ return [
282
+ id,
283
+ {
284
+ ...data,
285
+ selectedKeys: oldData.selectedKey ? [oldData.selectedKey] : []
286
+ }
287
+ ];
288
+ })
289
+ };
290
+ }
276
291
  return state;
277
292
  }
278
293
  })
@@ -302,7 +317,7 @@ var storeCreator = (set, get) => ({
302
317
  const id = crypto.randomUUID();
303
318
  const newTabData = {
304
319
  id,
305
- selectedKey: void 0,
320
+ selectedKeys: [],
306
321
  search: { key: "", type: void 0 },
307
322
  pinned: false
308
323
  };
@@ -395,16 +410,19 @@ var storeCreator = (set, get) => ({
395
410
  selectTab: (id) => {
396
411
  set({ selectedTab: id });
397
412
  },
398
- getSelectedKey: (tabId) => {
399
- return _optionalChain([get, 'call', _4 => _4(), 'access', _5 => _5.tabs, 'access', _6 => _6.find, 'call', _7 => _7(([id]) => id === tabId), 'optionalAccess', _8 => _8[1], 'optionalAccess', _9 => _9.selectedKey]);
413
+ getSelectedKeys: (tabId) => {
414
+ return _nullishCoalesce(_optionalChain([get, 'call', _4 => _4(), 'access', _5 => _5.tabs, 'access', _6 => _6.find, 'call', _7 => _7(([id]) => id === tabId), 'optionalAccess', _8 => _8[1], 'optionalAccess', _9 => _9.selectedKeys]), () => ( []));
400
415
  },
401
416
  setSelectedKey: (tabId, key) => {
417
+ get().setSelectedKeys(tabId, key ? [key] : []);
418
+ },
419
+ setSelectedKeys: (tabId, keys) => {
402
420
  set((old) => {
403
421
  const tabIndex = old.tabs.findIndex(([id]) => id === tabId);
404
422
  if (tabIndex === -1) return old;
405
423
  const newTabs = [...old.tabs];
406
424
  const [, tabData] = newTabs[tabIndex];
407
- newTabs[tabIndex] = [tabId, { ...tabData, selectedKey: key, selectedListItem: void 0 }];
425
+ newTabs[tabIndex] = [tabId, { ...tabData, selectedKeys: keys, selectedListItem: void 0 }];
408
426
  return { ...old, tabs: newTabs };
409
427
  });
410
428
  },
@@ -485,6 +503,7 @@ var useTab = () => {
485
503
  selectedTab,
486
504
  tabs,
487
505
  setSelectedKey,
506
+ setSelectedKeys,
488
507
  setSelectedListItem,
489
508
  setSearch,
490
509
  setSearchKey,
@@ -497,11 +516,14 @@ var useTab = () => {
497
516
  return _react.useMemo.call(void 0,
498
517
  () => ({
499
518
  active: selectedTab === tabId,
500
- selectedKey: tabData.selectedKey,
519
+ selectedKey: tabData.selectedKeys[0],
520
+ // Backwards compatibility - first selected key
521
+ selectedKeys: tabData.selectedKeys,
501
522
  selectedListItem: tabData.selectedListItem,
502
523
  search: tabData.search,
503
524
  pinned: tabData.pinned,
504
525
  setSelectedKey: (key) => setSelectedKey(tabId, key),
526
+ setSelectedKeys: (keys) => setSelectedKeys(tabId, keys),
505
527
  setSelectedListItem: (item) => setSelectedListItem(tabId, item),
506
528
  setSearch: (search) => setSearch(tabId, search),
507
529
  setSearchKey: (key) => setSearchKey(tabId, key),
@@ -3836,8 +3858,8 @@ var HeaderTTLBadge = ({ dataKey }) => {
3836
3858
  }
3837
3859
  );
3838
3860
  };
3839
- var Badge = ({ children, label }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-6 items-center gap-0.5 rounded-md bg-white px-2 text-xs text-zinc-700", children: [
3840
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-zinc-500", children: label }),
3861
+ var Badge = ({ children, label }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-6 items-center gap-0.5 rounded-md bg-white px-2 text-xs text-zinc-700 dark:bg-zinc-200", children: [
3862
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-zinc-500 dark:text-zinc-600", children: label }),
3841
3863
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-medium", children })
3842
3864
  ] });
3843
3865
 
@@ -4441,16 +4463,20 @@ function DeleteAlertDialog({
4441
4463
  onDeleteConfirm,
4442
4464
  open,
4443
4465
  onOpenChange,
4444
- deletionType
4466
+ deletionType,
4467
+ count: count2 = 1
4445
4468
  }) {
4469
+ const isPlural = count2 > 1;
4470
+ const itemLabel = deletionType === "item" ? "Item" : "Key";
4471
+ const itemsLabel = deletionType === "item" ? "Items" : "Keys";
4446
4472
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialog, { open, onOpenChange, children: [
4447
4473
  children && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AlertDialogTrigger, { asChild: true, children }),
4448
4474
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialogContent, { children: [
4449
4475
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialogHeader, { children: [
4450
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AlertDialogTitle, { children: deletionType === "item" ? "Delete Item" : "Delete Key" }),
4476
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AlertDialogTitle, { children: isPlural ? `Delete ${count2} ${itemsLabel}` : `Delete ${itemLabel}` }),
4451
4477
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialogDescription, { className: "mt-5", children: [
4452
- "Are you sure you want to delete this ",
4453
- deletionType,
4478
+ "Are you sure you want to delete ",
4479
+ isPlural ? `these ${count2} ${deletionType}s` : `this ${deletionType}`,
4454
4480
  "?",
4455
4481
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
4456
4482
  "This action cannot be undone."
@@ -4696,6 +4722,36 @@ var InfiniteScroll = ({
4696
4722
  // src/components/databrowser/components/display/display-header.tsx
4697
4723
 
4698
4724
 
4725
+ // src/components/ui/tooltip.tsx
4726
+
4727
+
4728
+
4729
+ var Tooltip = TooltipPrimitive.Root;
4730
+ var TooltipTrigger = TooltipPrimitive.Trigger;
4731
+ var TooltipContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4732
+ TooltipPrimitive.Content,
4733
+ {
4734
+ ref,
4735
+ sideOffset,
4736
+ className: cn(
4737
+ "z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
4738
+ className
4739
+ ),
4740
+ ...props
4741
+ }
4742
+ ) }));
4743
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
4744
+ var SimpleTooltip = ({
4745
+ content,
4746
+ children
4747
+ }) => {
4748
+ if (!content) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children });
4749
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tooltip, { delayDuration: 400, children: [
4750
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children }) }),
4751
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipContent, { side: "top", children: content })
4752
+ ] });
4753
+ };
4754
+
4699
4755
  // src/types/index.ts
4700
4756
  var DATA_TYPES = ["string", "list", "hash", "set", "zset", "json", "stream"];
4701
4757
  var DATA_TYPE_NAMES = {
@@ -4762,7 +4818,7 @@ var _reactdropdownmenu = require('@radix-ui/react-dropdown-menu'); var DropdownM
4762
4818
 
4763
4819
  var DropdownMenu = DropdownMenuPrimitive.Root;
4764
4820
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
4765
- var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4821
+ var DropdownMenuSubTrigger = React11.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4766
4822
  DropdownMenuPrimitive.SubTrigger,
4767
4823
  {
4768
4824
  ref,
@@ -4779,7 +4835,7 @@ var DropdownMenuSubTrigger = React10.forwardRef(({ className, inset, children, .
4779
4835
  }
4780
4836
  ));
4781
4837
  DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
4782
- var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4838
+ var DropdownMenuSubContent = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4783
4839
  DropdownMenuPrimitive.SubContent,
4784
4840
  {
4785
4841
  ref,
@@ -4791,7 +4847,7 @@ var DropdownMenuSubContent = React10.forwardRef(({ className, ...props }, ref) =
4791
4847
  }
4792
4848
  ));
4793
4849
  DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
4794
- var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4850
+ var DropdownMenuContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4795
4851
  DropdownMenuPrimitive.Content,
4796
4852
  {
4797
4853
  ref,
@@ -4805,12 +4861,12 @@ var DropdownMenuContent = React10.forwardRef(({ className, sideOffset = 4, ...pr
4805
4861
  }
4806
4862
  ) }));
4807
4863
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
4808
- var DropdownMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4864
+ var DropdownMenuItem = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4809
4865
  DropdownMenuPrimitive.Item,
4810
4866
  {
4811
4867
  ref,
4812
4868
  className: cn(
4813
- "data-[disabled]:opacity-50[&>svg]:size-4 relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none [&>svg]:shrink-0",
4869
+ "data-[disabled]:opacity-50[&>svg]:size-4 relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none [&>svg]:shrink-0",
4814
4870
  inset && "pl-8",
4815
4871
  className
4816
4872
  ),
@@ -4818,7 +4874,7 @@ var DropdownMenuItem = React10.forwardRef(({ className, inset, ...props }, ref)
4818
4874
  }
4819
4875
  ));
4820
4876
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
4821
- var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4877
+ var DropdownMenuCheckboxItem = React11.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4822
4878
  DropdownMenuPrimitive.CheckboxItem,
4823
4879
  {
4824
4880
  ref,
@@ -4835,7 +4891,7 @@ var DropdownMenuCheckboxItem = React10.forwardRef(({ className, children, checke
4835
4891
  }
4836
4892
  ));
4837
4893
  DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
4838
- var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4894
+ var DropdownMenuRadioItem = React11.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4839
4895
  DropdownMenuPrimitive.RadioItem,
4840
4896
  {
4841
4897
  ref,
@@ -4851,7 +4907,7 @@ var DropdownMenuRadioItem = React10.forwardRef(({ className, children, ...props
4851
4907
  }
4852
4908
  ));
4853
4909
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
4854
- var DropdownMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4910
+ var DropdownMenuLabel = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4855
4911
  DropdownMenuPrimitive.Label,
4856
4912
  {
4857
4913
  ref,
@@ -4860,7 +4916,7 @@ var DropdownMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref)
4860
4916
  }
4861
4917
  ));
4862
4918
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
4863
- var DropdownMenuSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4919
+ var DropdownMenuSeparator = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4864
4920
  DropdownMenuPrimitive.Separator,
4865
4921
  {
4866
4922
  ref,
@@ -4879,7 +4935,7 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
4879
4935
  function KeyActions({ dataKey, content }) {
4880
4936
  const { mutateAsync: deleteKey } = useDeleteKey();
4881
4937
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DropdownMenu, { modal: false, children: [
4882
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", "aria-label": "Key actions", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconDotsVertical, { className: "size-4 text-zinc-500" }) }) }),
4938
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", "aria-label": "Key actions", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconDotsVertical, { className: "size-4 text-zinc-500 dark:text-zinc-600" }) }) }),
4883
4939
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DropdownMenuContent, { className: "", align: "end", children: [
4884
4940
  content && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4885
4941
  DropdownMenuItem,
@@ -4936,7 +4992,7 @@ var DisplayHeader = ({
4936
4992
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-h-10 items-center justify-between gap-4", children: [
4937
4993
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "grow truncate text-base", children: dataKey.trim() === "" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "ml-1 text-zinc-500", children: "(Empty Key)" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-semibold", children: dataKey }) }),
4938
4994
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1", children: [
4939
- type !== "string" && type !== "json" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { onClick: handleAddItem, size: "icon-sm", "aria-label": "Add item", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "size-4 text-zinc-500" }) }),
4995
+ type !== "string" && type !== "json" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: "Add item", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { onClick: handleAddItem, size: "icon-sm", "aria-label": "Add item", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "size-4 text-zinc-500 dark:text-zinc-600" }) }) }),
4940
4996
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyActions, { dataKey, content })
4941
4997
  ] })
4942
4998
  ] }),
@@ -4952,36 +5008,6 @@ var DisplayHeader = ({
4952
5008
  // src/components/databrowser/components/display/display-list-edit.tsx
4953
5009
 
4954
5010
 
4955
- // src/components/ui/tooltip.tsx
4956
-
4957
-
4958
-
4959
- var Tooltip = TooltipPrimitive.Root;
4960
- var TooltipTrigger = TooltipPrimitive.Trigger;
4961
- var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipPrimitive.Portal, { container: portalRoot, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4962
- TooltipPrimitive.Content,
4963
- {
4964
- ref,
4965
- sideOffset,
4966
- className: cn(
4967
- "z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
4968
- className
4969
- ),
4970
- ...props
4971
- }
4972
- ) }));
4973
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
4974
- var SimpleTooltip = ({
4975
- content,
4976
- children
4977
- }) => {
4978
- if (!content) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children });
4979
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Tooltip, { delayDuration: 400, children: [
4980
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children }) }),
4981
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TooltipContent, { side: "top", children: content })
4982
- ] });
4983
- };
4984
-
4985
5011
  // src/components/databrowser/hooks/use-fetch-hash-ttl.ts
4986
5012
 
4987
5013
  var FETCH_HASH_FIELD_TTLS_QUERY_KEY = "fetch-hash-field-ttls";
@@ -5473,7 +5499,9 @@ var ListItems = ({
5473
5499
  onClick: () => {
5474
5500
  setSelectedListItem({ key });
5475
5501
  },
5476
- className: cn("h-10 border-b border-b-zinc-100 transition-colors hover:bg-zinc-100"),
5502
+ className: cn(
5503
+ "h-10 border-b border-b-zinc-100 transition-colors hover:bg-zinc-100 dark:border-b-zinc-200 dark:hover:bg-zinc-200"
5504
+ ),
5477
5505
  children: [
5478
5506
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5479
5507
  "td",
@@ -5495,7 +5523,7 @@ var ListItems = ({
5495
5523
  type !== "stream" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5496
5524
  "td",
5497
5525
  {
5498
- className: "w-0 min-w-0 p-0",
5526
+ className: "w-0 min-w-0 p-0 pr-2",
5499
5527
  onClick: (e) => {
5500
5528
  e.stopPropagation();
5501
5529
  },
@@ -5594,9 +5622,6 @@ var DataDisplay = () => {
5594
5622
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full p-4", children: !selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : !type ? query.isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-zinc-500", children: "Loading..." }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: type === "string" || type === "json" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListDisplay, { dataKey: selectedKey, type }) }) });
5595
5623
  };
5596
5624
 
5597
- // src/components/databrowser/components/sidebar/index.tsx
5598
-
5599
-
5600
5625
  // src/components/databrowser/components/add-key-modal.tsx
5601
5626
 
5602
5627
  var _reactdialog = require('@radix-ui/react-dialog'); var DialogPrimitive = _interopRequireWildcard(_reactdialog);
@@ -5737,7 +5762,7 @@ function AddKeyModal() {
5737
5762
  setOpen(open2);
5738
5763
  },
5739
5764
  children: [
5740
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "primary", size: "icon-sm", "aria-label": "Add key", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.PlusIcon, { className: "size-4" }) }) }),
5765
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTrigger, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: "Add key", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "primary", size: "icon-sm", "data-testid": "add-key-button", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.PlusIcon, { className: "size-4" }) }) }) }),
5741
5766
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, DialogContent, { className: "max-w-[400px]", children: [
5742
5767
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogTitle, { children: "Create new key" }) }),
5743
5768
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "sr-only", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactdialog.DialogDescription, { children: "Create new key" }) }),
@@ -5798,6 +5823,9 @@ var Empty = () => {
5798
5823
  ] }) });
5799
5824
  };
5800
5825
 
5826
+ // src/components/databrowser/components/sidebar/keys-list.tsx
5827
+
5828
+
5801
5829
  // src/components/databrowser/components/sidebar-context-menu.tsx
5802
5830
 
5803
5831
 
@@ -5806,19 +5834,22 @@ var Empty = () => {
5806
5834
  var SidebarContextMenu = ({ children }) => {
5807
5835
  const { mutate: deleteKey } = useDeleteKey();
5808
5836
  const [isAlertOpen, setAlertOpen] = _react.useState.call(void 0, false);
5809
- const [dataKey, setDataKey] = _react.useState.call(void 0, "");
5810
- const { addTab, setSelectedKey, selectTab, setSearch } = useDatabrowserStore();
5811
- const { search: currentSearch } = useTab();
5837
+ const [contextKeys, setContextKeys] = _react.useState.call(void 0, []);
5838
+ const { addTab, setSelectedKey: setSelectedKeyGlobal, selectTab, setSearch } = useDatabrowserStore();
5839
+ const { search: currentSearch, selectedKeys, setSelectedKey } = useTab();
5812
5840
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
5813
5841
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5814
5842
  DeleteAlertDialog,
5815
5843
  {
5816
5844
  deletionType: "key",
5845
+ count: contextKeys.length,
5817
5846
  open: isAlertOpen,
5818
5847
  onOpenChange: setAlertOpen,
5819
5848
  onDeleteConfirm: (e) => {
5820
5849
  e.stopPropagation();
5821
- deleteKey(dataKey);
5850
+ for (const key of contextKeys) {
5851
+ deleteKey(key);
5852
+ }
5822
5853
  setAlertOpen(false);
5823
5854
  }
5824
5855
  }
@@ -5831,7 +5862,13 @@ var SidebarContextMenu = ({ children }) => {
5831
5862
  const el = e.target;
5832
5863
  const key = el.closest("[data-key]");
5833
5864
  if (key && key instanceof HTMLElement && key.dataset.key !== void 0) {
5834
- setDataKey(key.dataset.key);
5865
+ const clickedKey = key.dataset.key;
5866
+ if (selectedKeys.includes(clickedKey)) {
5867
+ setContextKeys(selectedKeys);
5868
+ } else {
5869
+ setSelectedKey(clickedKey);
5870
+ setContextKeys([clickedKey]);
5871
+ }
5835
5872
  } else {
5836
5873
  throw new Error("Key not found");
5837
5874
  }
@@ -5844,12 +5881,13 @@ var SidebarContextMenu = ({ children }) => {
5844
5881
  ContextMenuItem,
5845
5882
  {
5846
5883
  onClick: () => {
5847
- navigator.clipboard.writeText(dataKey);
5884
+ navigator.clipboard.writeText(contextKeys[0]);
5848
5885
  toast({
5849
5886
  description: "Key copied to clipboard"
5850
5887
  });
5851
5888
  },
5852
5889
  className: "gap-2",
5890
+ disabled: contextKeys.length !== 1,
5853
5891
  children: [
5854
5892
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconCopy, { size: 16 }),
5855
5893
  "Copy key"
@@ -5861,11 +5899,12 @@ var SidebarContextMenu = ({ children }) => {
5861
5899
  {
5862
5900
  onClick: () => {
5863
5901
  const newTabId = addTab();
5864
- setSelectedKey(newTabId, dataKey);
5902
+ setSelectedKeyGlobal(newTabId, contextKeys[0]);
5865
5903
  setSearch(newTabId, currentSearch);
5866
5904
  selectTab(newTabId);
5867
5905
  },
5868
5906
  className: "gap-2",
5907
+ disabled: contextKeys.length !== 1,
5869
5908
  children: [
5870
5909
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconExternalLink, { size: 16 }),
5871
5910
  "Open in new tab"
@@ -5875,7 +5914,7 @@ var SidebarContextMenu = ({ children }) => {
5875
5914
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactcontextmenu.ContextMenuSeparator, {}),
5876
5915
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onClick: () => setAlertOpen(true), className: "gap-2", children: [
5877
5916
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconTrash, { size: 16 }),
5878
- "Delete key"
5917
+ contextKeys.length > 1 ? `Delete ${contextKeys.length} keys` : "Delete key"
5879
5918
  ] })
5880
5919
  ] })
5881
5920
  ] })
@@ -5886,7 +5925,23 @@ var SidebarContextMenu = ({ children }) => {
5886
5925
 
5887
5926
  var KeysList = () => {
5888
5927
  const { keys } = useKeys();
5889
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyItem, { nextKey: _nullishCoalesce(_optionalChain([keys, 'access', _53 => _53.at, 'call', _54 => _54(i + 1), 'optionalAccess', _55 => _55[0]]), () => ( "")), data }, data[0])) }) });
5928
+ const lastClickedIndexRef = _react.useRef.call(void 0, null);
5929
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
5930
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-px" }),
5931
+ keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
5932
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5933
+ KeyItem,
5934
+ {
5935
+ index: i,
5936
+ data,
5937
+ allKeys: keys,
5938
+ lastClickedIndexRef
5939
+ },
5940
+ data[0]
5941
+ ),
5942
+ i !== keys.length - 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "-z-10 mx-2 h-px bg-zinc-100 dark:bg-zinc-200" })
5943
+ ] }))
5944
+ ] }) });
5890
5945
  };
5891
5946
  var keyStyles = {
5892
5947
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5897,11 +5952,33 @@ var keyStyles = {
5897
5952
  list: "border-orange-400 !bg-orange-50 text-orange-900",
5898
5953
  stream: "border-green-400 !bg-green-50 text-green-900"
5899
5954
  };
5900
- var KeyItem = ({ data, nextKey }) => {
5901
- const { selectedKey, setSelectedKey } = useTab();
5955
+ var KeyItem = ({
5956
+ data,
5957
+ index,
5958
+ allKeys,
5959
+ lastClickedIndexRef
5960
+ }) => {
5961
+ const { selectedKeys, setSelectedKeys, setSelectedKey } = useTab();
5902
5962
  const [dataKey, dataType] = data;
5903
- const isKeySelected = selectedKey === dataKey;
5904
- const isNextKeySelected = selectedKey === nextKey;
5963
+ const isKeySelected = selectedKeys.includes(dataKey);
5964
+ const handleClick = (e) => {
5965
+ if (e.shiftKey && lastClickedIndexRef.current !== null) {
5966
+ const start = Math.min(lastClickedIndexRef.current, index);
5967
+ const end = Math.max(lastClickedIndexRef.current, index);
5968
+ const rangeKeys = allKeys.slice(start, end + 1).map(([key]) => key);
5969
+ setSelectedKeys(rangeKeys);
5970
+ } else if (e.metaKey || e.ctrlKey) {
5971
+ if (isKeySelected) {
5972
+ setSelectedKeys(selectedKeys.filter((k) => k !== dataKey));
5973
+ } else {
5974
+ setSelectedKeys([...selectedKeys, dataKey]);
5975
+ }
5976
+ lastClickedIndexRef.current = index;
5977
+ } else {
5978
+ setSelectedKey(dataKey);
5979
+ lastClickedIndexRef.current = index;
5980
+ }
5981
+ };
5905
5982
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5906
5983
  Button,
5907
5984
  {
@@ -5909,20 +5986,47 @@ var KeyItem = ({ data, nextKey }) => {
5909
5986
  variant: isKeySelected ? "default" : "ghost",
5910
5987
  className: cn(
5911
5988
  "relative flex h-10 w-full items-center justify-start gap-2 px-3 py-0 !ring-0 focus-visible:bg-zinc-50",
5912
- "select-none border border-transparent text-left",
5989
+ "-my-px select-none border border-transparent text-left",
5913
5990
  isKeySelected && "shadow-sm",
5914
5991
  isKeySelected && keyStyles[dataType]
5915
5992
  ),
5916
- onClick: () => setSelectedKey(dataKey),
5993
+ onClick: handleClick,
5917
5994
  children: [
5918
5995
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TypeTag, { variant: dataType, type: "icon" }),
5919
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate whitespace-nowrap", children: dataKey }),
5920
- !isKeySelected && !isNextKeySelected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute -bottom-px left-3 right-3 h-px bg-zinc-100" })
5996
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate whitespace-nowrap", children: dataKey })
5921
5997
  ]
5922
5998
  }
5923
5999
  );
5924
6000
  };
5925
6001
 
6002
+ // src/components/databrowser/components/sidebar/reload-button.tsx
6003
+
6004
+
6005
+
6006
+ var ReloadButton = ({
6007
+ onClick,
6008
+ isLoading: isLoadingProp
6009
+ }) => {
6010
+ const [isLoading, setIsLoading] = _react.useState.call(void 0, false);
6011
+ const handleClick = () => {
6012
+ setIsLoading(true);
6013
+ onClick();
6014
+ setTimeout(() => {
6015
+ setIsLoading(false);
6016
+ }, 350);
6017
+ };
6018
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: "Refresh", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6019
+ Button,
6020
+ {
6021
+ variant: "outline",
6022
+ size: "icon-sm",
6023
+ onClick: handleClick,
6024
+ disabled: isLoading || isLoadingProp,
6025
+ children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconLoader2, { className: "animate-spin text-zinc-500", size: 16 }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconRefresh, { className: "text-zinc-500 dark:text-zinc-600", size: 16 })
6026
+ }
6027
+ ) }) });
6028
+ };
6029
+
5926
6030
  // src/components/databrowser/components/sidebar/search-input.tsx
5927
6031
 
5928
6032
 
@@ -5962,7 +6066,7 @@ var SearchInput = () => {
5962
6066
  } else if (e.key === "Escape") {
5963
6067
  setState("");
5964
6068
  setFocusedIndex(-1);
5965
- _optionalChain([inputRef, 'access', _56 => _56.current, 'optionalAccess', _57 => _57.blur, 'call', _58 => _58()]);
6069
+ _optionalChain([inputRef, 'access', _53 => _53.current, 'optionalAccess', _54 => _54.blur, 'call', _55 => _55()]);
5966
6070
  } else if (e.key === "ArrowDown" || e.key === "Tab" && !e.shiftKey) {
5967
6071
  e.preventDefault();
5968
6072
  if (focusedIndex < filteredHistory.length - 1) {
@@ -5976,7 +6080,7 @@ var SearchInput = () => {
5976
6080
  setFocusedIndex(focusedIndex - 1);
5977
6081
  } else if (filteredHistory.length > 0 && focusedIndex === 0) {
5978
6082
  setFocusedIndex(-1);
5979
- _optionalChain([inputRef, 'access', _59 => _59.current, 'optionalAccess', _60 => _60.focus, 'call', _61 => _61()]);
6083
+ _optionalChain([inputRef, 'access', _56 => _56.current, 'optionalAccess', _57 => _57.focus, 'call', _58 => _58()]);
5980
6084
  } else if (filteredHistory.length > 0) {
5981
6085
  setFocusedIndex(filteredHistory.length - 1);
5982
6086
  }
@@ -5984,12 +6088,12 @@ var SearchInput = () => {
5984
6088
  };
5985
6089
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative grow", children: [
5986
6090
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Popover, { open: isFocus && filteredHistory.length > 0, children: [
5987
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6091
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-8 rounded-md rounded-l-none border border-zinc-300 font-normal", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5988
6092
  Input,
5989
6093
  {
5990
6094
  ref: inputRef,
5991
6095
  placeholder: "Search",
5992
- className: "rounded-l-none border-zinc-300 font-normal",
6096
+ className: "h-full rounded-l-none border-none pr-6",
5993
6097
  onKeyDown: handleKeyDown,
5994
6098
  onChange: (e) => {
5995
6099
  setState(e.currentTarget.value);
@@ -6092,10 +6196,8 @@ function Sidebar() {
6092
6196
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayDbSize, {}),
6093
6197
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-1", children: [
6094
6198
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6095
- Button,
6199
+ ReloadButton,
6096
6200
  {
6097
- "aria-label": "Refresh",
6098
- className: "h-7 w-7 px-0 text-zinc-500",
6099
6201
  onClick: () => {
6100
6202
  queryClient.invalidateQueries({
6101
6203
  queryKey: [FETCH_KEYS_QUERY_KEY]
@@ -6113,7 +6215,7 @@ function Sidebar() {
6113
6215
  queryKey: [FETCH_KEY_TYPE_QUERY_KEY]
6114
6216
  });
6115
6217
  },
6116
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Spinner, { isLoading: query.isFetching, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconRefresh, { size: 16 }) })
6218
+ isLoading: query.isFetching
6117
6219
  }
6118
6220
  ),
6119
6221
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AddKeyModal, {})
@@ -6279,7 +6381,7 @@ var useOverflow = () => {
6279
6381
  }
6280
6382
  if (!node) return;
6281
6383
  observerRef.current = new ResizeObserver((entries) => {
6282
- const el = _optionalChain([entries, 'access', _62 => _62.at, 'call', _63 => _63(0), 'optionalAccess', _64 => _64.target]);
6384
+ const el = _optionalChain([entries, 'access', _59 => _59.at, 'call', _60 => _60(0), 'optionalAccess', _61 => _61.target]);
6283
6385
  if (!el) return;
6284
6386
  setIsOverflow(el.scrollWidth > el.clientWidth);
6285
6387
  });
@@ -6287,7 +6389,7 @@ var useOverflow = () => {
6287
6389
  }, []);
6288
6390
  _react.useEffect.call(void 0, () => {
6289
6391
  return () => {
6290
- _optionalChain([observerRef, 'access', _65 => _65.current, 'optionalAccess', _66 => _66.disconnect, 'call', _67 => _67()]);
6392
+ _optionalChain([observerRef, 'access', _62 => _62.current, 'optionalAccess', _63 => _63.disconnect, 'call', _64 => _64()]);
6291
6393
  };
6292
6394
  }, []);
6293
6395
  return { ref, isOverflow };
@@ -6340,7 +6442,7 @@ var Tab = ({ id, isList }) => {
6340
6442
  e.stopPropagation();
6341
6443
  removeTab(id);
6342
6444
  },
6343
- className: "p-1 text-zinc-300 transition-colors hover:text-zinc-500",
6445
+ className: "p-1 text-zinc-300 transition-colors hover:text-zinc-500 dark:text-zinc-400",
6344
6446
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconX, { size: 16 })
6345
6447
  }
6346
6448
  )
@@ -6397,8 +6499,8 @@ var SortableTab = ({ id }) => {
6397
6499
  const [originalWidth, setOriginalWidth] = _react.useState.call(void 0, null);
6398
6500
  const textRef = _react.useRef.call(void 0, null);
6399
6501
  const { tabs } = useDatabrowserStore();
6400
- const tabData = _optionalChain([tabs, 'access', _68 => _68.find, 'call', _69 => _69(([tabId]) => tabId === id), 'optionalAccess', _70 => _70[1]]);
6401
- const isPinned = _optionalChain([tabData, 'optionalAccess', _71 => _71.pinned]);
6502
+ const tabData = _optionalChain([tabs, 'access', _65 => _65.find, 'call', _66 => _66(([tabId]) => tabId === id), 'optionalAccess', _67 => _67[1]]);
6503
+ const isPinned = _optionalChain([tabData, 'optionalAccess', _68 => _68.pinned]);
6402
6504
  const { attributes, listeners: listeners2, setNodeRef, transform, transition, isDragging } = _sortable.useSortable.call(void 0, {
6403
6505
  id,
6404
6506
  disabled: isPinned,
@@ -6618,7 +6720,7 @@ function AddTabButton() {
6618
6720
  const tabsId = addTab();
6619
6721
  selectTab(tabsId);
6620
6722
  setTimeout(() => {
6621
- const tab = _optionalChain([rootRef, 'optionalAccess', _72 => _72.current, 'optionalAccess', _73 => _73.querySelector, 'call', _74 => _74(`#tab-${tabsId}`)]);
6723
+ const tab = _optionalChain([rootRef, 'optionalAccess', _69 => _69.current, 'optionalAccess', _70 => _70.querySelector, 'call', _71 => _71(`#tab-${tabsId}`)]);
6622
6724
  if (!tab) return;
6623
6725
  tab.scrollIntoView({ behavior: "smooth" });
6624
6726
  }, 20);
@@ -6630,8 +6732,8 @@ function AddTabButton() {
6630
6732
  variant: "secondary",
6631
6733
  size: "icon-sm",
6632
6734
  onClick: handleAddTab,
6633
- className: "flex-shrink-0",
6634
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500", size: 16 })
6735
+ className: "flex-shrink-0 dark:bg-zinc-200",
6736
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500 dark:text-zinc-600", size: 16 })
6635
6737
  }
6636
6738
  );
6637
6739
  }
@@ -6652,7 +6754,7 @@ function TabsListButton({
6652
6754
  onSelectTab(id);
6653
6755
  setOpen(false);
6654
6756
  setTimeout(() => {
6655
- const tab = _optionalChain([rootRef, 'optionalAccess', _75 => _75.current, 'optionalAccess', _76 => _76.querySelector, 'call', _77 => _77(`#tab-${id}`)]);
6757
+ const tab = _optionalChain([rootRef, 'optionalAccess', _72 => _72.current, 'optionalAccess', _73 => _73.querySelector, 'call', _74 => _74(`#tab-${id}`)]);
6656
6758
  if (!tab) return;
6657
6759
  tab.scrollIntoView({ behavior: "smooth" });
6658
6760
  }, 20);