admindb 2.2.1 → 2.3.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/README.md +368 -364
- package/dist/app.js +25 -16
- package/dist/auth/config.d.ts +1 -1
- package/dist/auth/config.js +18 -30
- package/dist/auth/crypto.js +11 -21
- package/dist/auth/middleware.js +9 -16
- package/dist/auth/routes.js +9 -15
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +20 -29
- package/dist/cli/config.d.ts +1 -1
- package/dist/cli/config.js +15 -18
- package/dist/cli/runner.js +13 -13
- package/dist/data/chain.d.ts +1 -1
- package/dist/data/chain.js +40 -617
- package/dist/data/datasets.d.ts +1 -1
- package/dist/data/datasets.js +43 -1
- package/dist/data/detector.js +45 -21
- package/dist/data/engine.d.ts +1 -1
- package/dist/data/engine.js +483 -142
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +8 -0
- 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 +44 -283
- 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/validator.d.ts +1 -0
- package/dist/data/validator.js +160 -0
- package/dist/db/database.js +9 -14
- package/dist/db/export.js +32 -55
- package/dist/db/filters.d.ts +1 -1
- package/dist/db/filters.js +15 -38
- package/dist/db/introspection.js +4 -7
- package/dist/db/manager.d.ts +1 -1
- package/dist/db/manager.js +48 -53
- package/dist/db/migrations.js +7 -14
- package/dist/db/postgres.js +30 -78
- package/dist/index.d.ts +1 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/inspector.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/seed.js +1 -1
- package/dist/routes/api/erd.js +3 -8
- package/dist/routes/api/helpers.d.ts +1 -1
- package/dist/routes/api/helpers.js +75 -25
- package/dist/routes/api/import-export.js +1 -2
- package/dist/routes/api/query.js +2 -6
- package/dist/routes/api/rows.js +4 -8
- package/dist/routes/api/seed.js +35 -21
- package/dist/routes/api/tables.js +15 -30
- package/dist/routes/databases.js +8 -26
- package/dist/routes/pages.js +67 -18
- package/dist/serverless.js +31 -44
- package/dist/sql/generator.d.ts +1 -1
- package/dist/sql/generator.js +35 -109
- package/dist/types/api.d.ts +1 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +45 -85
- package/dist/utils/csv.d.ts +1 -1
- package/dist/utils/csv.js +11 -17
- package/dist/utils/datatype.js +46 -60
- package/dist/utils/icons.js +8 -8
- package/dist/views/layouts/main.hbs +1 -87
- package/dist/views/pages/databases.hbs +1 -233
- package/dist/views/pages/designer.hbs +1 -89
- package/dist/views/pages/erd.hbs +1 -1241
- package/dist/views/pages/error.hbs +1 -10
- package/dist/views/pages/form.hbs +1 -59
- package/dist/views/pages/home.hbs +1 -220
- package/dist/views/pages/info.hbs +1 -107
- package/dist/views/pages/login.hbs +1 -98
- package/dist/views/pages/query.hbs +1 -129
- package/dist/views/pages/schema.hbs +1 -298
- package/dist/views/pages/seed-select.hbs +251 -0
- package/dist/views/pages/seed.hbs +256 -414
- package/dist/views/pages/table.hbs +1 -327
- package/dist/views/partials/navbar.hbs +1 -83
- package/dist/views/partials/sidebar.hbs +1 -129
- package/docs/API.md +149 -149
- package/docs/EXAMPLES.md +579 -579
- package/docs/SECURITY.md +265 -265
- package/package.json +80 -79
|
@@ -1,233 +1 @@
|
|
|
1
|
-
<div class="space-y-6">
|
|
2
|
-
<div>
|
|
3
|
-
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Manager</p>
|
|
4
|
-
<h1 class="mt-1 text-3xl font-extrabold tracking-tight">Databases</h1>
|
|
5
|
-
<p class="mt-1.5 text-sm text-base-content/55">Connect to PostgreSQL databases, create SQLite files, or open existing local databases with configurable read/write access.</p>
|
|
6
|
-
</div>
|
|
7
|
-
<div class="grid grid-cols-1 gap-5 lg:grid-cols-2">
|
|
8
|
-
<div class="app-card p-5 border border-info/30 bg-info/[0.02]">
|
|
9
|
-
<div class="mb-3 flex items-center justify-between">
|
|
10
|
-
<h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-info">
|
|
11
|
-
{{{icon "database" class="h-4 w-4"}}}
|
|
12
|
-
Connect PostgreSQL
|
|
13
|
-
</h2>
|
|
14
|
-
<span class="rounded bg-info/15 px-2 py-0.5 text-[10px] font-bold text-info">Remote / Local</span>
|
|
15
|
-
</div>
|
|
16
|
-
<div class="space-y-3">
|
|
17
|
-
<div>
|
|
18
|
-
<label class="field-label" for="pg-conn-name">Connection Name <span class="text-base-content/40">(optional)</span></label>
|
|
19
|
-
<input id="pg-conn-name" class="field-input font-mono text-xs" placeholder="e.g. prod_postgres" autocomplete="off" spellcheck="false" />
|
|
20
|
-
</div>
|
|
21
|
-
<div>
|
|
22
|
-
<label class="field-label" for="pg-conn-uri">Connection URI <span class="chip chip-type">required</span></label>
|
|
23
|
-
<input id="pg-conn-uri" class="field-input font-mono text-xs" placeholder="postgresql://user:password@localhost:5432/mydb" autocomplete="off" spellcheck="false" />
|
|
24
|
-
</div>
|
|
25
|
-
<div>
|
|
26
|
-
<label class="flex items-center gap-2 cursor-pointer pt-0.5">
|
|
27
|
-
<input type="checkbox" id="pg-conn-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
|
|
28
|
-
<span class="text-xs font-medium text-base-content/75">Open as Read-only (block writes & schema changes)</span>
|
|
29
|
-
</label>
|
|
30
|
-
</div>
|
|
31
|
-
<div class="pt-1">
|
|
32
|
-
{{#unless readonly}}
|
|
33
|
-
<button id="connect-pg" type="button" class="btn btn-info btn-sm gap-1.5 w-full sm:w-auto">
|
|
34
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
35
|
-
Connect PostgreSQL
|
|
36
|
-
</button>
|
|
37
|
-
{{else}}
|
|
38
|
-
<span class="text-xs font-medium text-warning">Read-only mode — connecting databases is disabled.</span>
|
|
39
|
-
{{/unless}}
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
<p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
|
|
43
|
-
Credentials are encrypted in-memory and sanitized in the UI. Passwords are never sent to the client.
|
|
44
|
-
</p>
|
|
45
|
-
</div>
|
|
46
|
-
<div class="app-card p-5 border border-emerald-500/30 bg-emerald-500/[0.02]">
|
|
47
|
-
<div class="mb-3 flex items-center justify-between">
|
|
48
|
-
<h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-emerald-600 dark:text-emerald-400">
|
|
49
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
50
|
-
Create SQLite Database
|
|
51
|
-
</h2>
|
|
52
|
-
<span class="rounded bg-emerald-500/15 px-2 py-0.5 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">File-based</span>
|
|
53
|
-
</div>
|
|
54
|
-
<div class="space-y-3">
|
|
55
|
-
<div>
|
|
56
|
-
<label class="field-label" for="new-db-name">Database Name <span class="chip chip-type">required</span></label>
|
|
57
|
-
<input id="new-db-name" class="field-input font-mono text-xs" placeholder="e.g. analytics" autocomplete="off" spellcheck="false" />
|
|
58
|
-
</div>
|
|
59
|
-
<div class="pt-1">
|
|
60
|
-
{{#unless readonly}}
|
|
61
|
-
<button id="create-db" type="button" class="btn btn-primary btn-sm gap-1.5 w-full sm:w-auto">
|
|
62
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
63
|
-
Create SQLite DB
|
|
64
|
-
</button>
|
|
65
|
-
{{else}}
|
|
66
|
-
<span class="text-xs font-medium text-warning">Read-only — creating databases is disabled.</span>
|
|
67
|
-
{{/unless}}
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
<p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
|
|
71
|
-
Files are saved to <code class="font-mono">{{dbDir}}</code>. Any <code class="font-mono">.db</code> file dropped there is auto-discovered.
|
|
72
|
-
</p>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
<div>
|
|
76
|
-
<div class="mb-3 flex items-center justify-between">
|
|
77
|
-
<h2 class="text-lg font-bold">Available databases</h2>
|
|
78
|
-
<span class="text-sm text-base-content/45">{{databases.length}} total</span>
|
|
79
|
-
</div>
|
|
80
|
-
{{#if databases.length}}
|
|
81
|
-
<div class="app-card overflow-hidden">
|
|
82
|
-
<div class="overflow-x-auto">
|
|
83
|
-
<table class="table table-sm">
|
|
84
|
-
<thead>
|
|
85
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
86
|
-
<th class="font-semibold">Name</th>
|
|
87
|
-
<th class="font-semibold">Mode</th>
|
|
88
|
-
<th class="text-right font-semibold">Tables</th>
|
|
89
|
-
<th class="text-right font-semibold">Size</th>
|
|
90
|
-
<th class="font-semibold">Status / Modified</th>
|
|
91
|
-
<th class="text-right font-semibold">Actions</th>
|
|
92
|
-
</tr>
|
|
93
|
-
</thead>
|
|
94
|
-
<tbody>
|
|
95
|
-
{{#each databases}}
|
|
96
|
-
<tr class="group hover:bg-primary/[0.04]">
|
|
97
|
-
<td>
|
|
98
|
-
<a href="{{../basePath}}/{{this.id}}" class="inline-flex items-center gap-2.5">
|
|
99
|
-
<span class="grid h-8 w-8 shrink-0 place-items-center rounded-lg {{#if this.isPostgres}}bg-info/10 text-info group-hover:bg-info/20{{else}}bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 group-hover:bg-emerald-500/20{{/if}} transition-colors">
|
|
100
|
-
{{{icon "database" class="h-4 w-4"}}}
|
|
101
|
-
</span>
|
|
102
|
-
<span class="min-w-0">
|
|
103
|
-
<div class="flex items-center gap-1.5">
|
|
104
|
-
<span class="truncate font-mono text-[13.5px] font-semibold">{{this.name}}</span>
|
|
105
|
-
{{#if this.isPostgres}}
|
|
106
|
-
<span class="rounded bg-info/15 px-1.5 py-0.2 text-[10px] font-bold text-info">PostgreSQL</span>
|
|
107
|
-
{{else}}
|
|
108
|
-
<span class="rounded bg-emerald-500/15 px-1.5 py-0.2 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">SQLite</span>
|
|
109
|
-
{{/if}}
|
|
110
|
-
</div>
|
|
111
|
-
<span class="block max-w-[260px] truncate font-mono text-[11px] text-base-content/40" title="{{this.path}}">{{this.path}}</span>
|
|
112
|
-
</span>
|
|
113
|
-
</a>
|
|
114
|
-
</td>
|
|
115
|
-
<td class="align-middle">
|
|
116
|
-
{{#if ../readonly}}
|
|
117
|
-
<span class="rounded bg-warning/20 px-2 py-0.5 text-[10px] font-bold uppercase text-warning">Read-only</span>
|
|
118
|
-
{{else}}
|
|
119
|
-
<button type="button" class="js-toggle-db-mode rounded px-2 py-0.5 text-[10px] font-bold uppercase transition hover:opacity-80 {{#if this.readonly}}bg-warning/20 text-warning{{else}}bg-success/20 text-success{{/if}}"
|
|
120
|
-
data-id="{{this.id}}" data-readonly="{{#if this.readonly}}true{{else}}false{{/if}}" title="Click to toggle between Writable and Read-only">
|
|
121
|
-
{{#if this.readonly}}Read-only{{else}}Writable{{/if}} ⇄
|
|
122
|
-
</button>
|
|
123
|
-
{{/if}}
|
|
124
|
-
</td>
|
|
125
|
-
<td class="text-right tabular-nums text-base-content/60">{{this.tables}}</td>
|
|
126
|
-
<td class="text-right tabular-nums text-base-content/60">{{this.sizeLabel}}</td>
|
|
127
|
-
<td class="text-[13px] text-base-content/55">{{this.modifiedLabel}}</td>
|
|
128
|
-
<td class="whitespace-nowrap text-right">
|
|
129
|
-
<div class="row-actions">
|
|
130
|
-
<div class="join">
|
|
131
|
-
<a href="{{../basePath}}/{{this.id}}" class="btn btn-ghost btn-xs join-item gap-1 text-base-content/70 hover:text-primary">
|
|
132
|
-
{{{icon "arrowRight" class="h-3.5 w-3.5"}}}
|
|
133
|
-
Open
|
|
134
|
-
</a>
|
|
135
|
-
<div class="dropdown dropdown-end">
|
|
136
|
-
<label tabindex="0" role="button" class="btn btn-ghost btn-xs join-item px-1 text-base-content/60 hover:text-base-content" title="Open options">
|
|
137
|
-
{{{icon "chevronDown" class="h-3 w-3"}}}
|
|
138
|
-
</label>
|
|
139
|
-
<ul tabindex="0" class="dropdown-content menu z-50 w-44 rounded-xl border border-base-300 bg-base-100 p-1.5 shadow-lift text-xs">
|
|
140
|
-
<li>
|
|
141
|
-
<a href="{{../basePath}}/{{this.id}}?readonly=0" class="flex items-center gap-1.5 text-success">
|
|
142
|
-
{{{icon "check" class="h-3.5 w-3.5"}}}
|
|
143
|
-
Open Writable
|
|
144
|
-
</a>
|
|
145
|
-
</li>
|
|
146
|
-
<li>
|
|
147
|
-
<a href="{{../basePath}}/{{this.id}}?readonly=1" class="flex items-center gap-1.5 text-warning">
|
|
148
|
-
{{{icon "lock" class="h-3.5 w-3.5"}}}
|
|
149
|
-
Open Read-only
|
|
150
|
-
</a>
|
|
151
|
-
</li>
|
|
152
|
-
</ul>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
{{#unless ../readonly}}
|
|
156
|
-
{{#if this.isPostgres}}
|
|
157
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-warning js-disconnect-db" data-id="{{this.id}}" data-name="{{this.name}}" title="Disconnect this database from the manager list">
|
|
158
|
-
{{{icon "logout" class="h-3.5 w-3.5"}}}
|
|
159
|
-
Disconnect
|
|
160
|
-
</button>
|
|
161
|
-
{{else}}
|
|
162
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error js-delete-db" data-id="{{this.id}}" title="Delete database file from disk">
|
|
163
|
-
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
164
|
-
Delete
|
|
165
|
-
</button>
|
|
166
|
-
{{/if}}
|
|
167
|
-
{{/unless}}
|
|
168
|
-
</div>
|
|
169
|
-
</td>
|
|
170
|
-
</tr>
|
|
171
|
-
{{/each}}
|
|
172
|
-
</tbody>
|
|
173
|
-
</table>
|
|
174
|
-
</div>
|
|
175
|
-
</div>
|
|
176
|
-
{{else}}
|
|
177
|
-
<div class="empty-state">
|
|
178
|
-
<span class="empty-icon">{{{icon "database" class="h-7 w-7"}}}</span>
|
|
179
|
-
<p class="text-sm font-medium text-base-content/70">No databases yet</p>
|
|
180
|
-
<p class="max-w-sm text-sm text-base-content/45">
|
|
181
|
-
Connect a PostgreSQL database or create a new SQLite database above to get started.
|
|
182
|
-
</p>
|
|
183
|
-
</div>
|
|
184
|
-
{{/if}}
|
|
185
|
-
</div>
|
|
186
|
-
{{#if allowBrowse}}
|
|
187
|
-
<div class="app-card p-5">
|
|
188
|
-
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
|
189
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Open an existing SQLite file</h2>
|
|
190
|
-
<span class="text-xs text-base-content/40">.db · .sqlite · .sqlite3</span>
|
|
191
|
-
</div>
|
|
192
|
-
<div class="flex flex-wrap items-center gap-2">
|
|
193
|
-
<input id="fs-path" class="field-input font-mono sm:!w-96" placeholder="Absolute path to a folder, e.g. C:\data" autocomplete="off" spellcheck="false" />
|
|
194
|
-
<button id="fs-go" type="button" class="btn btn-outline btn-sm gap-1.5">
|
|
195
|
-
{{{icon "search" class="h-4 w-4"}}}
|
|
196
|
-
Go
|
|
197
|
-
</button>
|
|
198
|
-
<button id="fs-up" type="button" class="btn btn-ghost btn-sm gap-1.5">
|
|
199
|
-
{{{icon "arrowUp" class="h-4 w-4"}}}
|
|
200
|
-
Up
|
|
201
|
-
</button>
|
|
202
|
-
</div>
|
|
203
|
-
<div class="mt-2">
|
|
204
|
-
<label class="flex items-center gap-2 cursor-pointer">
|
|
205
|
-
<input type="checkbox" id="fs-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
|
|
206
|
-
<span class="text-xs font-medium text-base-content/70">Open selected file in Read-only mode</span>
|
|
207
|
-
</label>
|
|
208
|
-
</div>
|
|
209
|
-
<div class="mt-3 overflow-hidden rounded-xl border border-base-300">
|
|
210
|
-
<div id="fs-current" class="border-b border-base-200 bg-base-200/50 px-3 py-2 font-mono text-xs text-base-content/60"></div>
|
|
211
|
-
<div id="fs-listing" class="max-h-80 divide-y divide-base-200/70 overflow-auto"></div>
|
|
212
|
-
</div>
|
|
213
|
-
<p class="mt-2.5 text-xs text-base-content/45">
|
|
214
|
-
Browse the filesystem to select an existing database; opening it adds it to the list above.
|
|
215
|
-
{{#if browseRoot}}
|
|
216
|
-
<span class="font-medium text-base-content/60">Browsing is limited to <code class="font-mono">{{browseRoot}}</code>.</span>
|
|
217
|
-
{{/if}}
|
|
218
|
-
</p>
|
|
219
|
-
</div>
|
|
220
|
-
{{/if}}
|
|
221
|
-
<div class="rounded-xl border border-warning/30 bg-warning/[0.04] p-4 text-xs text-base-content/75 leading-relaxed">
|
|
222
|
-
<div class="flex items-start gap-2.5">
|
|
223
|
-
<span class="text-warning shrink-0 mt-0.5">
|
|
224
|
-
{{{icon "warning" class="h-4 w-4"}}}
|
|
225
|
-
</span>
|
|
226
|
-
<div>
|
|
227
|
-
<span class="font-bold text-warning">Security & Protection Notice:</span>
|
|
228
|
-
AdminDB's native authentication provides basic single-user password protection. For production environments and internet-facing networks, <strong>it is entirely your responsibility to secure this interface</strong> by placing it behind your web application's own authentication system (e.g., custom Express/Next.js auth middleware, SSO/OAuth, NextAuth), a secure VPN, or an IP-whitelisted reverse proxy with HTTPS.
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
<script src="{{basePath}}/js/databases.js" defer></script>
|
|
1
|
+
<div class="space-y-6">
|
|
234
2
|
<div class="page-header">
|
|
235
3
|
<div class="page-header-row">
|
|
236
4
|
<div>
|
|
237
5
|
<div class="page-pretitle">Manager</div>
|
|
238
6
|
<h1 class="page-title">Databases</h1>
|
|
239
7
|
<p class="mt-0.5 text-xs text-base-content/60">Connect to PostgreSQL databases, create SQLite files, or open existing local databases with configurable read/write access.</p>
|
|
240
8
|
</div>
|
|
241
9
|
</div>
|
|
242
10
|
</div>
|
|
243
11
|
<div class="grid grid-cols-1 gap-5 lg:grid-cols-2">
|
|
244
12
|
<div class="app-card p-5 border border-info/30 bg-info/[0.02]">
|
|
245
13
|
<div class="mb-3 flex items-center justify-between">
|
|
246
14
|
<h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-info">
|
|
247
15
|
{{{icon "database" class="h-4 w-4"}}}
|
|
248
16
|
Connect PostgreSQL
|
|
249
17
|
</h2>
|
|
250
18
|
<span class="rounded bg-info/15 px-2 py-0.5 text-[10px] font-bold text-info">Remote / Local</span>
|
|
251
19
|
</div>
|
|
252
20
|
<div class="space-y-3">
|
|
253
21
|
<div>
|
|
254
22
|
<label class="field-label" for="pg-conn-name">Connection Name <span class="text-base-content/40">(optional)</span></label>
|
|
255
23
|
<input id="pg-conn-name" class="field-input font-mono text-xs" placeholder="e.g. prod_postgres" autocomplete="off" spellcheck="false" />
|
|
256
24
|
</div>
|
|
257
25
|
<div>
|
|
258
26
|
<label class="field-label" for="pg-conn-uri">Connection URI <span class="chip chip-type">required</span></label>
|
|
259
27
|
<input id="pg-conn-uri" class="field-input font-mono text-xs" placeholder="postgresql://user:password@localhost:5432/mydb" autocomplete="off" spellcheck="false" />
|
|
260
28
|
</div>
|
|
261
29
|
<div>
|
|
262
30
|
<label class="flex items-center gap-2 cursor-pointer pt-0.5">
|
|
263
31
|
<input type="checkbox" id="pg-conn-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
|
|
264
32
|
<span class="text-xs font-medium text-base-content/75">Open as Read-only (block writes & schema changes)</span>
|
|
265
33
|
</label>
|
|
266
34
|
</div>
|
|
267
35
|
<div class="pt-1">
|
|
268
36
|
{{#unless readonly}}
|
|
269
37
|
<button id="connect-pg" type="button" class="btn btn-info btn-sm gap-1.5 w-full sm:w-auto">
|
|
270
38
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
271
39
|
Connect PostgreSQL
|
|
272
40
|
</button>
|
|
273
41
|
{{else}}
|
|
274
42
|
<span class="text-xs font-medium text-warning">Read-only mode — connecting databases is disabled.</span>
|
|
275
43
|
{{/unless}}
|
|
276
44
|
</div>
|
|
277
45
|
</div>
|
|
278
46
|
<p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
|
|
279
47
|
Credentials are encrypted in-memory and sanitized in the UI. Passwords are never sent to the client.
|
|
280
48
|
</p>
|
|
281
49
|
</div>
|
|
282
50
|
<div class="app-card p-5 border border-emerald-500/30 bg-emerald-500/[0.02]">
|
|
283
51
|
<div class="mb-3 flex items-center justify-between">
|
|
284
52
|
<h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-emerald-600 dark:text-emerald-400">
|
|
285
53
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
286
54
|
Create SQLite Database
|
|
287
55
|
</h2>
|
|
288
56
|
<span class="rounded bg-emerald-500/15 px-2 py-0.5 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">File-based</span>
|
|
289
57
|
</div>
|
|
290
58
|
<div class="space-y-3">
|
|
291
59
|
<div>
|
|
292
60
|
<label class="field-label" for="new-db-name">Database Name <span class="chip chip-type">required</span></label>
|
|
293
61
|
<input id="new-db-name" class="field-input font-mono text-xs" placeholder="e.g. analytics" autocomplete="off" spellcheck="false" />
|
|
294
62
|
</div>
|
|
295
63
|
<div class="pt-1">
|
|
296
64
|
{{#unless readonly}}
|
|
297
65
|
<button id="create-db" type="button" class="btn btn-primary btn-sm gap-1.5 w-full sm:w-auto">
|
|
298
66
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
299
67
|
Create SQLite DB
|
|
300
68
|
</button>
|
|
301
69
|
{{else}}
|
|
302
70
|
<span class="text-xs font-medium text-warning">Read-only — creating databases is disabled.</span>
|
|
303
71
|
{{/unless}}
|
|
304
72
|
</div>
|
|
305
73
|
</div>
|
|
306
74
|
<p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
|
|
307
75
|
Files are saved to <code class="font-mono">{{dbDir}}</code>. Any <code class="font-mono">.db</code> file dropped there is auto-discovered.
|
|
308
76
|
</p>
|
|
309
77
|
</div>
|
|
310
78
|
</div>
|
|
311
79
|
<div>
|
|
312
80
|
<div class="mb-3 flex items-center justify-between">
|
|
313
81
|
<h2 class="text-lg font-bold">Available databases</h2>
|
|
314
82
|
<span class="text-sm text-base-content/45">{{databases.length}} total</span>
|
|
315
83
|
</div>
|
|
316
84
|
{{#if databases.length}}
|
|
317
85
|
<div class="app-card overflow-hidden">
|
|
318
86
|
<div class="overflow-x-auto">
|
|
319
87
|
<table class="table table-sm">
|
|
320
88
|
<thead>
|
|
321
89
|
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
322
90
|
<th class="font-semibold">Name</th>
|
|
323
91
|
<th class="font-semibold">Mode</th>
|
|
324
92
|
<th class="text-right font-semibold">Tables</th>
|
|
325
93
|
<th class="text-right font-semibold">Size</th>
|
|
326
94
|
<th class="font-semibold">Status / Modified</th>
|
|
327
95
|
<th class="text-right font-semibold">Actions</th>
|
|
328
96
|
</tr>
|
|
329
97
|
</thead>
|
|
330
98
|
<tbody>
|
|
331
99
|
{{#each databases}}
|
|
332
100
|
<tr class="group hover:bg-primary/[0.04]">
|
|
333
101
|
<td>
|
|
334
102
|
<a href="{{../basePath}}/{{this.id}}" class="inline-flex items-center gap-2.5">
|
|
335
103
|
<span class="grid h-8 w-8 shrink-0 place-items-center rounded-lg {{#if this.isPostgres}}bg-info/10 text-info group-hover:bg-info/20{{else}}bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 group-hover:bg-emerald-500/20{{/if}} transition-colors">
|
|
336
104
|
{{{icon "database" class="h-4 w-4"}}}
|
|
337
105
|
</span>
|
|
338
106
|
<span class="min-w-0">
|
|
339
107
|
<div class="flex items-center gap-1.5">
|
|
340
108
|
<span class="truncate font-mono text-[13.5px] font-semibold">{{this.name}}</span>
|
|
341
109
|
{{#if this.isPostgres}}
|
|
342
110
|
<span class="rounded bg-info/15 px-1.5 py-0.2 text-[10px] font-bold text-info">PostgreSQL</span>
|
|
343
111
|
{{else}}
|
|
344
112
|
<span class="rounded bg-emerald-500/15 px-1.5 py-0.2 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">SQLite</span>
|
|
345
113
|
{{/if}}
|
|
346
114
|
</div>
|
|
347
115
|
<span class="block max-w-[260px] truncate font-mono text-[11px] text-base-content/40" title="{{this.path}}">{{this.path}}</span>
|
|
348
116
|
</span>
|
|
349
117
|
</a>
|
|
350
118
|
</td>
|
|
351
119
|
<td class="align-middle">
|
|
352
120
|
{{#if ../readonly}}
|
|
353
121
|
<span class="rounded bg-warning/20 px-2 py-0.5 text-[10px] font-bold uppercase text-warning">Read-only</span>
|
|
354
122
|
{{else}}
|
|
355
123
|
<button type="button" class="js-toggle-db-mode rounded px-2 py-0.5 text-[10px] font-bold uppercase transition hover:opacity-80 {{#if this.readonly}}bg-warning/20 text-warning{{else}}bg-success/20 text-success{{/if}}"
|
|
356
124
|
data-id="{{this.id}}" data-readonly="{{#if this.readonly}}true{{else}}false{{/if}}" title="Click to toggle between Writable and Read-only">
|
|
357
125
|
{{#if this.readonly}}Read-only{{else}}Writable{{/if}} ⇄
|
|
358
126
|
</button>
|
|
359
127
|
{{/if}}
|
|
360
128
|
</td>
|
|
361
129
|
<td class="text-right tabular-nums text-base-content/60">{{this.tables}}</td>
|
|
362
130
|
<td class="text-right tabular-nums text-base-content/60">{{this.sizeLabel}}</td>
|
|
363
131
|
<td class="text-[13px] text-base-content/55">{{this.modifiedLabel}}</td>
|
|
364
132
|
<td class="whitespace-nowrap text-right">
|
|
365
133
|
<div class="row-actions">
|
|
366
134
|
<div class="join">
|
|
367
135
|
<a href="{{../basePath}}/{{this.id}}" class="btn btn-ghost btn-xs join-item gap-1 text-base-content/70 hover:text-primary">
|
|
368
136
|
{{{icon "arrowRight" class="h-3.5 w-3.5"}}}
|
|
369
137
|
Open
|
|
370
138
|
</a>
|
|
371
139
|
<div class="dropdown dropdown-end">
|
|
372
140
|
<label tabindex="0" role="button" class="btn btn-ghost btn-xs join-item px-1 text-base-content/60 hover:text-base-content" title="Open options">
|
|
373
141
|
{{{icon "chevronDown" class="h-3 w-3"}}}
|
|
374
142
|
</label>
|
|
375
143
|
<ul tabindex="0" class="dropdown-content menu z-50 w-44 rounded-xl border border-base-300 bg-base-100 p-1.5 shadow-lift text-xs">
|
|
376
144
|
<li>
|
|
377
145
|
<a href="{{../basePath}}/{{this.id}}?readonly=0" class="flex items-center gap-1.5 text-success">
|
|
378
146
|
{{{icon "check" class="h-3.5 w-3.5"}}}
|
|
379
147
|
Open Writable
|
|
380
148
|
</a>
|
|
381
149
|
</li>
|
|
382
150
|
<li>
|
|
383
151
|
<a href="{{../basePath}}/{{this.id}}?readonly=1" class="flex items-center gap-1.5 text-warning">
|
|
384
152
|
{{{icon "lock" class="h-3.5 w-3.5"}}}
|
|
385
153
|
Open Read-only
|
|
386
154
|
</a>
|
|
387
155
|
</li>
|
|
388
156
|
</ul>
|
|
389
157
|
</div>
|
|
390
158
|
</div>
|
|
391
159
|
{{#unless ../readonly}}
|
|
392
160
|
{{#if this.isPostgres}}
|
|
393
161
|
<button type="button" class="btn btn-ghost btn-xs gap-1 text-warning js-disconnect-db" data-id="{{this.id}}" data-name="{{this.name}}" title="Disconnect this database from the manager list">
|
|
394
162
|
{{{icon "logout" class="h-3.5 w-3.5"}}}
|
|
395
163
|
Disconnect
|
|
396
164
|
</button>
|
|
397
165
|
{{else}}
|
|
398
166
|
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error js-delete-db" data-id="{{this.id}}" title="Delete database file from disk">
|
|
399
167
|
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
400
168
|
Delete
|
|
401
169
|
</button>
|
|
402
170
|
{{/if}}
|
|
403
171
|
{{/unless}}
|
|
404
172
|
</div>
|
|
405
173
|
</td>
|
|
406
174
|
</tr>
|
|
407
175
|
{{/each}}
|
|
408
176
|
</tbody>
|
|
409
177
|
</table>
|
|
410
178
|
</div>
|
|
411
179
|
</div>
|
|
412
180
|
{{else}}
|
|
413
181
|
<div class="empty-state">
|
|
414
182
|
<span class="empty-icon">{{{icon "database" class="h-7 w-7"}}}</span>
|
|
415
183
|
<p class="text-sm font-medium text-base-content/70">No databases yet</p>
|
|
416
184
|
<p class="max-w-sm text-sm text-base-content/45">
|
|
417
185
|
Connect a PostgreSQL database or create a new SQLite database above to get started.
|
|
418
186
|
</p>
|
|
419
187
|
</div>
|
|
420
188
|
{{/if}}
|
|
421
189
|
</div>
|
|
422
190
|
{{#if allowBrowse}}
|
|
423
191
|
<div class="app-card p-5">
|
|
424
192
|
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
|
425
193
|
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Open an existing SQLite file</h2>
|
|
426
194
|
<span class="text-xs text-base-content/40">.db · .sqlite · .sqlite3</span>
|
|
427
195
|
</div>
|
|
428
196
|
<div class="flex flex-wrap items-center gap-2">
|
|
429
197
|
<input id="fs-path" class="field-input font-mono sm:!w-96" placeholder="Absolute path to a folder, e.g. C:\data" autocomplete="off" spellcheck="false" />
|
|
430
198
|
<button id="fs-go" type="button" class="btn btn-outline btn-sm gap-1.5">
|
|
431
199
|
{{{icon "search" class="h-4 w-4"}}}
|
|
432
200
|
Go
|
|
433
201
|
</button>
|
|
434
202
|
<button id="fs-up" type="button" class="btn btn-ghost btn-sm gap-1.5">
|
|
435
203
|
{{{icon "arrowUp" class="h-4 w-4"}}}
|
|
436
204
|
Up
|
|
437
205
|
</button>
|
|
438
206
|
</div>
|
|
439
207
|
<div class="mt-2">
|
|
440
208
|
<label class="flex items-center gap-2 cursor-pointer">
|
|
441
209
|
<input type="checkbox" id="fs-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
|
|
442
210
|
<span class="text-xs font-medium text-base-content/70">Open selected file in Read-only mode</span>
|
|
443
211
|
</label>
|
|
444
212
|
</div>
|
|
445
213
|
<div class="mt-3 overflow-hidden rounded-xl border border-base-300">
|
|
446
214
|
<div id="fs-current" class="border-b border-base-200 bg-base-200/50 px-3 py-2 font-mono text-xs text-base-content/60"></div>
|
|
447
215
|
<div id="fs-listing" class="max-h-80 divide-y divide-base-200/70 overflow-auto"></div>
|
|
448
216
|
</div>
|
|
449
217
|
<p class="mt-2.5 text-xs text-base-content/45">
|
|
450
218
|
Browse the filesystem to select an existing database; opening it adds it to the list above.
|
|
451
219
|
{{#if browseRoot}}
|
|
452
220
|
<span class="font-medium text-base-content/60">Browsing is limited to <code class="font-mono">{{browseRoot}}</code>.</span>
|
|
453
221
|
{{/if}}
|
|
454
222
|
</p>
|
|
455
223
|
</div>
|
|
456
224
|
{{/if}}
|
|
457
225
|
<div class="rounded-xl border border-warning/30 bg-warning/[0.04] p-4 text-xs text-base-content/75 leading-relaxed">
|
|
458
226
|
<div class="flex items-start gap-2.5">
|
|
459
227
|
<span class="text-warning shrink-0 mt-0.5">
|
|
460
228
|
{{{icon "warning" class="h-4 w-4"}}}
|
|
461
229
|
</span>
|
|
462
230
|
<div>
|
|
463
231
|
<span class="font-bold text-warning">Security & Protection Notice:</span>
|
|
464
232
|
AdminDB's native authentication provides basic single-user password protection. For production environments and internet-facing networks, <strong>it is entirely your responsibility to secure this interface</strong> by placing it behind your web application's own authentication system (e.g., custom Express/Next.js auth middleware, SSO/OAuth, NextAuth), a secure VPN, or an IP-whitelisted reverse proxy with HTTPS.
|
|
465
233
|
</div>
|
|
466
234
|
</div>
|
|
467
235
|
</div>
|