admindb 2.1.1 → 2.3.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/README.md +368 -335
- package/dist/app.js +227 -1
- package/dist/auth/config.d.ts +1 -1
- package/dist/auth/config.js +109 -1
- package/dist/auth/crypto.js +98 -1
- package/dist/auth/index.js +21 -1
- package/dist/auth/middleware.js +78 -1
- package/dist/auth/routes.js +64 -1
- package/dist/auth/types.js +7 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +309 -1
- package/dist/cli/config.js +118 -1
- package/dist/cli/index.js +20 -1
- package/dist/cli/runner.js +208 -1
- package/dist/cli.js +4 -1
- package/dist/data/chain.d.ts +1 -0
- package/dist/data/chain.js +130 -0
- package/dist/data/datasets.d.ts +1 -1
- package/dist/data/datasets.js +171 -1
- package/dist/data/detector.d.ts +1 -1
- package/dist/data/detector.js +535 -1
- package/dist/data/engine.d.ts +1 -1
- package/dist/data/engine.js +586 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +30 -1
- package/dist/data/prng.d.ts +1 -0
- package/dist/data/prng.js +73 -0
- package/dist/data/registry.d.ts +1 -0
- package/dist/data/registry.js +805 -0
- package/dist/data/schema-graph.d.ts +1 -0
- package/dist/data/schema-graph.js +210 -0
- package/dist/data/strategies.d.ts +1 -1
- package/dist/data/strategies.js +100 -1
- package/dist/data/templates.d.ts +1 -0
- package/dist/data/templates.js +134 -0
- package/dist/data/types.d.ts +1 -1
- package/dist/data/types.js +5 -1
- package/dist/data/validator.d.ts +1 -0
- package/dist/data/validator.js +160 -0
- package/dist/db/database.d.ts +1 -1
- package/dist/db/database.js +472 -1
- package/dist/db/export.d.ts +1 -1
- package/dist/db/export.js +67 -1
- package/dist/db/filters.d.ts +1 -1
- package/dist/db/filters.js +119 -1
- package/dist/db/index.js +24 -1
- package/dist/db/introspection.js +164 -1
- package/dist/db/manager.js +327 -1
- package/dist/db/migrations.js +100 -1
- package/dist/db/postgres.d.ts +1 -1
- package/dist/db/postgres.js +687 -1
- package/dist/db/types.d.ts +1 -1
- package/dist/db/types.js +6 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +52 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/api.js +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/common.js +1 -0
- package/dist/public/js/databases.js +1 -1
- package/dist/public/js/designer.js +1 -1
- package/dist/public/js/forms.js +1 -1
- package/dist/public/js/home.js +1 -0
- package/dist/public/js/inspector.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/schema.js +1 -1
- package/dist/public/js/seed.js +1 -1
- package/dist/routes/api/erd.d.ts +1 -0
- package/dist/routes/api/erd.js +45 -0
- package/dist/routes/api/helpers.d.ts +1 -1
- package/dist/routes/api/helpers.js +213 -1
- package/dist/routes/api/import-export.js +82 -1
- package/dist/routes/api/index.js +48 -1
- package/dist/routes/api/query.js +74 -1
- package/dist/routes/api/rows.js +358 -1
- package/dist/routes/api/seed.js +167 -1
- package/dist/routes/api/tables.js +216 -1
- package/dist/routes/databases.js +210 -1
- package/dist/routes/index.js +19 -1
- package/dist/routes/pages.js +446 -1
- package/dist/serverless.js +149 -1
- package/dist/sql/classifier.js +24 -1
- package/dist/sql/error-analyzer.d.ts +1 -0
- package/dist/sql/error-analyzer.js +550 -0
- package/dist/sql/generator.d.ts +1 -1
- package/dist/sql/generator.js +245 -1
- package/dist/sql/index.js +18 -1
- package/dist/types/api.d.ts +1 -1
- package/dist/types/api.js +2 -1
- package/dist/utils/colors.js +54 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +185 -1
- package/dist/utils/csv.d.ts +1 -1
- package/dist/utils/csv.js +61 -1
- package/dist/utils/datatype.js +167 -1
- package/dist/utils/icons.js +81 -1
- package/dist/utils/index.js +20 -1
- package/dist/utils/logger.js +36 -1
- package/dist/views/layouts/main.hbs +1 -74
- package/dist/views/pages/databases.hbs +1 -233
- package/dist/views/pages/designer.hbs +1 -89
- package/dist/views/pages/erd.hbs +1 -0
- package/dist/views/pages/error.hbs +1 -10
- package/dist/views/pages/form.hbs +1 -59
- package/dist/views/pages/home.hbs +1 -124
- package/dist/views/pages/info.hbs +1 -0
- package/dist/views/pages/login.hbs +1 -98
- package/dist/views/pages/query.hbs +1 -87
- package/dist/views/pages/schema.hbs +1 -298
- package/dist/views/pages/seed-select.hbs +251 -0
- package/dist/views/pages/seed.hbs +273 -167
- package/dist/views/pages/table.hbs +1 -327
- package/dist/views/partials/navbar.hbs +1 -83
- package/dist/views/partials/sidebar.hbs +1 -117
- package/docs/API.md +149 -144
- package/docs/EXAMPLES.md +579 -576
- package/docs/SECURITY.md +265 -265
- package/package.json +79 -78
- package/dist/public/js/icons.js +0 -1
|
@@ -1,98 +1 @@
|
|
|
1
|
-
<div class="flex min-h-[75vh] items-center justify-center py-6 px-4">
|
|
2
|
-
<div class="w-full max-w-md">
|
|
3
|
-
<div class="mb-8 text-center">
|
|
4
|
-
<div class="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 text-primary shadow-soft">
|
|
5
|
-
{{{icon "database" class="h-8 w-8"}}}
|
|
6
|
-
</div>
|
|
7
|
-
<h1 class="text-2xl font-extrabold tracking-tight text-base-content sm:text-3xl">
|
|
8
|
-
Admin<span class="text-primary">DB</span>
|
|
9
|
-
</h1>
|
|
10
|
-
<p class="mt-1 text-sm text-base-content/60">
|
|
11
|
-
Sign in to access your database administration console
|
|
12
|
-
</p>
|
|
13
|
-
</div>
|
|
14
|
-
<div class="app-card border border-base-300/80 bg-base-100 p-6 sm:p-8 shadow-soft">
|
|
15
|
-
{{#if error}}
|
|
16
|
-
<div class="mb-6 flex items-start gap-3 rounded-xl bg-error/10 p-4 text-sm text-error border border-error/20" role="alert">
|
|
17
|
-
<span class="shrink-0 mt-0.5">
|
|
18
|
-
{{{icon "warning" class="h-5 w-5"}}}
|
|
19
|
-
</span>
|
|
20
|
-
<div class="font-medium">{{error}}</div>
|
|
21
|
-
</div>
|
|
22
|
-
{{/if}}
|
|
23
|
-
{{#if isDefaultPassword}}
|
|
24
|
-
<div class="mb-6 rounded-xl bg-info/10 p-3.5 text-xs text-info border border-info/20">
|
|
25
|
-
<div class="font-semibold flex items-center gap-1.5 mb-1">
|
|
26
|
-
{{{icon "warning" class="h-4 w-4 shrink-0"}}}
|
|
27
|
-
Default Credentials Active
|
|
28
|
-
</div>
|
|
29
|
-
<p class="text-base-content/70">
|
|
30
|
-
Username: <code class="font-mono font-semibold text-primary">admin</code> · Password: <code class="font-mono font-semibold text-primary">admin</code>
|
|
31
|
-
</p>
|
|
32
|
-
<p class="mt-1 text-[11px] text-base-content/50">
|
|
33
|
-
Set <code class="font-mono">ADMINDB_PASSWORD</code> in production to secure your console.
|
|
34
|
-
</p>
|
|
35
|
-
</div>
|
|
36
|
-
{{/if}}
|
|
37
|
-
<form method="POST" action="{{basePath}}/login" class="space-y-4">
|
|
38
|
-
{{#if next}}
|
|
39
|
-
<input type="hidden" name="next" value="{{next}}" />
|
|
40
|
-
{{/if}}
|
|
41
|
-
<div>
|
|
42
|
-
<label class="field-label" for="login-username">
|
|
43
|
-
<span>Username</span>
|
|
44
|
-
</label>
|
|
45
|
-
<div class="relative">
|
|
46
|
-
<input
|
|
47
|
-
id="login-username"
|
|
48
|
-
type="text"
|
|
49
|
-
name="username"
|
|
50
|
-
value="{{#if username}}{{username}}{{else}}admin{{/if}}"
|
|
51
|
-
required
|
|
52
|
-
autofocus
|
|
53
|
-
placeholder="Username"
|
|
54
|
-
class="field-input pl-10"
|
|
55
|
-
autocomplete="username"
|
|
56
|
-
/>
|
|
57
|
-
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-base-content/40">
|
|
58
|
-
{{{icon "user" class="h-5 w-5"}}}
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<div>
|
|
63
|
-
<label class="field-label" for="login-password">
|
|
64
|
-
<span>Password</span>
|
|
65
|
-
</label>
|
|
66
|
-
<div class="relative">
|
|
67
|
-
<input
|
|
68
|
-
id="login-password"
|
|
69
|
-
type="password"
|
|
70
|
-
name="password"
|
|
71
|
-
required
|
|
72
|
-
placeholder="••••••••"
|
|
73
|
-
class="field-input pl-10"
|
|
74
|
-
autocomplete="current-password"
|
|
75
|
-
/>
|
|
76
|
-
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-base-content/40">
|
|
77
|
-
{{{icon "lock" class="h-5 w-5"}}}
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
<div class="pt-2">
|
|
82
|
-
<button type="submit" class="btn btn-primary w-full gap-2 font-semibold shadow-soft">
|
|
83
|
-
{{{icon "logout" class="h-4 w-4 rotate-180"}}}
|
|
84
|
-
Sign In
|
|
85
|
-
</button>
|
|
86
|
-
</div>
|
|
87
|
-
</form>
|
|
88
|
-
</div>
|
|
89
|
-
<div class="mt-6 space-y-2 text-center text-xs text-base-content/55">
|
|
90
|
-
<p class="leading-relaxed">
|
|
91
|
-
<span class="font-semibold text-base-content/80">Security Notice:</span> Built-in auth provides basic access control. For production, protect your admin routes using your own application authentication, VPN, or reverse proxy.
|
|
92
|
-
</p>
|
|
93
|
-
<p class="text-base-content/40">
|
|
94
|
-
Native authentication can be disabled via <code class="font-mono">--no-auth</code> or <code class="font-mono">auth: false</code>.
|
|
95
|
-
</p>
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
1
|
+
<div class="flex min-h-[75vh] items-center justify-center py-6 px-4">
|
|
99
2
|
<div class="w-full max-w-md">
|
|
100
3
|
<div class="mb-8 text-center">
|
|
101
4
|
<div class="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 text-primary shadow-soft">
|
|
102
5
|
{{{icon "database" class="h-8 w-8"}}}
|
|
103
6
|
</div>
|
|
104
7
|
<h1 class="font-headings text-2xl font-extrabold tracking-tight text-base-content sm:text-3xl">
|
|
105
8
|
Admin<span class="text-primary">DB</span>
|
|
106
9
|
</h1>
|
|
107
10
|
<p class="mt-1 text-sm text-base-content/60">
|
|
108
11
|
Sign in to access your database administration console
|
|
109
12
|
</p>
|
|
110
13
|
</div>
|
|
111
14
|
<div class="app-card border bg-base-100/90 p-6 sm:p-8 shadow-card backdrop-blur-md">
|
|
112
15
|
{{#if error}}
|
|
113
16
|
<div class="mb-6 flex items-start gap-3 rounded-xl bg-error/10 p-4 text-sm text-error border border-error/20" role="alert">
|
|
114
17
|
<span class="shrink-0 mt-0.5">
|
|
115
18
|
{{{icon "warning" class="h-5 w-5"}}}
|
|
116
19
|
</span>
|
|
117
20
|
<div class="font-medium">{{error}}</div>
|
|
118
21
|
</div>
|
|
119
22
|
{{/if}}
|
|
120
23
|
{{#if isDefaultPassword}}
|
|
121
24
|
<div class="mb-6 rounded-xl bg-info/10 p-3.5 text-xs text-info border border-info/20">
|
|
122
25
|
<div class="font-semibold flex items-center gap-1.5 mb-1">
|
|
123
26
|
{{{icon "warning" class="h-4 w-4 shrink-0"}}}
|
|
124
27
|
Default Credentials Active
|
|
125
28
|
</div>
|
|
126
29
|
<p class="text-base-content/70">
|
|
127
30
|
Username: <code class="font-mono font-semibold text-primary">admin</code> · Password: <code class="font-mono font-semibold text-primary">admin</code>
|
|
128
31
|
</p>
|
|
129
32
|
<p class="mt-1 text-[11px] text-base-content/50">
|
|
130
33
|
Set <code class="font-mono">ADMINDB_PASSWORD</code> in production to secure your console.
|
|
131
34
|
</p>
|
|
132
35
|
</div>
|
|
133
36
|
{{/if}}
|
|
134
37
|
<form method="POST" action="{{basePath}}/login" class="space-y-4">
|
|
135
38
|
{{#if next}}
|
|
136
39
|
<input type="hidden" name="next" value="{{next}}" />
|
|
137
40
|
{{/if}}
|
|
138
41
|
<div>
|
|
139
42
|
<label class="field-label" for="login-username">
|
|
140
43
|
<span>Username</span>
|
|
141
44
|
</label>
|
|
142
45
|
<div class="relative">
|
|
143
46
|
<input
|
|
144
47
|
id="login-username"
|
|
145
48
|
type="text"
|
|
146
49
|
name="username"
|
|
147
50
|
value="{{#if username}}{{username}}{{else}}admin{{/if}}"
|
|
148
51
|
required
|
|
149
52
|
autofocus
|
|
150
53
|
placeholder="Username"
|
|
151
54
|
class="field-input pl-10"
|
|
152
55
|
autocomplete="username"
|
|
153
56
|
/>
|
|
154
57
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-base-content/40">
|
|
155
58
|
{{{icon "user" class="h-5 w-5"}}}
|
|
156
59
|
</div>
|
|
157
60
|
</div>
|
|
158
61
|
</div>
|
|
159
62
|
<div>
|
|
160
63
|
<label class="field-label" for="login-password">
|
|
161
64
|
<span>Password</span>
|
|
162
65
|
</label>
|
|
163
66
|
<div class="relative">
|
|
164
67
|
<input
|
|
165
68
|
id="login-password"
|
|
166
69
|
type="password"
|
|
167
70
|
name="password"
|
|
168
71
|
required
|
|
169
72
|
placeholder="••••••••"
|
|
170
73
|
class="field-input pl-10"
|
|
171
74
|
autocomplete="current-password"
|
|
172
75
|
/>
|
|
173
76
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-base-content/40">
|
|
174
77
|
{{{icon "lock" class="h-5 w-5"}}}
|
|
175
78
|
</div>
|
|
176
79
|
</div>
|
|
177
80
|
</div>
|
|
178
81
|
<div class="pt-2">
|
|
179
82
|
<button type="submit" class="btn btn-primary w-full gap-2 font-semibold shadow-soft">
|
|
180
83
|
{{{icon "logout" class="h-4 w-4 rotate-180"}}}
|
|
181
84
|
Sign In
|
|
182
85
|
</button>
|
|
183
86
|
</div>
|
|
184
87
|
</form>
|
|
185
88
|
</div>
|
|
186
89
|
<div class="mt-6 space-y-2 text-center text-xs text-base-content/55">
|
|
187
90
|
<p class="leading-relaxed">
|
|
188
91
|
<span class="font-semibold text-base-content/80">Security Notice:</span> Built-in auth provides basic access control. For production, protect your admin routes using your own application authentication, VPN, or reverse proxy.
|
|
189
92
|
</p>
|
|
190
93
|
<p class="text-base-content/40">
|
|
191
94
|
Native authentication can be disabled via <code class="font-mono">--no-auth</code> or <code class="font-mono">auth: false</code>.
|
|
192
95
|
</p>
|
|
193
96
|
</div>
|
|
194
97
|
</div>
|
|
@@ -1,87 +1 @@
|
|
|
1
|
-
<div class="space-y-6">
|
|
2
|
-
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
3
|
-
<div>
|
|
4
|
-
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Workspace</p>
|
|
5
|
-
<h1 class="mt-1 text-3xl font-extrabold tracking-tight">Query editor</h1>
|
|
6
|
-
<p class="mt-1.5 text-sm text-base-content/55">Run arbitrary SQL — SELECT results render as a table, COUNT gives a summary, and write statements execute.</p>
|
|
7
|
-
</div>
|
|
8
|
-
<div class="flex flex-wrap gap-2">
|
|
9
|
-
{{#unless readonly}}
|
|
10
|
-
<button id="save-query" type="button" class="btn btn-outline btn-sm gap-1.5">
|
|
11
|
-
{{{icon "save" class="h-4 w-4"}}}
|
|
12
|
-
Save query
|
|
13
|
-
</button>
|
|
14
|
-
{{/unless}}
|
|
15
|
-
<button id="run-query" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
16
|
-
{{{icon "run" class="h-4 w-4"}}}
|
|
17
|
-
Run
|
|
18
|
-
</button>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="flex flex-wrap items-end gap-3">
|
|
22
|
-
<div class="form-control w-full max-w-xs">
|
|
23
|
-
<label class="field-label" for="saved-query-select">Saved queries</label>
|
|
24
|
-
<select id="saved-query-select" class="field-select">
|
|
25
|
-
<option value="">— select a saved query —</option>
|
|
26
|
-
{{#each savedQueries}}
|
|
27
|
-
<option value="{{this.id}}">{{this.name}}</option>
|
|
28
|
-
{{/each}}
|
|
29
|
-
</select>
|
|
30
|
-
</div>
|
|
31
|
-
{{#unless readonly}}
|
|
32
|
-
<button id="delete-query" type="button" class="btn btn-ghost btn-sm mb-0.5 text-error" disabled>Delete saved</button>
|
|
33
|
-
<div class="form-control w-full max-w-xs">
|
|
34
|
-
<label class="field-label" for="save-query-name">Save current SQL as</label>
|
|
35
|
-
<div class="join w-full">
|
|
36
|
-
<input id="save-query-name" type="text" class="field-input join-item !rounded-r-none" placeholder="query name" autocomplete="off" />
|
|
37
|
-
<button id="save-query-inline" type="button" class="btn btn-outline join-item">Save</button>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
{{/unless}}
|
|
41
|
-
</div>
|
|
42
|
-
<div class="app-card overflow-hidden">
|
|
43
|
-
<div class="flex items-center justify-between border-b border-base-200 bg-base-200/40 px-4 py-2.5">
|
|
44
|
-
<span class="flex items-center gap-2 text-sm font-semibold text-base-content/60">
|
|
45
|
-
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/10 text-primary">
|
|
46
|
-
{{{icon "query" class="h-3.5 w-3.5"}}}
|
|
47
|
-
</span>
|
|
48
|
-
query.sql
|
|
49
|
-
</span>
|
|
50
|
-
<span class="text-[11px] text-base-content/40">Ctrl/⌘ + Enter to run</span>
|
|
51
|
-
</div>
|
|
52
|
-
<div>
|
|
53
|
-
<div class="sql-editor-wrap">
|
|
54
|
-
<pre id="query-gutter" class="sql-gutter" aria-hidden="true">1</pre>
|
|
55
|
-
<textarea id="query-sql" class="sql-input" rows="10" placeholder="SELECT * FROM users WHERE …" spellcheck="false"></textarea>
|
|
56
|
-
</div>
|
|
57
|
-
<div id="query-message"></div>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div id="query-result" class="hidden">
|
|
61
|
-
<div class="app-card overflow-hidden">
|
|
62
|
-
<div class="flex items-center gap-2 border-b border-base-200 px-4 py-3">
|
|
63
|
-
<span id="result-kind" class="grid h-6 w-6 place-items-center rounded-md bg-success/10 text-success">
|
|
64
|
-
{{{icon "check" class="h-4 w-4"}}}
|
|
65
|
-
</span>
|
|
66
|
-
<span id="result-summary" class="text-sm font-medium text-base-content/60"></span>
|
|
67
|
-
<div class="ml-auto flex items-center gap-1.5">
|
|
68
|
-
<button id="export-csv" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" disabled>
|
|
69
|
-
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
70
|
-
CSV
|
|
71
|
-
</button>
|
|
72
|
-
<button id="export-json" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" disabled>
|
|
73
|
-
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
74
|
-
JSON
|
|
75
|
-
</button>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
<div class="overflow-x-auto">
|
|
79
|
-
<table class="table table-sm table-pin-rows">
|
|
80
|
-
<thead id="query-result-head" class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50"></thead>
|
|
81
|
-
<tbody id="query-result-body"></tbody>
|
|
82
|
-
</table>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
<script src="{{basePath}}/js/query.js" defer></script>
|
|
1
|
+
<div class="space-y-6">
|
|
88
2
|
<div class="page-header">
|
|
89
3
|
<div class="page-header-row">
|
|
90
4
|
<div>
|
|
91
5
|
<div class="page-pretitle">Workspace</div>
|
|
92
6
|
<h1 class="page-title">Query editor</h1>
|
|
93
7
|
<p class="mt-0.5 text-xs text-base-content/60">Run arbitrary SQL — SELECT results render as a table, COUNT gives a summary, and write statements execute.</p>
|
|
94
8
|
</div>
|
|
95
9
|
<div class="page-actions">
|
|
96
10
|
{{#unless readonly}}
|
|
97
11
|
<button id="save-query" type="button" class="btn btn-outline btn-sm gap-1.5">
|
|
98
12
|
{{{icon "save" class="h-4 w-4"}}}
|
|
99
13
|
Save query
|
|
100
14
|
</button>
|
|
101
15
|
{{/unless}}
|
|
102
16
|
<button id="run-query" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
103
17
|
{{{icon "run" class="h-4 w-4"}}}
|
|
104
18
|
Run query
|
|
105
19
|
</button>
|
|
106
20
|
</div>
|
|
107
21
|
</div>
|
|
108
22
|
</div>
|
|
109
23
|
<div class="flex flex-wrap items-end gap-3">
|
|
110
24
|
<div class="form-control w-full max-w-xs">
|
|
111
25
|
<label class="field-label" for="saved-query-select">Saved queries</label>
|
|
112
26
|
<select id="saved-query-select" class="field-select">
|
|
113
27
|
<option value="">— select a saved query —</option>
|
|
114
28
|
{{#each savedQueries}}
|
|
115
29
|
<option value="{{this.id}}">{{this.name}}</option>
|
|
116
30
|
{{/each}}
|
|
117
31
|
</select>
|
|
118
32
|
</div>
|
|
119
33
|
{{#unless readonly}}
|
|
120
34
|
<button id="delete-query" type="button" class="btn btn-ghost btn-sm mb-0.5 text-error" disabled>Delete saved</button>
|
|
121
35
|
<div class="form-control w-full max-w-xs">
|
|
122
36
|
<label class="field-label" for="save-query-name">Save current SQL as</label>
|
|
123
37
|
<div class="join w-full">
|
|
124
38
|
<input id="save-query-name" type="text" class="field-input join-item !rounded-r-none" placeholder="query name" autocomplete="off" />
|
|
125
39
|
<button id="save-query-inline" type="button" class="btn btn-outline join-item">Save</button>
|
|
126
40
|
</div>
|
|
127
41
|
</div>
|
|
128
42
|
{{/unless}}
|
|
129
43
|
</div>
|
|
130
44
|
<div class="app-card overflow-hidden">
|
|
131
45
|
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 bg-base-200/40 px-4 py-2">
|
|
132
46
|
<div class="flex items-center gap-2">
|
|
133
47
|
<span class="flex items-center gap-1.5 text-xs font-semibold text-base-content/70">
|
|
134
48
|
<span class="grid h-5 w-5 place-items-center rounded bg-primary/10 text-primary">
|
|
135
49
|
{{{icon "query" class="h-3.5 w-3.5"}}}
|
|
136
50
|
</span>
|
|
137
51
|
query.sql
|
|
138
52
|
</span>
|
|
139
53
|
<span class="badge badge-sm badge-ghost font-mono text-[10px] uppercase font-bold">{{#if isPostgres}}Postgres{{else}}SQLite{{/if}}</span>
|
|
140
54
|
</div>
|
|
141
55
|
<div class="flex flex-wrap items-center gap-1.5">
|
|
142
56
|
<div class="dropdown dropdown-end">
|
|
143
57
|
<label tabindex="0" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
|
|
144
58
|
{{{icon "terminal" class="h-3.5 w-3.5"}}}
|
|
145
59
|
Snippets
|
|
146
60
|
</label>
|
|
147
61
|
<ul tabindex="0" class="dropdown-content z-30 menu p-1.5 shadow-2xl bg-base-100 rounded-xl w-56 border border-base-300 text-xs">
|
|
148
62
|
<li class="menu-title text-[10px] uppercase tracking-wider text-base-content/40">Query Templates</li>
|
|
149
63
|
<li><a class="js-snippet" data-snippet="SELECT * FROM table_name\nWHERE condition\nORDER BY id DESC\nLIMIT 50;">SELECT rows</a></li>
|
|
150
64
|
<li><a class="js-snippet" data-snippet="SELECT COUNT(*) AS total\nFROM table_name;">COUNT summary</a></li>
|
|
151
65
|
<li><a class="js-snippet" data-snippet="SELECT a.*, b.*\nFROM table_a a\nJOIN table_b b ON b.a_id = a.id\nLIMIT 50;">JOIN tables</a></li>
|
|
152
66
|
<li><a class="js-snippet" data-snippet="INSERT INTO table_name (col1, col2)\nVALUES ('value1', 'value2');">INSERT row</a></li>
|
|
153
67
|
<li><a class="js-snippet" data-snippet="UPDATE table_name\nSET col1 = 'value1'\nWHERE id = 1;">UPDATE row</a></li>
|
|
154
68
|
<li><a class="js-snippet" data-snippet="DELETE FROM table_name\nWHERE id = 1;">DELETE row</a></li>
|
|
155
69
|
<li><a class="js-snippet" data-snippet="CREATE TABLE new_table (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n created_at TEXT DEFAULT (datetime('now'))\n);">CREATE TABLE</a></li>
|
|
156
70
|
</ul>
|
|
157
71
|
</div>
|
|
158
72
|
<button id="format-query" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" title="Format SQL (Beautify)">
|
|
159
73
|
{{{icon "format" class="h-3.5 w-3.5"}}}
|
|
160
74
|
Format
|
|
161
75
|
</button>
|
|
162
76
|
<button id="copy-query" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" title="Copy SQL to clipboard">
|
|
163
77
|
{{{icon "copy" class="h-3.5 w-3.5"}}}
|
|
164
78
|
Copy
|
|
165
79
|
</button>
|
|
166
80
|
<button id="clear-query" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-error" title="Clear editor">
|
|
167
81
|
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
168
82
|
Clear
|
|
169
83
|
</button>
|
|
170
84
|
<span class="hidden sm:inline-block text-[11px] text-base-content/35 border-l border-base-300 pl-2">Ctrl/⌘ + Enter to run</span>
|
|
171
85
|
</div>
|
|
172
86
|
</div>
|
|
173
87
|
<div class="sql-editor-wrap">
|
|
174
88
|
<div id="query-gutter" class="sql-gutter" aria-hidden="true">
|
|
175
89
|
<div class="sql-gutter-line">1</div>
|
|
176
90
|
</div>
|
|
177
91
|
<div class="sql-editor-stage">
|
|
178
92
|
<pre id="query-highlight" class="sql-code-highlight" aria-hidden="true"><code id="query-code"></code></pre>
|
|
179
93
|
<textarea id="query-sql" class="sql-code-input" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="-- Write SQL here or choose a snippet/saved query SELECT * FROM table_name WHERE …"></textarea>
|
|
180
94
|
</div>
|
|
181
95
|
</div>
|
|
182
96
|
<div class="flex items-center justify-between border-t border-base-200 bg-base-200/30 px-3.5 py-1.5 text-[11px] font-mono text-base-content/50">
|
|
183
97
|
<div class="flex items-center gap-3">
|
|
184
98
|
<span id="editor-cursor-pos">Ln 1, Col 1</span>
|
|
185
99
|
<span id="editor-stats">0 chars</span>
|
|
186
100
|
</div>
|
|
187
101
|
<div class="flex items-center gap-2">
|
|
188
102
|
<span class="text-[10px] text-base-content/40">Tab to indent · Ctrl+Z / Ctrl+Y to undo/redo · Ctrl+/ to comment</span>
|
|
189
103
|
</div>
|
|
190
104
|
</div>
|
|
191
105
|
<div id="query-message" class="p-3"></div>
|
|
192
106
|
</div>
|
|
193
107
|
<div id="query-result" class="hidden">
|
|
194
108
|
<div class="app-card overflow-hidden">
|
|
195
109
|
<div class="flex items-center gap-2 border-b border-base-200 px-4 py-3">
|
|
196
110
|
<span id="result-kind" class="grid h-6 w-6 place-items-center rounded-md bg-success/10 text-success">
|
|
197
111
|
{{{icon "check" class="h-4 w-4"}}}
|
|
198
112
|
</span>
|
|
199
113
|
<span id="result-summary" class="text-sm font-medium text-base-content/60"></span>
|
|
200
114
|
<div class="ml-auto flex items-center gap-1.5">
|
|
201
115
|
<button id="export-csv" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" disabled>
|
|
202
116
|
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
203
117
|
CSV
|
|
204
118
|
</button>
|
|
205
119
|
<button id="export-json" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary" disabled>
|
|
206
120
|
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
207
121
|
JSON
|
|
208
122
|
</button>
|
|
209
123
|
</div>
|
|
210
124
|
</div>
|
|
211
125
|
<div class="overflow-x-auto">
|
|
212
126
|
<table class="table table-sm table-pin-rows">
|
|
213
127
|
<thead id="query-result-head" class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50"></thead>
|
|
214
128
|
<tbody id="query-result-body"></tbody>
|
|
215
129
|
</table>
|
|
216
130
|
</div>
|
|
217
131
|
</div>
|
|
218
132
|
</div>
|