@upstash/react-redis-browser 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/components/databrowser/index.tsx
2
- var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react); var React3 = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react); var React5 = _interopRequireWildcard(_react); var React6 = _interopRequireWildcard(_react); var React7 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react); var React9 = _interopRequireWildcard(_react); var React10 = _interopRequireWildcard(_react); var React11 = _interopRequireWildcard(_react); var React12 = _interopRequireWildcard(_react);
2
+ var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react); var React3 = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react); var React5 = _interopRequireWildcard(_react); var React6 = _interopRequireWildcard(_react); var React7 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react); var React9 = _interopRequireWildcard(_react); var React10 = _interopRequireWildcard(_react); var React11 = _interopRequireWildcard(_react); var React12 = _interopRequireWildcard(_react); var React13 = _interopRequireWildcard(_react);
3
3
 
4
4
  // src/redis-context.tsx
5
5
 
6
6
 
7
7
  // src/lib/clients.ts
8
8
  var _reactquery = require('@tanstack/react-query');
9
- var _redis = require('@upstash/redis');
9
+ var _cloudflare = require('@upstash/redis/cloudflare');
10
10
 
11
11
  // src/components/ui/use-toast.ts
12
12
 
@@ -144,7 +144,7 @@ var redisClient = ({
144
144
  if (!token) {
145
145
  throw new Error("Redis TOKEN is missing!");
146
146
  }
147
- const redis = new (0, _redis.Redis)({
147
+ const redis = new (0, _cloudflare.Redis)({
148
148
  url,
149
149
  token,
150
150
  enableAutoPipelining: pipelining,
@@ -219,7 +219,8 @@ var _middleware = require('zustand/middleware');
219
219
  var DatabrowserContext = _react.createContext.call(void 0, void 0);
220
220
  var DatabrowserProvider = ({
221
221
  children,
222
- storage
222
+ storage,
223
+ rootRef
223
224
  }) => {
224
225
  const store = _react.useMemo.call(void 0, () => {
225
226
  if (!storage) return _zustand.create.call(void 0, storeCreator);
@@ -241,18 +242,29 @@ var DatabrowserProvider = ({
241
242
  removeItem: () => {
242
243
  }
243
244
  },
244
- version: 1,
245
+ version: 2,
245
246
  // @ts-expect-error Reset the store for < v1
246
- migrate: (state, version) => {
247
+ migrate: (originalState, version) => {
248
+ const state = originalState;
247
249
  if (version === 0) {
248
250
  return;
249
251
  }
252
+ if (version === 1) {
253
+ return {
254
+ ...state,
255
+ tabs: state.tabs.map(([id, data]) => [id, { ...data, id }])
256
+ };
257
+ }
250
258
  return state;
251
259
  }
252
260
  })
253
261
  );
254
262
  }, []);
255
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserContext.Provider, { value: { store }, children });
263
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserContext.Provider, { value: { store, rootRef }, children });
264
+ };
265
+ var useDatabrowserRootRef = () => {
266
+ const { rootRef } = useDatabrowser();
267
+ return rootRef;
256
268
  };
257
269
  var useDatabrowser = () => {
258
270
  const context = _react.useContext.call(void 0, DatabrowserContext);
@@ -271,8 +283,10 @@ var storeCreator = (set, get) => ({
271
283
  addTab: () => {
272
284
  const id = crypto.randomUUID();
273
285
  const newTabData = {
286
+ id,
274
287
  selectedKey: void 0,
275
- search: { key: "", type: void 0 }
288
+ search: { key: "", type: void 0 },
289
+ pinned: false
276
290
  };
277
291
  set((old) => ({
278
292
  tabs: [...old.tabs, [id, newTabData]],
@@ -282,6 +296,9 @@ var storeCreator = (set, get) => ({
282
296
  },
283
297
  reorderTabs: (oldIndex, newIndex) => {
284
298
  set((old) => {
299
+ const [, oldTabData] = old.tabs[oldIndex];
300
+ const [, newTabData] = old.tabs[newIndex];
301
+ if (oldTabData.pinned || newTabData.pinned) return old;
285
302
  const newTabs = [...old.tabs];
286
303
  const [movedTab] = newTabs.splice(oldIndex, 1);
287
304
  newTabs.splice(newIndex, 0, movedTab);
@@ -292,6 +309,8 @@ var storeCreator = (set, get) => ({
292
309
  set((old) => {
293
310
  const tabIndex = old.tabs.findIndex(([tabId]) => tabId === id);
294
311
  if (tabIndex === -1) return old;
312
+ const [, tabData] = old.tabs[tabIndex];
313
+ if (tabData.pinned) return old;
295
314
  const newTabs = [...old.tabs];
296
315
  newTabs.splice(tabIndex, 1);
297
316
  let selectedTab = old.selectedTab;
@@ -302,6 +321,59 @@ var storeCreator = (set, get) => ({
302
321
  return { tabs: newTabs, selectedTab };
303
322
  });
304
323
  },
324
+ forceRemoveTab: (id) => {
325
+ set((old) => {
326
+ const tabIndex = old.tabs.findIndex(([tabId]) => tabId === id);
327
+ if (tabIndex === -1) return old;
328
+ const newTabs = [...old.tabs];
329
+ newTabs.splice(tabIndex, 1);
330
+ let selectedTab = old.selectedTab;
331
+ if (selectedTab === id) {
332
+ const [newId] = _nullishCoalesce(newTabs[tabIndex - 1], () => ( newTabs[tabIndex]));
333
+ selectedTab = newTabs.length > 0 ? newId : void 0;
334
+ }
335
+ return { tabs: newTabs, selectedTab };
336
+ });
337
+ },
338
+ togglePinTab: (id) => {
339
+ set((old) => {
340
+ const tabIndex = old.tabs.findIndex(([tabId2]) => tabId2 === id);
341
+ if (tabIndex === -1) return old;
342
+ const newTabs = [...old.tabs];
343
+ const [tabId, tabData] = newTabs[tabIndex];
344
+ newTabs[tabIndex] = [tabId, { ...tabData, pinned: !tabData.pinned }];
345
+ return { ...old, tabs: newTabs };
346
+ });
347
+ },
348
+ duplicateTab: (id) => {
349
+ let newId;
350
+ set((old) => {
351
+ const tabIndex = old.tabs.findIndex(([tabId]) => tabId === id);
352
+ if (tabIndex === -1) return old;
353
+ const newTabs = [...old.tabs];
354
+ const [, tabData] = newTabs[tabIndex];
355
+ newId = crypto.randomUUID();
356
+ const duplicated = [newId, { ...tabData, id: newId }];
357
+ newTabs.splice(tabIndex + 1, 0, duplicated);
358
+ return { ...old, tabs: newTabs, selectedTab: newId };
359
+ });
360
+ return newId;
361
+ },
362
+ closeOtherTabs: (id) => {
363
+ set((old) => {
364
+ const exists = old.tabs.some(([tabId]) => tabId === id);
365
+ if (!exists) return old;
366
+ const newTabs = old.tabs.filter(([tabId]) => tabId === id);
367
+ return { ...old, tabs: newTabs, selectedTab: id };
368
+ });
369
+ },
370
+ closeAllButPinned: () => {
371
+ set((old) => {
372
+ const newTabs = old.tabs.filter(([, data]) => data.pinned);
373
+ const newSelected = newTabs.length > 0 ? newTabs[0][0] : void 0;
374
+ return { ...old, tabs: newTabs, selectedTab: newSelected };
375
+ });
376
+ },
305
377
  selectTab: (id) => {
306
378
  set({ selectedTab: id });
307
379
  },
@@ -410,6 +482,7 @@ var useTab = () => {
410
482
  selectedKey: tabData.selectedKey,
411
483
  selectedListItem: tabData.selectedListItem,
412
484
  search: tabData.search,
485
+ pinned: tabData.pinned,
413
486
  setSelectedKey: (key) => setSelectedKey(tabId, key),
414
487
  setSelectedListItem: (item) => setSelectedListItem(tabId, item),
415
488
  setSearch: (search) => setSearch(tabId, search),
@@ -3334,8 +3407,7 @@ var useAddKey = () => {
3334
3407
  }
3335
3408
  case "hash": {
3336
3409
  await redis.hset(key, {
3337
- field: "field",
3338
- value: "value"
3410
+ field: "value"
3339
3411
  });
3340
3412
  break;
3341
3413
  }
@@ -4150,6 +4222,7 @@ var useSetTTL = () => {
4150
4222
 
4151
4223
  // src/components/databrowser/components/item-context-menu.tsx
4152
4224
 
4225
+
4153
4226
  var _reactcontextmenu = require('@radix-ui/react-context-menu'); var ContextMenuPrimitive = _interopRequireWildcard(_reactcontextmenu);
4154
4227
 
4155
4228
  // src/components/ui/context-menu.tsx
@@ -4448,7 +4521,7 @@ var ItemContextMenu = ({
4448
4521
  }
4449
4522
  ),
4450
4523
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuContent, { children: [
4451
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4524
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4452
4525
  ContextMenuItem,
4453
4526
  {
4454
4527
  onClick: () => {
@@ -4458,10 +4531,14 @@ var ItemContextMenu = ({
4458
4531
  description: "Key copied to clipboard"
4459
4532
  });
4460
4533
  },
4461
- children: "Copy key"
4534
+ className: "gap-2",
4535
+ children: [
4536
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconCopy, { size: 16 }),
4537
+ "Copy key"
4538
+ ]
4462
4539
  }
4463
4540
  ),
4464
- _optionalChain([data, 'optionalAccess', _32 => _32.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4541
+ _optionalChain([data, 'optionalAccess', _32 => _32.value]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4465
4542
  ContextMenuItem,
4466
4543
  {
4467
4544
  onClick: () => {
@@ -4470,10 +4547,14 @@ var ItemContextMenu = ({
4470
4547
  description: "Value copied to clipboard"
4471
4548
  });
4472
4549
  },
4473
- children: "Copy value"
4550
+ className: "gap-2",
4551
+ children: [
4552
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconCopy, { size: 16 }),
4553
+ "Copy value"
4554
+ ]
4474
4555
  }
4475
4556
  ),
4476
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4557
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4477
4558
  ContextMenuItem,
4478
4559
  {
4479
4560
  onClick: () => {
@@ -4485,11 +4566,26 @@ var ItemContextMenu = ({
4485
4566
  key: data.key
4486
4567
  });
4487
4568
  },
4488
- children: "Open in new tab"
4569
+ className: "gap-2",
4570
+ children: [
4571
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconExternalLink, { size: 16 }),
4572
+ "Open in new tab"
4573
+ ]
4489
4574
  }
4490
4575
  ),
4491
4576
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactcontextmenu.ContextMenuSeparator, {}),
4492
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuItem, { disabled: type === "stream", onClick: () => setAlertOpen(true), children: "Delete item" })
4577
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4578
+ ContextMenuItem,
4579
+ {
4580
+ disabled: type === "stream",
4581
+ onClick: () => setAlertOpen(true),
4582
+ className: "gap-2",
4583
+ children: [
4584
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconTrash, { size: 16 }),
4585
+ "Delete item"
4586
+ ]
4587
+ }
4588
+ )
4493
4589
  ] })
4494
4590
  ] })
4495
4591
  ] });
@@ -5067,7 +5163,8 @@ var CustomEditor = ({
5067
5163
  lineDecorationsWidth: 0,
5068
5164
  automaticLayout: true,
5069
5165
  scrollBeyondLastLine: false,
5070
- renderLineHighlight: "none"
5166
+ renderLineHighlight: "none",
5167
+ unusualLineTerminators: "auto"
5071
5168
  }
5072
5169
  }
5073
5170
  );
@@ -5697,6 +5794,7 @@ var Empty = () => {
5697
5794
 
5698
5795
 
5699
5796
 
5797
+
5700
5798
  var SidebarContextMenu = ({ children }) => {
5701
5799
  const { mutate: deleteKey } = useDeleteKey();
5702
5800
  const [isAlertOpen, setAlertOpen] = _react.useState.call(void 0, false);
@@ -5734,7 +5832,7 @@ var SidebarContextMenu = ({ children }) => {
5734
5832
  }
5735
5833
  ),
5736
5834
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuContent, { children: [
5737
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5835
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5738
5836
  ContextMenuItem,
5739
5837
  {
5740
5838
  onClick: () => {
@@ -5743,10 +5841,14 @@ var SidebarContextMenu = ({ children }) => {
5743
5841
  description: "Key copied to clipboard"
5744
5842
  });
5745
5843
  },
5746
- children: "Copy key"
5844
+ className: "gap-2",
5845
+ children: [
5846
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconCopy, { size: 16 }),
5847
+ "Copy key"
5848
+ ]
5747
5849
  }
5748
5850
  ),
5749
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5851
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5750
5852
  ContextMenuItem,
5751
5853
  {
5752
5854
  onClick: () => {
@@ -5755,11 +5857,18 @@ var SidebarContextMenu = ({ children }) => {
5755
5857
  setSearch(newTabId, currentSearch);
5756
5858
  selectTab(newTabId);
5757
5859
  },
5758
- children: "Open in new tab"
5860
+ className: "gap-2",
5861
+ children: [
5862
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconExternalLink, { size: 16 }),
5863
+ "Open in new tab"
5864
+ ]
5759
5865
  }
5760
5866
  ),
5761
5867
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactcontextmenu.ContextMenuSeparator, {}),
5762
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuItem, { onClick: () => setAlertOpen(true), children: "Delete key" })
5868
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onClick: () => setAlertOpen(true), className: "gap-2", children: [
5869
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconTrash, { size: 16 }),
5870
+ "Delete key"
5871
+ ] })
5763
5872
  ] })
