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,298 +1 @@
|
|
|
1
|
-
<div class="space-y-6">
|
|
2
|
-
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
3
|
-
<div class="flex items-center gap-3.5">
|
|
4
|
-
<a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
|
|
5
|
-
{{{icon "arrowLeft" class="h-5 w-5"}}}
|
|
6
|
-
</a>
|
|
7
|
-
<div>
|
|
8
|
-
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Schema editor</p>
|
|
9
|
-
<h1 class="font-mono text-2xl font-bold tracking-tight">{{table}}</h1>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
<div class="flex flex-wrap gap-2">
|
|
13
|
-
<a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost btn-sm gap-1.5">
|
|
14
|
-
{{{icon "table" class="h-4 w-4"}}}
|
|
15
|
-
View data
|
|
16
|
-
</a>
|
|
17
|
-
<a href="{{basePath}}/query" class="btn btn-outline btn-sm gap-1.5">
|
|
18
|
-
{{{icon "query" class="h-4 w-4"}}}
|
|
19
|
-
Query
|
|
20
|
-
</a>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="app-card p-5">
|
|
24
|
-
<div class="flex flex-wrap items-end gap-3">
|
|
25
|
-
<div class="w-full max-w-sm">
|
|
26
|
-
<label class="field-label" for="table-rename-input">Table name</label>
|
|
27
|
-
<input id="table-rename-input" class="field-input font-mono" value="{{table}}" spellcheck="false" autocomplete="off" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}} />
|
|
28
|
-
</div>
|
|
29
|
-
<button id="rename-table" type="button" class="btn btn-primary btn-sm mb-0.5" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}}>
|
|
30
|
-
{{{icon "edit" class="h-4 w-4"}}}
|
|
31
|
-
Rename table
|
|
32
|
-
</button>
|
|
33
|
-
{{#if isInternal}}<span class="mb-1 text-xs text-base-content/45">Internal tables cannot be renamed.</span>{{/if}}
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
<div class="app-card overflow-hidden">
|
|
37
|
-
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
38
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
39
|
-
Columns
|
|
40
|
-
<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>
|
|
41
|
-
</h2>
|
|
42
|
-
<button id="add-column" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
43
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
44
|
-
Add column
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
<div id="add-column-panel" class="hidden border-b border-base-200 p-4">
|
|
48
|
-
<div class="mb-2 text-xs font-bold uppercase tracking-wider text-primary">Add New Column</div>
|
|
49
|
-
<div id="add-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
50
|
-
<div id="add-column-error" class="hidden mt-3"></div>
|
|
51
|
-
<div class="mt-3.5 flex gap-2">
|
|
52
|
-
<button id="add-column-submit" type="button" class="btn btn-primary btn-sm">Add column</button>
|
|
53
|
-
<button id="add-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
<div id="edit-column-panel" class="hidden border-b border-base-200 bg-base-200/30 p-4">
|
|
57
|
-
<div class="mb-2.5 flex items-center justify-between">
|
|
58
|
-
<div class="flex items-center gap-2">
|
|
59
|
-
<span class="text-xs font-bold uppercase tracking-wider text-primary">Edit Column:</span>
|
|
60
|
-
<span id="edit-column-target" class="font-mono text-sm font-bold text-base-content"></span>
|
|
61
|
-
</div>
|
|
62
|
-
<span class="text-[11px] text-base-content/45">Change data type, default value, primary key, nullability, uniqueness, or foreign key.</span>
|
|
63
|
-
</div>
|
|
64
|
-
<div id="edit-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
65
|
-
<div id="edit-column-error" class="hidden mt-3"></div>
|
|
66
|
-
<div class="mt-3.5 flex gap-2">
|
|
67
|
-
<button id="edit-column-submit" type="button" class="btn btn-primary btn-sm">Save Changes</button>
|
|
68
|
-
<button id="edit-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
<div class="overflow-x-auto">
|
|
72
|
-
<table class="table table-sm">
|
|
73
|
-
<thead>
|
|
74
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
75
|
-
<th class="font-semibold">Name</th>
|
|
76
|
-
<th class="font-semibold">Type</th>
|
|
77
|
-
<th class="font-semibold">Constraints</th>
|
|
78
|
-
<th class="font-semibold">Default</th>
|
|
79
|
-
<th class="text-right font-semibold">Actions</th>
|
|
80
|
-
</tr>
|
|
81
|
-
</thead>
|
|
82
|
-
<tbody>
|
|
83
|
-
{{#each schema.columns}}
|
|
84
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
85
|
-
<td class="col-name-cell align-middle" data-column="{{this.name}}">
|
|
86
|
-
<span class="name-display font-mono text-[13px] font-semibold">{{this.name}}</span>
|
|
87
|
-
</td>
|
|
88
|
-
<td class="align-middle"><span class="chip chip-type">{{this.type}}</span></td>
|
|
89
|
-
<td class="align-middle">
|
|
90
|
-
<div class="flex flex-wrap gap-1">
|
|
91
|
-
{{#if (gt this.pk 0)}}<span class="chip chip-pk">PK</span>{{/if}}
|
|
92
|
-
{{#if this.notnull}}<span class="chip chip-type">NOT NULL</span>{{/if}}
|
|
93
|
-
{{#if this.unique}}{{#unless (gt this.pk 0)}}<span class="chip chip-type">UNIQUE</span>{{/unless}}{{/if}}
|
|
94
|
-
{{#if this.fk}}<span class="chip chip-type">FK → {{this.fk.table}}.{{this.fk.to}}</span>{{/if}}
|
|
95
|
-
{{#if this.indexed}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
96
|
-
{{#if this.referencedBy.length}}<span class="chip chip-null" title="Referenced by {{this.referencedBy.length}} table(s)">REF × {{this.referencedBy.length}}</span>{{/if}}
|
|
97
|
-
</div>
|
|
98
|
-
</td>
|
|
99
|
-
<td class="align-middle font-mono text-[13px] text-base-content/60">
|
|
100
|
-
{{#if this.dflt_value}}{{this.dflt_value}}{{else}}<span class="text-base-content/25">—</span>{{/if}}
|
|
101
|
-
</td>
|
|
102
|
-
<td class="whitespace-nowrap text-right align-middle">
|
|
103
|
-
<div class="flex items-center justify-end gap-1">
|
|
104
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary col-edit"
|
|
105
|
-
data-column="{{this.name}}"
|
|
106
|
-
data-type="{{this.type}}"
|
|
107
|
-
data-pk="{{#if (gt this.pk 0)}}true{{else}}false{{/if}}"
|
|
108
|
-
data-notnull="{{#if this.notnull}}true{{else}}false{{/if}}"
|
|
109
|
-
data-unique="{{#if this.unique}}true{{else}}false{{/if}}"
|
|
110
|
-
data-default="{{this.dflt_value}}"
|
|
111
|
-
data-fk-table="{{this.fk.table}}"
|
|
112
|
-
data-fk-to="{{this.fk.to}}"
|
|
113
|
-
{{#if ../readonly}}disabled{{/if}}>
|
|
114
|
-
{{{icon "edit" class="h-3.5 w-3.5"}}}
|
|
115
|
-
Edit
|
|
116
|
-
</button>
|
|
117
|
-
<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}}>
|
|
118
|
-
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
119
|
-
Delete
|
|
120
|
-
</button>
|
|
121
|
-
</div>
|
|
122
|
-
</td>
|
|
123
|
-
</tr>
|
|
124
|
-
{{/each}}
|
|
125
|
-
</tbody>
|
|
126
|
-
</table>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
129
|
-
{{#if schema.foreignKeys.length}}
|
|
130
|
-
<div class="app-card overflow-hidden">
|
|
131
|
-
<div class="border-b border-base-200 px-5 py-4">
|
|
132
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Foreign keys</h2>
|
|
133
|
-
</div>
|
|
134
|
-
<div class="overflow-x-auto">
|
|
135
|
-
<table class="table table-sm">
|
|
136
|
-
<thead>
|
|
137
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
138
|
-
<th class="font-semibold">Column</th>
|
|
139
|
-
<th class="font-semibold">References</th>
|
|
140
|
-
<th class="font-semibold">On delete</th>
|
|
141
|
-
<th class="font-semibold">On update</th>
|
|
142
|
-
</tr>
|
|
143
|
-
</thead>
|
|
144
|
-
<tbody>
|
|
145
|
-
{{#each schema.foreignKeys}}
|
|
146
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
147
|
-
<td class="align-middle font-mono text-[13px]">{{this.from}}</td>
|
|
148
|
-
<td class="align-middle font-mono text-[13px] text-primary">{{this.table}}.{{this.to}}</td>
|
|
149
|
-
<td class="align-middle text-[13px] text-base-content/60">{{this.on_delete}}</td>
|
|
150
|
-
<td class="align-middle text-[13px] text-base-content/60">{{this.on_update}}</td>
|
|
151
|
-
</tr>
|
|
152
|
-
{{/each}}
|
|
153
|
-
</tbody>
|
|
154
|
-
</table>
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
{{/if}}
|
|
158
|
-
<div class="app-card overflow-hidden">
|
|
159
|
-
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
160
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
161
|
-
Indexes
|
|
162
|
-
<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>
|
|
163
|
-
</h2>
|
|
164
|
-
<button id="add-index" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
165
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
166
|
-
Add index
|
|
167
|
-
</button>
|
|
168
|
-
</div>
|
|
169
|
-
<div id="add-index-panel" class="hidden border-b border-base-200 p-4">
|
|
170
|
-
<div class="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
171
|
-
<div>
|
|
172
|
-
<label class="field-label" for="index-name">Index name <span class="text-base-content/40">(optional)</span></label>
|
|
173
|
-
<input id="index-name" class="field-input font-mono" placeholder="idx_users_email" spellcheck="false" autocomplete="off" />
|
|
174
|
-
</div>
|
|
175
|
-
<div class="flex items-end pb-1">
|
|
176
|
-
<label class="flex cursor-pointer items-center gap-2">
|
|
177
|
-
<input id="index-unique" type="checkbox" class="checkbox checkbox-primary checkbox-sm" />
|
|
178
|
-
<span class="text-sm font-medium text-base-content/70">Unique index</span>
|
|
179
|
-
</label>
|
|
180
|
-
</div>
|
|
181
|
-
<div class="sm:col-span-3">
|
|
182
|
-
<label class="field-label">Columns <span class="text-base-content/40">— click in the order they should appear</span></label>
|
|
183
|
-
<div id="index-columns" class="flex flex-wrap gap-2">
|
|
184
|
-
{{#each schema.columns}}
|
|
185
|
-
<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}}">
|
|
186
|
-
<span class="index-col-num mr-1 hidden rounded bg-primary/15 px-1 text-[10px] font-bold text-primary">1</span>{{this.name}}
|
|
187
|
-
</button>
|
|
188
|
-
{{/each}}
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
|
-
</div>
|
|
192
|
-
<div id="index-preview" class="mt-3 hidden">
|
|
193
|
-
<div class="rounded-xl bg-base-200/60 p-3">
|
|
194
|
-
<div class="mb-1 text-[10px] font-semibold uppercase tracking-wider text-base-content/40">Generated SQL</div>
|
|
195
|
-
<pre class="code-panel !m-0"><code id="index-preview-code"></code></pre>
|
|
196
|
-
</div>
|
|
197
|
-
</div>
|
|
198
|
-
<div id="add-index-error" class="mt-3 hidden"></div>
|
|
199
|
-
<div class="mt-3 flex gap-2">
|
|
200
|
-
<button id="add-index-submit" type="button" class="btn btn-primary btn-sm">Create index</button>
|
|
201
|
-
<button id="add-index-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
<div class="overflow-x-auto">
|
|
205
|
-
{{#if schema.indexes.length}}
|
|
206
|
-
<table class="table table-sm">
|
|
207
|
-
<thead>
|
|
208
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
209
|
-
<th class="font-semibold">Name</th>
|
|
210
|
-
<th class="font-semibold">Columns</th>
|
|
211
|
-
<th class="font-semibold">Kind</th>
|
|
212
|
-
<th class="font-semibold">SQL</th>
|
|
213
|
-
<th class="text-right font-semibold">Actions</th>
|
|
214
|
-
</tr>
|
|
215
|
-
</thead>
|
|
216
|
-
<tbody>
|
|
217
|
-
{{#each schema.indexes}}
|
|
218
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
219
|
-
<td class="align-middle font-mono text-[13px]">{{this.name}}</td>
|
|
220
|
-
<td class="align-middle font-mono text-[13px] text-base-content/70">{{join this.columns ", "}}</td>
|
|
221
|
-
<td class="align-middle">
|
|
222
|
-
<div class="flex flex-wrap gap-1">
|
|
223
|
-
{{#if this.unique}}<span class="chip chip-type">UNIQUE</span>{{else}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
224
|
-
{{#unless (eq this.origin 'c')}}<span class="chip chip-null" title="Automatic index (created by SQLite)">AUTO</span>{{/unless}}
|
|
225
|
-
</div>
|
|
226
|
-
</td>
|
|
227
|
-
<td class="align-middle">
|
|
228
|
-
{{#if this.sql}}
|
|
229
|
-
<details class="group">
|
|
230
|
-
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">View SQL</summary>
|
|
231
|
-
<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>
|
|
232
|
-
</details>
|
|
233
|
-
{{else}}
|
|
234
|
-
<span class="text-base-content/30">—</span>
|
|
235
|
-
{{/if}}
|
|
236
|
-
</td>
|
|
237
|
-
<td class="whitespace-nowrap text-right align-middle">
|
|
238
|
-
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error index-drop"
|
|
239
|
-
data-index="{{this.name}}" {{#if ../readonly}}disabled{{/if}} {{#unless (eq this.origin 'c')}}disabled title="Automatic index — cannot be dropped"{{/unless}}>
|
|
240
|
-
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
241
|
-
Drop
|
|
242
|
-
</button>
|
|
243
|
-
</td>
|
|
244
|
-
</tr>
|
|
245
|
-
{{/each}}
|
|
246
|
-
</tbody>
|
|
247
|
-
</table>
|
|
248
|
-
{{else}}
|
|
249
|
-
<div class="px-5 py-8 text-center text-sm text-base-content/45">No indexes on this table yet.</div>
|
|
250
|
-
{{/if}}
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
{{#if schema.references.length}}
|
|
254
|
-
<div class="app-card overflow-hidden">
|
|
255
|
-
<div class="border-b border-base-200 px-5 py-4">
|
|
256
|
-
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Referenced by</h2>
|
|
257
|
-
</div>
|
|
258
|
-
<div class="overflow-x-auto">
|
|
259
|
-
<table class="table table-sm">
|
|
260
|
-
<thead>
|
|
261
|
-
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
262
|
-
<th class="font-semibold">Table</th>
|
|
263
|
-
<th class="font-semibold">Via</th>
|
|
264
|
-
</tr>
|
|
265
|
-
</thead>
|
|
266
|
-
<tbody>
|
|
267
|
-
{{#each schema.references}}
|
|
268
|
-
<tr class="hover:bg-primary/[0.04]">
|
|
269
|
-
<td class="align-middle font-mono text-[13px]">{{this.table}}</td>
|
|
270
|
-
<td class="align-middle font-mono text-[13px] text-base-content/70">{{this.from}} → {{this.to}}</td>
|
|
271
|
-
</tr>
|
|
272
|
-
{{/each}}
|
|
273
|
-
</tbody>
|
|
274
|
-
</table>
|
|
275
|
-
</div>
|
|
276
|
-
</div>
|
|
277
|
-
{{/if}}
|
|
278
|
-
{{#unless isInternal}}
|
|
279
|
-
<div class="rounded-2xl border border-error/25 bg-error/[0.03] p-5">
|
|
280
|
-
<h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-error">
|
|
281
|
-
{{{icon "warning" class="h-4 w-4"}}}
|
|
282
|
-
Danger zone
|
|
283
|
-
</h2>
|
|
284
|
-
<p class="mt-1 text-sm text-base-content/55">Dropping this table permanently removes its schema and all of its data.</p>
|
|
285
|
-
<div class="mt-3 flex flex-wrap items-center gap-3">
|
|
286
|
-
<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}}>
|
|
287
|
-
Drop table
|
|
288
|
-
</button>
|
|
289
|
-
{{#if readonly}}<span class="text-xs text-base-content/50">Read-only — table changes are disabled.</span>{{/if}}
|
|
290
|
-
{{#if schema.references.length}}
|
|
291
|
-
<span class="text-xs text-base-content/50">Cannot drop — referenced by {{schema.references.length}} table(s).</span>
|
|
292
|
-
{{/if}}
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
{{/unless}}
|
|
296
|
-
</div>
|
|
297
|
-
<script id="schema-config" type="application/json">{{{json config}}}</script>
|
|
298
|
-
<script src="{{basePath}}/js/schema.js" defer></script>
|
|
1
|
+
<div class="space-y-6">
|
|
299
2
|
<div class="page-header">
|
|
300
3
|
<div class="page-header-row">
|
|
301
4
|
<div class="flex items-center gap-3">
|
|
302
5
|
<a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
|
|
303
6
|
{{{icon "arrowLeft" class="h-4 w-4"}}}
|
|
304
7
|
</a>
|
|
305
8
|
<div>
|
|
306
9
|
<div class="page-pretitle">Schema Editor</div>
|
|
307
10
|
<h1 class="page-title font-mono text-xl sm:text-2xl">{{table}}</h1>
|
|
308
11
|
</div>
|
|
309
12
|
</div>
|
|
310
13
|
<div class="page-actions">
|
|
311
14
|
<a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost btn-sm gap-1.5">
|
|
312
15
|
{{{icon "table" class="h-4 w-4"}}}
|
|
313
16
|
View data
|
|
314
17
|
</a>
|
|
315
18
|
<a href="{{basePath}}/query" class="btn btn-outline btn-sm gap-1.5">
|
|
316
19
|
{{{icon "query" class="h-4 w-4"}}}
|
|
317
20
|
Query
|
|
318
21
|
</a>
|
|
319
22
|
</div>
|
|
320
23
|
</div>
|
|
321
24
|
</div>
|
|
322
25
|
<div class="app-card p-5">
|
|
323
26
|
<div class="flex flex-wrap items-end gap-3">
|
|
324
27
|
<div class="w-full max-w-sm">
|
|
325
28
|
<label class="field-label" for="table-rename-input">Table name</label>
|
|
326
29
|
<input id="table-rename-input" class="field-input font-mono" value="{{table}}" spellcheck="false" autocomplete="off" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}} />
|
|
327
30
|
</div>
|
|
328
31
|
<button id="rename-table" type="button" class="btn btn-primary btn-sm mb-0.5" {{#if isInternal}}disabled{{/if}} {{#if readonly}}disabled{{/if}}>
|
|
329
32
|
{{{icon "edit" class="h-4 w-4"}}}
|
|
330
33
|
Rename table
|
|
331
34
|
</button>
|
|
332
35
|
{{#if isInternal}}<span class="mb-1 text-xs text-base-content/45">Internal tables cannot be renamed.</span>{{/if}}
|
|
333
36
|
</div>
|
|
334
37
|
</div>
|
|
335
38
|
<div class="app-card overflow-hidden">
|
|
336
39
|
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
337
40
|
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
338
41
|
Columns
|
|
339
42
|
<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>
|
|
340
43
|
</h2>
|
|
341
44
|
<button id="add-column" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
342
45
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
343
46
|
Add column
|
|
344
47
|
</button>
|
|
345
48
|
</div>
|
|
346
49
|
<div id="add-column-panel" class="hidden border-b border-base-200 p-4">
|
|
347
50
|
<div class="mb-2 text-xs font-bold uppercase tracking-wider text-primary">Add New Column</div>
|
|
348
51
|
<div id="add-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
349
52
|
<div id="add-column-error" class="hidden mt-3"></div>
|
|
350
53
|
<div class="mt-3.5 flex gap-2">
|
|
351
54
|
<button id="add-column-submit" type="button" class="btn btn-primary btn-sm">Add column</button>
|
|
352
55
|
<button id="add-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
353
56
|
</div>
|
|
354
57
|
</div>
|
|
355
58
|
<div id="edit-column-panel" class="hidden border-b border-base-200 bg-base-200/30 p-4">
|
|
356
59
|
<div class="mb-2.5 flex items-center justify-between">
|
|
357
60
|
<div class="flex items-center gap-2">
|
|
358
61
|
<span class="text-xs font-bold uppercase tracking-wider text-primary">Edit Column:</span>
|
|
359
62
|
<span id="edit-column-target" class="font-mono text-sm font-bold text-base-content"></span>
|
|
360
63
|
</div>
|
|
361
64
|
<span class="text-[11px] text-base-content/45">Change data type, default value, primary key, nullability, uniqueness, or foreign key.</span>
|
|
362
65
|
</div>
|
|
363
66
|
<div id="edit-column-form" class="grid grid-cols-2 items-end gap-2.5 sm:grid-cols-12"></div>
|
|
364
67
|
<div id="edit-column-error" class="hidden mt-3"></div>
|
|
365
68
|
<div class="mt-3.5 flex gap-2">
|
|
366
69
|
<button id="edit-column-submit" type="button" class="btn btn-primary btn-sm">Save Changes</button>
|
|
367
70
|
<button id="edit-column-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
368
71
|
</div>
|
|
369
72
|
</div>
|
|
370
73
|
<div class="overflow-x-auto">
|
|
371
74
|
<table class="table table-sm">
|
|
372
75
|
<thead>
|
|
373
76
|
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
374
77
|
<th class="font-semibold">Name</th>
|
|
375
78
|
<th class="font-semibold">Type</th>
|
|
376
79
|
<th class="font-semibold">Constraints</th>
|
|
377
80
|
<th class="font-semibold">Default</th>
|
|
378
81
|
<th class="text-right font-semibold">Actions</th>
|
|
379
82
|
</tr>
|
|
380
83
|
</thead>
|
|
381
84
|
<tbody>
|
|
382
85
|
{{#each schema.columns}}
|
|
383
86
|
<tr class="hover:bg-primary/[0.04]">
|
|
384
87
|
<td class="col-name-cell align-middle" data-column="{{this.name}}">
|
|
385
88
|
<span class="name-display font-mono text-[13px] font-semibold">{{this.name}}</span>
|
|
386
89
|
</td>
|
|
387
90
|
<td class="align-middle"><span class="chip chip-type">{{this.type}}</span></td>
|
|
388
91
|
<td class="align-middle">
|
|
389
92
|
<div class="flex flex-wrap gap-1">
|
|
390
93
|
{{#if (gt this.pk 0)}}<span class="chip chip-pk">PK</span>{{/if}}
|
|
391
94
|
{{#if this.notnull}}<span class="chip chip-type">NOT NULL</span>{{/if}}
|
|
392
95
|
{{#if this.unique}}{{#unless (gt this.pk 0)}}<span class="chip chip-type">UNIQUE</span>{{/unless}}{{/if}}
|
|
393
96
|
{{#if this.fk}}<span class="chip chip-type">FK → {{this.fk.table}}.{{this.fk.to}}</span>{{/if}}
|
|
394
97
|
{{#if this.indexed}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
395
98
|
{{#if this.referencedBy.length}}<span class="chip chip-null" title="Referenced by {{this.referencedBy.length}} table(s)">REF × {{this.referencedBy.length}}</span>{{/if}}
|
|
396
99
|
</div>
|
|
397
100
|
</td>
|
|
398
101
|
<td class="align-middle font-mono text-[13px] text-base-content/60">
|
|
399
102
|
{{#if this.dflt_value}}{{this.dflt_value}}{{else}}<span class="text-base-content/25">—</span>{{/if}}
|
|
400
103
|
</td>
|
|
401
104
|
<td class="whitespace-nowrap text-right align-middle">
|
|
402
105
|
<div class="flex items-center justify-end gap-1">
|
|
403
106
|
<button type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary col-edit"
|
|
404
107
|
data-column="{{this.name}}"
|
|
405
108
|
data-type="{{this.type}}"
|
|
406
109
|
data-pk="{{#if (gt this.pk 0)}}true{{else}}false{{/if}}"
|
|
407
110
|
data-notnull="{{#if this.notnull}}true{{else}}false{{/if}}"
|
|
408
111
|
data-unique="{{#if this.unique}}true{{else}}false{{/if}}"
|
|
409
112
|
data-default="{{this.dflt_value}}"
|
|
410
113
|
data-fk-table="{{this.fk.table}}"
|
|
411
114
|
data-fk-to="{{this.fk.to}}"
|
|
412
115
|
{{#if ../readonly}}disabled{{/if}}>
|
|
413
116
|
{{{icon "edit" class="h-3.5 w-3.5"}}}
|
|
414
117
|
Edit
|
|
415
118
|
</button>
|
|
416
119
|
<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}}>
|
|
417
120
|
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
418
121
|
Delete
|
|
419
122
|
</button>
|
|
420
123
|
</div>
|
|
421
124
|
</td>
|
|
422
125
|
</tr>
|
|
423
126
|
{{/each}}
|
|
424
127
|
</tbody>
|
|
425
128
|
</table>
|
|
426
129
|
</div>
|
|
427
130
|
</div>
|
|
428
131
|
{{#if schema.foreignKeys.length}}
|
|
429
132
|
<div class="app-card overflow-hidden">
|
|
430
133
|
<div class="border-b border-base-200 px-5 py-4">
|
|
431
134
|
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Foreign keys</h2>
|
|
432
135
|
</div>
|
|
433
136
|
<div class="overflow-x-auto">
|
|
434
137
|
<table class="table table-sm">
|
|
435
138
|
<thead>
|
|
436
139
|
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
437
140
|
<th class="font-semibold">Column</th>
|
|
438
141
|
<th class="font-semibold">References</th>
|
|
439
142
|
<th class="font-semibold">On delete</th>
|
|
440
143
|
<th class="font-semibold">On update</th>
|
|
441
144
|
</tr>
|
|
442
145
|
</thead>
|
|
443
146
|
<tbody>
|
|
444
147
|
{{#each schema.foreignKeys}}
|
|
445
148
|
<tr class="hover:bg-primary/[0.04]">
|
|
446
149
|
<td class="align-middle font-mono text-[13px]">{{this.from}}</td>
|
|
447
150
|
<td class="align-middle font-mono text-[13px] text-primary">{{this.table}}.{{this.to}}</td>
|
|
448
151
|
<td class="align-middle text-[13px] text-base-content/60">{{this.on_delete}}</td>
|
|
449
152
|
<td class="align-middle text-[13px] text-base-content/60">{{this.on_update}}</td>
|
|
450
153
|
</tr>
|
|
451
154
|
{{/each}}
|
|
452
155
|
</tbody>
|
|
453
156
|
</table>
|
|
454
157
|
</div>
|
|
455
158
|
</div>
|
|
456
159
|
{{/if}}
|
|
457
160
|
<div class="app-card overflow-hidden">
|
|
458
161
|
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
459
162
|
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
460
163
|
Indexes
|
|
461
164
|
<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>
|
|
462
165
|
</h2>
|
|
463
166
|
<button id="add-index" type="button" class="btn btn-outline btn-sm gap-1.5" {{#if readonly}}disabled{{/if}}>
|
|
464
167
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
465
168
|
Add index
|
|
466
169
|
</button>
|
|
467
170
|
</div>
|
|
468
171
|
<div id="add-index-panel" class="hidden border-b border-base-200 p-4">
|
|
469
172
|
<div class="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
470
173
|
<div>
|
|
471
174
|
<label class="field-label" for="index-name">Index name <span class="text-base-content/40">(optional)</span></label>
|
|
472
175
|
<input id="index-name" class="field-input font-mono" placeholder="idx_users_email" spellcheck="false" autocomplete="off" />
|
|
473
176
|
</div>
|
|
474
177
|
<div class="flex items-end pb-1">
|
|
475
178
|
<label class="flex cursor-pointer items-center gap-2">
|
|
476
179
|
<input id="index-unique" type="checkbox" class="checkbox checkbox-primary checkbox-sm" />
|
|
477
180
|
<span class="text-sm font-medium text-base-content/70">Unique index</span>
|
|
478
181
|
</label>
|
|
479
182
|
</div>
|
|
480
183
|
<div class="sm:col-span-3">
|
|
481
184
|
<label class="field-label">Columns <span class="text-base-content/40">— click in the order they should appear</span></label>
|
|
482
185
|
<div id="index-columns" class="flex flex-wrap gap-2">
|
|
483
186
|
{{#each schema.columns}}
|
|
484
187
|
<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}}">
|
|
485
188
|
<span class="index-col-num mr-1 hidden rounded bg-primary/15 px-1 text-[10px] font-bold text-primary">1</span>{{this.name}}
|
|
486
189
|
</button>
|
|
487
190
|
{{/each}}
|
|
488
191
|
</div>
|
|
489
192
|
</div>
|
|
490
193
|
</div>
|
|
491
194
|
<div id="index-preview" class="mt-3 hidden">
|
|
492
195
|
<div class="rounded-xl bg-base-200/60 p-3">
|
|
493
196
|
<div class="mb-1 text-[10px] font-semibold uppercase tracking-wider text-base-content/40">Generated SQL</div>
|
|
494
197
|
<pre class="code-panel !m-0"><code id="index-preview-code"></code></pre>
|
|
495
198
|
</div>
|
|
496
199
|
</div>
|
|
497
200
|
<div id="add-index-error" class="mt-3 hidden"></div>
|
|
498
201
|
<div class="mt-3 flex gap-2">
|
|
499
202
|
<button id="add-index-submit" type="button" class="btn btn-primary btn-sm">Create index</button>
|
|
500
203
|
<button id="add-index-cancel" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
501
204
|
</div>
|
|
502
205
|
</div>
|
|
503
206
|
<div class="overflow-x-auto">
|
|
504
207
|
{{#if schema.indexes.length}}
|
|
505
208
|
<table class="table table-sm">
|
|
506
209
|
<thead>
|
|
507
210
|
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
508
211
|
<th class="font-semibold">Name</th>
|
|
509
212
|
<th class="font-semibold">Columns</th>
|
|
510
213
|
<th class="font-semibold">Kind</th>
|
|
511
214
|
<th class="font-semibold">SQL</th>
|
|
512
215
|
<th class="text-right font-semibold">Actions</th>
|
|
513
216
|
</tr>
|
|
514
217
|
</thead>
|
|
515
218
|
<tbody>
|
|
516
219
|
{{#each schema.indexes}}
|
|
517
220
|
<tr class="hover:bg-primary/[0.04]">
|
|
518
221
|
<td class="align-middle font-mono text-[13px]">{{this.name}}</td>
|
|
519
222
|
<td class="align-middle font-mono text-[13px] text-base-content/70">{{join this.columns ", "}}</td>
|
|
520
223
|
<td class="align-middle">
|
|
521
224
|
<div class="flex flex-wrap gap-1">
|
|
522
225
|
{{#if this.unique}}<span class="chip chip-type">UNIQUE</span>{{else}}<span class="chip chip-type">INDEX</span>{{/if}}
|
|
523
226
|
{{#unless (eq this.origin 'c')}}<span class="chip chip-null" title="Automatic index (created by SQLite)">AUTO</span>{{/unless}}
|
|
524
227
|
</div>
|
|
525
228
|
</td>
|
|
526
229
|
<td class="align-middle">
|
|
527
230
|
{{#if this.sql}}
|
|
528
231
|
<details class="group">
|
|
529
232
|
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">View SQL</summary>
|
|
530
233
|
<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>
|
|
531
234
|
</details>
|
|
532
235
|
{{else}}
|
|
533
236
|
<span class="text-base-content/30">—</span>
|
|
534
237
|
{{/if}}
|
|
535
238
|
</td>
|
|
536
239
|
<td class="whitespace-nowrap text-right align-middle">
|
|
537
240
|
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error index-drop"
|
|
538
241
|
data-index="{{this.name}}" {{#if ../readonly}}disabled{{/if}} {{#unless (eq this.origin 'c')}}disabled title="Automatic index — cannot be dropped"{{/unless}}>
|
|
539
242
|
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
540
243
|
Drop
|
|
541
244
|
</button>
|
|
542
245
|
</td>
|
|
543
246
|
</tr>
|
|
544
247
|
{{/each}}
|
|
545
248
|
</tbody>
|
|
546
249
|
</table>
|
|
547
250
|
{{else}}
|
|
548
251
|
<div class="px-5 py-8 text-center text-sm text-base-content/45">No indexes on this table yet.</div>
|
|
549
252
|
{{/if}}
|
|
550
253
|
</div>
|
|
551
254
|
</div>
|
|
552
255
|
{{#if schema.references.length}}
|
|
553
256
|
<div class="app-card overflow-hidden">
|
|
554
257
|
<div class="border-b border-base-200 px-5 py-4">
|
|
555
258
|
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Referenced by</h2>
|
|
556
259
|
</div>
|
|
557
260
|
<div class="overflow-x-auto">
|
|
558
261
|
<table class="table table-sm">
|
|
559
262
|
<thead>
|
|
560
263
|
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
561
264
|
<th class="font-semibold">Table</th>
|
|
562
265
|
<th class="font-semibold">Via</th>
|
|
563
266
|
</tr>
|
|
564
267
|
</thead>
|
|
565
268
|
<tbody>
|
|
566
269
|
{{#each schema.references}}
|
|
567
270
|
<tr class="hover:bg-primary/[0.04]">
|
|
568
271
|
<td class="align-middle font-mono text-[13px]">{{this.table}}</td>
|
|
569
272
|
<td class="align-middle font-mono text-[13px] text-base-content/70">{{this.from}} → {{this.to}}</td>
|
|
570
273
|
</tr>
|
|
571
274
|
{{/each}}
|
|
572
275
|
</tbody>
|
|
573
276
|
</table>
|
|
574
277
|
</div>
|
|
575
278
|
</div>
|
|
576
279
|
{{/if}}
|
|
577
280
|
{{#unless isInternal}}
|
|
578
281
|
<div class="rounded-2xl border border-error/25 bg-error/[0.03] p-5">
|
|
579
282
|
<h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-error">
|
|
580
283
|
{{{icon "warning" class="h-4 w-4"}}}
|
|
581
284
|
Danger zone
|
|
582
285
|
</h2>
|
|
583
286
|
<p class="mt-1 text-sm text-base-content/55">Dropping this table permanently removes its schema and all of its data.</p>
|
|
584
287
|
<div class="mt-3 flex flex-wrap items-center gap-3">
|
|
585
288
|
<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}}>
|
|
586
289
|
Drop table
|
|
587
290
|
</button>
|
|
588
291
|
{{#if readonly}}<span class="text-xs text-base-content/50">Read-only — table changes are disabled.</span>{{/if}}
|
|
589
292
|
{{#if schema.references.length}}
|
|
590
293
|
<span class="text-xs text-base-content/50">Cannot drop — referenced by {{schema.references.length}} table(s).</span>
|
|
591
294
|
{{/if}}
|
|
592
295
|
</div>
|
|
593
296
|
</div>
|
|
594
297
|
{{/unless}}
|