db-studio 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/web-dist/assets/{_pathlessLayout-eo6iLvBo.js → _pathlessLayout-CJRtdlfu.js} +73 -73
- package/dist/web-dist/assets/_pathlessLayout-CJRtdlfu.js.map +1 -0
- package/dist/web-dist/assets/_pathlessLayout-ciCuJ1PR.js +1 -0
- package/dist/web-dist/assets/{_pathlessLayout-CEv6uosT.js.map → _pathlessLayout-ciCuJ1PR.js.map} +1 -1
- package/dist/web-dist/assets/_queryId-6swfGplM.js +1 -0
- package/dist/web-dist/assets/{_queryId-Bq64AuuI.js.map → _queryId-6swfGplM.js.map} +1 -1
- package/dist/web-dist/assets/{_table-Bt9of1on.js → _table-DHk3bHnN.js} +1 -1
- package/dist/web-dist/assets/{_table-Bt9of1on.js.map → _table-DHk3bHnN.js.map} +1 -1
- package/dist/web-dist/assets/_table-dUsH_2LP.js +1 -0
- package/dist/web-dist/assets/{_table-CQhKMAcZ.js.map → _table-dUsH_2LP.js.map} +1 -1
- package/dist/web-dist/assets/{browser-CFsrLhq1.js → browser-CKmBpcoz.js} +1 -1
- package/dist/web-dist/assets/{browser-CFsrLhq1.js.map → browser-CKmBpcoz.js.map} +1 -1
- package/dist/web-dist/assets/code-editor-C9H5SO98.js +9 -0
- package/dist/web-dist/assets/code-editor-C9H5SO98.js.map +1 -0
- package/dist/web-dist/assets/database.store-BvoUSH8Y.js +1 -0
- package/dist/web-dist/assets/database.store-BvoUSH8Y.js.map +1 -0
- package/dist/web-dist/assets/{dist-B90HBock.js → dist-C-7rnx4R.js} +1 -1
- package/dist/web-dist/assets/{dist-B90HBock.js.map → dist-C-7rnx4R.js.map} +1 -1
- package/dist/web-dist/assets/highlighted-body-OFNGDK62-qZDgwznf.js +1 -0
- package/dist/web-dist/assets/{highlighted-body-OFNGDK62-BGFI1Y6G.js.map → highlighted-body-OFNGDK62-qZDgwznf.js.map} +1 -1
- package/dist/web-dist/assets/icons-0UA1AvNu.js +1 -0
- package/dist/web-dist/assets/icons-0UA1AvNu.js.map +1 -0
- package/dist/web-dist/assets/index-BSNZ1oRs.js +35 -0
- package/dist/web-dist/assets/index-BSNZ1oRs.js.map +1 -0
- package/dist/web-dist/assets/index-BWKgNfEb.css +2 -0
- package/dist/web-dist/assets/{indexes-BKOZUa9Z.js → indexes-D-oUHra7.js} +1 -1
- package/dist/web-dist/assets/{indexes-BKOZUa9Z.js.map → indexes-D-oUHra7.js.map} +1 -1
- package/dist/web-dist/assets/{logs-DHha3vDy.js → logs-wkipM6zd.js} +1 -1
- package/dist/web-dist/assets/{logs-DHha3vDy.js.map → logs-wkipM6zd.js.map} +1 -1
- package/dist/web-dist/assets/mermaid-GHXKKRXX-BZ1Tdv8E.js +1 -0
- package/dist/web-dist/assets/middleware-CCyr6cvp.js +1 -0
- package/dist/web-dist/assets/middleware-CCyr6cvp.js.map +1 -0
- package/dist/web-dist/assets/popover-WwEzK7ho.js +1 -0
- package/dist/web-dist/assets/popover-WwEzK7ho.js.map +1 -0
- package/dist/web-dist/assets/query-runner-B-lngX3P.js +9 -0
- package/dist/web-dist/assets/query-runner-B-lngX3P.js.map +1 -0
- package/dist/web-dist/assets/{radix-ui-BUv2Nuc1.js → radix-ui-6dcJ5m4U.js} +1 -1
- package/dist/web-dist/assets/{radix-ui-BUv2Nuc1.js.map → radix-ui-6dcJ5m4U.js.map} +1 -1
- package/dist/web-dist/assets/react-B_x-GW6a.js +1 -0
- package/dist/web-dist/assets/react-B_x-GW6a.js.map +1 -0
- package/dist/web-dist/assets/{react-dom-0lXVP1OR.js → react-dom-CsRkF-uK.js} +1 -1
- package/dist/web-dist/assets/{react-dom-0lXVP1OR.js.map → react-dom-CsRkF-uK.js.map} +1 -1
- package/dist/web-dist/assets/{redis-value-CJoRCZun.js → redis-value-Dq29EMpv.js} +1 -1
- package/dist/web-dist/assets/{redis-value-CJoRCZun.js.map → redis-value-Dq29EMpv.js.map} +1 -1
- package/dist/web-dist/assets/runner-CL63BPMX.js +1 -0
- package/dist/web-dist/assets/{runner-CZKDzRoU.js.map → runner-CL63BPMX.js.map} +1 -1
- package/dist/web-dist/assets/schema-BNzZaUjg.js +64 -0
- package/dist/web-dist/assets/schema-BNzZaUjg.js.map +1 -0
- package/dist/web-dist/assets/{schema-0sozVL-z.js → schema-CIr5j9z3.js} +1 -1
- package/dist/web-dist/assets/{schema-0sozVL-z.js.map → schema-CIr5j9z3.js.map} +1 -1
- package/dist/web-dist/assets/{table-CPQhgD-a.js → table-BoQghHv7.js} +1 -1
- package/dist/web-dist/assets/{table-CPQhgD-a.js.map → table-BoQghHv7.js.map} +1 -1
- package/dist/web-dist/assets/tanstack-C-qfmRNM.js +10 -0
- package/dist/web-dist/assets/tanstack-C-qfmRNM.js.map +1 -0
- package/dist/web-dist/assets/toggle-group-CxRlYNqR.js +1 -0
- package/dist/web-dist/assets/toggle-group-CxRlYNqR.js.map +1 -0
- package/dist/web-dist/assets/{tooltip-DinwklI8.js → tooltip-1-bWFncb.js} +2 -2
- package/dist/web-dist/assets/{tooltip-DinwklI8.js.map → tooltip-1-bWFncb.js.map} +1 -1
- package/dist/web-dist/assets/{visualizer-DTPn0ywW.js → visualizer-qFaRAy7F.js} +1 -1
- package/dist/web-dist/assets/{visualizer-DTPn0ywW.js.map → visualizer-qFaRAy7F.js.map} +1 -1
- package/dist/web-dist/index.html +13 -11
- package/package.json +1 -1
- package/dist/web-dist/assets/_pathlessLayout-CEv6uosT.js +0 -1
- package/dist/web-dist/assets/_pathlessLayout-eo6iLvBo.js.map +0 -1
- package/dist/web-dist/assets/_queryId-Bq64AuuI.js +0 -1
- package/dist/web-dist/assets/_table-CQhKMAcZ.js +0 -1
- package/dist/web-dist/assets/code-editor-DQ86aZkm.js +0 -9
- package/dist/web-dist/assets/code-editor-DQ86aZkm.js.map +0 -1
- package/dist/web-dist/assets/database.store-KDHkiedw.js +0 -1
- package/dist/web-dist/assets/database.store-KDHkiedw.js.map +0 -1
- package/dist/web-dist/assets/highlighted-body-OFNGDK62-BGFI1Y6G.js +0 -1
- package/dist/web-dist/assets/icons-Bm7rSZLJ.js +0 -1
- package/dist/web-dist/assets/icons-Bm7rSZLJ.js.map +0 -1
- package/dist/web-dist/assets/index-BtqHnOp0.js +0 -23
- package/dist/web-dist/assets/index-BtqHnOp0.js.map +0 -1
- package/dist/web-dist/assets/index-ktDWx_UP.css +0 -2
- package/dist/web-dist/assets/mermaid-GHXKKRXX-DjR37lQN.js +0 -1
- package/dist/web-dist/assets/popover-Cm3PsrMh.js +0 -1
- package/dist/web-dist/assets/popover-Cm3PsrMh.js.map +0 -1
- package/dist/web-dist/assets/query-runner-6BhVPaC9.js +0 -9
- package/dist/web-dist/assets/query-runner-6BhVPaC9.js.map +0 -1
- package/dist/web-dist/assets/runner-CZKDzRoU.js +0 -1
- package/dist/web-dist/assets/schema-cZHeTHA0.js +0 -64
- package/dist/web-dist/assets/schema-cZHeTHA0.js.map +0 -1
- package/dist/web-dist/assets/tanstack-D6l4LIt3.js +0 -10
- package/dist/web-dist/assets/tanstack-D6l4LIt3.js.map +0 -1
- package/dist/web-dist/assets/toggle-group-BRWnLosM.js +0 -1
- package/dist/web-dist/assets/toggle-group-BRWnLosM.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-CFsrLhq1.js","names":["RedisBrowserScreen","SplitComponent","component"],"sources":["../../src/features/redis-browser/components/redis-copy-button.tsx","../../src/features/redis-browser/components/redis-key-header.tsx","../../src/features/redis-browser/components/redis-value-editors.tsx","../../src/features/redis-browser/screens/redis-browser-screen.tsx","../../src/routes/_pathlessLayout/browser.tsx?tsr-split=component"],"sourcesContent":["import { Button } from \"@db-studio/ui/button\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@db-studio/ui/tooltip\";\nimport { Check, Copy } from \"lucide-react\";\nimport { useState } from \"react\";\n\n/**\n * Icon button that copies `text` (or its lazy producer) to the clipboard and\n * flashes a check mark. Used for key names, values, and JSON exports.\n */\nexport const RedisCopyButton = ({\n\ttext,\n\tlabel,\n\tclassName,\n}: {\n\ttext: string | (() => string);\n\tlabel: string;\n\tclassName?: string;\n}) => {\n\tconst [copied, setCopied] = useState(false);\n\treturn (\n\t\t<Tooltip>\n\t\t\t<TooltipTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\tawait navigator.clipboard.writeText(typeof text === \"function\" ? text() : text);\n\t\t\t\t\t\tsetCopied(true);\n\t\t\t\t\t\twindow.setTimeout(() => setCopied(false), 1_200);\n\t\t\t\t\t}}\n\t\t\t\t\taria-label={label}\n\t\t\t\t>\n\t\t\t\t\t{copied ? <Check /> : <Copy />}\n\t\t\t\t</Button>\n\t\t\t</TooltipTrigger>\n\t\t\t<TooltipContent>{copied ? \"Copied\" : label}</TooltipContent>\n\t\t</Tooltip>\n\t);\n};\n","import type {\n\tEncodedRedisValueSchemaType,\n\tKeyDetailsResultSchemaType,\n} from \"@db-studio/shared/types\";\nimport { Badge } from \"@db-studio/ui/badge\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Field, FieldDescription, FieldGroup, FieldLabel } from \"@db-studio/ui/field\";\nimport { Input } from \"@db-studio/ui/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@db-studio/ui/popover\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@db-studio/ui/tooltip\";\nimport { cn } from \"@db-studio/ui/utils\";\nimport { ArrowRight, Pencil, RefreshCw, Terminal, Trash2 } from \"lucide-react\";\nimport { type ReactNode, useEffect, useReducer, useState } from \"react\";\nimport { RedisCopyButton } from \"./redis-copy-button\";\nimport { RedisValueInput } from \"./redis-value\";\nimport type { RedisAct } from \"./redis-value-editors\";\n\nconst TTL_PRESETS = [\n\t{ label: \"60s\", ttlMs: 60_000 },\n\t{ label: \"10m\", ttlMs: 600_000 },\n\t{ label: \"1h\", ttlMs: 3_600_000 },\n\t{ label: \"1d\", ttlMs: 86_400_000 },\n\t{ label: \"7d\", ttlMs: 604_800_000 },\n] as const;\n\nconst formatBytes = (bytes: number | null): string => {\n\tif (bytes === null) return \"—\";\n\tif (bytes < 1_024) return `${bytes} B`;\n\tif (bytes < 1_048_576) return `${(bytes / 1_024).toFixed(1)} KiB`;\n\treturn `${(bytes / 1_048_576).toFixed(1)} MiB`;\n};\n\nconst formatDuration = (ms: number): string => {\n\tconst seconds = Math.max(0, Math.ceil(ms / 1_000));\n\tif (seconds < 60) return `${seconds}s`;\n\tconst minutes = Math.floor(seconds / 60);\n\tif (minutes < 60) return `${minutes}m ${seconds % 60}s`;\n\tconst hours = Math.floor(minutes / 60);\n\tif (hours < 24) return `${hours}h ${minutes % 60}m`;\n\treturn `${Math.floor(hours / 24)}d ${hours % 24}h`;\n};\n\n/** Re-renders once a second while `active`, so TTLs count down live. */\nconst useSecondTick = (active: boolean) => {\n\tconst [, tick] = useReducer((count: number) => count + 1, 0);\n\tuseEffect(() => {\n\t\tif (!active) return;\n\t\tconst id = window.setInterval(tick, 1_000);\n\t\treturn () => window.clearInterval(id);\n\t}, [active]);\n};\n\n/**\n * Key toolbar: name + copy, type badge, live stats, refresh, open-in-runner,\n * rename/TTL popover, and delete. Mount with `key={detail.key.base64}` so the\n * rename/TTL drafts reset when the selected key changes.\n */\nexport const RedisKeyHeader = ({\n\tdetail,\n\tlabel,\n\tloadedCount,\n\tfetchedAt,\n\tisFetching,\n\tpending,\n\tcommand,\n\tact,\n\tonRefresh,\n\tonOpenRunner,\n\tonDelete,\n}: {\n\tdetail: KeyDetailsResultSchemaType;\n\tlabel: string;\n\tloadedCount: number | null;\n\tfetchedAt: number;\n\tisFetching: boolean;\n\tpending: boolean;\n\tcommand: string | null;\n\tact: RedisAct;\n\tonRefresh: () => void;\n\tonOpenRunner: () => void;\n\tonDelete: () => void;\n}) => {\n\tconst [rename, setRename] = useState<EncodedRedisValueSchemaType | null>(detail.key);\n\tconst [ttl, setTtl] = useState(\"\");\n\tuseSecondTick(detail.ttlMs > 0);\n\n\tconst remainingMs =\n\t\tdetail.ttlMs > 0 ? detail.ttlMs - (Date.now() - fetchedAt) : detail.ttlMs;\n\tconst persistent = detail.ttlMs === -1;\n\tconst expired = !persistent && remainingMs <= 0;\n\tconst stats: { name: string; value: ReactNode; hint: string; alert?: boolean }[] = [\n\t\t{\n\t\t\tname: \"TTL\",\n\t\t\tvalue: persistent ? \"∞\" : expired ? \"expired\" : formatDuration(remainingMs),\n\t\t\thint: persistent\n\t\t\t\t? \"No expiry — the key persists until deleted.\"\n\t\t\t\t: expired\n\t\t\t\t\t? \"The TTL elapsed; Redis has evicted or is about to evict this key.\"\n\t\t\t\t\t: `Expires ${new Date(fetchedAt + detail.ttlMs).toLocaleString()}`,\n\t\t\talert: expired,\n\t\t},\n\t\t{\n\t\t\tname: \"MEM\",\n\t\t\tvalue: formatBytes(detail.memoryBytes),\n\t\t\thint: \"Approximate memory usage reported by MEMORY USAGE.\",\n\t\t},\n\t\t{\n\t\t\tname: \"LEN\",\n\t\t\tvalue: detail.length?.toLocaleString() ?? \"—\",\n\t\t\thint:\n\t\t\t\tloadedCount !== null && detail.length !== null\n\t\t\t\t\t? `${loadedCount.toLocaleString()} of ${detail.length.toLocaleString()} entries loaded in this view.`\n\t\t\t\t\t: \"Length reported by Redis (entries, or bytes for strings).\",\n\t\t},\n\t\t{\n\t\t\tname: \"REV\",\n\t\t\tvalue: detail.revision.slice(0, 8),\n\t\t\thint: \"Optimistic-lock revision. Writes are rejected when the key changed since this fetch.\",\n\t\t},\n\t\t{\n\t\t\tname: \"AT\",\n\t\t\tvalue: new Date(fetchedAt).toLocaleTimeString(),\n\t\t\thint: \"When this snapshot was fetched from Redis.\",\n\t\t},\n\t];\n\n\treturn (\n\t\t<header className=\"border-b border-border\">\n\t\t\t<div className=\"flex min-h-10 items-stretch justify-between\">\n\t\t\t\t<div className=\"flex min-w-0 flex-1 items-stretch overflow-x-auto\">\n\t\t\t\t\t<div className=\"flex min-w-0 max-w-[min(36rem,45vw)] shrink items-center gap-1 px-3 py-1.5\">\n\t\t\t\t\t\t<code\n\t\t\t\t\t\t\tclassName=\"min-w-0 truncate text-sm text-foreground\"\n\t\t\t\t\t\t\ttitle={label}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{label || \"(empty key)\"}\n\t\t\t\t\t\t</code>\n\t\t\t\t\t\t<RedisCopyButton\n\t\t\t\t\t\t\ttext={detail.key.utf8 ?? detail.key.base64}\n\t\t\t\t\t\t\tlabel=\"Copy key name\"\n\t\t\t\t\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tclassName=\"h-4 shrink-0 rounded-sm px-1.5 text-[8px] font-normal uppercase text-muted-foreground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{detail.type}\n\t\t\t\t\t\t</Badge>\n\t\t\t\t\t</div>\n\t\t\t\t\t{stats.map(({ name, value, hint, alert }, index) => (\n\t\t\t\t\t\t<Tooltip key={name}>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"flex shrink-0 cursor-default items-center gap-1.5 border-s border-border px-2 text-[10px]\",\n\t\t\t\t\t\t\t\t\t\tindex === stats.length - 1 && \"border-e\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">{name}</span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"tabular-nums\",\n\t\t\t\t\t\t\t\t\t\t\talert ? \"text-destructive\" : \"text-foreground\",\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{value}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent side=\"bottom\">{hint}</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex shrink-0 items-stretch\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\tonClick={onRefresh}\n\t\t\t\t\t\tdisabled={isFetching}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RefreshCw className={cn(isFetching && \"animate-spin\")} /> Refresh\n\t\t\t\t\t</Button>\n\t\t\t\t\t{command && (\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\t\t\t\tonClick={onOpenRunner}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Terminal /> Runner\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent side=\"bottom\">\n\t\t\t\t\t\t\t\tOpen in the query runner as <code className=\"font-mono\">{command}</code>\n\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<Popover>\n\t\t\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Pencil /> Edit\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</PopoverTrigger>\n\t\t\t\t\t\t<PopoverContent\n\t\t\t\t\t\t\talign=\"end\"\n\t\t\t\t\t\t\tclassName=\"w-72 rounded-sm p-3 font-mono\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<FieldGroup className=\"gap-4\">\n\t\t\t\t\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t\t\t\t\t<FieldLabel htmlFor=\"redis-key-rename\">Rename key</FieldLabel>\n\t\t\t\t\t\t\t\t\t<form\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex\"\n\t\t\t\t\t\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tif (rename === null || rename.base64 === detail.key.base64 || pending)\n\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\tact({ action: \"rename\", newKey: rename });\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\t\t\t\t\t\tid=\"redis-key-rename\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={rename}\n\t\t\t\t\t\t\t\t\t\t\tonChange={setRename}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-e-none font-mono\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-auto self-stretch rounded-s-none border-0 bg-clip-border\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\t\t\trename === null || rename.base64 === detail.key.base64 || pending\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Rename key\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<ArrowRight />\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t</Field>\n\t\t\t\t\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t\t\t\t\t<FieldLabel htmlFor=\"redis-key-ttl-operation\">TTL in seconds</FieldLabel>\n\t\t\t\t\t\t\t\t\t<form\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex\"\n\t\t\t\t\t\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tif (pending) return;\n\t\t\t\t\t\t\t\t\t\t\tact({ action: \"setTtl\", ttlMs: ttl ? Number(ttl) * 1_000 : null });\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\t\tid=\"redis-key-ttl-operation\"\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tvalue={ttl}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(event) => setTtl(event.target.value)}\n\t\t\t\t\t\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\t\t\t\t\t\tdetail.ttlMs > 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t? String(Math.ceil(detail.ttlMs / 1_000))\n\t\t\t\t\t\t\t\t\t\t\t\t\t: \"Persistent\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-e-none font-mono\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-auto self-stretch rounded-s-none border-0 bg-clip-border\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tApply\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t\t\t\t\t\t{TTL_PRESETS.map((preset) => (\n\t\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\t\tkey={preset.label}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => act({ action: \"setTtl\", ttlMs: preset.ttlMs })}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{preset.label}\n\t\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={pending || persistent}\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => act({ action: \"setTtl\", ttlMs: null })}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tPersist\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<FieldDescription>Leave empty to persist the key.</FieldDescription>\n\t\t\t\t\t\t\t\t</Field>\n\t\t\t\t\t\t\t</FieldGroup>\n\t\t\t\t\t\t</PopoverContent>\n\t\t\t\t\t</Popover>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\tonClick={onDelete}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2 /> Delete\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</header>\n\t);\n};\n","import type {\n\tEncodedRedisValueSchemaType,\n\tKeyActionSchemaType,\n\tKeyDetailsResultSchemaType,\n} from \"@db-studio/shared/types\";\nimport { Alert } from \"@db-studio/ui/alert\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Field, FieldLabel } from \"@db-studio/ui/field\";\nimport { Input } from \"@db-studio/ui/input\";\nimport { ToggleGroup, ToggleGroupItem } from \"@db-studio/ui/toggle-group\";\nimport { Plus, Save, Search, Trash2 } from \"lucide-react\";\nimport { type FormEvent, type ReactNode, useState } from \"react\";\nimport { RedisCopyButton } from \"./redis-copy-button\";\nimport { encodeTextValue, RedisValue, RedisValueInput } from \"./redis-value\";\n\n/**\n * Runs one key operation against the server. Resolves `true` on success so\n * add-forms know when to clear; conflict handling lives in the screen.\n */\nexport type RedisAct = (\n\toperation: KeyActionSchemaType[\"operation\"],\n\tforce?: boolean,\n) => Promise<boolean>;\n\nexport type StreamDirection = \"forward\" | \"backward\";\n\ntype RedisValueUnion = KeyDetailsResultSchemaType[\"value\"];\ntype HashValue = Extract<RedisValueUnion, { kind: \"hash\" }>;\ntype ListValue = Extract<RedisValueUnion, { kind: \"list\" }>;\ntype SetValue = Extract<RedisValueUnion, { kind: \"set\" }>;\ntype ZsetValue = Extract<RedisValueUnion, { kind: \"zset\" }>;\ntype StreamValue = Extract<RedisValueUnion, { kind: \"stream\" }>;\n\nconst emptyValue = encodeTextValue(\"\");\n\n/** `null` = the input's visible draft is unparseable and MUST NOT be submitted. */\ntype DraftValue = EncodedRedisValueSchemaType | null;\n\nconst textOf = (value: EncodedRedisValueSchemaType): string =>\n\tvalue.utf8 ?? `base64:${value.base64}`;\n\nconst matches = (needle: string, ...haystack: (string | number)[]): boolean =>\n\thaystack.some((part) => String(part).toLowerCase().includes(needle));\n\n/** Serializes the loaded (client-side) entries so devs can yank them into code. */\nconst collectionJson = (value: RedisValueUnion): string => {\n\tswitch (value.kind) {\n\t\tcase \"string\":\n\t\t\treturn JSON.stringify(textOf(value.value), null, 2);\n\t\tcase \"hash\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tvalue.entries.map((entry) => [textOf(entry.field), textOf(entry.value)]),\n\t\t\t\t),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => textOf(entry.value)),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"set\":\n\t\t\treturn JSON.stringify(value.members.map(textOf), null, 2);\n\t\tcase \"zset\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => ({ member: textOf(entry.member), score: entry.score })),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"stream\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tfields: Object.fromEntries(\n\t\t\t\t\t\tentry.fields.map((field) => [textOf(field.field), textOf(field.value)]),\n\t\t\t\t\t),\n\t\t\t\t})),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n};\n\n/**\n * Local draft that re-syncs whenever the server value changes (identified by\n * `revision`), without wiping unrelated drafts on every refetch.\n */\nconst useSyncedDraft = <T,>(server: T, revision: string): [T, (next: T) => void] => {\n\tconst [draft, setDraft] = useState(server);\n\tconst [synced, setSynced] = useState(revision);\n\tif (synced !== revision) {\n\t\tsetSynced(revision);\n\t\tsetDraft(server);\n\t}\n\treturn [draft, setDraft];\n};\n\nconst EmptyRow = ({ filtered }: { filtered: boolean }) => (\n\t<div className=\"flex h-10 items-center justify-center px-2 text-xs text-muted-foreground\">\n\t\t{filtered ? \"No loaded entries match the filter.\" : \"No entries loaded.\"}\n\t</div>\n);\n\n/**\n * Frame around every collection editor: a client-side filter over the loaded\n * entries, a loaded/total counter, copy-as-JSON, and an optional `extra` slot\n * (e.g. the stream direction toggle).\n */\nconst CollectionShell = ({\n\tfilter,\n\tonFilterChange,\n\tshownCount,\n\tloadedCount,\n\ttotalCount,\n\tcopyJson,\n\textra,\n\theader,\n\tchildren,\n\tfooter,\n}: {\n\tfilter: string;\n\tonFilterChange: (next: string) => void;\n\tshownCount: number;\n\tloadedCount: number;\n\ttotalCount: number | null;\n\tcopyJson: () => string;\n\textra?: ReactNode;\n\theader: ReactNode;\n\tchildren: ReactNode;\n\tfooter: ReactNode;\n}) => (\n\t<div className=\"overflow-hidden border border-border\">\n\t\t<div className=\"flex h-8 items-center gap-1 border-b border-border bg-muted/10 px-1\">\n\t\t\t<Search className=\"ms-1 size-3 shrink-0 text-muted-foreground\" />\n\t\t\t<Input\n\t\t\t\tvariant=\"outline\"\n\t\t\t\tvalue={filter}\n\t\t\t\tonChange={(event) => onFilterChange(event.target.value)}\n\t\t\t\tplaceholder=\"Filter loaded entries\"\n\t\t\t\taria-label=\"Filter loaded entries\"\n\t\t\t\tclassName=\"h-6 flex-1 rounded-none border-none px-1 font-mono focus-visible:ring-0\"\n\t\t\t/>\n\t\t\t{extra}\n\t\t\t<span className=\"shrink-0 px-1 text-[10px] tabular-nums text-muted-foreground\">\n\t\t\t\t{filter\n\t\t\t\t\t? `${shownCount} / ${loadedCount}`\n\t\t\t\t\t: totalCount !== null && totalCount > loadedCount\n\t\t\t\t\t\t? `${loadedCount.toLocaleString()} of ${totalCount.toLocaleString()}`\n\t\t\t\t\t\t: loadedCount.toLocaleString()}\n\t\t\t</span>\n\t\t\t<RedisCopyButton\n\t\t\t\ttext={copyJson}\n\t\t\t\tlabel=\"Copy loaded entries as JSON\"\n\t\t\t/>\n\t\t</div>\n\t\t{header}\n\t\t{children}\n\t\t{footer}\n\t</div>\n);\n\nconst AddPair = ({\n\tlabels,\n\tonSave,\n\tpending,\n\tscore = false,\n}: {\n\tlabels: [string, string];\n\tonSave: (\n\t\tfirst: EncodedRedisValueSchemaType,\n\t\tsecond: EncodedRedisValueSchemaType | number,\n\t) => Promise<boolean>;\n\tpending: boolean;\n\tscore?: boolean;\n}) => {\n\tconst [first, setFirst] = useState<DraftValue>(emptyValue);\n\tconst [second, setSecond] = useState<DraftValue>(emptyValue);\n\tconst [numeric, setNumeric] = useState(\"0\");\n\tconst invalid = first === null || (!score && second === null);\n\tconst submit = async (event: FormEvent) => {\n\t\tevent.preventDefault();\n\t\tif (first === null || second === null) return;\n\t\tconst saved = await onSave(first, score ? Number(numeric) : second);\n\t\tif (!saved) return;\n\t\tsetFirst(emptyValue);\n\t\tsetSecond(emptyValue);\n\t\tsetNumeric(\"0\");\n\t};\n\treturn (\n\t\t<form\n\t\t\tonSubmit={submit}\n\t\t\tclassName=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={first}\n\t\t\t\tonChange={setFirst}\n\t\t\t\tplaceholder={labels[0]}\n\t\t\t/>\n\t\t\t{score ? (\n\t\t\t\t<Input\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tstep=\"any\"\n\t\t\t\t\tvalue={numeric}\n\t\t\t\t\tonChange={(event) => setNumeric(event.target.value)}\n\t\t\t\t\tplaceholder={labels[1]}\n\t\t\t\t\tclassName=\"font-mono\"\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<RedisValueInput\n\t\t\t\t\tvalue={second}\n\t\t\t\t\tonChange={setSecond}\n\t\t\t\t\tplaceholder={labels[1]}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<Button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tdisabled={pending || invalid}\n\t\t\t>\n\t\t\t\t<Plus /> Add\n\t\t\t</Button>\n\t\t</form>\n\t);\n};\n\nconst StringEditor = ({\n\tvalue,\n\ttruncated,\n\tact,\n\tpending,\n\tonLoadFull,\n\tonDownload,\n}: {\n\tvalue: EncodedRedisValueSchemaType;\n\ttruncated: boolean;\n\tact: RedisAct;\n\tpending: boolean;\n\tonLoadFull: () => void;\n\tonDownload: () => void;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, value.base64);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"space-y-3\">\n\t\t\t{truncated && (\n\t\t\t\t<div className=\"grid gap-2 border-b border-border pb-3 sm:grid-cols-[1fr_auto] sm:items-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\ttitle=\"Preview truncated\"\n\t\t\t\t\t\tmessage=\"Load the full value before editing (up to the 8 MiB response cap).\"\n\t\t\t\t\t\tclassName=\"rounded-sm\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tonClick={onLoadFull}\n\t\t\t\t\t>\n\t\t\t\t\t\tLoad full\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<RedisValue\n\t\t\t\tvalue={value}\n\t\t\t\tonDownload={onDownload}\n\t\t\t/>\n\t\t\t<form\n\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif (draft !== null && dirty) act({ action: \"setString\", value: draft });\n\t\t\t\t}}\n\t\t\t\tclassName=\"border border-border p-3\"\n\t\t\t>\n\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t<FieldLabel htmlFor=\"redis-string-value\">Replace value</FieldLabel>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tid=\"redis-string-value\"\n\t\t\t\t\t\tvalue={draft}\n\t\t\t\t\t\tonChange={setDraft}\n\t\t\t\t\t/>\n\t\t\t\t</Field>\n\t\t\t\t<Button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tclassName=\"mt-3\"\n\t\t\t\t\tdisabled={truncated || pending || !dirty}\n\t\t\t\t>\n\t\t\t\t\t<Save /> Save value\n\t\t\t\t</Button>\n\t\t\t</form>\n\t\t</div>\n\t);\n};\n\nconst HashRow = ({\n\tfield,\n\tvalue,\n\tact,\n\tpending,\n}: {\n\tfield: EncodedRedisValueSchemaType;\n\tvalue: EncodedRedisValueSchemaType;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, value.base64);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[minmax(10rem,0.7fr)_1fr_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<RedisValue\n\t\t\t\tvalue={field}\n\t\t\t\tcompact\n\t\t\t/>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={setDraft}\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty}\n\t\t\t\t\tonClick={() => draft !== null && act({ action: \"upsertHash\", field, value: draft })}\n\t\t\t\t\taria-label=\"Save hash value\"\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"deleteHash\", field })}\n\t\t\t\t\taria-label=\"Delete hash field\"\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst HashEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: HashValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) =>\n\t\t\t\tmatches(needle, textOf(entry.field), textOf(entry.value)),\n\t\t\t)\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[minmax(10rem,0.7fr)_1fr_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Field</span>\n\t\t\t\t\t<span>Value</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tlabels={[\"field\", \"value\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(field, next) =>\n\t\t\t\t\t\tact({ action: \"upsertHash\", field, value: next as EncodedRedisValueSchemaType })\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<HashRow\n\t\t\t\t\t\tkey={entry.field.base64}\n\t\t\t\t\t\tfield={entry.field}\n\t\t\t\t\t\tvalue={entry.value}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst ListRow = ({\n\tindex,\n\tvalue,\n\trevision,\n\tact,\n\tpending,\n}: {\n\tindex: number;\n\tvalue: EncodedRedisValueSchemaType;\n\trevision: string;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, `${revision}:${value.base64}`);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[3rem_1fr_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<code className=\"text-xs text-muted-foreground\">{index}</code>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={setDraft}\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty}\n\t\t\t\t\tonClick={() => draft !== null && act({ action: \"setList\", index, value: draft })}\n\t\t\t\t\taria-label={`Save list item ${index}`}\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"deleteList\", index })}\n\t\t\t\t\taria-label={`Delete list item ${index}`}\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst ListEditor = ({\n\tvalue,\n\trevision,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: ListValue;\n\trevision: string;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst [item, setItem] = useState<DraftValue>(emptyValue);\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) => matches(needle, entry.index, textOf(entry.value)))\n\t\t: value.entries;\n\tconst push = async (side: \"left\" | \"right\") => {\n\t\tif (item === null) return;\n\t\tconst saved = await act({ action: \"pushList\", side, value: item });\n\t\tif (saved) setItem(emptyValue);\n\t};\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[3rem_1fr_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Index</span>\n\t\t\t\t\t<span>Value</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<form\n\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tpush(\"right\");\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"grid grid-cols-[1fr_auto_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t\t\t>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tvalue={item}\n\t\t\t\t\t\tonChange={setItem}\n\t\t\t\t\t\tplaceholder=\"new item\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tdisabled={pending || item === null}\n\t\t\t\t\t\tonClick={() => push(\"left\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tPush left\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={pending || item === null}\n\t\t\t\t\t>\n\t\t\t\t\t\tPush right\n\t\t\t\t\t</Button>\n\t\t\t\t</form>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<ListRow\n\t\t\t\t\t\tkey={entry.index}\n\t\t\t\t\t\tindex={entry.index}\n\t\t\t\t\t\tvalue={entry.value}\n\t\t\t\t\t\trevision={revision}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst SetEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: SetValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst [member, setMember] = useState<DraftValue>(emptyValue);\n\tconst needle = filter.trim().toLowerCase();\n\tconst members = needle\n\t\t? value.members.filter((entry) => matches(needle, textOf(entry)))\n\t\t: value.members;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={members.length}\n\t\t\tloadedCount={value.members.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[1fr_2rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Member</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<form\n\t\t\t\t\tonSubmit={async (event) => {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tif (member === null) return;\n\t\t\t\t\t\tconst saved = await act({ action: \"addSet\", member });\n\t\t\t\t\t\tif (saved) setMember(emptyValue);\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"grid grid-cols-[1fr_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t\t\t>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tvalue={member}\n\t\t\t\t\t\tonChange={setMember}\n\t\t\t\t\t\tplaceholder=\"new member\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={pending || member === null}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus /> Add member\n\t\t\t\t\t</Button>\n\t\t\t\t</form>\n\t\t\t}\n\t\t>\n\t\t\t{members.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tmembers.map((entry) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={entry.base64}\n\t\t\t\t\t\tclassName=\"flex min-h-8 items-center gap-2 border-b border-border px-2 py-1\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\tvalue={entry}\n\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\tonClick={() => act({ action: \"removeSet\", member: entry })}\n\t\t\t\t\t\t\taria-label=\"Remove set member\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst ZsetRow = ({\n\tmember,\n\tscore,\n\tact,\n\tpending,\n}: {\n\tmember: EncodedRedisValueSchemaType;\n\tscore: number | \"inf\" | \"-inf\";\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft(String(score), String(score));\n\tconst parsedDraft = Number(draft);\n\tconst dirty = draft !== String(score);\n\tconst valid = Number.isFinite(parsedDraft);\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[1fr_8rem_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<RedisValue\n\t\t\t\tvalue={member}\n\t\t\t\tcompact\n\t\t\t/>\n\t\t\t<Input\n\t\t\t\tinputMode=\"decimal\"\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={(event) => setDraft(event.target.value)}\n\t\t\t\taria-label=\"Sorted set score\"\n\t\t\t\tclassName=\"font-mono\"\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty || !valid}\n\t\t\t\t\tonClick={() => act({ action: \"upsertZset\", member, score: parsedDraft })}\n\t\t\t\t\taria-label=\"Save sorted set score\"\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"removeZset\", member })}\n\t\t\t\t\taria-label=\"Remove sorted set member\"\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst ZsetEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: ZsetValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) => matches(needle, textOf(entry.member), entry.score))\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[1fr_8rem_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Member</span>\n\t\t\t\t\t<span>Score</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tscore\n\t\t\t\t\tlabels={[\"member\", \"score\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(member, score) =>\n\t\t\t\t\t\tact({ action: \"upsertZset\", member, score: score as number })\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<ZsetRow\n\t\t\t\t\t\tkey={entry.member.base64}\n\t\t\t\t\t\tmember={entry.member}\n\t\t\t\t\t\tscore={entry.score}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst StreamEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n\tdirection,\n\tonDirectionChange,\n}: {\n\tvalue: StreamValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n\tdirection: StreamDirection;\n\tonDirectionChange: (direction: StreamDirection) => void;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) =>\n\t\t\t\tmatches(\n\t\t\t\t\tneedle,\n\t\t\t\t\tentry.id,\n\t\t\t\t\t...entry.fields.flatMap((field) => [textOf(field.field), textOf(field.value)]),\n\t\t\t\t),\n\t\t\t)\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\textra={\n\t\t\t\t<ToggleGroup\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tvalue={direction}\n\t\t\t\t\tonValueChange={(next) => next && onDirectionChange(next as StreamDirection)}\n\t\t\t\t\taria-label=\"Stream order\"\n\t\t\t\t\tclassName=\"shrink-0 rounded-none\"\n\t\t\t\t>\n\t\t\t\t\t<ToggleGroupItem\n\t\t\t\t\t\tvalue=\"forward\"\n\t\t\t\t\t\tclassName=\"h-6 rounded-none px-2 text-[10px]\"\n\t\t\t\t\t>\n\t\t\t\t\t\tOldest first\n\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t\t<ToggleGroupItem\n\t\t\t\t\t\tvalue=\"backward\"\n\t\t\t\t\t\tclassName=\"h-6 rounded-none px-2 text-[10px]\"\n\t\t\t\t\t>\n\t\t\t\t\t\tNewest first\n\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t</ToggleGroup>\n\t\t\t}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[10rem_1fr_2rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Entry ID</span>\n\t\t\t\t\t<span>Fields</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tlabels={[\"field\", \"value\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(field, next) =>\n\t\t\t\t\t\tact({\n\t\t\t\t\t\t\taction: \"appendStream\",\n\t\t\t\t\t\t\tid: \"*\",\n\t\t\t\t\t\t\tfields: [{ field, value: next as EncodedRedisValueSchemaType }],\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={entry.id}\n\t\t\t\t\t\tclassName=\"grid grid-cols-[10rem_1fr_2rem] border-b border-border\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<code className=\"border-e border-border px-2 py-1.5 text-xs text-primary\">\n\t\t\t\t\t\t\t{entry.id}\n\t\t\t\t\t\t</code>\n\t\t\t\t\t\t<div className=\"grid gap-1 px-2 py-1.5\">\n\t\t\t\t\t\t\t{entry.fields.map((field) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={field.field.base64}\n\t\t\t\t\t\t\t\t\tclassName=\"grid grid-cols-[minmax(8rem,0.4fr)_1fr] gap-3\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\t\t\tvalue={field.field}\n\t\t\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\tclassName=\"rounded-none text-muted-foreground hover:text-destructive\"\n\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\tonClick={() => act({ action: \"deleteStream\", id: entry.id })}\n\t\t\t\t\t\t\taria-label={`Delete stream entry ${entry.id}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\n/** Dispatches the loaded key to the editor matching its Redis type. */\nexport const RedisValueEditor = ({\n\tdetail,\n\tact,\n\tpending,\n\tonLoadFull,\n\tonDownload,\n\tstreamDirection,\n\tonStreamDirectionChange,\n}: {\n\tdetail: KeyDetailsResultSchemaType;\n\tact: RedisAct;\n\tpending: boolean;\n\tonLoadFull: () => void;\n\tonDownload: () => void;\n\tstreamDirection: StreamDirection;\n\tonStreamDirectionChange: (direction: StreamDirection) => void;\n}) => {\n\tconst value = detail.value;\n\tswitch (value.kind) {\n\t\tcase \"string\":\n\t\t\treturn (\n\t\t\t\t<StringEditor\n\t\t\t\t\tvalue={value.value}\n\t\t\t\t\ttruncated={value.truncated}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonLoadFull={onLoadFull}\n\t\t\t\t\tonDownload={onDownload}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"hash\":\n\t\t\treturn (\n\t\t\t\t<HashEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn (\n\t\t\t\t<ListEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\trevision={detail.revision}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"set\":\n\t\t\treturn (\n\t\t\t\t<SetEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"zset\":\n\t\t\treturn (\n\t\t\t\t<ZsetEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"stream\":\n\t\t\treturn (\n\t\t\t\t<StreamEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tdirection={streamDirection}\n\t\t\t\t\tonDirectionChange={onStreamDirectionChange}\n\t\t\t\t/>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn (\n\t\t\t\t<Alert\n\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\ttitle=\"Metadata only\"\n\t\t\t\t\tmessage=\"This Redis module type cannot be edited in this release.\"\n\t\t\t\t\tclassName=\"rounded-sm\"\n\t\t\t\t/>\n\t\t\t);\n\t}\n};\n","import type { KeyActionSchemaType, KeyDetailsResultSchemaType } from \"@db-studio/shared/types\";\nimport { Alert } from \"@db-studio/ui/alert\";\nimport {\n\tAlertDialog,\n\tAlertDialogAction,\n\tAlertDialogCancel,\n\tAlertDialogContent,\n\tAlertDialogDescription,\n\tAlertDialogFooter,\n\tAlertDialogHeader,\n\tAlertDialogTitle,\n} from \"@db-studio/ui/alert-dialog\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Spinner } from \"@db-studio/ui/spinner\";\nimport { useNavigate } from \"@tanstack/react-router\";\nimport { DatabaseZap, Plus } from \"lucide-react\";\nimport { useQueryState } from \"nuqs\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\nimport { getRedisStringChunk } from \"@/shared/api\";\nimport { useDatabaseStore } from \"@/stores/database.store\";\nimport { useOverlayStore } from \"@/stores/overlay.store\";\nimport { useQueriesStore } from \"@/stores/queries.store\";\nimport { RedisKeyHeader } from \"../components/redis-key-header\";\nimport { bytesFromBase64Url } from \"../components/redis-value\";\nimport {\n\ttype RedisAct,\n\tRedisValueEditor,\n\ttype StreamDirection,\n} from \"../components/redis-value-editors\";\nimport { useRedisKey, useRedisKeyMutations } from \"../hooks/use-redis-browser\";\n\n/** The read command a dev would run for this key, used by \"Open in runner\". */\nconst runnerCommand = (detail: KeyDetailsResultSchemaType): string | null => {\n\tif (detail.key.utf8 === undefined) return null;\n\tconst key = JSON.stringify(detail.key.utf8);\n\tswitch (detail.type) {\n\t\tcase \"string\":\n\t\t\treturn `GET ${key}`;\n\t\tcase \"hash\":\n\t\t\treturn `HGETALL ${key}`;\n\t\tcase \"list\":\n\t\t\treturn `LRANGE ${key} 0 -1`;\n\t\tcase \"set\":\n\t\t\treturn `SMEMBERS ${key}`;\n\t\tcase \"zset\":\n\t\t\treturn `ZRANGE ${key} 0 -1 WITHSCORES`;\n\t\tcase \"stream\":\n\t\t\treturn `XRANGE ${key} - + COUNT 100`;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\n/** Entries fetched so far across pages; null for scalar/unknown values. */\nconst countLoaded = (detail: KeyDetailsResultSchemaType): number | null => {\n\tswitch (detail.value.kind) {\n\t\tcase \"hash\":\n\t\tcase \"list\":\n\t\tcase \"zset\":\n\t\tcase \"stream\":\n\t\t\treturn detail.value.entries.length;\n\t\tcase \"set\":\n\t\t\treturn detail.value.members.length;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const RedisBrowserScreen = () => {\n\tconst navigate = useNavigate();\n\tconst { selectedDatabase } = useDatabaseStore();\n\tconst { openOverlay } = useOverlayStore();\n\tconst { addQuery, updateQuery } = useQueriesStore();\n\tconst [selectedKey, setSelectedKey] = useQueryState(\"key\");\n\tconst [fullKey, setFullKey] = useState<string | null>(null);\n\tconst [reverseStreamKey, setReverseStreamKey] = useState<string | null>(null);\n\tconst streamDirection: StreamDirection =\n\t\treverseStreamKey === selectedKey ? \"backward\" : \"forward\";\n\tconst query = useRedisKey(selectedKey, fullKey === selectedKey, streamDirection);\n\tconst { applyAction, deleteKey, isPending } = useRedisKeyMutations();\n\tconst pages = query.data?.pages;\n\tconst detail = pages?.[0];\n\tconst [confirmingDelete, setConfirmingDelete] = useState(false);\n\tconst [conflictOperation, setConflictOperation] = useState<\n\t\tKeyActionSchemaType[\"operation\"] | null\n\t>(null);\n\tconst label = detail?.key.utf8 ?? (detail ? `binary:${detail.key.base64}` : \"\");\n\tconst command = detail ? runnerCommand(detail) : null;\n\n\tconst mergedDetail = useMemo(() => {\n\t\tif (!detail || !pages || pages.length === 1) return detail;\n\t\tconst next = structuredClone(detail);\n\t\tfor (const page of pages.slice(1)) {\n\t\t\tif (next.value.kind === \"hash\" && page.value.kind === \"hash\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"list\" && page.value.kind === \"list\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"set\" && page.value.kind === \"set\")\n\t\t\t\tnext.value.members.push(...page.value.members);\n\t\t\tif (next.value.kind === \"zset\" && page.value.kind === \"zset\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"stream\" && page.value.kind === \"stream\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t}\n\t\treturn next;\n\t}, [detail, pages]);\n\tconst loadedCount = mergedDetail ? countLoaded(mergedDetail) : null;\n\n\tconst act: RedisAct = async (operation, force = false) => {\n\t\tif (!selectedKey || !detail) return false;\n\t\ttry {\n\t\t\tconst result = await applyAction(selectedKey, {\n\t\t\t\texpectedRevision: detail.revision,\n\t\t\t\tforce,\n\t\t\t\toperation,\n\t\t\t});\n\t\t\tsetConflictOperation(null);\n\t\t\tif (result.deleted) setSelectedKey(null);\n\t\t\telse if ((result.key.base64 || \"-\") !== selectedKey)\n\t\t\t\tsetSelectedKey(result.key.base64 || \"-\");\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\t// toast.promise in the mutation hook already surfaced the failure.\n\t\t\tif ((error as Error & { status?: number }).status === 409)\n\t\t\t\tsetConflictOperation(operation);\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst openInRunner = () => {\n\t\tif (!command) return;\n\t\tconst queryId = addQuery(`redis: ${label.slice(0, 40)}`);\n\t\tupdateQuery(queryId, { query: command });\n\t\tnavigate({ to: \"/runner/$queryId\", params: { queryId } });\n\t};\n\n\tconst downloadOriginalString = async () => {\n\t\tif (!selectedKey || !detail || detail.type !== \"string\") return;\n\t\tconst chunks: Uint8Array[] = [];\n\t\tlet offset = 0;\n\t\tlet hasMore = true;\n\t\twhile (hasMore) {\n\t\t\tconst response = await getRedisStringChunk({\n\t\t\t\tdb: selectedDatabase ?? \"\",\n\t\t\t\tkey: selectedKey,\n\t\t\t\toffset,\n\t\t\t\texpectedRevision: detail.revision,\n\t\t\t});\n\t\t\tconst page = response.data.data;\n\t\t\tchunks.push(bytesFromBase64Url(page.chunk.base64));\n\t\t\thasMore = page.hasMore;\n\t\t\tif (page.hasMore && (page.nextOffset === null || page.nextOffset <= offset)) {\n\t\t\t\tthrow new Error(\"Redis download made no forward progress\");\n\t\t\t}\n\t\t\toffset = page.nextOffset ?? offset;\n\t\t}\n\t\tconst size = chunks.reduce((total, chunk) => total + chunk.length, 0);\n\t\tconst bytes = new Uint8Array(size);\n\t\tlet position = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, position);\n\t\t\tposition += chunk.length;\n\t\t}\n\t\tconst url = URL.createObjectURL(new Blob([bytes.buffer as ArrayBuffer]));\n\t\tconst anchor = document.createElement(\"a\");\n\t\tanchor.href = url;\n\t\tanchor.download = `${detail.key.utf8?.replaceAll(/[^\\w.-]+/g, \"_\") || \"redis-value\"}.bin`;\n\t\tanchor.click();\n\t\tURL.revokeObjectURL(url);\n\t};\n\n\tif (!selectedKey)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center bg-background font-mono\">\n\t\t\t\t<div className=\"max-w-sm text-center\">\n\t\t\t\t\t<DatabaseZap className=\"mx-auto mb-3 size-5 text-muted-foreground\" />\n\t\t\t\t\t<h1 className=\"text-sm font-medium text-foreground\">No key selected</h1>\n\t\t\t\t\t<p className=\"mt-1 text-xs leading-5 text-muted-foreground\">\n\t\t\t\t\t\tSelect a key from the navigator or create one to inspect its value.\n\t\t\t\t\t</p>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tclassName=\"mt-3\"\n\t\t\t\t\t\tonClick={() => openOverlay(\"redis-browser.create-key\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus /> Create key\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t);\n\tif (query.isLoading)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center\">\n\t\t\t\t<Spinner />\n\t\t\t</main>\n\t\t);\n\tif (query.error || !detail || !mergedDetail)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center bg-background p-4\">\n\t\t\t\t<div className=\"w-full max-w-md text-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"error\"\n\t\t\t\t\t\ttitle=\"Unable to load key\"\n\t\t\t\t\t\tmessage={query.error?.message ?? \"The key no longer exists.\"}\n\t\t\t\t\t\tclassName=\"rounded-sm text-start\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tclassName=\"mt-4\"\n\t\t\t\t\t\tonClick={() => setSelectedKey(null)}\n\t\t\t\t\t>\n\t\t\t\t\t\tBack to keyspace\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t);\n\n\tconst remaining =\n\t\tmergedDetail.length !== null && loadedCount !== null\n\t\t\t? Math.max(0, mergedDetail.length - loadedCount)\n\t\t\t: null;\n\n\treturn (\n\t\t<main className=\"flex min-h-0 flex-1 flex-col bg-background font-mono\">\n\t\t\t<RedisKeyHeader\n\t\t\t\tkey={detail.key.base64}\n\t\t\t\tdetail={detail}\n\t\t\t\tlabel={label}\n\t\t\t\tloadedCount={loadedCount}\n\t\t\t\tfetchedAt={query.dataUpdatedAt}\n\t\t\t\tisFetching={query.isFetching}\n\t\t\t\tpending={isPending}\n\t\t\t\tcommand={command}\n\t\t\t\tact={act}\n\t\t\t\tonRefresh={() => query.refetch()}\n\t\t\t\tonOpenRunner={openInRunner}\n\t\t\t\tonDelete={() => setConfirmingDelete(true)}\n\t\t\t/>\n\t\t\t<AlertDialog\n\t\t\t\topen={confirmingDelete}\n\t\t\t\tonOpenChange={setConfirmingDelete}\n\t\t\t>\n\t\t\t\t<AlertDialogContent>\n\t\t\t\t\t<AlertDialogHeader>\n\t\t\t\t\t\t<AlertDialogTitle>Delete key</AlertDialogTitle>\n\t\t\t\t\t\t<AlertDialogDescription>\n\t\t\t\t\t\t\tAre you sure you want to delete{\" \"}\n\t\t\t\t\t\t\t<code className=\"break-all text-foreground\">{label || \"(empty key)\"}</code>? This\n\t\t\t\t\t\t\taction cannot be undone.\n\t\t\t\t\t\t</AlertDialogDescription>\n\t\t\t\t\t</AlertDialogHeader>\n\t\t\t\t\t<AlertDialogFooter>\n\t\t\t\t\t\t<AlertDialogCancel>Cancel</AlertDialogCancel>\n\t\t\t\t\t\t<AlertDialogAction\n\t\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\t\t\tsetConfirmingDelete(false);\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tawait deleteKey(selectedKey, detail.revision);\n\t\t\t\t\t\t\t\t\tsetSelectedKey(null);\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t// toast.promise in the mutation hook already surfaced the failure.\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tDelete\n\t\t\t\t\t\t</AlertDialogAction>\n\t\t\t\t\t</AlertDialogFooter>\n\t\t\t\t</AlertDialogContent>\n\t\t\t</AlertDialog>\n\t\t\t{conflictOperation && (\n\t\t\t\t<div className=\"grid gap-2 border-b border-border p-2 sm:grid-cols-[1fr_auto] sm:items-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\ttitle=\"Revision conflict\"\n\t\t\t\t\t\tmessage=\"This key changed on the server. Reload it or overwrite with the pending change.\"\n\t\t\t\t\t\tclassName=\"rounded-sm py-2\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tsetConflictOperation(null);\n\t\t\t\t\t\t\t\tquery.refetch();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tReload\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tdisabled={isPending}\n\t\t\t\t\t\t\tonClick={() => act(conflictOperation, true)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOverwrite\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"min-h-0 flex-1 overflow-auto\">\n\t\t\t\t<section className=\"p-3\">\n\t\t\t\t\t<RedisValueEditor\n\t\t\t\t\t\tkey={detail.key.base64}\n\t\t\t\t\t\tdetail={mergedDetail}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={isPending}\n\t\t\t\t\t\tonLoadFull={() => setFullKey(selectedKey)}\n\t\t\t\t\t\tonDownload={() => {\n\t\t\t\t\t\t\ttoast.promise(downloadOriginalString(), {\n\t\t\t\t\t\t\t\tloading: \"Downloading original Redis bytes…\",\n\t\t\t\t\t\t\t\tsuccess: \"Redis value downloaded\",\n\t\t\t\t\t\t\t\terror: (error: Error) => error.message || \"Download failed\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tstreamDirection={streamDirection}\n\t\t\t\t\t\tonStreamDirectionChange={(direction) =>\n\t\t\t\t\t\t\tsetReverseStreamKey(direction === \"backward\" ? selectedKey : null)\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t\t{query.hasNextPage && (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tclassName=\"mt-3 w-full\"\n\t\t\t\t\t\t\tonClick={() => query.fetchNextPage()}\n\t\t\t\t\t\t\tdisabled={query.isFetchingNextPage}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{query.isFetchingNextPage\n\t\t\t\t\t\t\t\t? \"Loading…\"\n\t\t\t\t\t\t\t\t: detail.type === \"stream\" && streamDirection === \"backward\"\n\t\t\t\t\t\t\t\t\t? \"Load 100 older entries\"\n\t\t\t\t\t\t\t\t\t: `Load next 100${remaining !== null ? ` (${remaining.toLocaleString()} remaining)` : \"\"}`}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</main>\n\t);\n};\n","import { createFileRoute } from \"@tanstack/react-router\";\nimport { RedisBrowserScreen } from \"@/features/redis-browser\";\n\nexport const Route = createFileRoute(\"/_pathlessLayout/browser\")({\n\tcomponent: RedisBrowserScreen,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"browser-CKmBpcoz.js","names":["RedisBrowserScreen","SplitComponent","component"],"sources":["../../src/features/redis-browser/components/redis-copy-button.tsx","../../src/features/redis-browser/components/redis-key-header.tsx","../../src/features/redis-browser/components/redis-value-editors.tsx","../../src/features/redis-browser/screens/redis-browser-screen.tsx","../../src/routes/_pathlessLayout/browser.tsx?tsr-split=component"],"sourcesContent":["import { Button } from \"@db-studio/ui/button\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@db-studio/ui/tooltip\";\nimport { Check, Copy } from \"lucide-react\";\nimport { useState } from \"react\";\n\n/**\n * Icon button that copies `text` (or its lazy producer) to the clipboard and\n * flashes a check mark. Used for key names, values, and JSON exports.\n */\nexport const RedisCopyButton = ({\n\ttext,\n\tlabel,\n\tclassName,\n}: {\n\ttext: string | (() => string);\n\tlabel: string;\n\tclassName?: string;\n}) => {\n\tconst [copied, setCopied] = useState(false);\n\treturn (\n\t\t<Tooltip>\n\t\t\t<TooltipTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\tawait navigator.clipboard.writeText(typeof text === \"function\" ? text() : text);\n\t\t\t\t\t\tsetCopied(true);\n\t\t\t\t\t\twindow.setTimeout(() => setCopied(false), 1_200);\n\t\t\t\t\t}}\n\t\t\t\t\taria-label={label}\n\t\t\t\t>\n\t\t\t\t\t{copied ? <Check /> : <Copy />}\n\t\t\t\t</Button>\n\t\t\t</TooltipTrigger>\n\t\t\t<TooltipContent>{copied ? \"Copied\" : label}</TooltipContent>\n\t\t</Tooltip>\n\t);\n};\n","import type {\n\tEncodedRedisValueSchemaType,\n\tKeyDetailsResultSchemaType,\n} from \"@db-studio/shared/types\";\nimport { Badge } from \"@db-studio/ui/badge\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Field, FieldDescription, FieldGroup, FieldLabel } from \"@db-studio/ui/field\";\nimport { Input } from \"@db-studio/ui/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@db-studio/ui/popover\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@db-studio/ui/tooltip\";\nimport { cn } from \"@db-studio/ui/utils\";\nimport { ArrowRight, Pencil, RefreshCw, Terminal, Trash2 } from \"lucide-react\";\nimport { type ReactNode, useEffect, useReducer, useState } from \"react\";\nimport { RedisCopyButton } from \"./redis-copy-button\";\nimport { RedisValueInput } from \"./redis-value\";\nimport type { RedisAct } from \"./redis-value-editors\";\n\nconst TTL_PRESETS = [\n\t{ label: \"60s\", ttlMs: 60_000 },\n\t{ label: \"10m\", ttlMs: 600_000 },\n\t{ label: \"1h\", ttlMs: 3_600_000 },\n\t{ label: \"1d\", ttlMs: 86_400_000 },\n\t{ label: \"7d\", ttlMs: 604_800_000 },\n] as const;\n\nconst formatBytes = (bytes: number | null): string => {\n\tif (bytes === null) return \"—\";\n\tif (bytes < 1_024) return `${bytes} B`;\n\tif (bytes < 1_048_576) return `${(bytes / 1_024).toFixed(1)} KiB`;\n\treturn `${(bytes / 1_048_576).toFixed(1)} MiB`;\n};\n\nconst formatDuration = (ms: number): string => {\n\tconst seconds = Math.max(0, Math.ceil(ms / 1_000));\n\tif (seconds < 60) return `${seconds}s`;\n\tconst minutes = Math.floor(seconds / 60);\n\tif (minutes < 60) return `${minutes}m ${seconds % 60}s`;\n\tconst hours = Math.floor(minutes / 60);\n\tif (hours < 24) return `${hours}h ${minutes % 60}m`;\n\treturn `${Math.floor(hours / 24)}d ${hours % 24}h`;\n};\n\n/** Re-renders once a second while `active`, so TTLs count down live. */\nconst useSecondTick = (active: boolean) => {\n\tconst [, tick] = useReducer((count: number) => count + 1, 0);\n\tuseEffect(() => {\n\t\tif (!active) return;\n\t\tconst id = window.setInterval(tick, 1_000);\n\t\treturn () => window.clearInterval(id);\n\t}, [active]);\n};\n\n/**\n * Key toolbar: name + copy, type badge, live stats, refresh, open-in-runner,\n * rename/TTL popover, and delete. Mount with `key={detail.key.base64}` so the\n * rename/TTL drafts reset when the selected key changes.\n */\nexport const RedisKeyHeader = ({\n\tdetail,\n\tlabel,\n\tloadedCount,\n\tfetchedAt,\n\tisFetching,\n\tpending,\n\tcommand,\n\tact,\n\tonRefresh,\n\tonOpenRunner,\n\tonDelete,\n}: {\n\tdetail: KeyDetailsResultSchemaType;\n\tlabel: string;\n\tloadedCount: number | null;\n\tfetchedAt: number;\n\tisFetching: boolean;\n\tpending: boolean;\n\tcommand: string | null;\n\tact: RedisAct;\n\tonRefresh: () => void;\n\tonOpenRunner: () => void;\n\tonDelete: () => void;\n}) => {\n\tconst [rename, setRename] = useState<EncodedRedisValueSchemaType | null>(detail.key);\n\tconst [ttl, setTtl] = useState(\"\");\n\tuseSecondTick(detail.ttlMs > 0);\n\n\tconst remainingMs =\n\t\tdetail.ttlMs > 0 ? detail.ttlMs - (Date.now() - fetchedAt) : detail.ttlMs;\n\tconst persistent = detail.ttlMs === -1;\n\tconst expired = !persistent && remainingMs <= 0;\n\tconst stats: { name: string; value: ReactNode; hint: string; alert?: boolean }[] = [\n\t\t{\n\t\t\tname: \"TTL\",\n\t\t\tvalue: persistent ? \"∞\" : expired ? \"expired\" : formatDuration(remainingMs),\n\t\t\thint: persistent\n\t\t\t\t? \"No expiry — the key persists until deleted.\"\n\t\t\t\t: expired\n\t\t\t\t\t? \"The TTL elapsed; Redis has evicted or is about to evict this key.\"\n\t\t\t\t\t: `Expires ${new Date(fetchedAt + detail.ttlMs).toLocaleString()}`,\n\t\t\talert: expired,\n\t\t},\n\t\t{\n\t\t\tname: \"MEM\",\n\t\t\tvalue: formatBytes(detail.memoryBytes),\n\t\t\thint: \"Approximate memory usage reported by MEMORY USAGE.\",\n\t\t},\n\t\t{\n\t\t\tname: \"LEN\",\n\t\t\tvalue: detail.length?.toLocaleString() ?? \"—\",\n\t\t\thint:\n\t\t\t\tloadedCount !== null && detail.length !== null\n\t\t\t\t\t? `${loadedCount.toLocaleString()} of ${detail.length.toLocaleString()} entries loaded in this view.`\n\t\t\t\t\t: \"Length reported by Redis (entries, or bytes for strings).\",\n\t\t},\n\t\t{\n\t\t\tname: \"REV\",\n\t\t\tvalue: detail.revision.slice(0, 8),\n\t\t\thint: \"Optimistic-lock revision. Writes are rejected when the key changed since this fetch.\",\n\t\t},\n\t\t{\n\t\t\tname: \"AT\",\n\t\t\tvalue: new Date(fetchedAt).toLocaleTimeString(),\n\t\t\thint: \"When this snapshot was fetched from Redis.\",\n\t\t},\n\t];\n\n\treturn (\n\t\t<header className=\"border-b border-border\">\n\t\t\t<div className=\"flex min-h-10 items-stretch justify-between\">\n\t\t\t\t<div className=\"flex min-w-0 flex-1 items-stretch overflow-x-auto\">\n\t\t\t\t\t<div className=\"flex min-w-0 max-w-[min(36rem,45vw)] shrink items-center gap-1 px-3 py-1.5\">\n\t\t\t\t\t\t<code\n\t\t\t\t\t\t\tclassName=\"min-w-0 truncate text-sm text-foreground\"\n\t\t\t\t\t\t\ttitle={label}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{label || \"(empty key)\"}\n\t\t\t\t\t\t</code>\n\t\t\t\t\t\t<RedisCopyButton\n\t\t\t\t\t\t\ttext={detail.key.utf8 ?? detail.key.base64}\n\t\t\t\t\t\t\tlabel=\"Copy key name\"\n\t\t\t\t\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tclassName=\"h-4 shrink-0 rounded-sm px-1.5 text-[8px] font-normal uppercase text-muted-foreground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{detail.type}\n\t\t\t\t\t\t</Badge>\n\t\t\t\t\t</div>\n\t\t\t\t\t{stats.map(({ name, value, hint, alert }, index) => (\n\t\t\t\t\t\t<Tooltip key={name}>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"flex shrink-0 cursor-default items-center gap-1.5 border-s border-border px-2 text-[10px]\",\n\t\t\t\t\t\t\t\t\t\tindex === stats.length - 1 && \"border-e\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">{name}</span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"tabular-nums\",\n\t\t\t\t\t\t\t\t\t\t\talert ? \"text-destructive\" : \"text-foreground\",\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{value}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent side=\"bottom\">{hint}</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex shrink-0 items-stretch\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\tonClick={onRefresh}\n\t\t\t\t\t\tdisabled={isFetching}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RefreshCw className={cn(isFetching && \"animate-spin\")} /> Refresh\n\t\t\t\t\t</Button>\n\t\t\t\t\t{command && (\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\t\t\t\tonClick={onOpenRunner}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Terminal /> Runner\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent side=\"bottom\">\n\t\t\t\t\t\t\t\tOpen in the query runner as <code className=\"font-mono\">{command}</code>\n\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<Popover>\n\t\t\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Pencil /> Edit\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</PopoverTrigger>\n\t\t\t\t\t\t<PopoverContent\n\t\t\t\t\t\t\talign=\"end\"\n\t\t\t\t\t\t\tclassName=\"w-72 rounded-sm p-3 font-mono\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<FieldGroup className=\"gap-4\">\n\t\t\t\t\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t\t\t\t\t<FieldLabel htmlFor=\"redis-key-rename\">Rename key</FieldLabel>\n\t\t\t\t\t\t\t\t\t<form\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex\"\n\t\t\t\t\t\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tif (rename === null || rename.base64 === detail.key.base64 || pending)\n\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\tact({ action: \"rename\", newKey: rename });\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\t\t\t\t\t\tid=\"redis-key-rename\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={rename}\n\t\t\t\t\t\t\t\t\t\t\tonChange={setRename}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-e-none font-mono\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-auto self-stretch rounded-s-none border-0 bg-clip-border\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\t\t\trename === null || rename.base64 === detail.key.base64 || pending\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Rename key\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<ArrowRight />\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t</Field>\n\t\t\t\t\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t\t\t\t\t<FieldLabel htmlFor=\"redis-key-ttl-operation\">TTL in seconds</FieldLabel>\n\t\t\t\t\t\t\t\t\t<form\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex\"\n\t\t\t\t\t\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\tif (pending) return;\n\t\t\t\t\t\t\t\t\t\t\tact({ action: \"setTtl\", ttlMs: ttl ? Number(ttl) * 1_000 : null });\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\t\tid=\"redis-key-ttl-operation\"\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tvalue={ttl}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(event) => setTtl(event.target.value)}\n\t\t\t\t\t\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\t\t\t\t\t\tdetail.ttlMs > 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t? String(Math.ceil(detail.ttlMs / 1_000))\n\t\t\t\t\t\t\t\t\t\t\t\t\t: \"Persistent\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"rounded-e-none font-mono\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-auto self-stretch rounded-s-none border-0 bg-clip-border\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tApply\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</form>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t\t\t\t\t\t{TTL_PRESETS.map((preset) => (\n\t\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\t\tkey={preset.label}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => act({ action: \"setTtl\", ttlMs: preset.ttlMs })}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{preset.label}\n\t\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={pending || persistent}\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => act({ action: \"setTtl\", ttlMs: null })}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tPersist\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<FieldDescription>Leave empty to persist the key.</FieldDescription>\n\t\t\t\t\t\t\t\t</Field>\n\t\t\t\t\t\t\t</FieldGroup>\n\t\t\t\t\t\t</PopoverContent>\n\t\t\t\t\t</Popover>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclassName=\"h-auto rounded-none border-y-0 border-s border-e-0 border-border px-2\"\n\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\tonClick={onDelete}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2 /> Delete\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</header>\n\t);\n};\n","import type {\n\tEncodedRedisValueSchemaType,\n\tKeyActionSchemaType,\n\tKeyDetailsResultSchemaType,\n} from \"@db-studio/shared/types\";\nimport { Alert } from \"@db-studio/ui/alert\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Field, FieldLabel } from \"@db-studio/ui/field\";\nimport { Input } from \"@db-studio/ui/input\";\nimport { ToggleGroup, ToggleGroupItem } from \"@db-studio/ui/toggle-group\";\nimport { Plus, Save, Search, Trash2 } from \"lucide-react\";\nimport { type FormEvent, type ReactNode, useState } from \"react\";\nimport { RedisCopyButton } from \"./redis-copy-button\";\nimport { encodeTextValue, RedisValue, RedisValueInput } from \"./redis-value\";\n\n/**\n * Runs one key operation against the server. Resolves `true` on success so\n * add-forms know when to clear; conflict handling lives in the screen.\n */\nexport type RedisAct = (\n\toperation: KeyActionSchemaType[\"operation\"],\n\tforce?: boolean,\n) => Promise<boolean>;\n\nexport type StreamDirection = \"forward\" | \"backward\";\n\ntype RedisValueUnion = KeyDetailsResultSchemaType[\"value\"];\ntype HashValue = Extract<RedisValueUnion, { kind: \"hash\" }>;\ntype ListValue = Extract<RedisValueUnion, { kind: \"list\" }>;\ntype SetValue = Extract<RedisValueUnion, { kind: \"set\" }>;\ntype ZsetValue = Extract<RedisValueUnion, { kind: \"zset\" }>;\ntype StreamValue = Extract<RedisValueUnion, { kind: \"stream\" }>;\n\nconst emptyValue = encodeTextValue(\"\");\n\n/** `null` = the input's visible draft is unparseable and MUST NOT be submitted. */\ntype DraftValue = EncodedRedisValueSchemaType | null;\n\nconst textOf = (value: EncodedRedisValueSchemaType): string =>\n\tvalue.utf8 ?? `base64:${value.base64}`;\n\nconst matches = (needle: string, ...haystack: (string | number)[]): boolean =>\n\thaystack.some((part) => String(part).toLowerCase().includes(needle));\n\n/** Serializes the loaded (client-side) entries so devs can yank them into code. */\nconst collectionJson = (value: RedisValueUnion): string => {\n\tswitch (value.kind) {\n\t\tcase \"string\":\n\t\t\treturn JSON.stringify(textOf(value.value), null, 2);\n\t\tcase \"hash\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tvalue.entries.map((entry) => [textOf(entry.field), textOf(entry.value)]),\n\t\t\t\t),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => textOf(entry.value)),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"set\":\n\t\t\treturn JSON.stringify(value.members.map(textOf), null, 2);\n\t\tcase \"zset\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => ({ member: textOf(entry.member), score: entry.score })),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tcase \"stream\":\n\t\t\treturn JSON.stringify(\n\t\t\t\tvalue.entries.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tfields: Object.fromEntries(\n\t\t\t\t\t\tentry.fields.map((field) => [textOf(field.field), textOf(field.value)]),\n\t\t\t\t\t),\n\t\t\t\t})),\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t);\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n};\n\n/**\n * Local draft that re-syncs whenever the server value changes (identified by\n * `revision`), without wiping unrelated drafts on every refetch.\n */\nconst useSyncedDraft = <T,>(server: T, revision: string): [T, (next: T) => void] => {\n\tconst [draft, setDraft] = useState(server);\n\tconst [synced, setSynced] = useState(revision);\n\tif (synced !== revision) {\n\t\tsetSynced(revision);\n\t\tsetDraft(server);\n\t}\n\treturn [draft, setDraft];\n};\n\nconst EmptyRow = ({ filtered }: { filtered: boolean }) => (\n\t<div className=\"flex h-10 items-center justify-center px-2 text-xs text-muted-foreground\">\n\t\t{filtered ? \"No loaded entries match the filter.\" : \"No entries loaded.\"}\n\t</div>\n);\n\n/**\n * Frame around every collection editor: a client-side filter over the loaded\n * entries, a loaded/total counter, copy-as-JSON, and an optional `extra` slot\n * (e.g. the stream direction toggle).\n */\nconst CollectionShell = ({\n\tfilter,\n\tonFilterChange,\n\tshownCount,\n\tloadedCount,\n\ttotalCount,\n\tcopyJson,\n\textra,\n\theader,\n\tchildren,\n\tfooter,\n}: {\n\tfilter: string;\n\tonFilterChange: (next: string) => void;\n\tshownCount: number;\n\tloadedCount: number;\n\ttotalCount: number | null;\n\tcopyJson: () => string;\n\textra?: ReactNode;\n\theader: ReactNode;\n\tchildren: ReactNode;\n\tfooter: ReactNode;\n}) => (\n\t<div className=\"overflow-hidden border border-border\">\n\t\t<div className=\"flex h-8 items-center gap-1 border-b border-border bg-muted/10 px-1\">\n\t\t\t<Search className=\"ms-1 size-3 shrink-0 text-muted-foreground\" />\n\t\t\t<Input\n\t\t\t\tvariant=\"outline\"\n\t\t\t\tvalue={filter}\n\t\t\t\tonChange={(event) => onFilterChange(event.target.value)}\n\t\t\t\tplaceholder=\"Filter loaded entries\"\n\t\t\t\taria-label=\"Filter loaded entries\"\n\t\t\t\tclassName=\"h-6 flex-1 rounded-none border-none px-1 font-mono focus-visible:ring-0\"\n\t\t\t/>\n\t\t\t{extra}\n\t\t\t<span className=\"shrink-0 px-1 text-[10px] tabular-nums text-muted-foreground\">\n\t\t\t\t{filter\n\t\t\t\t\t? `${shownCount} / ${loadedCount}`\n\t\t\t\t\t: totalCount !== null && totalCount > loadedCount\n\t\t\t\t\t\t? `${loadedCount.toLocaleString()} of ${totalCount.toLocaleString()}`\n\t\t\t\t\t\t: loadedCount.toLocaleString()}\n\t\t\t</span>\n\t\t\t<RedisCopyButton\n\t\t\t\ttext={copyJson}\n\t\t\t\tlabel=\"Copy loaded entries as JSON\"\n\t\t\t/>\n\t\t</div>\n\t\t{header}\n\t\t{children}\n\t\t{footer}\n\t</div>\n);\n\nconst AddPair = ({\n\tlabels,\n\tonSave,\n\tpending,\n\tscore = false,\n}: {\n\tlabels: [string, string];\n\tonSave: (\n\t\tfirst: EncodedRedisValueSchemaType,\n\t\tsecond: EncodedRedisValueSchemaType | number,\n\t) => Promise<boolean>;\n\tpending: boolean;\n\tscore?: boolean;\n}) => {\n\tconst [first, setFirst] = useState<DraftValue>(emptyValue);\n\tconst [second, setSecond] = useState<DraftValue>(emptyValue);\n\tconst [numeric, setNumeric] = useState(\"0\");\n\tconst invalid = first === null || (!score && second === null);\n\tconst submit = async (event: FormEvent) => {\n\t\tevent.preventDefault();\n\t\tif (first === null || second === null) return;\n\t\tconst saved = await onSave(first, score ? Number(numeric) : second);\n\t\tif (!saved) return;\n\t\tsetFirst(emptyValue);\n\t\tsetSecond(emptyValue);\n\t\tsetNumeric(\"0\");\n\t};\n\treturn (\n\t\t<form\n\t\t\tonSubmit={submit}\n\t\t\tclassName=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={first}\n\t\t\t\tonChange={setFirst}\n\t\t\t\tplaceholder={labels[0]}\n\t\t\t/>\n\t\t\t{score ? (\n\t\t\t\t<Input\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tstep=\"any\"\n\t\t\t\t\tvalue={numeric}\n\t\t\t\t\tonChange={(event) => setNumeric(event.target.value)}\n\t\t\t\t\tplaceholder={labels[1]}\n\t\t\t\t\tclassName=\"font-mono\"\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<RedisValueInput\n\t\t\t\t\tvalue={second}\n\t\t\t\t\tonChange={setSecond}\n\t\t\t\t\tplaceholder={labels[1]}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<Button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tdisabled={pending || invalid}\n\t\t\t>\n\t\t\t\t<Plus /> Add\n\t\t\t</Button>\n\t\t</form>\n\t);\n};\n\nconst StringEditor = ({\n\tvalue,\n\ttruncated,\n\tact,\n\tpending,\n\tonLoadFull,\n\tonDownload,\n}: {\n\tvalue: EncodedRedisValueSchemaType;\n\ttruncated: boolean;\n\tact: RedisAct;\n\tpending: boolean;\n\tonLoadFull: () => void;\n\tonDownload: () => void;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, value.base64);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"space-y-3\">\n\t\t\t{truncated && (\n\t\t\t\t<div className=\"grid gap-2 border-b border-border pb-3 sm:grid-cols-[1fr_auto] sm:items-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\ttitle=\"Preview truncated\"\n\t\t\t\t\t\tmessage=\"Load the full value before editing (up to the 8 MiB response cap).\"\n\t\t\t\t\t\tclassName=\"rounded-sm\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tonClick={onLoadFull}\n\t\t\t\t\t>\n\t\t\t\t\t\tLoad full\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<RedisValue\n\t\t\t\tvalue={value}\n\t\t\t\tonDownload={onDownload}\n\t\t\t/>\n\t\t\t<form\n\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif (draft !== null && dirty) act({ action: \"setString\", value: draft });\n\t\t\t\t}}\n\t\t\t\tclassName=\"border border-border p-3\"\n\t\t\t>\n\t\t\t\t<Field className=\"gap-1.5\">\n\t\t\t\t\t<FieldLabel htmlFor=\"redis-string-value\">Replace value</FieldLabel>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tid=\"redis-string-value\"\n\t\t\t\t\t\tvalue={draft}\n\t\t\t\t\t\tonChange={setDraft}\n\t\t\t\t\t/>\n\t\t\t\t</Field>\n\t\t\t\t<Button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tclassName=\"mt-3\"\n\t\t\t\t\tdisabled={truncated || pending || !dirty}\n\t\t\t\t>\n\t\t\t\t\t<Save /> Save value\n\t\t\t\t</Button>\n\t\t\t</form>\n\t\t</div>\n\t);\n};\n\nconst HashRow = ({\n\tfield,\n\tvalue,\n\tact,\n\tpending,\n}: {\n\tfield: EncodedRedisValueSchemaType;\n\tvalue: EncodedRedisValueSchemaType;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, value.base64);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[minmax(10rem,0.7fr)_1fr_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<RedisValue\n\t\t\t\tvalue={field}\n\t\t\t\tcompact\n\t\t\t/>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={setDraft}\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty}\n\t\t\t\t\tonClick={() => draft !== null && act({ action: \"upsertHash\", field, value: draft })}\n\t\t\t\t\taria-label=\"Save hash value\"\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"deleteHash\", field })}\n\t\t\t\t\taria-label=\"Delete hash field\"\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst HashEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: HashValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) =>\n\t\t\t\tmatches(needle, textOf(entry.field), textOf(entry.value)),\n\t\t\t)\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[minmax(10rem,0.7fr)_1fr_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Field</span>\n\t\t\t\t\t<span>Value</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tlabels={[\"field\", \"value\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(field, next) =>\n\t\t\t\t\t\tact({ action: \"upsertHash\", field, value: next as EncodedRedisValueSchemaType })\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<HashRow\n\t\t\t\t\t\tkey={entry.field.base64}\n\t\t\t\t\t\tfield={entry.field}\n\t\t\t\t\t\tvalue={entry.value}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst ListRow = ({\n\tindex,\n\tvalue,\n\trevision,\n\tact,\n\tpending,\n}: {\n\tindex: number;\n\tvalue: EncodedRedisValueSchemaType;\n\trevision: string;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft<DraftValue>(value, `${revision}:${value.base64}`);\n\tconst dirty = draft !== null && draft.base64 !== value.base64;\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[3rem_1fr_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<code className=\"text-xs text-muted-foreground\">{index}</code>\n\t\t\t<RedisValueInput\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={setDraft}\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty}\n\t\t\t\t\tonClick={() => draft !== null && act({ action: \"setList\", index, value: draft })}\n\t\t\t\t\taria-label={`Save list item ${index}`}\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"deleteList\", index })}\n\t\t\t\t\taria-label={`Delete list item ${index}`}\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst ListEditor = ({\n\tvalue,\n\trevision,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: ListValue;\n\trevision: string;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst [item, setItem] = useState<DraftValue>(emptyValue);\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) => matches(needle, entry.index, textOf(entry.value)))\n\t\t: value.entries;\n\tconst push = async (side: \"left\" | \"right\") => {\n\t\tif (item === null) return;\n\t\tconst saved = await act({ action: \"pushList\", side, value: item });\n\t\tif (saved) setItem(emptyValue);\n\t};\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[3rem_1fr_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Index</span>\n\t\t\t\t\t<span>Value</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<form\n\t\t\t\t\tonSubmit={(event) => {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tpush(\"right\");\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"grid grid-cols-[1fr_auto_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t\t\t>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tvalue={item}\n\t\t\t\t\t\tonChange={setItem}\n\t\t\t\t\t\tplaceholder=\"new item\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tdisabled={pending || item === null}\n\t\t\t\t\t\tonClick={() => push(\"left\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tPush left\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={pending || item === null}\n\t\t\t\t\t>\n\t\t\t\t\t\tPush right\n\t\t\t\t\t</Button>\n\t\t\t\t</form>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<ListRow\n\t\t\t\t\t\tkey={entry.index}\n\t\t\t\t\t\tindex={entry.index}\n\t\t\t\t\t\tvalue={entry.value}\n\t\t\t\t\t\trevision={revision}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst SetEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: SetValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst [member, setMember] = useState<DraftValue>(emptyValue);\n\tconst needle = filter.trim().toLowerCase();\n\tconst members = needle\n\t\t? value.members.filter((entry) => matches(needle, textOf(entry)))\n\t\t: value.members;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={members.length}\n\t\t\tloadedCount={value.members.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[1fr_2rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Member</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<form\n\t\t\t\t\tonSubmit={async (event) => {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tif (member === null) return;\n\t\t\t\t\t\tconst saved = await act({ action: \"addSet\", member });\n\t\t\t\t\t\tif (saved) setMember(emptyValue);\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"grid grid-cols-[1fr_auto] items-center gap-2 border-t border-border bg-muted/10 p-2\"\n\t\t\t\t>\n\t\t\t\t\t<RedisValueInput\n\t\t\t\t\t\tvalue={member}\n\t\t\t\t\t\tonChange={setMember}\n\t\t\t\t\t\tplaceholder=\"new member\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={pending || member === null}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus /> Add member\n\t\t\t\t\t</Button>\n\t\t\t\t</form>\n\t\t\t}\n\t\t>\n\t\t\t{members.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tmembers.map((entry) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={entry.base64}\n\t\t\t\t\t\tclassName=\"flex min-h-8 items-center gap-2 border-b border-border px-2 py-1\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\tvalue={entry}\n\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\tonClick={() => act({ action: \"removeSet\", member: entry })}\n\t\t\t\t\t\t\taria-label=\"Remove set member\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst ZsetRow = ({\n\tmember,\n\tscore,\n\tact,\n\tpending,\n}: {\n\tmember: EncodedRedisValueSchemaType;\n\tscore: number | \"inf\" | \"-inf\";\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [draft, setDraft] = useSyncedDraft(String(score), String(score));\n\tconst parsedDraft = Number(draft);\n\tconst dirty = draft !== String(score);\n\tconst valid = Number.isFinite(parsedDraft);\n\treturn (\n\t\t<div className=\"grid min-h-8 grid-cols-[1fr_8rem_5rem] items-center gap-2 border-b border-border px-2 py-1\">\n\t\t\t<RedisValue\n\t\t\t\tvalue={member}\n\t\t\t\tcompact\n\t\t\t/>\n\t\t\t<Input\n\t\t\t\tinputMode=\"decimal\"\n\t\t\t\tvalue={draft}\n\t\t\t\tonChange={(event) => setDraft(event.target.value)}\n\t\t\t\taria-label=\"Sorted set score\"\n\t\t\t\tclassName=\"font-mono\"\n\t\t\t/>\n\t\t\t<div className=\"flex\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName={dirty ? \"text-primary\" : undefined}\n\t\t\t\t\tdisabled={pending || !dirty || !valid}\n\t\t\t\t\tonClick={() => act({ action: \"upsertZset\", member, score: parsedDraft })}\n\t\t\t\t\taria-label=\"Save sorted set score\"\n\t\t\t\t>\n\t\t\t\t\t<Save />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tclassName=\"text-muted-foreground hover:text-destructive\"\n\t\t\t\t\tdisabled={pending}\n\t\t\t\t\tonClick={() => act({ action: \"removeZset\", member })}\n\t\t\t\t\taria-label=\"Remove sorted set member\"\n\t\t\t\t>\n\t\t\t\t\t<Trash2 />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nconst ZsetEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n}: {\n\tvalue: ZsetValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) => matches(needle, textOf(entry.member), entry.score))\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[1fr_8rem_5rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Member</span>\n\t\t\t\t\t<span>Score</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tscore\n\t\t\t\t\tlabels={[\"member\", \"score\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(member, score) =>\n\t\t\t\t\t\tact({ action: \"upsertZset\", member, score: score as number })\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<ZsetRow\n\t\t\t\t\t\tkey={entry.member.base64}\n\t\t\t\t\t\tmember={entry.member}\n\t\t\t\t\t\tscore={entry.score}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={pending}\n\t\t\t\t\t/>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\nconst StreamEditor = ({\n\tvalue,\n\ttotal,\n\tact,\n\tpending,\n\tdirection,\n\tonDirectionChange,\n}: {\n\tvalue: StreamValue;\n\ttotal: number | null;\n\tact: RedisAct;\n\tpending: boolean;\n\tdirection: StreamDirection;\n\tonDirectionChange: (direction: StreamDirection) => void;\n}) => {\n\tconst [filter, setFilter] = useState(\"\");\n\tconst needle = filter.trim().toLowerCase();\n\tconst entries = needle\n\t\t? value.entries.filter((entry) =>\n\t\t\t\tmatches(\n\t\t\t\t\tneedle,\n\t\t\t\t\tentry.id,\n\t\t\t\t\t...entry.fields.flatMap((field) => [textOf(field.field), textOf(field.value)]),\n\t\t\t\t),\n\t\t\t)\n\t\t: value.entries;\n\treturn (\n\t\t<CollectionShell\n\t\t\tfilter={filter}\n\t\t\tonFilterChange={setFilter}\n\t\t\tshownCount={entries.length}\n\t\t\tloadedCount={value.entries.length}\n\t\t\ttotalCount={total}\n\t\t\tcopyJson={() => collectionJson(value)}\n\t\t\textra={\n\t\t\t\t<ToggleGroup\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tvalue={direction}\n\t\t\t\t\tonValueChange={(next) => next && onDirectionChange(next as StreamDirection)}\n\t\t\t\t\taria-label=\"Stream order\"\n\t\t\t\t\tclassName=\"shrink-0 rounded-none\"\n\t\t\t\t>\n\t\t\t\t\t<ToggleGroupItem\n\t\t\t\t\t\tvalue=\"forward\"\n\t\t\t\t\t\tclassName=\"h-6 rounded-none px-2 text-[10px]\"\n\t\t\t\t\t>\n\t\t\t\t\t\tOldest first\n\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t\t<ToggleGroupItem\n\t\t\t\t\t\tvalue=\"backward\"\n\t\t\t\t\t\tclassName=\"h-6 rounded-none px-2 text-[10px]\"\n\t\t\t\t\t>\n\t\t\t\t\t\tNewest first\n\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t</ToggleGroup>\n\t\t\t}\n\t\t\theader={\n\t\t\t\t<div className=\"grid h-8 grid-cols-[10rem_1fr_2rem] items-center border-b border-border bg-muted/20 px-2 text-[10px] uppercase tracking-wider text-muted-foreground\">\n\t\t\t\t\t<span>Entry ID</span>\n\t\t\t\t\t<span>Fields</span>\n\t\t\t\t\t<span />\n\t\t\t\t</div>\n\t\t\t}\n\t\t\tfooter={\n\t\t\t\t<AddPair\n\t\t\t\t\tlabels={[\"field\", \"value\"]}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonSave={(field, next) =>\n\t\t\t\t\t\tact({\n\t\t\t\t\t\t\taction: \"appendStream\",\n\t\t\t\t\t\t\tid: \"*\",\n\t\t\t\t\t\t\tfields: [{ field, value: next as EncodedRedisValueSchemaType }],\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t{entries.length === 0 ? (\n\t\t\t\t<EmptyRow filtered={needle.length > 0} />\n\t\t\t) : (\n\t\t\t\tentries.map((entry) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={entry.id}\n\t\t\t\t\t\tclassName=\"grid grid-cols-[10rem_1fr_2rem] border-b border-border\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<code className=\"border-e border-border px-2 py-1.5 text-xs text-primary\">\n\t\t\t\t\t\t\t{entry.id}\n\t\t\t\t\t\t</code>\n\t\t\t\t\t\t<div className=\"grid gap-1 px-2 py-1.5\">\n\t\t\t\t\t\t\t{entry.fields.map((field) => (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tkey={field.field.base64}\n\t\t\t\t\t\t\t\t\tclassName=\"grid grid-cols-[minmax(8rem,0.4fr)_1fr] gap-3\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\t\t\tvalue={field.field}\n\t\t\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<RedisValue\n\t\t\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\tclassName=\"rounded-none text-muted-foreground hover:text-destructive\"\n\t\t\t\t\t\t\tdisabled={pending}\n\t\t\t\t\t\t\tonClick={() => act({ action: \"deleteStream\", id: entry.id })}\n\t\t\t\t\t\t\taria-label={`Delete stream entry ${entry.id}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t</CollectionShell>\n\t);\n};\n\n/** Dispatches the loaded key to the editor matching its Redis type. */\nexport const RedisValueEditor = ({\n\tdetail,\n\tact,\n\tpending,\n\tonLoadFull,\n\tonDownload,\n\tstreamDirection,\n\tonStreamDirectionChange,\n}: {\n\tdetail: KeyDetailsResultSchemaType;\n\tact: RedisAct;\n\tpending: boolean;\n\tonLoadFull: () => void;\n\tonDownload: () => void;\n\tstreamDirection: StreamDirection;\n\tonStreamDirectionChange: (direction: StreamDirection) => void;\n}) => {\n\tconst value = detail.value;\n\tswitch (value.kind) {\n\t\tcase \"string\":\n\t\t\treturn (\n\t\t\t\t<StringEditor\n\t\t\t\t\tvalue={value.value}\n\t\t\t\t\ttruncated={value.truncated}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tonLoadFull={onLoadFull}\n\t\t\t\t\tonDownload={onDownload}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"hash\":\n\t\t\treturn (\n\t\t\t\t<HashEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn (\n\t\t\t\t<ListEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\trevision={detail.revision}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"set\":\n\t\t\treturn (\n\t\t\t\t<SetEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"zset\":\n\t\t\treturn (\n\t\t\t\t<ZsetEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"stream\":\n\t\t\treturn (\n\t\t\t\t<StreamEditor\n\t\t\t\t\tvalue={value}\n\t\t\t\t\ttotal={detail.length}\n\t\t\t\t\tact={act}\n\t\t\t\t\tpending={pending}\n\t\t\t\t\tdirection={streamDirection}\n\t\t\t\t\tonDirectionChange={onStreamDirectionChange}\n\t\t\t\t/>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn (\n\t\t\t\t<Alert\n\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\ttitle=\"Metadata only\"\n\t\t\t\t\tmessage=\"This Redis module type cannot be edited in this release.\"\n\t\t\t\t\tclassName=\"rounded-sm\"\n\t\t\t\t/>\n\t\t\t);\n\t}\n};\n","import type { KeyActionSchemaType, KeyDetailsResultSchemaType } from \"@db-studio/shared/types\";\nimport { Alert } from \"@db-studio/ui/alert\";\nimport {\n\tAlertDialog,\n\tAlertDialogAction,\n\tAlertDialogCancel,\n\tAlertDialogContent,\n\tAlertDialogDescription,\n\tAlertDialogFooter,\n\tAlertDialogHeader,\n\tAlertDialogTitle,\n} from \"@db-studio/ui/alert-dialog\";\nimport { Button } from \"@db-studio/ui/button\";\nimport { Spinner } from \"@db-studio/ui/spinner\";\nimport { useNavigate } from \"@tanstack/react-router\";\nimport { DatabaseZap, Plus } from \"lucide-react\";\nimport { useQueryState } from \"nuqs\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\nimport { getRedisStringChunk } from \"@/shared/api\";\nimport { useDatabaseStore } from \"@/stores/database.store\";\nimport { useOverlayStore } from \"@/stores/overlay.store\";\nimport { useQueriesStore } from \"@/stores/queries.store\";\nimport { RedisKeyHeader } from \"../components/redis-key-header\";\nimport { bytesFromBase64Url } from \"../components/redis-value\";\nimport {\n\ttype RedisAct,\n\tRedisValueEditor,\n\ttype StreamDirection,\n} from \"../components/redis-value-editors\";\nimport { useRedisKey, useRedisKeyMutations } from \"../hooks/use-redis-browser\";\n\n/** The read command a dev would run for this key, used by \"Open in runner\". */\nconst runnerCommand = (detail: KeyDetailsResultSchemaType): string | null => {\n\tif (detail.key.utf8 === undefined) return null;\n\tconst key = JSON.stringify(detail.key.utf8);\n\tswitch (detail.type) {\n\t\tcase \"string\":\n\t\t\treturn `GET ${key}`;\n\t\tcase \"hash\":\n\t\t\treturn `HGETALL ${key}`;\n\t\tcase \"list\":\n\t\t\treturn `LRANGE ${key} 0 -1`;\n\t\tcase \"set\":\n\t\t\treturn `SMEMBERS ${key}`;\n\t\tcase \"zset\":\n\t\t\treturn `ZRANGE ${key} 0 -1 WITHSCORES`;\n\t\tcase \"stream\":\n\t\t\treturn `XRANGE ${key} - + COUNT 100`;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\n/** Entries fetched so far across pages; null for scalar/unknown values. */\nconst countLoaded = (detail: KeyDetailsResultSchemaType): number | null => {\n\tswitch (detail.value.kind) {\n\t\tcase \"hash\":\n\t\tcase \"list\":\n\t\tcase \"zset\":\n\t\tcase \"stream\":\n\t\t\treturn detail.value.entries.length;\n\t\tcase \"set\":\n\t\t\treturn detail.value.members.length;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const RedisBrowserScreen = () => {\n\tconst navigate = useNavigate();\n\tconst { selectedDatabase } = useDatabaseStore();\n\tconst { openOverlay } = useOverlayStore();\n\tconst { addQuery, updateQuery } = useQueriesStore();\n\tconst [selectedKey, setSelectedKey] = useQueryState(\"key\");\n\tconst [fullKey, setFullKey] = useState<string | null>(null);\n\tconst [reverseStreamKey, setReverseStreamKey] = useState<string | null>(null);\n\tconst streamDirection: StreamDirection =\n\t\treverseStreamKey === selectedKey ? \"backward\" : \"forward\";\n\tconst query = useRedisKey(selectedKey, fullKey === selectedKey, streamDirection);\n\tconst { applyAction, deleteKey, isPending } = useRedisKeyMutations();\n\tconst pages = query.data?.pages;\n\tconst detail = pages?.[0];\n\tconst [confirmingDelete, setConfirmingDelete] = useState(false);\n\tconst [conflictOperation, setConflictOperation] = useState<\n\t\tKeyActionSchemaType[\"operation\"] | null\n\t>(null);\n\tconst label = detail?.key.utf8 ?? (detail ? `binary:${detail.key.base64}` : \"\");\n\tconst command = detail ? runnerCommand(detail) : null;\n\n\tconst mergedDetail = useMemo(() => {\n\t\tif (!detail || !pages || pages.length === 1) return detail;\n\t\tconst next = structuredClone(detail);\n\t\tfor (const page of pages.slice(1)) {\n\t\t\tif (next.value.kind === \"hash\" && page.value.kind === \"hash\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"list\" && page.value.kind === \"list\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"set\" && page.value.kind === \"set\")\n\t\t\t\tnext.value.members.push(...page.value.members);\n\t\t\tif (next.value.kind === \"zset\" && page.value.kind === \"zset\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t\tif (next.value.kind === \"stream\" && page.value.kind === \"stream\")\n\t\t\t\tnext.value.entries.push(...page.value.entries);\n\t\t}\n\t\treturn next;\n\t}, [detail, pages]);\n\tconst loadedCount = mergedDetail ? countLoaded(mergedDetail) : null;\n\n\tconst act: RedisAct = async (operation, force = false) => {\n\t\tif (!selectedKey || !detail) return false;\n\t\ttry {\n\t\t\tconst result = await applyAction(selectedKey, {\n\t\t\t\texpectedRevision: detail.revision,\n\t\t\t\tforce,\n\t\t\t\toperation,\n\t\t\t});\n\t\t\tsetConflictOperation(null);\n\t\t\tif (result.deleted) setSelectedKey(null);\n\t\t\telse if ((result.key.base64 || \"-\") !== selectedKey)\n\t\t\t\tsetSelectedKey(result.key.base64 || \"-\");\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\t// toast.promise in the mutation hook already surfaced the failure.\n\t\t\tif ((error as Error & { status?: number }).status === 409)\n\t\t\t\tsetConflictOperation(operation);\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst openInRunner = () => {\n\t\tif (!command) return;\n\t\tconst queryId = addQuery(`redis: ${label.slice(0, 40)}`);\n\t\tupdateQuery(queryId, { query: command });\n\t\tnavigate({ to: \"/runner/$queryId\", params: { queryId } });\n\t};\n\n\tconst downloadOriginalString = async () => {\n\t\tif (!selectedKey || !detail || detail.type !== \"string\") return;\n\t\tconst chunks: Uint8Array[] = [];\n\t\tlet offset = 0;\n\t\tlet hasMore = true;\n\t\twhile (hasMore) {\n\t\t\tconst response = await getRedisStringChunk({\n\t\t\t\tdb: selectedDatabase ?? \"\",\n\t\t\t\tkey: selectedKey,\n\t\t\t\toffset,\n\t\t\t\texpectedRevision: detail.revision,\n\t\t\t});\n\t\t\tconst page = response.data.data;\n\t\t\tchunks.push(bytesFromBase64Url(page.chunk.base64));\n\t\t\thasMore = page.hasMore;\n\t\t\tif (page.hasMore && (page.nextOffset === null || page.nextOffset <= offset)) {\n\t\t\t\tthrow new Error(\"Redis download made no forward progress\");\n\t\t\t}\n\t\t\toffset = page.nextOffset ?? offset;\n\t\t}\n\t\tconst size = chunks.reduce((total, chunk) => total + chunk.length, 0);\n\t\tconst bytes = new Uint8Array(size);\n\t\tlet position = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, position);\n\t\t\tposition += chunk.length;\n\t\t}\n\t\tconst url = URL.createObjectURL(new Blob([bytes.buffer as ArrayBuffer]));\n\t\tconst anchor = document.createElement(\"a\");\n\t\tanchor.href = url;\n\t\tanchor.download = `${detail.key.utf8?.replaceAll(/[^\\w.-]+/g, \"_\") || \"redis-value\"}.bin`;\n\t\tanchor.click();\n\t\tURL.revokeObjectURL(url);\n\t};\n\n\tif (!selectedKey)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center bg-background font-mono\">\n\t\t\t\t<div className=\"max-w-sm text-center\">\n\t\t\t\t\t<DatabaseZap className=\"mx-auto mb-3 size-5 text-muted-foreground\" />\n\t\t\t\t\t<h1 className=\"text-sm font-medium text-foreground\">No key selected</h1>\n\t\t\t\t\t<p className=\"mt-1 text-xs leading-5 text-muted-foreground\">\n\t\t\t\t\t\tSelect a key from the navigator or create one to inspect its value.\n\t\t\t\t\t</p>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tclassName=\"mt-3\"\n\t\t\t\t\t\tonClick={() => openOverlay(\"redis-browser.create-key\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus /> Create key\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t);\n\tif (query.isLoading)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center\">\n\t\t\t\t<Spinner />\n\t\t\t</main>\n\t\t);\n\tif (query.error || !detail || !mergedDetail)\n\t\treturn (\n\t\t\t<main className=\"flex flex-1 items-center justify-center bg-background p-4\">\n\t\t\t\t<div className=\"w-full max-w-md text-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"error\"\n\t\t\t\t\t\ttitle=\"Unable to load key\"\n\t\t\t\t\t\tmessage={query.error?.message ?? \"The key no longer exists.\"}\n\t\t\t\t\t\tclassName=\"rounded-sm text-start\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\tclassName=\"mt-4\"\n\t\t\t\t\t\tonClick={() => setSelectedKey(null)}\n\t\t\t\t\t>\n\t\t\t\t\t\tBack to keyspace\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t);\n\n\tconst remaining =\n\t\tmergedDetail.length !== null && loadedCount !== null\n\t\t\t? Math.max(0, mergedDetail.length - loadedCount)\n\t\t\t: null;\n\n\treturn (\n\t\t<main className=\"flex min-h-0 flex-1 flex-col bg-background font-mono\">\n\t\t\t<RedisKeyHeader\n\t\t\t\tkey={detail.key.base64}\n\t\t\t\tdetail={detail}\n\t\t\t\tlabel={label}\n\t\t\t\tloadedCount={loadedCount}\n\t\t\t\tfetchedAt={query.dataUpdatedAt}\n\t\t\t\tisFetching={query.isFetching}\n\t\t\t\tpending={isPending}\n\t\t\t\tcommand={command}\n\t\t\t\tact={act}\n\t\t\t\tonRefresh={() => query.refetch()}\n\t\t\t\tonOpenRunner={openInRunner}\n\t\t\t\tonDelete={() => setConfirmingDelete(true)}\n\t\t\t/>\n\t\t\t<AlertDialog\n\t\t\t\topen={confirmingDelete}\n\t\t\t\tonOpenChange={setConfirmingDelete}\n\t\t\t>\n\t\t\t\t<AlertDialogContent>\n\t\t\t\t\t<AlertDialogHeader>\n\t\t\t\t\t\t<AlertDialogTitle>Delete key</AlertDialogTitle>\n\t\t\t\t\t\t<AlertDialogDescription>\n\t\t\t\t\t\t\tAre you sure you want to delete{\" \"}\n\t\t\t\t\t\t\t<code className=\"break-all text-foreground\">{label || \"(empty key)\"}</code>? This\n\t\t\t\t\t\t\taction cannot be undone.\n\t\t\t\t\t\t</AlertDialogDescription>\n\t\t\t\t\t</AlertDialogHeader>\n\t\t\t\t\t<AlertDialogFooter>\n\t\t\t\t\t\t<AlertDialogCancel>Cancel</AlertDialogCancel>\n\t\t\t\t\t\t<AlertDialogAction\n\t\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\t\t\tsetConfirmingDelete(false);\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tawait deleteKey(selectedKey, detail.revision);\n\t\t\t\t\t\t\t\t\tsetSelectedKey(null);\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t// toast.promise in the mutation hook already surfaced the failure.\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tDelete\n\t\t\t\t\t\t</AlertDialogAction>\n\t\t\t\t\t</AlertDialogFooter>\n\t\t\t\t</AlertDialogContent>\n\t\t\t</AlertDialog>\n\t\t\t{conflictOperation && (\n\t\t\t\t<div className=\"grid gap-2 border-b border-border p-2 sm:grid-cols-[1fr_auto] sm:items-center\">\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\ttitle=\"Revision conflict\"\n\t\t\t\t\t\tmessage=\"This key changed on the server. Reload it or overwrite with the pending change.\"\n\t\t\t\t\t\tclassName=\"rounded-sm py-2\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tsetConflictOperation(null);\n\t\t\t\t\t\t\t\tquery.refetch();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tReload\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tdisabled={isPending}\n\t\t\t\t\t\t\tonClick={() => act(conflictOperation, true)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOverwrite\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"min-h-0 flex-1 overflow-auto\">\n\t\t\t\t<section className=\"p-3\">\n\t\t\t\t\t<RedisValueEditor\n\t\t\t\t\t\tkey={detail.key.base64}\n\t\t\t\t\t\tdetail={mergedDetail}\n\t\t\t\t\t\tact={act}\n\t\t\t\t\t\tpending={isPending}\n\t\t\t\t\t\tonLoadFull={() => setFullKey(selectedKey)}\n\t\t\t\t\t\tonDownload={() => {\n\t\t\t\t\t\t\ttoast.promise(downloadOriginalString(), {\n\t\t\t\t\t\t\t\tloading: \"Downloading original Redis bytes…\",\n\t\t\t\t\t\t\t\tsuccess: \"Redis value downloaded\",\n\t\t\t\t\t\t\t\terror: (error: Error) => error.message || \"Download failed\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tstreamDirection={streamDirection}\n\t\t\t\t\t\tonStreamDirectionChange={(direction) =>\n\t\t\t\t\t\t\tsetReverseStreamKey(direction === \"backward\" ? selectedKey : null)\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t\t{query.hasNextPage && (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tclassName=\"mt-3 w-full\"\n\t\t\t\t\t\t\tonClick={() => query.fetchNextPage()}\n\t\t\t\t\t\t\tdisabled={query.isFetchingNextPage}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{query.isFetchingNextPage\n\t\t\t\t\t\t\t\t? \"Loading…\"\n\t\t\t\t\t\t\t\t: detail.type === \"stream\" && streamDirection === \"backward\"\n\t\t\t\t\t\t\t\t\t? \"Load 100 older entries\"\n\t\t\t\t\t\t\t\t\t: `Load next 100${remaining !== null ? ` (${remaining.toLocaleString()} remaining)` : \"\"}`}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</main>\n\t);\n};\n","import { createFileRoute } from \"@tanstack/react-router\";\nimport { RedisBrowserScreen } from \"@/features/redis-browser\";\n\nexport const Route = createFileRoute(\"/_pathlessLayout/browser\")({\n\tcomponent: RedisBrowserScreen,\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{r as G}from"./rolldown-runtime-CXHxssQy.js";import{lt as U}from"./icons-0UA1AvNu.js";import{kt as b}from"./radix-ui-6dcJ5m4U.js";import{n as c}from"./dist-C-7rnx4R.js";import{i as e,n as T,r as O,t as d}from"./monaco-editor-CaQyRcyX.js";import{b as g}from"./index-BSNZ1oRs.js";var l=G(U(),1),D=["SELECT","FROM","WHERE","INSERT","UPDATE","DELETE","CREATE","DROP","ALTER","TABLE","INDEX","VIEW","DATABASE","SCHEMA","FUNCTION","PROCEDURE","TRIGGER","AND","OR","NOT","IN","BETWEEN","LIKE","IS","NULL","JOIN","LEFT","RIGHT","INNER","OUTER","CROSS","ON","USING","GROUP","BY","HAVING","ORDER","ASC","DESC","LIMIT","OFFSET","UNION","INTERSECT","EXCEPT","AS","DISTINCT","ALL","EXISTS","CASE","WHEN","THEN","ELSE","END","WITH","RECURSIVE","PRIMARY","KEY","FOREIGN","REFERENCES","UNIQUE","CHECK","DEFAULT","CASCADE","RESTRICT","NO","ACTION","SET","CONSTRAINT","BEGIN","COMMIT","ROLLBACK","SAVEPOINT","TRANSACTION","GRANT","REVOKE","PRIVILEGES","TO","RETURNING"],M=["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%",">>","<<","+=","-=","*=","/=","&=","|=","^=","%="],_=["COUNT","SUM","AVG","MIN","MAX","COALESCE","NULLIF","CAST","CONCAT","SUBSTRING","LOWER","UPPER","TRIM","LENGTH","NOW","CURRENT_DATE","CURRENT_TIME","CURRENT_TIMESTAMP","EXTRACT","DATE_TRUNC","AGE","ARRAY_AGG","JSON_BUILD_OBJECT","JSON_AGG","ROW_NUMBER","RANK","DENSE_RANK","LAG","LEAD","FIRST_VALUE","LAST_VALUE","STRING_AGG","GENERATE_SERIES"],B=["INTEGER","INT","SMALLINT","BIGINT","DECIMAL","NUMERIC","REAL","DOUBLE","PRECISION","SERIAL","BIGSERIAL","VARCHAR","CHAR","TEXT","BOOLEAN","BOOL","DATE","TIME","TIMESTAMP","TIMESTAMPTZ","INTERVAL","UUID","JSON","JSONB","ARRAY","BYTEA","INET","CIDR"],P=["SELECT","FROM","WHERE","INSERT INTO","UPDATE","DELETE FROM","CREATE TABLE","DROP TABLE","ALTER TABLE","JOIN","LEFT JOIN","RIGHT JOIN","INNER JOIN","GROUP BY","ORDER BY","HAVING","LIMIT"],x=["COUNT(*)","SUM()","AVG()","MIN()","MAX()","COALESCE()","CONCAT()","NOW()","CURRENT_DATE","CURRENT_TIMESTAMP","STRING_AGG()","ARRAY_AGG()","JSON_AGG()"],F=["INTEGER","VARCHAR","TEXT","BOOLEAN","TIMESTAMP","DATE","JSON","JSONB","UUID","SERIAL","BIGSERIAL"],k=b(),J=({initialQuery:S,queryId:R,savedQuery:I,language:a,onQueryChange:m,onUnsavedChanges:o,onExecuteQuery:p,onSaveQuery:L})=>{const N=(0,l.useRef)(null),C=(0,l.useRef)(null),{isDark:A}=g();return(0,l.useEffect)(()=>{C.current&&O.setTheme(A?"vs-dark":"vs")},[A]),(0,l.useEffect)(()=>{if(!N.current)return;const u=[];a==="pgsql"&&(e.register({id:"pgsql"}),u.push(e.registerDocumentFormattingEditProvider("pgsql",{provideDocumentFormattingEdits:t=>{const s=t.getValue().replace(/\s+/g," ").replace(/\s*,\s*/g,`,
|
|
2
|
+
`).replace(/\b(SELECT|FROM|WHERE|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET)\b/gi,`
|
|
3
|
+
$1`).replace(/\b(AND|OR)\b/gi,`
|
|
4
|
+
$1`).trim().split(`
|
|
5
|
+
`).map(E=>{const r=E.trim();return r.startsWith("AND")||r.startsWith("OR")||/^[^A-Z]/.test(r)?` ${r}`:r}).join(`
|
|
6
|
+
`);return[{range:t.getFullModelRange(),text:s}]}})),e.setMonarchTokensProvider("pgsql",{defaultToken:"",tokenPostfix:".sql",ignoreCase:!0,keywords:D,operators:M,builtinFunctions:_,builtinTypes:B,tokenizer:{root:[{include:"@comments"},{include:"@whitespace"},{include:"@numbers"},{include:"@strings"},{include:"@complexIdentifiers"},[/[;,.]/,"delimiter"],[/[()]/,"@brackets"],[/[\w@#$]+/,{cases:{"@keywords":"keyword","@operators":"operator","@builtinFunctions":"predefined","@builtinTypes":"type","@default":"identifier"}}],[/[<>=!%&+\-*/|~^]/,"operator"]],whitespace:[[/\s+/,"white"]],comments:[[/--+.*/,"comment"],[/\/\*/,{token:"comment.quote",next:"@comment"}]],comment:[[/[^*/]+/,"comment"],[/\*\//,{token:"comment.quote",next:"@pop"}],[/./,"comment"]],numbers:[[/0[xX][0-9a-fA-F]*/,"number"],[/[$][+-]*\d*(\.\d*)?/,"number"],[/((\d+(\.\d*)?)|(\.\d+))([eE][-+]?\d+)?/,"number"]],strings:[[/'/,{token:"string",next:"@string"}],[/"/,{token:"string.double",next:"@stringDouble"}]],string:[[/[^']+/,"string"],[/''/,"string"],[/'/,{token:"string",next:"@pop"}]],stringDouble:[[/[^"]+/,"string.double"],[/""/,"string.double"],[/"/,{token:"string.double",next:"@pop"}]],complexIdentifiers:[[/"/,{token:"identifier.quote",next:"@quotedIdentifier"}]],quotedIdentifier:[[/[^"]+/,"identifier"],[/""/,"identifier"],[/"/,{token:"identifier.quote",next:"@pop"}]]}}),u.push(e.registerCompletionItemProvider("pgsql",{provideCompletionItems:(t,s)=>{const E=t.getWordUntilPosition(s),r={startLineNumber:s.lineNumber,endLineNumber:s.lineNumber,startColumn:E.startColumn,endColumn:E.endColumn};return{suggestions:[...P.map(i=>({label:i,kind:e.CompletionItemKind.Keyword,insertText:i,range:r})),...x.map(i=>({label:i,kind:e.CompletionItemKind.Function,insertText:i.includes("(*)")?i:i.replace("()","($0)"),insertTextRules:e.CompletionItemInsertTextRule.InsertAsSnippet,range:r})),...F.map(i=>({label:i,kind:e.CompletionItemKind.TypeParameter,insertText:i,range:r})),{label:"select-template",kind:e.CompletionItemKind.Snippet,insertText:["SELECT ${1:columns}","FROM ${2:table}","WHERE ${3:condition};"].join(`
|
|
7
|
+
`),insertTextRules:e.CompletionItemInsertTextRule.InsertAsSnippet,documentation:"SELECT statement template",range:r},{label:"create-table-template",kind:e.CompletionItemKind.Snippet,insertText:["CREATE TABLE ${1:table_name} ("," ${2:id} SERIAL PRIMARY KEY,"," ${3:column_name} ${4:VARCHAR(255)} ${5:NOT NULL},"," created_at TIMESTAMP DEFAULT NOW()",");"].join(`
|
|
8
|
+
`),insertTextRules:e.CompletionItemInsertTextRule.InsertAsSnippet,documentation:"CREATE TABLE template",range:r},{label:"insert-template",kind:e.CompletionItemKind.Snippet,insertText:["INSERT INTO ${1:table} (${2:columns})","VALUES (${3:values})","RETURNING *;"].join(`
|
|
9
|
+
`),insertTextRules:e.CompletionItemInsertTextRule.InsertAsSnippet,documentation:"INSERT statement template",range:r}]}}})));const n=O.create(N.current,{value:S,language:a,theme:A?"vs-dark":"vs",fontSize:14,minimap:{enabled:!1},lineNumbers:"on",roundedSelection:!0,scrollBeyondLastLine:!0,scrollbar:{horizontal:"hidden",vertical:"hidden",useShadows:!1,verticalHasArrows:!1,horizontalHasArrows:!1,arrowSize:0},automaticLayout:!0,tabSize:4,insertSpaces:!0,wordWrap:"on",folding:!0,bracketPairColorization:{enabled:!0},suggest:{showKeywords:!0,showSnippets:!0},quickSuggestions:{other:!0,comments:!1,strings:!1}});C.current=n,n.addCommand(T.CtrlCmd|d.Enter,()=>{const t=n.getValue();if(!t.trim()){c.error("Query is empty!");return}p(t)}),n.addCommand(T.CtrlCmd|T.Shift|d.KeyF,()=>{n.trigger("keyboard","editor.action.formatDocument",{}),c.success("Query formatted")}),n.addCommand(T.CtrlCmd|d.KeyS,()=>{L()}),m(n.getValue()),o(R?n.getValue()!==I:!1);const f=n.onDidChangeModelContent(()=>{const t=n.getValue();if(m(t),!R){o(!1);return}o(t!==I)});return()=>{for(const t of u)t.dispose();f.dispose(),n.dispose()}},[S,R,I,a,m,o,p]),(0,k.jsx)("div",{ref:N,className:"flex-1 min-h-0 overflow-y-scroll"})};export{J as CodeEditor};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-editor-C9H5SO98.js","names":[],"sources":["../../src/utils/constants/runner-editor.ts","../../src/features/query-runner/components/code-editor.tsx"],"sourcesContent":["export const KEYWORDS = [\n\t\"SELECT\",\n\t\"FROM\",\n\t\"WHERE\",\n\t\"INSERT\",\n\t\"UPDATE\",\n\t\"DELETE\",\n\t\"CREATE\",\n\t\"DROP\",\n\t\"ALTER\",\n\t\"TABLE\",\n\t\"INDEX\",\n\t\"VIEW\",\n\t\"DATABASE\",\n\t\"SCHEMA\",\n\t\"FUNCTION\",\n\t\"PROCEDURE\",\n\t\"TRIGGER\",\n\t\"AND\",\n\t\"OR\",\n\t\"NOT\",\n\t\"IN\",\n\t\"BETWEEN\",\n\t\"LIKE\",\n\t\"IS\",\n\t\"NULL\",\n\t\"JOIN\",\n\t\"LEFT\",\n\t\"RIGHT\",\n\t\"INNER\",\n\t\"OUTER\",\n\t\"CROSS\",\n\t\"ON\",\n\t\"USING\",\n\t\"GROUP\",\n\t\"BY\",\n\t\"HAVING\",\n\t\"ORDER\",\n\t\"ASC\",\n\t\"DESC\",\n\t\"LIMIT\",\n\t\"OFFSET\",\n\t\"UNION\",\n\t\"INTERSECT\",\n\t\"EXCEPT\",\n\t\"AS\",\n\t\"DISTINCT\",\n\t\"ALL\",\n\t\"EXISTS\",\n\t\"CASE\",\n\t\"WHEN\",\n\t\"THEN\",\n\t\"ELSE\",\n\t\"END\",\n\t\"WITH\",\n\t\"RECURSIVE\",\n\t\"PRIMARY\",\n\t\"KEY\",\n\t\"FOREIGN\",\n\t\"REFERENCES\",\n\t\"UNIQUE\",\n\t\"CHECK\",\n\t\"DEFAULT\",\n\t\"CASCADE\",\n\t\"RESTRICT\",\n\t\"NO\",\n\t\"ACTION\",\n\t\"SET\",\n\t\"CONSTRAINT\",\n\t\"BEGIN\",\n\t\"COMMIT\",\n\t\"ROLLBACK\",\n\t\"SAVEPOINT\",\n\t\"TRANSACTION\",\n\t\"GRANT\",\n\t\"REVOKE\",\n\t\"PRIVILEGES\",\n\t\"TO\",\n\t\"RETURNING\",\n];\nexport const OPERATORS = [\n\t\"=\",\n\t\">\",\n\t\"<\",\n\t\"!\",\n\t\"~\",\n\t\"?\",\n\t\":\",\n\t\"==\",\n\t\"<=\",\n\t\">=\",\n\t\"!=\",\n\t\"&&\",\n\t\"||\",\n\t\"++\",\n\t\"--\",\n\t\"+\",\n\t\"-\",\n\t\"*\",\n\t\"/\",\n\t\"&\",\n\t\"|\",\n\t\"^\",\n\t\"%\",\n\t\">>\",\n\t\"<<\",\n\t\"+=\",\n\t\"-=\",\n\t\"*=\",\n\t\"/=\",\n\t\"&=\",\n\t\"|=\",\n\t\"^=\",\n\t\"%=\",\n];\n\nexport const BUILTIN_FUNCTIONS = [\n\t\"COUNT\",\n\t\"SUM\",\n\t\"AVG\",\n\t\"MIN\",\n\t\"MAX\",\n\t\"COALESCE\",\n\t\"NULLIF\",\n\t\"CAST\",\n\t\"CONCAT\",\n\t\"SUBSTRING\",\n\t\"LOWER\",\n\t\"UPPER\",\n\t\"TRIM\",\n\t\"LENGTH\",\n\t\"NOW\",\n\t\"CURRENT_DATE\",\n\t\"CURRENT_TIME\",\n\t\"CURRENT_TIMESTAMP\",\n\t\"EXTRACT\",\n\t\"DATE_TRUNC\",\n\t\"AGE\",\n\t\"ARRAY_AGG\",\n\t\"JSON_BUILD_OBJECT\",\n\t\"JSON_AGG\",\n\t\"ROW_NUMBER\",\n\t\"RANK\",\n\t\"DENSE_RANK\",\n\t\"LAG\",\n\t\"LEAD\",\n\t\"FIRST_VALUE\",\n\t\"LAST_VALUE\",\n\t\"STRING_AGG\",\n\t\"GENERATE_SERIES\",\n];\n\nexport const BUILTIN_TYPES = [\n\t\"INTEGER\",\n\t\"INT\",\n\t\"SMALLINT\",\n\t\"BIGINT\",\n\t\"DECIMAL\",\n\t\"NUMERIC\",\n\t\"REAL\",\n\t\"DOUBLE\",\n\t\"PRECISION\",\n\t\"SERIAL\",\n\t\"BIGSERIAL\",\n\t\"VARCHAR\",\n\t\"CHAR\",\n\t\"TEXT\",\n\t\"BOOLEAN\",\n\t\"BOOL\",\n\t\"DATE\",\n\t\"TIME\",\n\t\"TIMESTAMP\",\n\t\"TIMESTAMPTZ\",\n\t\"INTERVAL\",\n\t\"UUID\",\n\t\"JSON\",\n\t\"JSONB\",\n\t\"ARRAY\",\n\t\"BYTEA\",\n\t\"INET\",\n\t\"CIDR\",\n];\n\nexport const SUGGESTIONS = [\n\t\"SELECT\",\n\t\"FROM\",\n\t\"WHERE\",\n\t\"INSERT INTO\",\n\t\"UPDATE\",\n\t\"DELETE FROM\",\n\t\"CREATE TABLE\",\n\t\"DROP TABLE\",\n\t\"ALTER TABLE\",\n\t\"JOIN\",\n\t\"LEFT JOIN\",\n\t\"RIGHT JOIN\",\n\t\"INNER JOIN\",\n\t\"GROUP BY\",\n\t\"ORDER BY\",\n\t\"HAVING\",\n\t\"LIMIT\",\n];\n\nexport const FUNCTIONS = [\n\t\"COUNT(*)\",\n\t\"SUM()\",\n\t\"AVG()\",\n\t\"MIN()\",\n\t\"MAX()\",\n\t\"COALESCE()\",\n\t\"CONCAT()\",\n\t\"NOW()\",\n\t\"CURRENT_DATE\",\n\t\"CURRENT_TIMESTAMP\",\n\t\"STRING_AGG()\",\n\t\"ARRAY_AGG()\",\n\t\"JSON_AGG()\",\n];\n\nexport const DATA_TYPES = [\n\t\"INTEGER\",\n\t\"VARCHAR\",\n\t\"TEXT\",\n\t\"BOOLEAN\",\n\t\"TIMESTAMP\",\n\t\"DATE\",\n\t\"JSON\",\n\t\"JSONB\",\n\t\"UUID\",\n\t\"SERIAL\",\n\t\"BIGSERIAL\",\n];\n","import * as monaco from \"monaco-editor\";\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { useTheme } from \"@/hooks/use-theme\";\nimport {\n\tBUILTIN_FUNCTIONS,\n\tBUILTIN_TYPES,\n\tDATA_TYPES,\n\tFUNCTIONS,\n\tKEYWORDS,\n\tOPERATORS,\n\tSUGGESTIONS,\n} from \"@/utils/constants/runner-editor\";\n\ninterface CodeEditorProps {\n\tinitialQuery: string;\n\tqueryId?: string;\n\tsavedQuery: string;\n\tlanguage: \"pgsql\" | \"json\" | \"plaintext\";\n\tonQueryChange: (query: string) => void;\n\tonUnsavedChanges: (hasChanges: boolean) => void;\n\tonExecuteQuery: (query: string) => void;\n\tonFormatQuery: () => void;\n\tonSaveQuery: () => void;\n}\n\nexport const CodeEditor = ({\n\tinitialQuery,\n\tqueryId,\n\tsavedQuery,\n\tlanguage,\n\tonQueryChange,\n\tonUnsavedChanges,\n\tonExecuteQuery,\n\tonSaveQuery,\n}: CodeEditorProps) => {\n\tconst monacoEl = useRef<HTMLDivElement>(null);\n\tconst editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);\n\tconst { isDark } = useTheme();\n\n\tuseEffect(() => {\n\t\tif (editorRef.current) {\n\t\t\tmonaco.editor.setTheme(isDark ? \"vs-dark\" : \"vs\");\n\t\t}\n\t}, [isDark]);\n\n\tuseEffect(() => {\n\t\tif (!monacoEl.current) return;\n\t\tconst languageDisposables: monaco.IDisposable[] = [];\n\n\t\tif (language === \"pgsql\") {\n\t\t\tmonaco.languages.register({ id: \"pgsql\" });\n\n\t\t\tlanguageDisposables.push(\n\t\t\t\tmonaco.languages.registerDocumentFormattingEditProvider(\"pgsql\", {\n\t\t\t\t\tprovideDocumentFormattingEdits: (model) => {\n\t\t\t\t\t\tconst text = model.getValue();\n\t\t\t\t\t\tconst formatted = text\n\t\t\t\t\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t\t\t\t\t.replace(/\\s*,\\s*/g, \",\\n\\t\")\n\t\t\t\t\t\t\t.replace(\n\t\t\t\t\t\t\t\t/\\b(SELECT|FROM|WHERE|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET)\\b/gi,\n\t\t\t\t\t\t\t\t\"\\n$1\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.replace(/\\b(AND|OR)\\b/gi, \"\\n\\t$1\")\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t.map((line) => {\n\t\t\t\t\t\t\t\tconst trimmed = line.trim();\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttrimmed.startsWith(\"AND\") ||\n\t\t\t\t\t\t\t\t\ttrimmed.startsWith(\"OR\") ||\n\t\t\t\t\t\t\t\t\t/^[^A-Z]/.test(trimmed)\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn `\\t${trimmed}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn trimmed;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.join(\"\\n\");\n\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trange: model.getFullModelRange(),\n\t\t\t\t\t\t\t\ttext: formatted,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t];\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tmonaco.languages.setMonarchTokensProvider(\"pgsql\", {\n\t\t\t\tdefaultToken: \"\",\n\t\t\t\ttokenPostfix: \".sql\",\n\t\t\t\tignoreCase: true,\n\n\t\t\t\tkeywords: KEYWORDS,\n\t\t\t\toperators: OPERATORS,\n\t\t\t\tbuiltinFunctions: BUILTIN_FUNCTIONS,\n\t\t\t\tbuiltinTypes: BUILTIN_TYPES,\n\n\t\t\t\ttokenizer: {\n\t\t\t\t\troot: [\n\t\t\t\t\t\t{ include: \"@comments\" },\n\t\t\t\t\t\t{ include: \"@whitespace\" },\n\t\t\t\t\t\t{ include: \"@numbers\" },\n\t\t\t\t\t\t{ include: \"@strings\" },\n\t\t\t\t\t\t{ include: \"@complexIdentifiers\" },\n\t\t\t\t\t\t[/[;,.]/, \"delimiter\"],\n\t\t\t\t\t\t[/[()]/, \"@brackets\"],\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t/[\\w@#$]+/,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcases: {\n\t\t\t\t\t\t\t\t\t\"@keywords\": \"keyword\",\n\t\t\t\t\t\t\t\t\t\"@operators\": \"operator\",\n\t\t\t\t\t\t\t\t\t\"@builtinFunctions\": \"predefined\",\n\t\t\t\t\t\t\t\t\t\"@builtinTypes\": \"type\",\n\t\t\t\t\t\t\t\t\t\"@default\": \"identifier\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\t[/[<>=!%&+\\-*/|~^]/, \"operator\"],\n\t\t\t\t\t],\n\t\t\t\t\twhitespace: [[/\\s+/, \"white\"]],\n\t\t\t\t\tcomments: [\n\t\t\t\t\t\t[/--+.*/, \"comment\"],\n\t\t\t\t\t\t[/\\/\\*/, { token: \"comment.quote\", next: \"@comment\" }],\n\t\t\t\t\t],\n\t\t\t\t\tcomment: [\n\t\t\t\t\t\t[/[^*/]+/, \"comment\"],\n\t\t\t\t\t\t[/\\*\\//, { token: \"comment.quote\", next: \"@pop\" }],\n\t\t\t\t\t\t[/./, \"comment\"],\n\t\t\t\t\t],\n\t\t\t\t\tnumbers: [\n\t\t\t\t\t\t[/0[xX][0-9a-fA-F]*/, \"number\"],\n\t\t\t\t\t\t[/[$][+-]*\\d*(\\.\\d*)?/, \"number\"],\n\t\t\t\t\t\t[/((\\d+(\\.\\d*)?)|(\\.\\d+))([eE][-+]?\\d+)?/, \"number\"],\n\t\t\t\t\t],\n\t\t\t\t\tstrings: [\n\t\t\t\t\t\t[/'/, { token: \"string\", next: \"@string\" }],\n\t\t\t\t\t\t[/\"/, { token: \"string.double\", next: \"@stringDouble\" }],\n\t\t\t\t\t],\n\t\t\t\t\tstring: [\n\t\t\t\t\t\t[/[^']+/, \"string\"],\n\t\t\t\t\t\t[/''/, \"string\"],\n\t\t\t\t\t\t[/'/, { token: \"string\", next: \"@pop\" }],\n\t\t\t\t\t],\n\t\t\t\t\tstringDouble: [\n\t\t\t\t\t\t[/[^\"]+/, \"string.double\"],\n\t\t\t\t\t\t[/\"\"/, \"string.double\"],\n\t\t\t\t\t\t[/\"/, { token: \"string.double\", next: \"@pop\" }],\n\t\t\t\t\t],\n\t\t\t\t\tcomplexIdentifiers: [\n\t\t\t\t\t\t[/\"/, { token: \"identifier.quote\", next: \"@quotedIdentifier\" }],\n\t\t\t\t\t],\n\t\t\t\t\tquotedIdentifier: [\n\t\t\t\t\t\t[/[^\"]+/, \"identifier\"],\n\t\t\t\t\t\t[/\"\"/, \"identifier\"],\n\t\t\t\t\t\t[/\"/, { token: \"identifier.quote\", next: \"@pop\" }],\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tlanguageDisposables.push(\n\t\t\t\tmonaco.languages.registerCompletionItemProvider(\"pgsql\", {\n\t\t\t\t\tprovideCompletionItems: (model, position) => {\n\t\t\t\t\t\tconst word = model.getWordUntilPosition(position);\n\t\t\t\t\t\tconst range = {\n\t\t\t\t\t\t\tstartLineNumber: position.lineNumber,\n\t\t\t\t\t\t\tendLineNumber: position.lineNumber,\n\t\t\t\t\t\t\tstartColumn: word.startColumn,\n\t\t\t\t\t\t\tendColumn: word.endColumn,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst suggestions = [\n\t\t\t\t\t\t\t...SUGGESTIONS.map((kw) => ({\n\t\t\t\t\t\t\t\tlabel: kw,\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.Keyword,\n\t\t\t\t\t\t\t\tinsertText: kw,\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t...FUNCTIONS.map((fn) => ({\n\t\t\t\t\t\t\t\tlabel: fn,\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.Function,\n\t\t\t\t\t\t\t\tinsertText: fn.includes(\"(*)\") ? fn : fn.replace(\"()\", \"($0)\"),\n\t\t\t\t\t\t\t\tinsertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t...DATA_TYPES.map((type) => ({\n\t\t\t\t\t\t\t\tlabel: type,\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.TypeParameter,\n\t\t\t\t\t\t\t\tinsertText: type,\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: \"select-template\",\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.Snippet,\n\t\t\t\t\t\t\t\tinsertText: [\n\t\t\t\t\t\t\t\t\t\"SELECT ${1:columns}\",\n\t\t\t\t\t\t\t\t\t\"FROM ${2:table}\",\n\t\t\t\t\t\t\t\t\t\"WHERE ${3:condition};\",\n\t\t\t\t\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\t\t\t\tinsertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n\t\t\t\t\t\t\t\tdocumentation: \"SELECT statement template\",\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: \"create-table-template\",\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.Snippet,\n\t\t\t\t\t\t\t\tinsertText: [\n\t\t\t\t\t\t\t\t\t\"CREATE TABLE ${1:table_name} (\",\n\t\t\t\t\t\t\t\t\t\" ${2:id} SERIAL PRIMARY KEY,\",\n\t\t\t\t\t\t\t\t\t\" ${3:column_name} ${4:VARCHAR(255)} ${5:NOT NULL},\",\n\t\t\t\t\t\t\t\t\t\" created_at TIMESTAMP DEFAULT NOW()\",\n\t\t\t\t\t\t\t\t\t\");\",\n\t\t\t\t\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\t\t\t\tinsertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n\t\t\t\t\t\t\t\tdocumentation: \"CREATE TABLE template\",\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: \"insert-template\",\n\t\t\t\t\t\t\t\tkind: monaco.languages.CompletionItemKind.Snippet,\n\t\t\t\t\t\t\t\tinsertText: [\n\t\t\t\t\t\t\t\t\t\"INSERT INTO ${1:table} (${2:columns})\",\n\t\t\t\t\t\t\t\t\t\"VALUES (${3:values})\",\n\t\t\t\t\t\t\t\t\t\"RETURNING *;\",\n\t\t\t\t\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\t\t\t\tinsertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n\t\t\t\t\t\t\t\tdocumentation: \"INSERT statement template\",\n\t\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\treturn { suggestions };\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst editorInstance = monaco.editor.create(monacoEl.current, {\n\t\t\tvalue: initialQuery,\n\t\t\tlanguage,\n\t\t\ttheme: isDark ? \"vs-dark\" : \"vs\",\n\t\t\tfontSize: 14,\n\t\t\tminimap: { enabled: false },\n\t\t\tlineNumbers: \"on\",\n\t\t\troundedSelection: true,\n\t\t\tscrollBeyondLastLine: true,\n\t\t\tscrollbar: {\n\t\t\t\thorizontal: \"hidden\",\n\t\t\t\tvertical: \"hidden\",\n\t\t\t\tuseShadows: false,\n\t\t\t\tverticalHasArrows: false,\n\t\t\t\thorizontalHasArrows: false,\n\t\t\t\tarrowSize: 0,\n\t\t\t},\n\t\t\tautomaticLayout: true,\n\t\t\ttabSize: 4,\n\t\t\tinsertSpaces: true,\n\t\t\twordWrap: \"on\",\n\t\t\tfolding: true,\n\t\t\tbracketPairColorization: {\n\t\t\t\tenabled: true,\n\t\t\t},\n\t\t\tsuggest: {\n\t\t\t\tshowKeywords: true,\n\t\t\t\tshowSnippets: true,\n\t\t\t},\n\t\t\tquickSuggestions: {\n\t\t\t\tother: true,\n\t\t\t\tcomments: false,\n\t\t\t\tstrings: false,\n\t\t\t},\n\t\t});\n\n\t\teditorRef.current = editorInstance;\n\n\t\teditorInstance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => {\n\t\t\tconst query = editorInstance.getValue();\n\t\t\tif (!query.trim()) {\n\t\t\t\ttoast.error(\"Query is empty!\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tonExecuteQuery(query);\n\t\t});\n\n\t\teditorInstance.addCommand(\n\t\t\tmonaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n\t\t\t() => {\n\t\t\t\teditorInstance.trigger(\"keyboard\", \"editor.action.formatDocument\", {});\n\t\t\t\ttoast.success(\"Query formatted\");\n\t\t\t},\n\t\t);\n\n\t\teditorInstance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {\n\t\t\tonSaveQuery();\n\t\t});\n\n\t\tonQueryChange(editorInstance.getValue());\n\n\t\tif (queryId) {\n\t\t\tconst initialValue = editorInstance.getValue();\n\t\t\tonUnsavedChanges(initialValue !== savedQuery);\n\t\t} else {\n\t\t\tonUnsavedChanges(false);\n\t\t}\n\n\t\tconst disposable = editorInstance.onDidChangeModelContent(() => {\n\t\t\tconst currentValue = editorInstance.getValue();\n\t\t\tonQueryChange(currentValue);\n\n\t\t\tif (!queryId) {\n\t\t\t\tonUnsavedChanges(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tonUnsavedChanges(currentValue !== savedQuery);\n\t\t});\n\n\t\treturn () => {\n\t\t\tfor (const d of languageDisposables) d.dispose();\n\t\t\tdisposable.dispose();\n\t\t\teditorInstance.dispose();\n\t\t};\n\t}, [\n\t\tinitialQuery,\n\t\tqueryId,\n\t\tsavedQuery,\n\t\tlanguage,\n\t\tonQueryChange,\n\t\tonUnsavedChanges,\n\t\tonExecuteQuery,\n\t]);\n\n\treturn (\n\t\t<div\n\t\t\tref={monacoEl}\n\t\t\tclassName=\"flex-1 min-h-0 overflow-y-scroll\"\n\t\t/>\n\t);\n};\n"],"mappings":"2SAAa,EAAW,CACvB,SACA,OACA,QACA,SACA,SACA,SACA,SACA,OACA,QACA,QACA,QACA,OACA,WACA,SACA,WACA,YACA,UACA,MACA,KACA,MACA,KACA,UACA,OACA,KACA,OACA,OACA,OACA,QACA,QACA,QACA,QACA,KACA,QACA,QACA,KACA,SACA,QACA,MACA,OACA,QACA,SACA,QACA,YACA,SACA,KACA,WACA,MACA,SACA,OACA,OACA,OACA,OACA,MACA,OACA,YACA,UACA,MACA,UACA,aACA,SACA,QACA,UACA,UACA,WACA,KACA,SACA,MACA,aACA,QACA,SACA,WACA,YACA,cACA,QACA,SACA,aACA,KACA,WACD,EACa,EAAY,CACxB,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,IACD,EAEa,EAAoB,CAChC,QACA,MACA,MACA,MACA,MACA,WACA,SACA,OACA,SACA,YACA,QACA,QACA,OACA,SACA,MACA,eACA,eACA,oBACA,UACA,aACA,MACA,YACA,oBACA,WACA,aACA,OACA,aACA,MACA,OACA,cACA,aACA,aACA,iBACD,EAEa,EAAgB,CAC5B,UACA,MACA,WACA,SACA,UACA,UACA,OACA,SACA,YACA,SACA,YACA,UACA,OACA,OACA,UACA,OACA,OACA,OACA,YACA,cACA,WACA,OACA,OACA,QACA,QACA,QACA,OACA,MACD,EAEa,EAAc,CAC1B,SACA,OACA,QACA,cACA,SACA,cACA,eACA,aACA,cACA,OACA,YACA,aACA,aACA,WACA,WACA,SACA,OACD,EAEa,EAAY,CACxB,WACA,QACA,QACA,QACA,QACA,aACA,WACA,QACA,eACA,oBACA,eACA,cACA,YACD,EAEa,EAAa,CACzB,UACA,UACA,OACA,UACA,YACA,OACA,OACA,QACA,OACA,SACA,WACD,QC7Ma,EAAA,CAAc,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as s}from"./monitoring-B_X9D1H-.js";import{t as r}from"./react-B_x-GW6a.js";var p=r()((t,c)=>({selectedDatabase:null,setSelectedDatabase:e=>{t({selectedDatabase:e});const{dbType:a}=c();e&&a&&s.capture("db_selected",{db_type:a,database:e})},dbType:null,setDbType:e=>{t({dbType:e}),e&&s.capture("db_connected",{db_type:e})}}));export{p as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.store-BvoUSH8Y.js","names":[],"sources":["../../src/stores/database.store.ts"],"sourcesContent":["import type { DatabaseTypeSchema } from \"@db-studio/shared/types\";\nimport { create } from \"zustand\";\nimport { posthogAnalytics } from \"@/lib/posthog\";\n\ninterface DatabaseStore {\n\tselectedDatabase: string | null;\n\tsetSelectedDatabase: (database: string | null) => void;\n\tdbType: DatabaseTypeSchema | null;\n\tsetDbType: (dbType: DatabaseTypeSchema | null) => void;\n}\n\nexport const useDatabaseStore = create<DatabaseStore>()((set, get) => ({\n\tselectedDatabase: null,\n\tsetSelectedDatabase: (database) => {\n\t\tset({ selectedDatabase: database });\n\t\tconst { dbType } = get();\n\t\tif (database && dbType)\n\t\t\tposthogAnalytics.capture(\"db_selected\", { db_type: dbType, database });\n\t},\n\tdbType: null,\n\tsetDbType: (dbType) => {\n\t\tset({ dbType });\n\t\tif (dbType) posthogAnalytics.capture(\"db_connected\", { db_type: dbType });\n\t},\n}));\n"],"mappings":"qFAWA,IAAa,EAAmB,EAAsB,EAAC,CAAE,EAAK,KAAS,CACtE,iBAAkB,KAClB,oBAAsB,GAAa,CAClC,EAAI,CAAE,iBAAkB,CAAS,CAAC,EAClC,KAAM,CAAE,OAAA,CAAA,EAAW,EAAI,EACnB,GAAY,GACf,EAAiB,QAAQ,cAAe,CAAE,QAAS,EAAQ,SAAA,CAAS,CAAC,CACvE,EACA,OAAQ,KACR,UAAY,GAAW,CACtB,EAAI,CAAE,OAAA,CAAO,CAAC,EACV,GAAQ,EAAiB,QAAQ,eAAgB,CAAE,QAAS,CAAO,CAAC,CACzE,CACD,EAAE"}
|