5764
5873
  ] })
5765
5874
  ] });
@@ -5833,7 +5942,7 @@ var SearchInput = () => {
5833
5942
  setState(value);
5834
5943
  };
5835
5944
  const filteredHistory = dedupeSearchHistory(
5836
- searchHistory.filter((item) => item.includes(state) && item !== state)
5945
+ searchHistory.filter((item) => item.trim() !== "" && item.trim() !== "*").filter((item) => item.includes(state) && item !== state)
5837
5946
  ).slice(0, 5).map((item) => item.endsWith("*") ? item.slice(0, -1) : item);
5838
5947
  _react.useEffect.call(void 0, () => {
5839
5948
  setFocusedIndex(-1);
@@ -6050,9 +6159,116 @@ var _sortable = require('@dnd-kit/sortable');
6050
6159
  var _utilities = require('@dnd-kit/utilities');
6051
6160
 
6052
6161
 
6162
+ // src/components/ui/command.tsx
6163
+
6164
+ var _cmdk = require('cmdk');
6165
+
6166
+
6167
+ var Command = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6168
+ _cmdk.Command,
6169
+ {
6170
+ ref,
6171
+ className: cn(
6172
+ "flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50",
6173
+ className
6174
+ ),
6175
+ ...props
6176
+ }
6177
+ ));
6178
+ Command.displayName = _cmdk.Command.displayName;
6179
+ var CommandInput = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center border-b px-3", "cmdk-input-wrapper": "", children: [
6180
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacticons.MagnifyingGlassIcon, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
6181
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6182
+ _cmdk.Command.Input,
6183
+ {
6184
+ ref,
6185
+ className: cn(
6186
+ "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-neutral-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-neutral-400",
6187
+ className
6188
+ ),
6189
+ ...props
6190
+ }
6191
+ )
6192
+ ] }));
6193
+ CommandInput.displayName = _cmdk.Command.Input.displayName;
6194
+ var CommandList = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6195
+ _cmdk.Command.List,
6196
+ {
6197
+ ref,
6198
+ className: cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
6199
+ ...props
6200
+ }
6201
+ ));
6202
+ CommandList.displayName = _cmdk.Command.List.displayName;
6203
+ var CommandEmpty = React13.forwardRef((props, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6204
+ _cmdk.Command.Empty,
6205
+ {
6206
+ ref,
6207
+ className: "py-6 text-center text-sm",
6208
+ ...props
6209
+ }
6210
+ ));
6211
+ CommandEmpty.displayName = _cmdk.Command.Empty.displayName;
6212
+ var CommandGroup = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6213
+ _cmdk.Command.Group,
6214
+ {
6215
+ ref,
6216
+ className: cn(
6217
+ "overflow-hidden p-1 text-neutral-950 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-neutral-500 dark:text-neutral-50 dark:[&_[cmdk-group-heading]]:text-neutral-400",
6218
+ className
6219
+ ),
6220
+ ...props
6221
+ }
6222
+ ));
6223
+ CommandGroup.displayName = _cmdk.Command.Group.displayName;
6224
+ var CommandSeparator = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6225
+ _cmdk.Command.Separator,
6226
+ {
6227
+ ref,
6228
+ className: cn("-mx-1 h-px bg-neutral-200 dark:bg-neutral-800", className),
6229
+ ...props
6230
+ }
6231
+ ));
6232
+ CommandSeparator.displayName = _cmdk.Command.Separator.displayName;
6233
+ var CommandItem = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6234
+ _cmdk.Command.Item,
6235
+ {
6236
+ ref,
6237
+ className: cn(
6238
+ "relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-neutral-100 data-[selected=true]:text-neutral-900 data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:data-[selected=true]:bg-neutral-800 dark:data-[selected=true]:text-neutral-50",
6239
+ className
6240
+ ),
6241
+ ...props
6242
+ }
6243
+ ));
6244
+ CommandItem.displayName = _cmdk.Command.Item.displayName;
6245
+ var CommandShortcut = ({
6246
+ className,
6247
+ ...props
6248
+ }) => {
6249
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6250
+ "span",
6251
+ {
6252
+ className: cn(
6253
+ "ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400",
6254
+ className
6255
+ ),
6256
+ ...props
6257
+ }
6258
+ );
6259
+ };
6260
+ CommandShortcut.displayName = "CommandShortcut";
6261
+
6053
6262
  // src/components/databrowser/components/tab.tsx
