admindb 1.0.1 → 1.0.3
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 +20 -20
- package/README.md +333 -325
- package/dist/db/database.d.ts +3 -2
- package/dist/db/database.js +12 -9
- package/dist/db/database.js.map +1 -1
- package/dist/db/manager.js +1 -1
- package/dist/db/manager.js.map +1 -1
- package/dist/public/css/input.css +179 -179
- package/dist/public/js/api.js +47 -47
- package/dist/public/js/app.js +120 -120
- package/dist/public/js/browse.js +123 -123
- package/dist/public/js/databases.js +45 -45
- package/dist/public/js/designer.js +205 -205
- package/dist/public/js/forms.js +244 -244
- package/dist/public/js/query.js +232 -232
- package/dist/public/js/schema.js +314 -314
- package/dist/public/js/triggers.js +155 -155
- package/dist/public/js/views.js +176 -176
- package/dist/views/layouts/main.hbs +49 -49
- package/dist/views/pages/databases.hbs +102 -102
- package/dist/views/pages/designer.hbs +81 -81
- package/dist/views/pages/error.hbs +12 -12
- package/dist/views/pages/form.hbs +62 -62
- package/dist/views/pages/home.hbs +123 -123
- package/dist/views/pages/query.hbs +94 -94
- package/dist/views/pages/schema.hbs +290 -290
- package/dist/views/pages/table.hbs +203 -203
- package/dist/views/pages/triggers.hbs +162 -162
- package/dist/views/pages/views.hbs +134 -134
- package/dist/views/partials/navbar.hbs +50 -50
- package/dist/views/partials/sidebar.hbs +128 -128
- package/package.json +66 -62
|
@@ -1,290 +1,290 @@
|
|
|
1
|
-
<div class="space-y-6">
|
|
2
|
-
<!-- Header -->
|
|
3
|
-
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
4
|
-
<div class="flex items-center gap-3.5">
|
|
5
|
-
<a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
|
|
6
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
|
|
7
|
-
</a>
|
|
8
|
-
<div>
|
|
9
|
-
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Schema editor</p>
|
|
10
|
-
<h1 class="font-mono text-2xl font-bold tracking-tight">{{table}}</h1>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
<div class="flex flex-wrap gap-2">
|
|
14
|
-
<a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost btn-sm gap-1.5">
|
|
15
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" /></svg>
|
|
16
|
-
View data
|
|
17
|
-
</a>
|
|
18
|
-
<a href="{{basePath}}/query" class="btn btn-outline btn-sm gap-1.5">
|
|
19
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
|
20
|
-
Query
|
|
21
|
-
</a>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<!-- Rename table -->
|
|
26
|
-
<div class="app-card p-5">
|
|
27
|
-
<div class="flex flex-wrap items-end gap-3">
|
|
28
|
-
<div class="w-full max-w-sm">
|
|
29
|
-
<label class="field-label" for="table-rename-input">Table name</label>
|
|
30
|
-
<input id="table-rename-input" class="field-input font-mono" value="{{table}}" spellcheck="false" autocomplete="off" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}} />
|
|
31
|
-
</div>
|
|
32
|
-
<button id="rename-table" type="button" class="btn btn-primary btn-sm mb-0.5" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}}>
|
|
33
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
|
|
34
|
-
Rename table
|
|
35
|
-
</button>
|
|
36
|
-
{{#if isInternal}}<span class="mb-1 text-xs text-base-content/45">Internal tables cannot be renamed.</span>{{/if}}
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<!-- Columns -->
|
|
41
|
-
<div class="app-card overflow-hidden">
|
|
42
|
-
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
43
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
44
|
-
Columns
|
|
45
|
-
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{schema.columns.length}}</span>
|
|
46
|
-
</h2>
|
|
47
|
-
<button id="add-column" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
48
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
|
|
49
|
-
Add column
|
|
50
|
-
</button>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<div id="add-column-panel" class="hidden border-b border-base-200 p-4">
|
|
54
|
-
<div id="add-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
55
|
-
<div id="add-column-error" class="hidden mt-3"></div>
|
|
56
|
-
<div class="mt-3 flex gap-2">
|
|
57
|
-
<button id="add-column-submit" type="button" class="btn btn-primary btn-sm">Add column</button>
|
|
58
|
-
<button id="add-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div class="overflow-x-auto">
|
|
63
|
-
<table class="table table-sm">
|
|
64
|
-
<thead>
|
|
65
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
66
|
-
<th class="font-semibold">Name</th>
|
|
67
|
-
<th class="font-semibold">Type</th>
|
|
68
|
-
<th class="font-semibold">Constraints</th>
|
|
69
|
-
<th class="font-semibold">Default</th>
|
|
70
|
-
<th class="text-right font-semibold">Actions</th>
|
|
71
|
-
</tr>
|
|
72
|
-
</thead>
|
|
73
|
-
<tbody>
|
|
74
|
-
{{#each schema.columns}}
|
|
75
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
76
|
-
<td class="col-name-cell align-middle" data-column="{{this.name}}">
|
|
77
|
-
<span class="name-display font-mono text-[13px] font-semibold">{{this.name}}</span>
|
|
78
|
-
</td>
|
|
79
|
-
<td class="align-middle"><span class="chip chip-type">{{this.type}}</span></td>
|
|
80
|
-
<td class="align-middle">
|
|
81
|
-
<div class="flex flex-wrap gap-1">
|
|
82
|
-
{{#if (gt this.pk 0)}}<span class="chip chip-pk">PK</span>{{/if}}
|
|
83
|
-
{{#if this.notnull}}<span class="chip chip-type">NOT NULL</span>{{/if}}
|
|
84
|
-
{{#if this.unique}}{{#unless (gt this.pk 0)}}<span class="chip chip-type">UNIQUE</span>{{/unless}}{{/if}}
|
|
85
|
-
{{#if this.fk}}<span class="chip chip-type">FK → {{this.fk.table}}.{{this.fk.to}}</span>{{/if}}
|
|
86
|
-
{{#if this.indexed}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
87
|
-
{{#if this.referencedBy.length}}<span class="chip chip-null" title="Referenced by {{this.referencedBy.length}} table(s)">REF × {{this.referencedBy.length}}</span>{{/if}}
|
|
88
|
-
</div>
|
|
89
|
-
</td>
|
|
90
|
-
<td class="align-middle font-mono text-[13px] text-base-content/60">
|
|
91
|
-
{{#if this.dflt_value}}{{this.dflt_value}}{{else}}<span class="text-base-content/25">—</span>{{/if}}
|
|
92
|
-
</td>
|
|
93
|
-
<td class="whitespace-nowrap text-right align-middle">
|
|
94
|
-
<div class="flex items-center justify-end gap-1">
|
|
95
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary col-rename" {{#if ../readonly}}disabled{{/if}}>
|
|
96
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
|
|
97
|
-
Rename
|
|
98
|
-
</button>
|
|
99
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error col-drop" {{#if ../readonly}}disabled{{/if}} {{#unless this.canDrop}}disabled title="{{join this.dropBlockers "; "}}"{{/unless}}>
|
|
100
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
|
|
101
|
-
Delete
|
|
102
|
-
</button>
|
|
103
|
-
</div>
|
|
104
|
-
</td>
|
|
105
|
-
</tr>
|
|
106
|
-
{{/each}}
|
|
107
|
-
</tbody>
|
|
108
|
-
</table>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<!-- Foreign keys -->
|
|
113
|
-
{{#if schema.foreignKeys.length}}
|
|
114
|
-
<div class="app-card overflow-hidden">
|
|
115
|
-
<div class="border-b border-base-200 px-5 py-4">
|
|
116
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Foreign keys</h2>
|
|
117
|
-
</div>
|
|
118
|
-
<div class="overflow-x-auto">
|
|
119
|
-
<table class="table table-sm">
|
|
120
|
-
<thead>
|
|
121
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
122
|
-
<th class="font-semibold">Column</th>
|
|
123
|
-
<th class="font-semibold">References</th>
|
|
124
|
-
<th class="font-semibold">On delete</th>
|
|
125
|
-
<th class="font-semibold">On update</th>
|
|
126
|
-
</tr>
|
|
127
|
-
</thead>
|
|
128
|
-
<tbody>
|
|
129
|
-
{{#each schema.foreignKeys}}
|
|
130
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
131
|
-
<td class="align-middle font-mono text-[13px]">{{this.from}}</td>
|
|
132
|
-
<td class="align-middle font-mono text-[13px] text-primary">{{this.table}}.{{this.to}}</td>
|
|
133
|
-
<td class="align-middle text-[13px] text-base-content/60">{{this.on_delete}}</td>
|
|
134
|
-
<td class="align-middle text-[13px] text-base-content/60">{{this.on_update}}</td>
|
|
135
|
-
</tr>
|
|
136
|
-
{{/each}}
|
|
137
|
-
</tbody>
|
|
138
|
-
</table>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
{{/if}}
|
|
142
|
-
|
|
143
|
-
<!-- Indexes -->
|
|
144
|
-
<div class="app-card overflow-hidden">
|
|
145
|
-
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
146
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
147
|
-
Indexes
|
|
148
|
-
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{schema.indexes.length}}</span>
|
|
149
|
-
</h2>
|
|
150
|
-
<button id="add-index" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
151
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
|
|
152
|
-
Add index
|
|
153
|
-
</button>
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
<div id="add-index-panel" class="hidden border-b border-base-200 p-4">
|
|
157
|
-
<div class="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
158
|
-
<div>
|
|
159
|
-
<label class="field-label" for="index-name">Index name <span class="text-base-content/40">(optional)</span></label>
|
|
160
|
-
<input id="index-name" class="field-input font-mono" placeholder="idx_users_email" spellcheck="false" autocomplete="off" />
|
|
161
|
-
</div>
|
|
162
|
-
<div class="flex items-end pb-1">
|
|
163
|
-
<label class="flex cursor-pointer items-center gap-2">
|
|
164
|
-
<input id="index-unique" type="checkbox" class="checkbox checkbox-primary checkbox-sm" />
|
|
165
|
-
<span class="text-sm font-medium text-base-content/70">Unique index</span>
|
|
166
|
-
</label>
|
|
167
|
-
</div>
|
|
168
|
-
<div class="sm:col-span-3">
|
|
169
|
-
<label class="field-label">Columns <span class="text-base-content/40">— click in the order they should appear</span></label>
|
|
170
|
-
<div id="index-columns" class="flex flex-wrap gap-2">
|
|
171
|
-
{{#each schema.columns}}
|
|
172
|
-
<button type="button" class="index-col-btn rounded-lg border border-base-300 px-2.5 py-1.5 text-[13px] font-mono hover:border-primary/50" data-column="{{this.name}}">
|
|
173
|
-
<span class="index-col-num mr-1 hidden rounded bg-primary/15 px-1 text-[10px] font-bold text-primary">1</span>{{this.name}}
|
|
174
|
-
</button>
|
|
175
|
-
{{/each}}
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
<div id="index-preview" class="mt-3 hidden">
|
|
180
|
-
<div class="rounded-xl bg-base-200/60 p-3">
|
|
181
|
-
<div class="mb-1 text-[10px] font-semibold uppercase tracking-wider text-base-content/40">Generated SQL</div>
|
|
182
|
-
<pre class="code-panel !m-0"><code id="index-preview-code"></code></pre>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
<div id="add-index-error" class="mt-3 hidden"></div>
|
|
186
|
-
<div class="mt-3 flex gap-2">
|
|
187
|
-
<button id="add-index-submit" type="button" class="btn btn-primary btn-sm">Create index</button>
|
|
188
|
-
<button id="add-index-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
<div class="overflow-x-auto">
|
|
193
|
-
{{#if schema.indexes.length}}
|
|
194
|
-
<table class="table table-sm">
|
|
195
|
-
<thead>
|
|
196
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
197
|
-
<th class="font-semibold">Name</th>
|
|
198
|
-
<th class="font-semibold">Columns</th>
|
|
199
|
-
<th class="font-semibold">Kind</th>
|
|
200
|
-
<th class="font-semibold">SQL</th>
|
|
201
|
-
<th class="text-right font-semibold">Actions</th>
|
|
202
|
-
</tr>
|
|
203
|
-
</thead>
|
|
204
|
-
<tbody>
|
|
205
|
-
{{#each schema.indexes}}
|
|
206
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
207
|
-
<td class="align-middle font-mono text-[13px]">{{this.name}}</td>
|
|
208
|
-
<td class="align-middle font-mono text-[13px] text-base-content/70">{{join this.columns ", "}}</td>
|
|
209
|
-
<td class="align-middle">
|
|
210
|
-
<div class="flex flex-wrap gap-1">
|
|
211
|
-
{{#if this.unique}}<span class="chip chip-type">UNIQUE</span>{{else}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
212
|
-
{{#unless (eq this.origin 'c')}}<span class="chip chip-null" title="Automatic index (created by SQLite)">AUTO</span>{{/unless}}
|
|
213
|
-
</div>
|
|
214
|
-
</td>
|
|
215
|
-
<td class="align-middle">
|
|
216
|
-
{{#if this.sql}}
|
|
217
|
-
<details class="group">
|
|
218
|
-
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">View SQL</summary>
|
|
219
|
-
<pre class="mt-1 max-w-[26rem] overflow-x-auto rounded-lg bg-base-200/70 p-2 font-mono text-[11px] leading-relaxed text-base-content/70">{{this.sql}}</pre>
|
|
220
|
-
</details>
|
|
221
|
-
{{else}}
|
|
222
|
-
<span class="text-base-content/30">—</span>
|
|
223
|
-
{{/if}}
|
|
224
|
-
</td>
|
|
225
|
-
<td class="whitespace-nowrap text-right align-middle">
|
|
226
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error index-drop"
|
|
227
|
-
data-index="{{this.name}}" {{#if ../readonly}}disabled{{/if}} {{#unless (eq this.origin 'c')}}disabled title="Automatic index — cannot be dropped"{{/unless}}>
|
|
228
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
|
|
229
|
-
Drop
|
|
230
|
-
</button>
|
|
231
|
-
</td>
|
|
232
|
-
</tr>
|
|
233
|
-
{{/each}}
|
|
234
|
-
</tbody>
|
|
235
|
-
</table>
|
|
236
|
-
{{else}}
|
|
237
|
-
<div class="px-5 py-8 text-center text-sm text-base-content/45">No indexes on this table yet.</div>
|
|
238
|
-
{{/if}}
|
|
239
|
-
</div>
|
|
240
|
-
</div>
|
|
241
|
-
|
|
242
|
-
<!-- Referenced by -->
|
|
243
|
-
{{#if schema.references.length}}
|
|
244
|
-
<div class="app-card overflow-hidden">
|
|
245
|
-
<div class="border-b border-base-200 px-5 py-4">
|
|
246
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Referenced by</h2>
|
|
247
|
-
</div>
|
|
248
|
-
<div class="overflow-x-auto">
|
|
249
|
-
<table class="table table-sm">
|
|
250
|
-
<thead>
|
|
251
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
252
|
-
<th class="font-semibold">Table</th>
|
|
253
|
-
<th class="font-semibold">Via</th>
|
|
254
|
-
</tr>
|
|
255
|
-
</thead>
|
|
256
|
-
<tbody>
|
|
257
|
-
{{#each schema.references}}
|
|
258
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
259
|
-
<td class="align-middle font-mono text-[13px]">{{this.table}}</td>
|
|
260
|
-
<td class="align-middle font-mono text-[13px] text-base-content/70">{{this.from}} → {{this.to}}</td>
|
|
261
|
-
</tr>
|
|
262
|
-
{{/each}}
|
|
263
|
-
</tbody>
|
|
264
|
-
</table>
|
|
265
|
-
</div>
|
|
266
|
-
</div>
|
|
267
|
-
{{/if}}
|
|
268
|
-
|
|
269
|
-
<!-- Danger zone -->
|
|
270
|
-
{{#unless isInternal}}
|
|
271
|
-
<div class="rounded-2xl border border-error/25 bg-error/[0.03] p-5">
|
|
272
|
-
<h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-error">
|
|
273
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
|
274
|
-
Danger zone
|
|
275
|
-
</h2>
|
|
276
|
-
<p class="mt-1 text-sm text-base-content/55">Dropping this table permanently removes its schema and all of its data.</p>
|
|
277
|
-
<div class="mt-3 flex flex-wrap items-center gap-3">
|
|
278
|
-
<button id="drop-table" type="button" class="btn btn-error btn-sm" {{#if readonly}}disabled{{/if}} {{#if schema.references.length}}disabled title="Referenced by {{schema.references.length}} table(s)"{{/if}}>
|
|
279
|
-
Drop table
|
|
280
|
-
</button>
|
|
281
|
-
{{#if readonly}}<span class="text-xs text-base-content/50">Read-only — table changes are disabled.</span>{{/if}}
|
|
282
|
-
{{#if schema.references.length}}
|
|
283
|
-
<span class="text-xs text-base-content/50">Cannot drop — referenced by {{schema.references.length}} table(s).</span>
|
|
284
|
-
{{/if}}
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
{{/unless}}
|
|
288
|
-
</div>
|
|
289
|
-
<script id="schema-config" type="application/json">{{{json config}}}</script>
|
|
290
|
-
<script src="{{basePath}}/js/schema.js" defer></script>
|
|
1
|
+
<div class="space-y-6">
|
|
2
|
+
<!-- Header -->
|
|
3
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
4
|
+
<div class="flex items-center gap-3.5">
|
|
5
|
+
<a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
|
|
6
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
|
|
7
|
+
</a>
|
|
8
|
+
<div>
|
|
9
|
+
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Schema editor</p>
|
|
10
|
+
<h1 class="font-mono text-2xl font-bold tracking-tight">{{table}}</h1>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="flex flex-wrap gap-2">
|
|
14
|
+
<a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost btn-sm gap-1.5">
|
|
15
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" /></svg>
|
|
16
|
+
View data
|
|
17
|
+
</a>
|
|
18
|
+
<a href="{{basePath}}/query" class="btn btn-outline btn-sm gap-1.5">
|
|
19
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
|
20
|
+
Query
|
|
21
|
+
</a>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- Rename table -->
|
|
26
|
+
<div class="app-card p-5">
|
|
27
|
+
<div class="flex flex-wrap items-end gap-3">
|
|
28
|
+
<div class="w-full max-w-sm">
|
|
29
|
+
<label class="field-label" for="table-rename-input">Table name</label>
|
|
30
|
+
<input id="table-rename-input" class="field-input font-mono" value="{{table}}" spellcheck="false" autocomplete="off" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}} />
|
|
31
|
+
</div>
|
|
32
|
+
<button id="rename-table" type="button" class="btn btn-primary btn-sm mb-0.5" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}}>
|
|
33
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
|
|
34
|
+
Rename table
|
|
35
|
+
</button>
|
|
36
|
+
{{#if isInternal}}<span class="mb-1 text-xs text-base-content/45">Internal tables cannot be renamed.</span>{{/if}}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- Columns -->
|
|
41
|
+
<div class="app-card overflow-hidden">
|
|
42
|
+
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
43
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
44
|
+
Columns
|
|
45
|
+
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{schema.columns.length}}</span>
|
|
46
|
+
</h2>
|
|
47
|
+
<button id="add-column" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
48
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
|
|
49
|
+
Add column
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div id="add-column-panel" class="hidden border-b border-base-200 p-4">
|
|
54
|
+
<div id="add-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
55
|
+
<div id="add-column-error" class="hidden mt-3"></div>
|
|
56
|
+
<div class="mt-3 flex gap-2">
|
|
57
|
+
<button id="add-column-submit" type="button" class="btn btn-primary btn-sm">Add column</button>
|
|
58
|
+
<button id="add-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="overflow-x-auto">
|
|
63
|
+
<table class="table table-sm">
|
|
64
|
+
<thead>
|
|
65
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
66
|
+
<th class="font-semibold">Name</th>
|
|
67
|
+
<th class="font-semibold">Type</th>
|
|
68
|
+
<th class="font-semibold">Constraints</th>
|
|
69
|
+
<th class="font-semibold">Default</th>
|
|
70
|
+
<th class="text-right font-semibold">Actions</th>
|
|
71
|
+
</tr>
|
|
72
|
+
</thead>
|
|
73
|
+
<tbody>
|
|
74
|
+
{{#each schema.columns}}
|
|
75
|
+
<tr class="hover:bg-primary/[0.04]">
|
|
76
|
+
<td class="col-name-cell align-middle" data-column="{{this.name}}">
|
|
77
|
+
<span class="name-display font-mono text-[13px] font-semibold">{{this.name}}</span>
|
|
78
|
+
</td>
|
|
79
|
+
<td class="align-middle"><span class="chip chip-type">{{this.type}}</span></td>
|
|
80
|
+
<td class="align-middle">
|
|
81
|
+
<div class="flex flex-wrap gap-1">
|
|
82
|
+
{{#if (gt this.pk 0)}}<span class="chip chip-pk">PK</span>{{/if}}
|
|
83
|
+
{{#if this.notnull}}<span class="chip chip-type">NOT NULL</span>{{/if}}
|
|
84
|
+
{{#if this.unique}}{{#unless (gt this.pk 0)}}<span class="chip chip-type">UNIQUE</span>{{/unless}}{{/if}}
|
|
85
|
+
{{#if this.fk}}<span class="chip chip-type">FK → {{this.fk.table}}.{{this.fk.to}}</span>{{/if}}
|
|
86
|
+
{{#if this.indexed}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
87
|
+
{{#if this.referencedBy.length}}<span class="chip chip-null" title="Referenced by {{this.referencedBy.length}} table(s)">REF × {{this.referencedBy.length}}</span>{{/if}}
|
|
88
|
+
</div>
|
|
89
|
+
</td>
|
|
90
|
+
<td class="align-middle font-mono text-[13px] text-base-content/60">
|
|
91
|
+
{{#if this.dflt_value}}{{this.dflt_value}}{{else}}<span class="text-base-content/25">—</span>{{/if}}
|
|
92
|
+
</td>
|
|
93
|
+
<td class="whitespace-nowrap text-right align-middle">
|
|
94
|
+
<div class="flex items-center justify-end gap-1">
|
|
95
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary col-rename" {{#if ../readonly}}disabled{{/if}}>
|
|
96
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
|
|
97
|
+
Rename
|
|
98
|
+
</button>
|
|
99
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error col-drop" {{#if ../readonly}}disabled{{/if}} {{#unless this.canDrop}}disabled title="{{join this.dropBlockers "; "}}"{{/unless}}>
|
|
100
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
|
|
101
|
+
Delete
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
</td>
|
|
105
|
+
</tr>
|
|
106
|
+
{{/each}}
|
|
107
|
+
</tbody>
|
|
108
|
+
</table>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Foreign keys -->
|
|
113
|
+
{{#if schema.foreignKeys.length}}
|
|
114
|
+
<div class="app-card overflow-hidden">
|
|
115
|
+
<div class="border-b border-base-200 px-5 py-4">
|
|
116
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Foreign keys</h2>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="overflow-x-auto">
|
|
119
|
+
<table class="table table-sm">
|
|
120
|
+
<thead>
|
|
121
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
122
|
+
<th class="font-semibold">Column</th>
|
|
123
|
+
<th class="font-semibold">References</th>
|
|
124
|
+
<th class="font-semibold">On delete</th>
|
|
125
|
+
<th class="font-semibold">On update</th>
|
|
126
|
+
</tr>
|
|
127
|
+
</thead>
|
|
128
|
+
<tbody>
|
|
129
|
+
{{#each schema.foreignKeys}}
|
|
130
|
+
<tr class="hover:bg-primary/[0.04]">
|
|
131
|
+
<td class="align-middle font-mono text-[13px]">{{this.from}}</td>
|
|
132
|
+
<td class="align-middle font-mono text-[13px] text-primary">{{this.table}}.{{this.to}}</td>
|
|
133
|
+
<td class="align-middle text-[13px] text-base-content/60">{{this.on_delete}}</td>
|
|
134
|
+
<td class="align-middle text-[13px] text-base-content/60">{{this.on_update}}</td>
|
|
135
|
+
</tr>
|
|
136
|
+
{{/each}}
|
|
137
|
+
</tbody>
|
|
138
|
+
</table>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
{{/if}}
|
|
142
|
+
|
|
143
|
+
<!-- Indexes -->
|
|
144
|
+
<div class="app-card overflow-hidden">
|
|
145
|
+
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
146
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
147
|
+
Indexes
|
|
148
|
+
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{schema.indexes.length}}</span>
|
|
149
|
+
</h2>
|
|
150
|
+
<button id="add-index" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
151
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
|
|
152
|
+
Add index
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div id="add-index-panel" class="hidden border-b border-base-200 p-4">
|
|
157
|
+
<div class="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
158
|
+
<div>
|
|
159
|
+
<label class="field-label" for="index-name">Index name <span class="text-base-content/40">(optional)</span></label>
|
|
160
|
+
<input id="index-name" class="field-input font-mono" placeholder="idx_users_email" spellcheck="false" autocomplete="off" />
|
|
161
|
+
</div>
|
|
162
|
+
<div class="flex items-end pb-1">
|
|
163
|
+
<label class="flex cursor-pointer items-center gap-2">
|
|
164
|
+
<input id="index-unique" type="checkbox" class="checkbox checkbox-primary checkbox-sm" />
|
|
165
|
+
<span class="text-sm font-medium text-base-content/70">Unique index</span>
|
|
166
|
+
</label>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="sm:col-span-3">
|
|
169
|
+
<label class="field-label">Columns <span class="text-base-content/40">— click in the order they should appear</span></label>
|
|
170
|
+
<div id="index-columns" class="flex flex-wrap gap-2">
|
|
171
|
+
{{#each schema.columns}}
|
|
172
|
+
<button type="button" class="index-col-btn rounded-lg border border-base-300 px-2.5 py-1.5 text-[13px] font-mono hover:border-primary/50" data-column="{{this.name}}">
|
|
173
|
+
<span class="index-col-num mr-1 hidden rounded bg-primary/15 px-1 text-[10px] font-bold text-primary">1</span>{{this.name}}
|
|
174
|
+
</button>
|
|
175
|
+
{{/each}}
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div id="index-preview" class="mt-3 hidden">
|
|
180
|
+
<div class="rounded-xl bg-base-200/60 p-3">
|
|
181
|
+
<div class="mb-1 text-[10px] font-semibold uppercase tracking-wider text-base-content/40">Generated SQL</div>
|
|
182
|
+
<pre class="code-panel !m-0"><code id="index-preview-code"></code></pre>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
<div id="add-index-error" class="mt-3 hidden"></div>
|
|
186
|
+
<div class="mt-3 flex gap-2">
|
|
187
|
+
<button id="add-index-submit" type="button" class="btn btn-primary btn-sm">Create index</button>
|
|
188
|
+
<button id="add-index-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div class="overflow-x-auto">
|
|
193
|
+
{{#if schema.indexes.length}}
|
|
194
|
+
<table class="table table-sm">
|
|
195
|
+
<thead>
|
|
196
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
197
|
+
<th class="font-semibold">Name</th>
|
|
198
|
+
<th class="font-semibold">Columns</th>
|
|
199
|
+
<th class="font-semibold">Kind</th>
|
|
200
|
+
<th class="font-semibold">SQL</th>
|
|
201
|
+
<th class="text-right font-semibold">Actions</th>
|
|
202
|
+
</tr>
|
|
203
|
+
</thead>
|
|
204
|
+
<tbody>
|
|
205
|
+
{{#each schema.indexes}}
|
|
206
|
+
<tr class="hover:bg-primary/[0.04]">
|
|
207
|
+
<td class="align-middle font-mono text-[13px]">{{this.name}}</td>
|
|
208
|
+
<td class="align-middle font-mono text-[13px] text-base-content/70">{{join this.columns ", "}}</td>
|
|
209
|
+
<td class="align-middle">
|
|
210
|
+
<div class="flex flex-wrap gap-1">
|
|
211
|
+
{{#if this.unique}}<span class="chip chip-type">UNIQUE</span>{{else}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
212
|
+
{{#unless (eq this.origin 'c')}}<span class="chip chip-null" title="Automatic index (created by SQLite)">AUTO</span>{{/unless}}
|
|
213
|
+
</div>
|
|
214
|
+
</td>
|
|
215
|
+
<td class="align-middle">
|
|
216
|
+
{{#if this.sql}}
|
|
217
|
+
<details class="group">
|
|
218
|
+
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">View SQL</summary>
|
|
219
|
+
<pre class="mt-1 max-w-[26rem] overflow-x-auto rounded-lg bg-base-200/70 p-2 font-mono text-[11px] leading-relaxed text-base-content/70">{{this.sql}}</pre>
|
|
220
|
+
</details>
|
|
221
|
+
{{else}}
|
|
222
|
+
<span class="text-base-content/30">—</span>
|
|
223
|
+
{{/if}}
|
|
224
|
+
</td>
|
|
225
|
+
<td class="whitespace-nowrap text-right align-middle">
|
|
226
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error index-drop"
|
|
227
|
+
data-index="{{this.name}}" {{#if ../readonly}}disabled{{/if}} {{#unless (eq this.origin 'c')}}disabled title="Automatic index — cannot be dropped"{{/unless}}>
|
|
228
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
|
|
229
|
+
Drop
|
|
230
|
+
</button>
|
|
231
|
+
</td>
|
|
232
|
+
</tr>
|
|
233
|
+
{{/each}}
|
|
234
|
+
</tbody>
|
|
235
|
+
</table>
|
|
236
|
+
{{else}}
|
|
237
|
+
<div class="px-5 py-8 text-center text-sm text-base-content/45">No indexes on this table yet.</div>
|
|
238
|
+
{{/if}}
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
|
|
242
|
+
<!-- Referenced by -->
|
|
243
|
+
{{#if schema.references.length}}
|
|
244
|
+
<div class="app-card overflow-hidden">
|
|
245
|
+
<div class="border-b border-base-200 px-5 py-4">
|
|
246
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Referenced by</h2>
|
|
247
|
+
</div>
|
|
248
|
+
<div class="overflow-x-auto">
|
|
249
|
+
<table class="table table-sm">
|
|
250
|
+
<thead>
|
|
251
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
252
|
+
<th class="font-semibold">Table</th>
|
|
253
|
+
<th class="font-semibold">Via</th>
|
|
254
|
+
</tr>
|
|
255
|
+
</thead>
|
|
256
|
+
<tbody>
|
|
257
|
+
{{#each schema.references}}
|
|
258
|
+
<tr class="hover:bg-primary/[0.04]">
|
|
259
|
+
<td class="align-middle font-mono text-[13px]">{{this.table}}</td>
|
|
260
|
+
<td class="align-middle font-mono text-[13px] text-base-content/70">{{this.from}} → {{this.to}}</td>
|
|
261
|
+
</tr>
|
|
262
|
+
{{/each}}
|
|
263
|
+
</tbody>
|
|
264
|
+
</table>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
{{/if}}
|
|
268
|
+
|
|
269
|
+
<!-- Danger zone -->
|
|
270
|
+
{{#unless isInternal}}
|
|
271
|
+
<div class="rounded-2xl border border-error/25 bg-error/[0.03] p-5">
|
|
272
|
+
<h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-error">
|
|
273
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
|
274
|
+
Danger zone
|
|
275
|
+
</h2>
|
|
276
|
+
<p class="mt-1 text-sm text-base-content/55">Dropping this table permanently removes its schema and all of its data.</p>
|
|
277
|
+
<div class="mt-3 flex flex-wrap items-center gap-3">
|
|
278
|
+
<button id="drop-table" type="button" class="btn btn-error btn-sm" {{#if readonly}}disabled{{/if}} {{#if schema.references.length}}disabled title="Referenced by {{schema.references.length}} table(s)"{{/if}}>
|
|
279
|
+
Drop table
|
|
280
|
+
</button>
|
|
281
|
+
{{#if readonly}}<span class="text-xs text-base-content/50">Read-only — table changes are disabled.</span>{{/if}}
|
|
282
|
+
{{#if schema.references.length}}
|
|
283
|
+
<span class="text-xs text-base-content/50">Cannot drop — referenced by {{schema.references.length}} table(s).</span>
|
|
284
|
+
{{/if}}
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
{{/unless}}
|
|
288
|
+
</div>
|
|
289
|
+
<script id="schema-config" type="application/json">{{{json config}}}</script>
|
|
290
|
+
<script src="{{basePath}}/js/schema.js" defer></script>
|