@reddb-io/ui 0.1.1
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/LICENSE +17 -0
- package/bin/red-ui.js +259 -0
- package/build/CNAME +1 -0
- package/build/_app/env.js +1 -0
- package/build/_app/immutable/assets/0.C63jY5jX.css +1 -0
- package/build/_app/immutable/assets/10.Dblyk0Kr.css +1 -0
- package/build/_app/immutable/assets/EmptyState.RXcH7ryE.css +1 -0
- package/build/_app/immutable/assets/Workspace.BCzG1DsH.css +1 -0
- package/build/_app/immutable/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2 +0 -0
- package/build/_app/immutable/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2 +0 -0
- package/build/_app/immutable/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2 +0 -0
- package/build/_app/immutable/assets/inter-greek-wght-normal.CkhJZR-_.woff2 +0 -0
- package/build/_app/immutable/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2 +0 -0
- package/build/_app/immutable/assets/inter-latin-wght-normal.Dx4kXJAl.woff2 +0 -0
- package/build/_app/immutable/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2 +0 -0
- package/build/_app/immutable/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
- package/build/_app/immutable/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
- package/build/_app/immutable/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
- package/build/_app/immutable/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
- package/build/_app/immutable/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
- package/build/_app/immutable/chunks/3j4cZ58b.js +1 -0
- package/build/_app/immutable/chunks/69_IOA4Y.js +1 -0
- package/build/_app/immutable/chunks/ALqaDrNQ.js +2 -0
- package/build/_app/immutable/chunks/BGcIe2ep.js +2 -0
- package/build/_app/immutable/chunks/BMHKbvs8.js +1 -0
- package/build/_app/immutable/chunks/BQHbwf54.js +916 -0
- package/build/_app/immutable/chunks/Bgso8cDH.js +311 -0
- package/build/_app/immutable/chunks/Bmgx1mfv.js +310 -0
- package/build/_app/immutable/chunks/BrvvOVaJ.js +1 -0
- package/build/_app/immutable/chunks/Bzak7iHL.js +1 -0
- package/build/_app/immutable/chunks/D9CTkMjK.js +1 -0
- package/build/_app/immutable/chunks/DIeogL5L.js +1 -0
- package/build/_app/immutable/chunks/DXY_Rxa7.js +113 -0
- package/build/_app/immutable/chunks/DhEqZVGG.js +1 -0
- package/build/_app/immutable/chunks/Ov8N-vxt.js +1 -0
- package/build/_app/immutable/chunks/oiO4RLqp.js +1 -0
- package/build/_app/immutable/entry/app.D_IVtpdv.js +2 -0
- package/build/_app/immutable/entry/start.3oC0UQ_Q.js +1 -0
- package/build/_app/immutable/nodes/0.CHPiFxDo.js +1 -0
- package/build/_app/immutable/nodes/1.BC_4YZ0h.js +1 -0
- package/build/_app/immutable/nodes/10.B7DMKSNc.js +60 -0
- package/build/_app/immutable/nodes/2.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/3.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/4.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/5.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/6.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/7.BZX9Iird.js +134 -0
- package/build/_app/immutable/nodes/8.CAG5_cGP.js +1 -0
- package/build/_app/immutable/nodes/9.CAG5_cGP.js +1 -0
- package/build/_app/version.json +1 -0
- package/build/favicon.png +0 -0
- package/build/index.html +59 -0
- package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js +26562 -0
- package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js.map +1 -0
- package/dist/embed/bundle-mjs-UuVRz3O4.js +3047 -0
- package/dist/embed/bundle-mjs-UuVRz3O4.js.map +1 -0
- package/dist/embed/core-QuRYvMt8.js +118 -0
- package/dist/embed/core-QuRYvMt8.js.map +1 -0
- package/dist/embed/index-B6ZQhCsu.js +577 -0
- package/dist/embed/index-B6ZQhCsu.js.map +1 -0
- package/dist/embed/index-client-ItCEU64C.js +3087 -0
- package/dist/embed/index-client-ItCEU64C.js.map +1 -0
- package/dist/embed/index-fad77a13.esm-BqPj0saH.js +1318 -0
- package/dist/embed/index-fad77a13.esm-BqPj0saH.js.map +1 -0
- package/dist/embed/index.js +11 -0
- package/dist/embed/index.js.map +1 -0
- package/dist/embed/sigma-node-border.esm-CGtlgqmo.js +432 -0
- package/dist/embed/sigma-node-border.esm-CGtlgqmo.js.map +1 -0
- package/dist/embed/sigma.esm-y0qgY-OC.js +2355 -0
- package/dist/embed/sigma.esm-y0qgY-OC.js.map +1 -0
- package/dist/embed/ui.css +1 -0
- package/package.json +101 -0
- package/src/app.css +238 -0
- package/src/lib/ActivityIndicator.svelte +100 -0
- package/src/lib/ClusterNode.svelte +119 -0
- package/src/lib/ClusterView.svelte +541 -0
- package/src/lib/CollectionHistory.svelte +266 -0
- package/src/lib/CollectionsView.svelte +14 -0
- package/src/lib/CommandPalette.svelte +237 -0
- package/src/lib/ConnectDropdown.svelte +222 -0
- package/src/lib/EmptyState.svelte +27 -0
- package/src/lib/LiveChanges.svelte +195 -0
- package/src/lib/MasterPasswordDialog.svelte +168 -0
- package/src/lib/PageHeader.svelte +32 -0
- package/src/lib/PendingChangesPanel.svelte +153 -0
- package/src/lib/QueryEditor.svelte +122 -0
- package/src/lib/ResultsPane.svelte +747 -0
- package/src/lib/SchemaTree.svelte +193 -0
- package/src/lib/SecurityView.svelte +255 -0
- package/src/lib/ShortcutOverlay.svelte +104 -0
- package/src/lib/Splash.svelte +46 -0
- package/src/lib/StatusBar.svelte +163 -0
- package/src/lib/SubNav.svelte +62 -0
- package/src/lib/Topbar.svelte +119 -0
- package/src/lib/Workspace.svelte +247 -0
- package/src/lib/activity.svelte.ts +91 -0
- package/src/lib/build-info.ts +41 -0
- package/src/lib/capability.ts +221 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/collection-catalog.ts +116 -0
- package/src/lib/collection-pages.ts +33 -0
- package/src/lib/connection-history.ts +301 -0
- package/src/lib/connections.svelte.ts +493 -0
- package/src/lib/embed/RedUiEmbedRoot.svelte +31 -0
- package/src/lib/embed/index.ts +234 -0
- package/src/lib/graph-loader/contract.ts +336 -0
- package/src/lib/graph-loader/drilldown.ts +334 -0
- package/src/lib/graph-loader/index.ts +13 -0
- package/src/lib/index.ts +114 -0
- package/src/lib/pending-changes.svelte.ts +149 -0
- package/src/lib/query-tabs.svelte.ts +130 -0
- package/src/lib/reddb/boot-params.ts +254 -0
- package/src/lib/reddb/cdc-stream-client.ts +234 -0
- package/src/lib/reddb/client.ts +698 -0
- package/src/lib/reddb/connection-bootstrap.ts +260 -0
- package/src/lib/reddb/connection-provider.contract.ts +72 -0
- package/src/lib/reddb/connection-provider.ts +72 -0
- package/src/lib/reddb/index.ts +14 -0
- package/src/lib/reddb/injected-client-provider.ts +76 -0
- package/src/lib/reddb/local-url-provider.ts +245 -0
- package/src/lib/reddb/secure-store.ts +41 -0
- package/src/lib/reddb/server-capabilities.ts +71 -0
- package/src/lib/reddb/tauri-encrypted-store.ts +64 -0
- package/src/lib/reddb/transports.ts +89 -0
- package/src/lib/reddb/types.ts +32 -0
- package/src/lib/reddb/uri.ts +54 -0
- package/src/lib/reddb/web-encrypted-store.ts +201 -0
- package/src/lib/renderers/DiffRenderer.svelte +184 -0
- package/src/lib/renderers/DocumentRenderer.svelte +134 -0
- package/src/lib/renderers/GraphRenderer.svelte +1328 -0
- package/src/lib/renderers/HypertableRenderer.svelte +253 -0
- package/src/lib/renderers/JsonRenderer.svelte +30 -0
- package/src/lib/renderers/KvRenderer.svelte +150 -0
- package/src/lib/renderers/QueueRenderer.svelte +286 -0
- package/src/lib/renderers/StatsRenderer.svelte +123 -0
- package/src/lib/renderers/TableRenderer.svelte +440 -0
- package/src/lib/renderers/VectorRenderer.svelte +388 -0
- package/src/lib/renderers/diff-render.ts +122 -0
- package/src/lib/renderers/diff.ts +9 -0
- package/src/lib/renderers/document-render.ts +64 -0
- package/src/lib/renderers/document.ts +9 -0
- package/src/lib/renderers/graph-render.ts +631 -0
- package/src/lib/renderers/graph-sigma.ts +395 -0
- package/src/lib/renderers/graph.ts +9 -0
- package/src/lib/renderers/hypertable-render.ts +320 -0
- package/src/lib/renderers/hypertable.ts +9 -0
- package/src/lib/renderers/index.ts +42 -0
- package/src/lib/renderers/json-render.ts +89 -0
- package/src/lib/renderers/json.ts +10 -0
- package/src/lib/renderers/kv-render.ts +193 -0
- package/src/lib/renderers/kv.ts +9 -0
- package/src/lib/renderers/queue-render.ts +197 -0
- package/src/lib/renderers/queue.ts +9 -0
- package/src/lib/renderers/registry.ts +68 -0
- package/src/lib/renderers/stats-render.ts +73 -0
- package/src/lib/renderers/stats.ts +9 -0
- package/src/lib/renderers/table-render.ts +156 -0
- package/src/lib/renderers/table.ts +11 -0
- package/src/lib/renderers/types.ts +33 -0
- package/src/lib/renderers/vector-render.ts +154 -0
- package/src/lib/renderers/vector.ts +9 -0
- package/src/lib/router.svelte.ts +163 -0
- package/src/lib/secureStore.svelte.ts +148 -0
- package/src/lib/shadow-dom-spike/ShadowDomSpikeCore.svelte +198 -0
- package/src/lib/shadow-dom-spike/mount-shadow-dom-spike.ts +94 -0
- package/src/lib/shortcuts.ts +22 -0
- package/src/lib/surface.ts +80 -0
- package/src/lib/tabs.svelte.ts +115 -0
- package/src/lib/theme.svelte.ts +63 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { pendingChanges, buildUpdateSql } from './pending-changes.svelte'
|
|
3
|
+
import { connection } from './connections.svelte'
|
|
4
|
+
import { X, AlertTriangle, Lock } from 'lucide-svelte'
|
|
5
|
+
|
|
6
|
+
// Mutations are committed against the server; block them while it reports
|
|
7
|
+
// read-only (#23). The reason explains *why* the control is disabled.
|
|
8
|
+
const readOnly = $derived(connection.readOnly)
|
|
9
|
+
const readOnlyReason = $derived(connection.readOnlyReason)
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
open: boolean
|
|
13
|
+
onClose: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { open, onClose }: Props = $props()
|
|
17
|
+
|
|
18
|
+
let committing = $state(false)
|
|
19
|
+
let lastError = $state<string | null>(null)
|
|
20
|
+
|
|
21
|
+
async function apply() {
|
|
22
|
+
if (committing) return
|
|
23
|
+
committing = true
|
|
24
|
+
lastError = null
|
|
25
|
+
try {
|
|
26
|
+
const r = await pendingChanges.commitAll()
|
|
27
|
+
if (r.failed.length === 0) {
|
|
28
|
+
onClose()
|
|
29
|
+
}
|
|
30
|
+
// On partial failure the panel stays open so the user can see the
|
|
31
|
+
// failures inline. We don't auto-close.
|
|
32
|
+
} catch (e) {
|
|
33
|
+
lastError = (e as Error).message
|
|
34
|
+
} finally {
|
|
35
|
+
committing = false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function discard() {
|
|
40
|
+
pendingChanges.discardAll()
|
|
41
|
+
onClose()
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
{#if open}
|
|
46
|
+
<div
|
|
47
|
+
class="fixed inset-0 z-50 grid place-items-center bg-bg-0/70 backdrop-blur-sm motion-reduce:backdrop-blur-none"
|
|
48
|
+
role="dialog"
|
|
49
|
+
aria-modal="true"
|
|
50
|
+
aria-label="Pending changes"
|
|
51
|
+
>
|
|
52
|
+
<div class="w-full max-w-2xl mx-4 bg-bg-1 border border-line-1 rounded-md shadow-lg overflow-hidden">
|
|
53
|
+
<div class="flex items-center justify-between px-4 py-3 border-b border-line-1">
|
|
54
|
+
<div>
|
|
55
|
+
<h2 class="type-h3 m-0">Pending changes</h2>
|
|
56
|
+
<p class="text-fg-3 text-[11px] font-mono m-0 mt-0.5">
|
|
57
|
+
{pendingChanges.count} staged · review before applying
|
|
58
|
+
</p>
|
|
59
|
+
</div>
|
|
60
|
+
<button
|
|
61
|
+
type="button"
|
|
62
|
+
class="p-1 text-fg-3 hover:text-fg-1"
|
|
63
|
+
aria-label="Close"
|
|
64
|
+
onclick={onClose}
|
|
65
|
+
>
|
|
66
|
+
<X class="size-4" />
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="max-h-[50vh] overflow-auto px-4 py-3">
|
|
71
|
+
{#if pendingChanges.count === 0}
|
|
72
|
+
<div class="text-fg-3 text-[12px] font-mono py-6 text-center">
|
|
73
|
+
No staged changes.
|
|
74
|
+
</div>
|
|
75
|
+
{:else}
|
|
76
|
+
<ul class="space-y-2 text-[12px] font-mono">
|
|
77
|
+
{#each pendingChanges.changes as change (change.id)}
|
|
78
|
+
<li class="border border-line-1 rounded px-2 py-1.5 bg-bg-2/30">
|
|
79
|
+
<div class="flex items-center justify-between gap-2 mb-1">
|
|
80
|
+
<span class="text-fg-2">
|
|
81
|
+
<span class="text-fg-1">{change.table}</span>
|
|
82
|
+
<span class="text-fg-3"> · rid </span>
|
|
83
|
+
<span class="text-fg-1 tabular-nums">{change.row}</span>
|
|
84
|
+
<span class="text-fg-3"> · </span>
|
|
85
|
+
<span class="text-fg-1">{change.col}</span>
|
|
86
|
+
</span>
|
|
87
|
+
<button
|
|
88
|
+
type="button"
|
|
89
|
+
class="text-fg-3 hover:text-fg-1 text-[11px]"
|
|
90
|
+
onclick={() => pendingChanges.unstage(change.id)}
|
|
91
|
+
>
|
|
92
|
+
Unstage
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="text-[11px] grid grid-cols-[auto_1fr] gap-x-2 gap-y-0.5">
|
|
96
|
+
<span class="text-fg-3">old</span>
|
|
97
|
+
<span class="text-fg-2 truncate">{String(change.oldValue ?? 'NULL')}</span>
|
|
98
|
+
<span class="text-fg-3">new</span>
|
|
99
|
+
<span class="text-accent truncate">{change.newValue}</span>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="text-fg-3 text-[10.5px] mt-1 truncate">
|
|
102
|
+
{buildUpdateSql(change)}
|
|
103
|
+
</div>
|
|
104
|
+
{#if change.error}
|
|
105
|
+
<div class="text-warn text-[11px] mt-1 inline-flex items-center gap-1">
|
|
106
|
+
<AlertTriangle class="size-3" /> {change.error}
|
|
107
|
+
</div>
|
|
108
|
+
{/if}
|
|
109
|
+
</li>
|
|
110
|
+
{/each}
|
|
111
|
+
</ul>
|
|
112
|
+
{/if}
|
|
113
|
+
{#if lastError}
|
|
114
|
+
<div class="text-warn text-[11px] font-mono mt-2">{lastError}</div>
|
|
115
|
+
{/if}
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
{#if readOnly}
|
|
119
|
+
<div class="flex items-center gap-1.5 px-4 py-2 text-warn text-[11px] font-mono border-t border-line-1 bg-warn/5">
|
|
120
|
+
<Lock class="size-3 shrink-0" />
|
|
121
|
+
<span>{readOnlyReason ?? 'Server is read-only (file in use) — changes can’t be applied.'}</span>
|
|
122
|
+
</div>
|
|
123
|
+
{/if}
|
|
124
|
+
|
|
125
|
+
<div class="flex items-center justify-end gap-2 px-4 py-3 border-t border-line-1 bg-bg-1/60">
|
|
126
|
+
<button
|
|
127
|
+
type="button"
|
|
128
|
+
class="text-[12px] font-mono px-3 py-1 text-fg-3 hover:text-fg-1"
|
|
129
|
+
onclick={onClose}
|
|
130
|
+
>
|
|
131
|
+
Cancel
|
|
132
|
+
</button>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
class="text-[12px] font-mono px-3 py-1 text-fg-1 border border-line-1 rounded hover:bg-bg-2"
|
|
136
|
+
onclick={discard}
|
|
137
|
+
disabled={pendingChanges.count === 0}
|
|
138
|
+
>
|
|
139
|
+
Discard all
|
|
140
|
+
</button>
|
|
141
|
+
<button
|
|
142
|
+
type="button"
|
|
143
|
+
class="text-[12px] font-mono px-3 py-1 bg-accent text-white rounded disabled:opacity-50"
|
|
144
|
+
onclick={apply}
|
|
145
|
+
disabled={pendingChanges.count === 0 || committing || readOnly}
|
|
146
|
+
title={readOnly ? (readOnlyReason ?? 'Server is read-only — mutations are disabled.') : undefined}
|
|
147
|
+
>
|
|
148
|
+
{committing ? 'Applying…' : 'Apply all'}
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
{/if}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Play, Loader2 } from 'lucide-svelte'
|
|
3
|
+
import { connection } from '$lib/connections.svelte'
|
|
4
|
+
import { queryTabs, deriveQueryLabel } from '$lib/query-tabs.svelte'
|
|
5
|
+
import { tabs } from '$lib/tabs.svelte'
|
|
6
|
+
import { registry } from '$lib/renderers'
|
|
7
|
+
import type { Capability } from '$lib/renderers'
|
|
8
|
+
import { Kbd } from '@reddb-io/ui-kit'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
tabId: string
|
|
12
|
+
fallbackLabel: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { tabId, fallbackLabel }: Props = $props()
|
|
16
|
+
|
|
17
|
+
// Ensure qs exists for this tab id.
|
|
18
|
+
$effect(() => {
|
|
19
|
+
queryTabs.ensure(tabId)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const qs = $derived(queryTabs.states[tabId])
|
|
23
|
+
const tab = $derived(tabs.tabs.find((t) => t.id === tabId))
|
|
24
|
+
|
|
25
|
+
let textareaEl: HTMLTextAreaElement | undefined = $state()
|
|
26
|
+
|
|
27
|
+
function setSql(value: string) {
|
|
28
|
+
queryTabs.setSql(tabId, value)
|
|
29
|
+
// Re-derive label live as the user types.
|
|
30
|
+
const label = deriveQueryLabel(value, fallbackLabel)
|
|
31
|
+
const tab = tabs.tabs.find((t) => t.id === tabId)
|
|
32
|
+
if (tab && tab.label !== label) tabs.rename(tabId, label)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function run() {
|
|
36
|
+
await queryTabs.run(tabId)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function onKey(e: KeyboardEvent) {
|
|
40
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
|
|
41
|
+
e.preventDefault()
|
|
42
|
+
void run()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function pickRenderer() {
|
|
47
|
+
if (!qs?.result) return null
|
|
48
|
+
return registry.pick(qs.result.capability as Capability | undefined, qs.result, tab?.overrideCapability)
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<div class="flex h-full flex-col">
|
|
53
|
+
<div class="flex flex-col border-b border-line-1 bg-bg-0" style="height: 40%;">
|
|
54
|
+
<div class="flex items-center justify-between px-3 py-1.5 border-b border-line-1">
|
|
55
|
+
<div class="flex items-center gap-2 text-fg-3 type-label">
|
|
56
|
+
<span>SQL</span>
|
|
57
|
+
{#if connection.connected}
|
|
58
|
+
<span class="text-fg-3">·</span>
|
|
59
|
+
<span class="text-fg-2 font-mono text-[11px] truncate max-w-[280px]">{connection.active.url}</span>
|
|
60
|
+
{:else}
|
|
61
|
+
<span class="text-warn font-mono text-[11px]">disconnected</span>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
<div class="flex items-center gap-2">
|
|
65
|
+
<span class="text-fg-3 font-mono text-[11px] hidden sm:inline">Run with <Kbd>⌘</Kbd><Kbd>↵</Kbd></span>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
class="inline-flex items-center gap-1 rounded border border-accent/60 bg-accent/10 px-2 py-1 text-[12px] font-mono text-accent hover:bg-accent/20 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
69
|
+
onclick={run}
|
|
70
|
+
disabled={qs?.running || !connection.connected}
|
|
71
|
+
aria-label="Run query"
|
|
72
|
+
>
|
|
73
|
+
{#if qs?.running}
|
|
74
|
+
<Loader2 class="size-3.5 animate-spin" />
|
|
75
|
+
<span>Running…</span>
|
|
76
|
+
{:else}
|
|
77
|
+
<Play class="size-3.5" />
|
|
78
|
+
<span>Run</span>
|
|
79
|
+
{/if}
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<textarea
|
|
84
|
+
bind:this={textareaEl}
|
|
85
|
+
class="flex-1 resize-none bg-bg-0 px-3 py-2 font-mono text-[13px] text-fg-1 outline-none placeholder:text-fg-3"
|
|
86
|
+
spellcheck="false"
|
|
87
|
+
autocapitalize="off"
|
|
88
|
+
placeholder={'SELECT * FROM users LIMIT 100'}
|
|
89
|
+
value={qs?.sql ?? ''}
|
|
90
|
+
oninput={(e) => setSql((e.currentTarget as HTMLTextAreaElement).value)}
|
|
91
|
+
onkeydown={onKey}
|
|
92
|
+
></textarea>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="flex-1 overflow-hidden bg-bg-0">
|
|
96
|
+
{#if qs?.error}
|
|
97
|
+
<div class="p-4 text-[12px] font-mono text-warn">
|
|
98
|
+
<div class="font-semibold mb-1">Query failed</div>
|
|
99
|
+
<pre class="whitespace-pre-wrap">{qs.error}</pre>
|
|
100
|
+
</div>
|
|
101
|
+
{:else if qs?.running && !qs.result}
|
|
102
|
+
<div class="h-full grid place-items-center text-fg-3 text-[12px] font-mono">
|
|
103
|
+
Running…
|
|
104
|
+
</div>
|
|
105
|
+
{:else if !qs?.result}
|
|
106
|
+
<div class="h-full grid place-items-center text-fg-3 text-[12px] font-mono">
|
|
107
|
+
Run a query to see results here.
|
|
108
|
+
</div>
|
|
109
|
+
{:else}
|
|
110
|
+
{#if qs.result.truncated}
|
|
111
|
+
<div class="px-3 py-1.5 border-b border-line-1 bg-bg-1 text-[11px] font-mono text-fg-3">
|
|
112
|
+
Streamed first {qs.result.record_count.toLocaleString()} rows — more remain on the server. Add a <span class="text-fg-2">LIMIT</span> to narrow.
|
|
113
|
+
</div>
|
|
114
|
+
{/if}
|
|
115
|
+
{@const renderer = pickRenderer()}
|
|
116
|
+
{#if renderer}
|
|
117
|
+
{@const Renderer = renderer.component}
|
|
118
|
+
<Renderer result={qs.result} showSystem={tab?.showSystemColumns ?? false} />
|
|
119
|
+
{/if}
|
|
120
|
+
{/if}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|