6054
6263
 
6055
6264
 
6265
+
6266
+
6267
+
6268
+
6269
+
6270
+
6271
+
6056
6272
  // src/components/databrowser/components/tab-type-icon.tsx
6057
6273
 
6058
6274
  function TabTypeIcon({ selectedKey }) {
@@ -6090,24 +6306,45 @@ var useOverflow = () => {
6090
6306
 
6091
6307
  // src/components/databrowser/components/tab.tsx
6092
6308
 
6093
- var Tab = ({ id }) => {
6094
- const { active, search, selectedKey } = useTab();
6095
- const { selectTab, removeTab, tabs } = useDatabrowserStore();
6309
+ var Tab = ({ id, isList }) => {
6310
+ const { active, search, selectedKey, pinned } = useTab();
6311
+ const {
6312
+ selectTab,
6313
+ removeTab,
6314
+ forceRemoveTab,
6315
+ tabs,
6316
+ togglePinTab,
6317
+ duplicateTab,
6318
+ closeOtherTabs,
6319
+ closeAllButPinned
6320
+ } = useDatabrowserStore();
6321
+ const hasPinnedTabs = tabs.some(([, data]) => data.pinned);
6096
6322
  const { ref, isOverflow } = useOverflow();
6097
6323
  const label = search.key || selectedKey;
6098
6324
  const iconNode = search.key ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconSearch, { size: 15 }) : selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabTypeIcon, { selectedKey }) : void 0;
6099
6325
  const tabNode = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6100
6326
  "div",
6101
6327
  {
6328
+ id: isList ? `list-tab-${id}` : `tab-${id}`,
6102
6329
  onClick: () => selectTab(id),
6103
6330
  className: cn(
6104
- "flex h-9 cursor-pointer items-center gap-2 rounded-t-lg border border-zinc-200 px-3 text-[13px] transition-colors",
6105
- active ? "border-b-white bg-white text-zinc-900" : "bg-zinc-100 hover:bg-zinc-50"
6331
+ "flex h-9 w-full cursor-pointer items-center gap-2 px-3 text-[13px] transition-colors",
6332
+ isList && "max-w-[370px]",
6333
+ !isList && "rounded-t-lg border border-zinc-200",
6334
+ !isList && (active ? "border-b-white bg-white text-zinc-900" : "bg-zinc-100 hover:bg-zinc-50")
6106
6335
  ),
6107
6336
  children: [
6108
6337
  iconNode,
6109
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { ref, className: "max-w-32 truncate whitespace-nowrap", children: label || "New Tab" }),
6110
- tabs.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6338
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6339
+ "span",
6340
+ {
6341
+ ref,
6342
+ className: cn("min-w-0 grow truncate whitespace-nowrap", !isList && "max-w-32"),
6343
+ children: label || "New Tab"
6344
+ }
6345
+ ),
6346
+ pinned && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPin, { size: 14, className: "text-zinc-500" }),
6347
+ tabs.length > 1 && !pinned && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6111
6348
  "button",
6112
6349
  {
6113
6350
  onClick: (e) => {
@@ -6121,7 +6358,48 @@ var Tab = ({ id }) => {
6121
6358
  ]
6122
6359
  }
6123
6360
  );
6124
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: isOverflow ? label : void 0, children: tabNode });
6361
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenu, { children: [
6362
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SimpleTooltip, { content: isOverflow ? label : void 0, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuTrigger, { asChild: true, children: tabNode }) }),
6363
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6364
+ ContextMenuContent,
6365
+ {
6366
+ onClick: (e) => {
6367
+ e.stopPropagation();
6368
+ },
6369
+ children: [
6370
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onSelect: () => togglePinTab(id), className: "gap-2", children: [
6371
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPin, { size: 16 }),
6372
+ pinned ? "Unpin Tab" : "Pin Tab"
6373
+ ] }),
6374
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onSelect: () => duplicateTab(id), className: "gap-2", children: [
6375
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconCopyPlus, { size: 16 }),
6376
+ "Duplicate Tab"
6377
+ ] }),
6378
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuSeparator, {}),
6379
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onSelect: () => forceRemoveTab(id), className: "gap-2", children: [
6380
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconX, { size: 16 }),
6381
+ "Close Tab"
6382
+ ] }),
6383
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuItem, { onSelect: () => closeOtherTabs(id), className: "gap-2", children: [
6384
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconSquareX, { size: 16 }),
6385
+ "Close Other Tabs"
6386
+ ] }),
6387
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6388
+ ContextMenuItem,
6389
+ {
6390
+ onSelect: () => closeAllButPinned(),
6391
+ className: "gap-2",
6392
+ disabled: !hasPinnedTabs,
6393
+ children: [
6394
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconArrowsMinimize, { size: 16 }),
6395
+ "Close All But Pinned"
6396
+ ]
6397
+ }
6398
+ )
6399
+ ]
6400
+ }
6401
+ )
6402
+ ] });
6125
6403
  };
