admindb 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +325 -0
- package/dist/app.d.ts +36 -0
- package/dist/app.js +186 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +61 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/csv.d.ts +15 -0
- package/dist/csv.js +80 -0
- package/dist/csv.js.map +1 -0
- package/dist/db/database.d.ts +225 -0
- package/dist/db/database.js +497 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/export.d.ts +12 -0
- package/dist/db/export.js +37 -0
- package/dist/db/export.js.map +1 -0
- package/dist/db/manager.d.ts +62 -0
- package/dist/db/manager.js +206 -0
- package/dist/db/manager.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.js +25 -0
- package/dist/logger.js.map +1 -0
- package/dist/public/css/app.css +1 -0
- package/dist/public/css/input.css +179 -0
- package/dist/public/js/api.js +47 -0
- package/dist/public/js/app.js +120 -0
- package/dist/public/js/browse.js +123 -0
- package/dist/public/js/databases.js +45 -0
- package/dist/public/js/designer.js +205 -0
- package/dist/public/js/forms.js +244 -0
- package/dist/public/js/query.js +232 -0
- package/dist/public/js/schema.js +314 -0
- package/dist/public/js/triggers.js +155 -0
- package/dist/public/js/views.js +176 -0
- package/dist/routes/api.d.ts +9 -0
- package/dist/routes/api.js +622 -0
- package/dist/routes/api.js.map +1 -0
- package/dist/routes/databases.d.ts +19 -0
- package/dist/routes/databases.js +99 -0
- package/dist/routes/databases.js.map +1 -0
- package/dist/routes/pages.d.ts +9 -0
- package/dist/routes/pages.js +253 -0
- package/dist/routes/pages.js.map +1 -0
- package/dist/sql/classifier.d.ts +19 -0
- package/dist/sql/classifier.js +37 -0
- package/dist/sql/classifier.js.map +1 -0
- package/dist/sql/generator.d.ts +99 -0
- package/dist/sql/generator.js +259 -0
- package/dist/sql/generator.js.map +1 -0
- package/dist/test/classifier.test.d.ts +1 -0
- package/dist/test/classifier.test.js +44 -0
- package/dist/test/classifier.test.js.map +1 -0
- package/dist/test/csv.test.d.ts +1 -0
- package/dist/test/csv.test.js +64 -0
- package/dist/test/csv.test.js.map +1 -0
- package/dist/test/database.test.d.ts +1 -0
- package/dist/test/database.test.js +224 -0
- package/dist/test/database.test.js.map +1 -0
- package/dist/test/generator.test.d.ts +1 -0
- package/dist/test/generator.test.js +164 -0
- package/dist/test/generator.test.js.map +1 -0
- package/dist/test/manager.test.d.ts +1 -0
- package/dist/test/manager.test.js +146 -0
- package/dist/test/manager.test.js.map +1 -0
- package/dist/util.d.ts +29 -0
- package/dist/util.js +127 -0
- package/dist/util.js.map +1 -0
- package/dist/views/layouts/main.hbs +49 -0
- package/dist/views/pages/databases.hbs +102 -0
- package/dist/views/pages/designer.hbs +81 -0
- package/dist/views/pages/error.hbs +12 -0
- package/dist/views/pages/form.hbs +62 -0
- package/dist/views/pages/home.hbs +123 -0
- package/dist/views/pages/query.hbs +94 -0
- package/dist/views/pages/schema.hbs +290 -0
- package/dist/views/pages/table.hbs +203 -0
- package/dist/views/pages/triggers.hbs +162 -0
- package/dist/views/pages/views.hbs +134 -0
- package/dist/views/partials/navbar.hbs +50 -0
- package/dist/views/partials/sidebar.hbs +128 -0
- package/package.json +62 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<div class="space-y-6">
|
|
2
|
+
<!-- Header -->
|
|
3
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
4
|
+
<div>
|
|
5
|
+
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Schema</p>
|
|
6
|
+
<h1 class="mt-1 text-3xl font-extrabold tracking-tight">Triggers</h1>
|
|
7
|
+
<p class="mt-1.5 text-sm text-base-content/55">Automated actions that run when rows in a table are inserted, updated, or deleted.</p>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex gap-2">
|
|
10
|
+
<a href="{{basePath}}/views" class="btn btn-ghost btn-sm gap-1.5">
|
|
11
|
+
<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="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
|
12
|
+
Views
|
|
13
|
+
</a>
|
|
14
|
+
{{#unless readonly}}
|
|
15
|
+
<button id="new-trigger" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
16
|
+
<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>
|
|
17
|
+
New trigger
|
|
18
|
+
</button>
|
|
19
|
+
{{/unless}}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- New trigger form -->
|
|
24
|
+
<div id="new-trigger-panel" class="app-card hidden p-5">
|
|
25
|
+
<div class="grid gap-4 lg:grid-cols-[1fr_360px]">
|
|
26
|
+
<div class="space-y-4">
|
|
27
|
+
<div class="grid gap-4 sm:grid-cols-3">
|
|
28
|
+
<div>
|
|
29
|
+
<label class="field-label" for="trigger-name">Trigger name</label>
|
|
30
|
+
<input id="trigger-name" class="field-input font-mono" placeholder="e.g. audit_user_updates" spellcheck="false" autocomplete="off" />
|
|
31
|
+
</div>
|
|
32
|
+
<div>
|
|
33
|
+
<label class="field-label" for="trigger-table">Table</label>
|
|
34
|
+
<select id="trigger-table" class="field-select font-mono">
|
|
35
|
+
<option value="">— select a table —</option>
|
|
36
|
+
{{#each tables}}
|
|
37
|
+
<option value="{{this}}">{{this}}</option>
|
|
38
|
+
{{/each}}
|
|
39
|
+
</select>
|
|
40
|
+
</div>
|
|
41
|
+
<div>
|
|
42
|
+
<label class="field-label" for="trigger-timing">Timing</label>
|
|
43
|
+
<select id="trigger-timing" class="field-select">
|
|
44
|
+
<option value="BEFORE">BEFORE</option>
|
|
45
|
+
<option value="AFTER" selected>AFTER</option>
|
|
46
|
+
<option value="INSTEAD OF">INSTEAD OF</option>
|
|
47
|
+
</select>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div>
|
|
52
|
+
<label class="field-label" for="trigger-event">Event</label>
|
|
53
|
+
<select id="trigger-event" class="field-select">
|
|
54
|
+
<option value="INSERT" selected>INSERT</option>
|
|
55
|
+
<option value="UPDATE">UPDATE</option>
|
|
56
|
+
<option value="DELETE">DELETE</option>
|
|
57
|
+
</select>
|
|
58
|
+
<p class="mt-1 text-xs text-base-content/45">SQLite allows one event per trigger. To react to several, create one trigger per event.</p>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div>
|
|
62
|
+
<label class="field-label" for="trigger-when">WHEN clause <span class="text-base-content/40">(optional)</span></label>
|
|
63
|
+
<input id="trigger-when" class="field-input font-mono" placeholder="NEW.age >= 18" spellcheck="false" autocomplete="off" />
|
|
64
|
+
<p class="mt-1 text-xs text-base-content/45">Use <code class="font-mono">NEW.</code> / <code class="font-mono">OLD.</code> to reference row values. Leave empty for “always”.</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div>
|
|
68
|
+
<label class="field-label" for="trigger-body">
|
|
69
|
+
Body
|
|
70
|
+
<span class="chip chip-type">required</span>
|
|
71
|
+
</label>
|
|
72
|
+
<div class="sql-editor-wrap">
|
|
73
|
+
<div id="trigger-gutter" class="sql-gutter"></div>
|
|
74
|
+
<textarea id="trigger-body" class="sql-input font-mono" rows="6" spellcheck="false" placeholder="INSERT INTO audit_log (table_name, action, changed_at) VALUES ('users', 'UPDATE', datetime('now'));"></textarea>
|
|
75
|
+
</div>
|
|
76
|
+
<p class="mt-1.5 text-xs text-base-content/45">One or more statements, each ended with <code class="font-mono">;</code>. Use <code class="font-mono">NEW.col</code> / <code class="font-mono">OLD.col</code>.</p>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div id="trigger-error" class="hidden"></div>
|
|
80
|
+
<div class="flex gap-2">
|
|
81
|
+
<button id="create-trigger" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
82
|
+
<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="M5 13l4 4L19 7" /></svg>
|
|
83
|
+
Create trigger
|
|
84
|
+
</button>
|
|
85
|
+
<button id="cancel-trigger" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<aside>
|
|
89
|
+
<div class="app-card overflow-hidden">
|
|
90
|
+
<div class="flex items-center justify-between border-b border-base-200 bg-base-200/40 px-4 py-3">
|
|
91
|
+
<h2 class="flex items-center gap-2 text-sm font-semibold text-base-content/60">
|
|
92
|
+
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/10 text-primary">
|
|
93
|
+
<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="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
|
94
|
+
</span>
|
|
95
|
+
SQL preview
|
|
96
|
+
</h2>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="p-4">
|
|
99
|
+
<pre id="trigger-preview" class="code-panel hidden"><code id="trigger-preview-code"></code></pre>
|
|
100
|
+
<p id="trigger-preview-hint" class="text-xs text-base-content/45">The generated <code class="font-mono">CREATE TRIGGER</code> statement appears here as you type.</p>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</aside>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<!-- List -->
|
|
108
|
+
<div class="app-card overflow-hidden">
|
|
109
|
+
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
110
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
111
|
+
Triggers
|
|
112
|
+
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{triggers.length}}</span>
|
|
113
|
+
</h2>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
{{#if triggers.length}}
|
|
117
|
+
<div class="overflow-x-auto">
|
|
118
|
+
<table class="table table-sm">
|
|
119
|
+
<thead>
|
|
120
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
121
|
+
<th class="font-semibold">Name</th>
|
|
122
|
+
<th class="font-semibold">On</th>
|
|
123
|
+
<th class="font-semibold">Definition</th>
|
|
124
|
+
<th class="text-right font-semibold">Actions</th>
|
|
125
|
+
</tr>
|
|
126
|
+
</thead>
|
|
127
|
+
<tbody>
|
|
128
|
+
{{#each triggers}}
|
|
129
|
+
<tr class="hover:bg-primary/[0.04] align-top">
|
|
130
|
+
<td class="whitespace-nowrap align-middle font-mono text-[13px] font-semibold">{{this.name}}</td>
|
|
131
|
+
<td class="whitespace-nowrap align-middle font-mono text-[13px] text-primary">{{this.table}}</td>
|
|
132
|
+
<td class="align-middle">
|
|
133
|
+
{{#if this.sql}}
|
|
134
|
+
<details class="group">
|
|
135
|
+
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">Trigger SQL</summary>
|
|
136
|
+
<pre class="mt-1 max-w-[42rem] overflow-x-auto rounded-lg bg-base-200/70 p-2.5 font-mono text-[11px] leading-relaxed text-base-content/70">{{this.sql}}</pre>
|
|
137
|
+
</details>
|
|
138
|
+
{{else}}
|
|
139
|
+
<span class="text-base-content/30">—</span>
|
|
140
|
+
{{/if}}
|
|
141
|
+
</td>
|
|
142
|
+
<td class="whitespace-nowrap text-right align-middle">
|
|
143
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error trigger-drop" data-trigger="{{this.name}}" {{#if ../readonly}}disabled{{/if}}>
|
|
144
|
+
<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>
|
|
145
|
+
Drop
|
|
146
|
+
</button>
|
|
147
|
+
</td>
|
|
148
|
+
</tr>
|
|
149
|
+
{{/each}}
|
|
150
|
+
</tbody>
|
|
151
|
+
</table>
|
|
152
|
+
</div>
|
|
153
|
+
{{else}}
|
|
154
|
+
<div class="px-5 py-10 text-center text-sm text-base-content/45">
|
|
155
|
+
No triggers yet. {{#unless readonly}}Create one with “New trigger”.{{/unless}}
|
|
156
|
+
</div>
|
|
157
|
+
{{/if}}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<script id="triggers-config" type="application/json">{{{json config}}}</script>
|
|
162
|
+
<script src="{{basePath}}/js/triggers.js" defer></script>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<div class="space-y-6">
|
|
2
|
+
<!-- Header -->
|
|
3
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
4
|
+
<div>
|
|
5
|
+
<p class="text-sm font-semibold uppercase tracking-wider text-primary">Schema</p>
|
|
6
|
+
<h1 class="mt-1 text-3xl font-extrabold tracking-tight">Views</h1>
|
|
7
|
+
<p class="mt-1.5 text-sm text-base-content/55">Saved SELECT statements you can query like a table. Views are read-only.</p>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex gap-2">
|
|
10
|
+
<a href="{{basePath}}/triggers" class="btn btn-ghost btn-sm gap-1.5">
|
|
11
|
+
<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>
|
|
12
|
+
Triggers
|
|
13
|
+
</a>
|
|
14
|
+
{{#unless readonly}}
|
|
15
|
+
<button id="new-view" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
16
|
+
<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>
|
|
17
|
+
New view
|
|
18
|
+
</button>
|
|
19
|
+
{{/unless}}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- New view form -->
|
|
24
|
+
<div id="new-view-panel" class="app-card hidden p-5">
|
|
25
|
+
<div class="grid gap-4 lg:grid-cols-[1fr_360px]">
|
|
26
|
+
<div class="space-y-4">
|
|
27
|
+
<div>
|
|
28
|
+
<label class="field-label" for="view-name">View name</label>
|
|
29
|
+
<input id="view-name" class="field-input font-mono" placeholder="e.g. active_users" spellcheck="false" autocomplete="off" />
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
<label class="field-label" for="view-sql">
|
|
33
|
+
SELECT statement
|
|
34
|
+
<span class="chip chip-type">required</span>
|
|
35
|
+
</label>
|
|
36
|
+
<div class="sql-editor-wrap">
|
|
37
|
+
<div id="view-gutter" class="sql-gutter"></div>
|
|
38
|
+
<textarea id="view-sql" class="sql-input font-mono" rows="8" spellcheck="false" placeholder="SELECT id, email, name FROM users WHERE active = 1"></textarea>
|
|
39
|
+
</div>
|
|
40
|
+
<p class="mt-1.5 text-xs text-base-content/45">A single SELECT statement. Sub-queries and CTEs are allowed.</p>
|
|
41
|
+
</div>
|
|
42
|
+
<div id="view-error" class="hidden"></div>
|
|
43
|
+
<div class="flex gap-2">
|
|
44
|
+
<button id="create-view" type="button" class="btn btn-primary btn-sm gap-1.5">
|
|
45
|
+
<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="M5 13l4 4L19 7" /></svg>
|
|
46
|
+
Create view
|
|
47
|
+
</button>
|
|
48
|
+
<button id="cancel-view" type="button" class="btn btn-ghost btn-sm">Cancel</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<aside>
|
|
52
|
+
<div class="app-card overflow-hidden">
|
|
53
|
+
<div class="flex items-center justify-between border-b border-base-200 bg-base-200/40 px-4 py-3">
|
|
54
|
+
<h2 class="flex items-center gap-2 text-sm font-semibold text-base-content/60">
|
|
55
|
+
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/10 text-primary">
|
|
56
|
+
<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="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
|
57
|
+
</span>
|
|
58
|
+
SQL preview
|
|
59
|
+
</h2>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="p-4">
|
|
62
|
+
<pre id="view-preview" class="code-panel hidden"><code id="view-preview-code"></code></pre>
|
|
63
|
+
<p id="view-preview-hint" class="text-xs text-base-content/45">The generated <code class="font-mono">CREATE VIEW</code> statement appears here as you type.</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</aside>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- List -->
|
|
71
|
+
<div class="app-card overflow-hidden">
|
|
72
|
+
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
|
|
73
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">
|
|
74
|
+
Views
|
|
75
|
+
<span class="ml-1 rounded-md bg-base-200 px-1.5 py-0.5 text-[10px] text-base-content/50">{{views.length}}</span>
|
|
76
|
+
</h2>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
{{#if views.length}}
|
|
80
|
+
<div class="overflow-x-auto">
|
|
81
|
+
<table class="table table-sm">
|
|
82
|
+
<thead>
|
|
83
|
+
<tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
|
|
84
|
+
<th class="font-semibold">Name</th>
|
|
85
|
+
<th class="font-semibold">Definition</th>
|
|
86
|
+
<th class="text-right font-semibold">Actions</th>
|
|
87
|
+
</tr>
|
|
88
|
+
</thead>
|
|
89
|
+
<tbody>
|
|
90
|
+
{{#each views}}
|
|
91
|
+
<tr class="hover:bg-primary/[0.04] align-top">
|
|
92
|
+
<td class="whitespace-nowrap align-middle font-mono text-[13px] font-semibold">{{this.name}}</td>
|
|
93
|
+
<td class="align-middle">
|
|
94
|
+
{{#if this.sql}}
|
|
95
|
+
<details class="group">
|
|
96
|
+
<summary class="cursor-pointer text-xs font-medium text-primary/80 hover:text-primary">View SQL</summary>
|
|
97
|
+
<pre class="mt-1 max-w-[42rem] overflow-x-auto rounded-lg bg-base-200/70 p-2.5 font-mono text-[11px] leading-relaxed text-base-content/70">{{this.sql}}</pre>
|
|
98
|
+
</details>
|
|
99
|
+
{{else}}
|
|
100
|
+
<span class="text-base-content/30">—</span>
|
|
101
|
+
{{/if}}
|
|
102
|
+
</td>
|
|
103
|
+
<td class="whitespace-nowrap text-right align-middle">
|
|
104
|
+
<div class="flex items-center justify-end gap-1">
|
|
105
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary view-browse" data-view="{{this.name}}">
|
|
106
|
+
<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="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
|
107
|
+
Preview rows
|
|
108
|
+
</button>
|
|
109
|
+
<button type="button" class="btn btn-ghost btn-xs gap-1 text-error view-drop" data-view="{{this.name}}" {{#if ../readonly}}disabled{{/if}}>
|
|
110
|
+
<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>
|
|
111
|
+
Drop
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</td>
|
|
115
|
+
</tr>
|
|
116
|
+
<tr class="view-preview-row hidden">
|
|
117
|
+
<td colspan="3" class="border-t-0 p-0">
|
|
118
|
+
<div class="px-5 py-4"></div>
|
|
119
|
+
</td>
|
|
120
|
+
</tr>
|
|
121
|
+
{{/each}}
|
|
122
|
+
</tbody>
|
|
123
|
+
</table>
|
|
124
|
+
</div>
|
|
125
|
+
{{else}}
|
|
126
|
+
<div class="px-5 py-10 text-center text-sm text-base-content/45">
|
|
127
|
+
No views yet. {{#unless readonly}}Create one with “New view”.{{/unless}}
|
|
128
|
+
</div>
|
|
129
|
+
{{/if}}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<script id="views-config" type="application/json">{{{json config}}}</script>
|
|
134
|
+
<script src="{{basePath}}/js/views.js" defer></script>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<div class="sticky top-0 z-30 border-b border-base-300/80 bg-base-100/85 backdrop-blur-md">
|
|
2
|
+
<div class="navbar mx-auto w-full max-w-[1500px] px-4 sm:px-6 lg:px-8">
|
|
3
|
+
<div class="flex-none lg:hidden">
|
|
4
|
+
<label for="sidebar-toggle" class="btn btn-square btn-ghost" aria-label="open sidebar">
|
|
5
|
+
<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">
|
|
6
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
|
7
|
+
</svg>
|
|
8
|
+
</label>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="flex-1">
|
|
11
|
+
<a href="{{basePath}}/" class="flex items-center gap-2.5">
|
|
12
|
+
<span class="grid h-9 w-9 place-items-center rounded-xl bg-gradient-to-br from-primary to-secondary text-white shadow-soft">
|
|
13
|
+
<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">
|
|
14
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" />
|
|
15
|
+
</svg>
|
|
16
|
+
</span>
|
|
17
|
+
<span class="text-lg font-bold tracking-tight">DB<span class="text-primary">Admin</span></span>
|
|
18
|
+
</a>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="flex items-center gap-1.5">
|
|
21
|
+
{{#unless databasesMode}}
|
|
22
|
+
{{#if databasesUrl}}
|
|
23
|
+
<a href="{{databasesUrl}}" class="btn btn-ghost btn-sm hidden gap-1.5 sm:inline-flex">
|
|
24
|
+
<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="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" /></svg>
|
|
25
|
+
Databases
|
|
26
|
+
</a>
|
|
27
|
+
{{/if}}
|
|
28
|
+
<a href="{{basePath}}/query" class="btn btn-ghost btn-sm hidden gap-1.5 sm:inline-flex">
|
|
29
|
+
<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>
|
|
30
|
+
Query
|
|
31
|
+
</a>
|
|
32
|
+
{{#unless readonly}}
|
|
33
|
+
<a href="{{basePath}}/designer" class="btn btn-ghost btn-sm hidden gap-1.5 sm:inline-flex">
|
|
34
|
+
<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>
|
|
35
|
+
New table
|
|
36
|
+
</a>
|
|
37
|
+
{{/unless}}
|
|
38
|
+
<a href="{{basePath}}/export" class="btn btn-ghost btn-sm hidden gap-1.5 md:inline-flex">
|
|
39
|
+
<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="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
|
|
40
|
+
Export
|
|
41
|
+
</a>
|
|
42
|
+
{{/unless}}
|
|
43
|
+
<button id="theme-toggle" type="button" class="btn btn-square btn-ghost btn-sm" aria-label="Toggle dark mode" title="Toggle dark mode">
|
|
44
|
+
<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">
|
|
45
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
46
|
+
</svg>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<aside class="flex h-full min-h-full w-72 flex-col bg-neutral text-neutral-content">
|
|
2
|
+
<div class="flex items-center gap-2.5 px-5 pb-4 pt-5">
|
|
3
|
+
<span class="grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-gradient-to-br from-primary to-secondary text-white shadow-soft">
|
|
4
|
+
<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">
|
|
5
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" />
|
|
6
|
+
</svg>
|
|
7
|
+
</span>
|
|
8
|
+
<div>
|
|
9
|
+
<div class="text-base font-bold leading-tight">AdminDB</div>
|
|
10
|
+
<div class="text-[11px] text-neutral-content/50">{{#if databasesMode}}Database manager{{else}}Database: {{dbId}}{{/if}}</div>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
{{#if databasesMode}}
|
|
15
|
+
<nav class="flex-1 overflow-y-auto px-3 py-2">
|
|
16
|
+
<ul class="space-y-0.5">
|
|
17
|
+
<li>
|
|
18
|
+
<a href="{{basePath}}/" class="side-link active">
|
|
19
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" /></svg>
|
|
20
|
+
Databases
|
|
21
|
+
</a>
|
|
22
|
+
</li>
|
|
23
|
+
</ul>
|
|
24
|
+
</nav>
|
|
25
|
+
{{else}}
|
|
26
|
+
<div class="px-4 pb-2">
|
|
27
|
+
<label class="relative block">
|
|
28
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-neutral-content/40" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
29
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
30
|
+
</svg>
|
|
31
|
+
<input id="table-search" type="search" placeholder="Filter tables…" autocomplete="off"
|
|
32
|
+
class="w-full rounded-lg border border-white/10 bg-white/[0.06] py-2 pl-9 pr-3 text-sm text-neutral-content outline-none transition placeholder:text-neutral-content/40 focus:border-primary/70 focus:ring-4 focus:ring-primary/20" />
|
|
33
|
+
</label>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<nav class="flex-1 overflow-y-auto px-3 py-2">
|
|
37
|
+
<ul class="space-y-0.5">
|
|
38
|
+
{{#if databasesUrl}}
|
|
39
|
+
<li>
|
|
40
|
+
<a href="{{databasesUrl}}" class="side-link">
|
|
41
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" /></svg>
|
|
42
|
+
Databases
|
|
43
|
+
</a>
|
|
44
|
+
</li>
|
|
45
|
+
{{/if}}
|
|
46
|
+
<li>
|
|
47
|
+
<a href="{{basePath}}/" class="side-link {{#if (eq currentPath '/')}}active{{/if}}">
|
|
48
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /></svg>
|
|
49
|
+
Home
|
|
50
|
+
</a>
|
|
51
|
+
</li>
|
|
52
|
+
<li>
|
|
53
|
+
<a href="{{basePath}}/query" class="side-link {{#if (startsWith currentPath '/query')}}active{{/if}}">
|
|
54
|
+
<svg xmlns="http://www.w3.org/2000/svg" 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>
|
|
55
|
+
Query editor
|
|
56
|
+
</a>
|
|
57
|
+
</li>
|
|
58
|
+
<li>
|
|
59
|
+
<a href="{{basePath}}/views" class="side-link {{#if (startsWith currentPath '/views')}}active{{/if}}">
|
|
60
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
|
61
|
+
Views
|
|
62
|
+
</a>
|
|
63
|
+
</li>
|
|
64
|
+
<li>
|
|
65
|
+
<a href="{{basePath}}/triggers" class="side-link {{#if (startsWith currentPath '/triggers')}}active{{/if}}">
|
|
66
|
+
<svg xmlns="http://www.w3.org/2000/svg" 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>
|
|
67
|
+
Triggers
|
|
68
|
+
</a>
|
|
69
|
+
</li>
|
|
70
|
+
{{#unless readonly}}
|
|
71
|
+
<li>
|
|
72
|
+
<a href="{{basePath}}/designer" class="side-link {{#if (startsWith currentPath '/designer')}}active{{/if}}">
|
|
73
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
|
|
74
|
+
New table
|
|
75
|
+
</a>
|
|
76
|
+
</li>
|
|
77
|
+
{{/unless}}
|
|
78
|
+
</ul>
|
|
79
|
+
|
|
80
|
+
<div class="mb-2 mt-6 flex items-center justify-between px-3">
|
|
81
|
+
<span class="text-[11px] font-semibold uppercase tracking-wider text-neutral-content/40">Tables</span>
|
|
82
|
+
<span id="table-count" class="rounded-md bg-white/[0.06] px-1.5 py-0.5 text-[10px] font-semibold text-neutral-content/50">{{tables.length}}</span>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<ul id="table-list" class="space-y-0.5">
|
|
86
|
+
{{#each tables}}
|
|
87
|
+
<li class="table-item" data-name="{{this}}">
|
|
88
|
+
<a href="{{../basePath}}/tables/{{this}}" class="side-link {{#if (eq ../currentTable this)}}active{{/if}}">
|
|
89
|
+
<span class="table-icon">
|
|
90
|
+
<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>
|
|
91
|
+
</span>
|
|
92
|
+
<span class="truncate">{{this}}</span>
|
|
93
|
+
</a>
|
|
94
|
+
</li>
|
|
95
|
+
{{else}}
|
|
96
|
+
<li class="px-3 py-2 text-xs text-neutral-content/40">No tables yet</li>
|
|
97
|
+
{{/each}}
|
|
98
|
+
</ul>
|
|
99
|
+
|
|
100
|
+
{{#if internalTables.length}}
|
|
101
|
+
<div class="mb-2 mt-6 px-3 text-[11px] font-semibold uppercase tracking-wider text-neutral-content/40">Internal</div>
|
|
102
|
+
<ul class="space-y-0.5">
|
|
103
|
+
{{#each internalTables}}
|
|
104
|
+
<li>
|
|
105
|
+
<a href="{{../basePath}}/tables/{{this}}" class="side-link {{#if (eq ../currentTable this)}}active{{/if}}">
|
|
106
|
+
<span class="table-icon">
|
|
107
|
+
<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 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /></svg>
|
|
108
|
+
</span>
|
|
109
|
+
<span class="truncate">{{this}}</span>
|
|
110
|
+
</a>
|
|
111
|
+
</li>
|
|
112
|
+
{{/each}}
|
|
113
|
+
</ul>
|
|
114
|
+
{{/if}}
|
|
115
|
+
</nav>
|
|
116
|
+
{{/if}}
|
|
117
|
+
|
|
118
|
+
<div class="border-t border-white/10 px-5 py-3">
|
|
119
|
+
<div class="text-[11px] font-medium uppercase tracking-wider text-neutral-content/40">{{#if databasesMode}}Directory{{else}}Database{{/if}}</div>
|
|
120
|
+
<div class="mt-0.5 truncate font-mono text-[11px] text-neutral-content/60" title="{{dbPath}}">{{dbPath}}</div>
|
|
121
|
+
{{#if readonly}}
|
|
122
|
+
<div class="mt-2 inline-flex items-center gap-1 rounded-md bg-warning/20 px-2 py-1 text-[10px] font-bold uppercase tracking-wider text-warning">
|
|
123
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 15v2m0 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>
|
|
124
|
+
Read-only
|
|
125
|
+
</div>
|
|
126
|
+
{{/if}}
|
|
127
|
+
</div>
|
|
128
|
+
</aside>
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "admindb",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Browser-based SQLite database administration tool — embed it in your Express app or run it standalone.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"admindb": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/MIbnEKhalid/admindb#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/MIbnEKhalid/admindb.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/MIbnEKhalid/admindb/issues"
|
|
17
|
+
},
|
|
18
|
+
"author": "MIbnEKhalid",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22.5.0"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-assets.mjs && npm run build:css",
|
|
29
|
+
"build:css": "tailwindcss -i ./src/public/css/input.css -o ./dist/public/css/app.css --minify",
|
|
30
|
+
"start": "node dist/cli.js",
|
|
31
|
+
"dev": "concurrently -k -n server,css \"tsx watch src/cli.ts\" \"npm run dev:css\"",
|
|
32
|
+
"dev:css": "tailwindcss -i ./src/public/css/input.css -o ./src/public/css/app.css --watch",
|
|
33
|
+
"prepack": "npm run build",
|
|
34
|
+
"test": "npm run build && node --test \"dist/test/**/*.test.js\""
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"sqlite",
|
|
38
|
+
"admin",
|
|
39
|
+
"database",
|
|
40
|
+
"express",
|
|
41
|
+
"handlebars",
|
|
42
|
+
"tailwind",
|
|
43
|
+
"daisyui"
|
|
44
|
+
],
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"registry": "https://registry.npmjs.org/"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"express": "^5.1.0",
|
|
51
|
+
"express-handlebars": "^8.0.3"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/express": "^4.17.21",
|
|
55
|
+
"@types/node": "^22.10.0",
|
|
56
|
+
"concurrently": "^9.1.0",
|
|
57
|
+
"daisyui": "^4.12.0",
|
|
58
|
+
"tailwindcss": "^3.4.17",
|
|
59
|
+
"tsx": "^4.19.0",
|
|
60
|
+
"typescript": "^5.7.0"
|
|
61
|
+
}
|
|
62
|
+
}
|