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.
@@ -1,162 +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>
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>
@@ -1,134 +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>
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>