6126
6404
 
6127
6405
  // src/components/databrowser/components/databrowser-tabs.tsx
@@ -6129,8 +6407,12 @@ var Tab = ({ id }) => {
6129
6407
  var SortableTab = ({ id }) => {
6130
6408
  const [originalWidth, setOriginalWidth] = _react.useState.call(void 0, null);
6131
6409
  const textRef = _react.useRef.call(void 0, null);
6410
+ const { tabs } = useDatabrowserStore();
6411
+ const tabData = _optionalChain([tabs, 'access', _68 => _68.find, 'call', _69 => _69(([tabId]) => tabId === id), 'optionalAccess', _70 => _70[1]]);
6412
+ const isPinned = _optionalChain([tabData, 'optionalAccess', _71 => _71.pinned]);
6132
6413
  const { attributes, listeners: listeners2, setNodeRef, transform, transition, isDragging } = _sortable.useSortable.call(void 0, {
6133
6414
  id,
6415
+ disabled: isPinned,
6134
6416
  resizeObserverConfig: {
6135
6417
  disabled: true
6136
6418
  }
@@ -6194,15 +6476,69 @@ var SortableTab = ({ id }) => {
6194
6476
  {
6195
6477
  ref: measureRef,
6196
6478
  style,
6197
- className: isDragging ? "cursor-grabbing" : "cursor-grab",
6479
+ className: isDragging ? "cursor-grabbing" : isPinned ? "cursor-default" : "cursor-grab",
6198
6480
  ...attributes,
6199
- ...listeners2,
6481
+ ...isPinned ? {} : listeners2,
6200
6482
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdProvider, { value: id, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tab, { id }) })
6201
6483
  }
6202
6484
  );
6203
6485
  };
6204
6486
  var DatabrowserTabs = () => {
6205
- const { tabs, addTab, reorderTabs, selectedTab } = useDatabrowserStore();
6487
+ const { tabs, reorderTabs, selectedTab, selectTab } = useDatabrowserStore();
6488
+ const sortedTabs = _react.useMemo.call(void 0, () => {
6489
+ return [...tabs].sort(([, a], [, b]) => {
6490
+ if (a.pinned && !b.pinned) return -1;
6491
+ if (!a.pinned && b.pinned) return 1;
6492
+ return 0;
6493
+ });
6494
+ }, [tabs]);
6495
+ const scrollRef = _react.useRef.call(void 0, null);
6496
+ const [hasLeftShadow, setHasLeftShadow] = _react.useState.call(void 0, false);
6497
+ const [hasRightShadow, setHasRightShadow] = _react.useState.call(void 0, false);
6498
+ const [isOverflow, setIsOverflow] = _react.useState.call(void 0, false);
6499
+ _react.useEffect.call(void 0, () => {
6500
+ const el = scrollRef.current;
6501
+ if (!el) return;
6502
+ const onWheel = (event) => {
6503
+ if (el.scrollWidth <= el.clientWidth) return;
6504
+ const primaryDelta = Math.abs(event.deltaY) > Math.abs(event.deltaX) ? event.deltaY : event.deltaX;
6505
+ if (primaryDelta !== 0) {
6506
+ el.scrollLeft += primaryDelta;
6507
+ event.preventDefault();
6508
+ requestAnimationFrame(() => {
6509
+ const { scrollLeft, scrollWidth, clientWidth } = el;
6510
+ setHasLeftShadow(scrollLeft > 0);
6511
+ setHasRightShadow(scrollLeft + clientWidth < scrollWidth - 1);
6512
+ setIsOverflow(scrollWidth > clientWidth + 1);
6513
+ });
6514
+ }
6515
+ };
6516
+ el.addEventListener("wheel", onWheel, { passive: false });
6517
+ return () => {
6518
+ el.removeEventListener("wheel", onWheel);
6519
+ };
6520
+ }, []);
6521
+ const recomputeShadows = _react.useCallback.call(void 0, () => {
6522
+ const el = scrollRef.current;
6523
+ if (!el) return;
6524
+ const { scrollLeft, scrollWidth, clientWidth } = el;
6525
+ setHasLeftShadow(scrollLeft > 0);
6526
+ setHasRightShadow(scrollLeft + clientWidth < scrollWidth - 1);
6527
+ setIsOverflow(scrollWidth > clientWidth + 1);
6528
+ }, []);
6529
+ _react.useEffect.call(void 0, () => {
6530
+ recomputeShadows();
6531
+ const el = scrollRef.current;
6532
+ if (!el) return;
6533
+ const onResize = () => recomputeShadows();
6534
+ window.addEventListener("resize", onResize);
6535
+ const obs = new ResizeObserver(onResize);
6536
+ obs.observe(el);
6537
+ return () => {
6538
+ window.removeEventListener("resize", onResize);
6539
+ obs.disconnect();
6540
+ };
6541
+ }, [recomputeShadows]);
6206
6542
  const sensors = _core.useSensors.call(void 0,
6207
6543
  _core.useSensor.call(void 0, _core.PointerSensor, {
6208
6544
  activationConstraint: {
@@ -6220,36 +6556,140 @@ var DatabrowserTabs = () => {
6220
6556
  };
6221
6557
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative mb-2 shrink-0", children: [
6222
6558
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute bottom-0 left-0 right-0 -z-10 h-[1px] w-full bg-zinc-200" }),
6223
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "scrollbar-hide flex translate-y-[1px] items-center gap-1 overflow-x-scroll pb-[1px] [&::-webkit-scrollbar]:hidden", children: [
6224
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6225
- _core.DndContext,
6226
- {
6227
- sensors,
6228
- collisionDetection: _core.closestCenter,
6229
- onDragEnd: handleDragEnd,
6230
- modifiers: [_modifiers.restrictToHorizontalAxis],
6231
- measuring: {
6232
- droppable: {
6233
- strategy: _core.MeasuringStrategy.Always
6234
- }
6235
- },
6236
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _sortable.SortableContext, { items: tabs.map(([id]) => id), strategy: _sortable.horizontalListSortingStrategy, children: selectedTab && tabs.map(([id]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SortableTab, { id }, id)) })
6237
- }
6238
- ),
6239
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6240
- Button,
6241
- {
6242
- variant: "secondary",
6243
- size: "icon-sm",
6244
- onClick: addTab,
6245
- className: "mr-1 flex-shrink-0",
6246
- title: "Add new tab",
6247
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500", size: 16 })
6248
- }
6249
- )
6559
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex translate-y-[1px] items-center gap-1", children: [
6560
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative min-w-0 flex-1", children: [
6561
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6562
+ "div",
6563
+ {
6564
+ className: `tabs-shadow-left pointer-events-none absolute left-0 top-0 z-10 h-full w-6 transition-opacity duration-200 ${hasLeftShadow ? "opacity-100" : "opacity-0"}`
6565
+ }
6566
+ ),
6567
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6568
+ "div",
6569
+ {
6570
+ className: `tabs-shadow-right pointer-events-none absolute right-0 top-0 z-10 h-full w-6 transition-opacity duration-200 ${hasRightShadow ? "opacity-100" : "opacity-0"}`
6571
+ }
6572
+ ),
6573
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6574
+ "div",
6575
+ {
6576
+ ref: scrollRef,
6577
+ onScroll: recomputeShadows,
6578
+ className: "scrollbar-hide flex min-w-0 flex-1 items-center gap-1 overflow-x-auto pb-[1px] [&::-webkit-scrollbar]:hidden",
6579
+ children: [
6580
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6581
+ _core.DndContext,
6582
+ {
6583
+ sensors,
6584
+ collisionDetection: _core.closestCenter,
6585
+ onDragEnd: handleDragEnd,
6586
+ modifiers: [_modifiers.restrictToHorizontalAxis],
6587
+ measuring: {
6588
+ droppable: {
6589
+ strategy: _core.MeasuringStrategy.Always
6590
+ }
6591
+ },
6592
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6593
+ _sortable.SortableContext,
6594
+ {
6595
+ items: sortedTabs.map(([id]) => id),
6596
+ strategy: _sortable.horizontalListSortingStrategy,
6597
+ children: selectedTab && sortedTabs.map(([id]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SortableTab, { id }, id))
6598
+ }
6599
+ )
6600
+ }
6601
+ ),
6602
+ !isOverflow && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-1 pl-1 pr-1", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AddTabButton, {}) })
6603
+ ]
6604
+ }
6605
+ )
6606
+ ] }),
6607
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1 pl-1", children: [
6608
+ isOverflow && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AddTabButton, {}),
6609
+ tabs.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabsListButton, { tabs, onSelectTab: selectTab })
6610
+ ] })
6250
6611
  ] })
6251
6612
  ] });
6252
6613
  };
6614
+ function AddTabButton() {
6615
+ const { addTab, selectTab } = useDatabrowserStore();
6616
+ const rootRef = useDatabrowserRootRef();
6617
+ const handleAddTab = () => {
6618
+ const tabsId = addTab();
6619
+ selectTab(tabsId);
6620
+ setTimeout(() => {
6621
+ const tab = _optionalChain([rootRef, 'optionalAccess', _72 => _72.current, 'optionalAccess', _73 => _73.querySelector, 'call', _74 => _74(`#tab-${tabsId}`)]);
6622
+ if (!tab) return;
6623
+ tab.scrollIntoView({ behavior: "smooth" });
6624
+ }, 20);
6625
+ };
6626
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6627
+ Button,
6628
+ {
6629
+ "aria-label": "Add new tab",
6630
+ variant: "secondary",
6631
+ size: "icon-sm",
6632
+ onClick: handleAddTab,
6633
+ className: "flex-shrink-0",
6634
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconPlus, { className: "text-zinc-500", size: 16 })
6635
+ }
6636
+ );
6637
+ }
6638
+ function TabsListButton({
6639
+ tabs,
6640
+ onSelectTab
6641
+ }) {
6642
+ const [open, setOpen] = _react.useState.call(void 0, false);
6643
+ const sorted = _react.useMemo.call(void 0, () => {
6644
+ return [...tabs].sort(([, a], [, b]) => {
6645
+ if (a.pinned && !b.pinned) return -1;
6646
+ if (!a.pinned && b.pinned) return 1;
6647
+ return 0;
6648
+ });
6649
+ }, [tabs]);
6650
+ const rootRef = useDatabrowserRootRef();
6651
+ const handleSelectTab = (id) => {
6652
+ onSelectTab(id);
6653
+ setOpen(false);
6654
+ setTimeout(() => {
6655
+ const tab = _optionalChain([rootRef, 'optionalAccess', _75 => _75.current, 'optionalAccess', _76 => _76.querySelector, 'call', _77 => _77(`#tab-${id}`)]);
6656
+ if (!tab) return;
6657
+ tab.scrollIntoView({ behavior: "smooth" });
6658
+ }, 20);
6659
+ };
6660
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Popover, { open, onOpenChange: setOpen, children: [
6661
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6662
+ Button,
6663
+ {
6664
+ variant: "secondary",
6665
+ size: "sm",
6666
+ className: "h-7 gap-1 px-2",
6667
+ "aria-label": "Search in tabs",
6668
+ children: [
6669
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-xs text-zinc-600", children: tabs.length }),
6670
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconChevronDown, { className: "text-zinc-500", size: 16 })
6671
+ ]
6672
+ }
6673
+ ) }),
6674
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverContent, { className: "w-96 p-0", align: "end", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Command, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, CommandList, { children: [
6675
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommandEmpty, { children: "No tabs" }),
6676
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommandGroup, { children: sorted.map(([_id, item]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6677
+ CommandItem,
6678
+ {
6679
+ style: {
6680
+ padding: 0
6681
+ },
6682
+ value: item.id,
6683
+ onSelect: () => {
6684
+ handleSelectTab(item.id);
6685
+ },
6686
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TabIdProvider, { value: _id, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Tab, { id: _id, isList: true }) })
6687
+ },
6688
+ item.id
6689
+ )) })
6690
+ ] }) }) })
6691
+ ] });
6692
+ }
6253
6693
 
6254
6694
  // src/components/databrowser/index.tsx
6255
6695
 
@@ -6260,14 +6700,16 @@ var RedisBrowser = ({
6260
6700
  storage
6261
6701
  }) => {
6262
6702
  const credentials = _react.useMemo.call(void 0, () => ({ token, url }), [token, url]);
6703
+ const rootRef = _react.useRef.call(void 0, null);
6263
6704
  _react.useEffect.call(void 0, () => {
6264
6705
  queryClient.resetQueries();
6265
6706
  }, [credentials.url]);
6266
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RedisProvider, { redisCredentials: credentials, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserProvider, { storage, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacttooltip.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6707
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RedisProvider, { redisCredentials: credentials, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserProvider, { storage, rootRef, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reacttooltip.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
6267
6708
  "div",
6268
6709
  {
6269
6710
  className: "ups-db",
6270
6711
  style: { height: "100%", display: "flex", flexDirection: "column" },
6712
+ ref: rootRef,
6271
6713
  children: [
6272
6714
  !hideTabs && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserTabs, {}),
6273
6715
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DatabrowserInstances, {})