admindb 1.2.1 → 2.1.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.
Files changed (208) hide show
  1. package/README.md +262 -329
  2. package/dist/app.d.ts +25 -4
  3. package/dist/app.js +79 -15
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/config.d.ts +19 -0
  6. package/dist/auth/config.js +147 -0
  7. package/dist/auth/config.js.map +1 -0
  8. package/dist/auth/crypto.d.ts +27 -0
  9. package/dist/auth/crypto.js +133 -0
  10. package/dist/auth/crypto.js.map +1 -0
  11. package/dist/auth/index.d.ts +5 -0
  12. package/dist/auth/index.js +22 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/auth/middleware.d.ts +14 -0
  15. package/dist/auth/middleware.js +100 -0
  16. package/dist/auth/middleware.js.map +1 -0
  17. package/dist/auth/routes.d.ts +7 -0
  18. package/dist/auth/routes.js +78 -0
  19. package/dist/auth/routes.js.map +1 -0
  20. package/dist/auth/types.d.ts +35 -0
  21. package/dist/auth/types.js +11 -0
  22. package/dist/auth/types.js.map +1 -0
  23. package/dist/cli/args.d.ts +45 -0
  24. package/dist/cli/args.js +328 -0
  25. package/dist/cli/args.js.map +1 -0
  26. package/dist/cli/config.d.ts +56 -0
  27. package/dist/cli/config.js +133 -0
  28. package/dist/cli/config.js.map +1 -0
  29. package/dist/cli/index.d.ts +4 -0
  30. package/dist/cli/index.js +21 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/runner.d.ts +1 -0
  33. package/dist/cli/runner.js +222 -0
  34. package/dist/cli/runner.js.map +1 -0
  35. package/dist/cli.js +2 -127
  36. package/dist/cli.js.map +1 -1
  37. package/dist/data/datasets.d.ts +17 -0
  38. package/dist/data/datasets.js +133 -0
  39. package/dist/data/datasets.js.map +1 -0
  40. package/dist/data/detector.d.ts +30 -0
  41. package/dist/data/detector.js +472 -0
  42. package/dist/data/detector.js.map +1 -0
  43. package/dist/data/engine.d.ts +10 -0
  44. package/dist/data/engine.js +211 -0
  45. package/dist/data/engine.js.map +1 -0
  46. package/dist/data/index.d.ts +5 -0
  47. package/dist/data/index.js +22 -0
  48. package/dist/data/index.js.map +1 -0
  49. package/dist/data/strategies.d.ts +30 -0
  50. package/dist/data/strategies.js +343 -0
  51. package/dist/data/strategies.js.map +1 -0
  52. package/dist/data/types.d.ts +73 -0
  53. package/dist/data/types.js +8 -0
  54. package/dist/data/types.js.map +1 -0
  55. package/dist/db/database.d.ts +14 -146
  56. package/dist/db/database.js +208 -461
  57. package/dist/db/database.js.map +1 -1
  58. package/dist/db/export.d.ts +2 -2
  59. package/dist/db/export.js +7 -2
  60. package/dist/db/export.js.map +1 -1
  61. package/dist/db/filters.d.ts +22 -0
  62. package/dist/db/filters.js +158 -0
  63. package/dist/db/filters.js.map +1 -0
  64. package/dist/db/index.d.ts +8 -0
  65. package/dist/db/index.js +25 -0
  66. package/dist/db/index.js.map +1 -0
  67. package/dist/db/introspection.d.ts +6 -0
  68. package/dist/db/introspection.js +172 -0
  69. package/dist/db/introspection.js.map +1 -0
  70. package/dist/db/manager.d.ts +32 -19
  71. package/dist/db/manager.js +203 -44
  72. package/dist/db/manager.js.map +1 -1
  73. package/dist/db/migrations.d.ts +5 -0
  74. package/dist/db/migrations.js +110 -0
  75. package/dist/db/migrations.js.map +1 -0
  76. package/dist/db/postgres.d.ts +85 -0
  77. package/dist/db/postgres.js +745 -0
  78. package/dist/db/postgres.js.map +1 -0
  79. package/dist/db/types.d.ts +206 -0
  80. package/dist/db/types.js +7 -0
  81. package/dist/db/types.js.map +1 -0
  82. package/dist/index.d.ts +9 -2
  83. package/dist/index.js +46 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/public/css/app.css +1 -1
  86. package/dist/public/css/input.css +74 -11
  87. package/dist/public/js/app.js +142 -0
  88. package/dist/public/js/browse.js +591 -104
  89. package/dist/public/js/databases.js +105 -13
  90. package/dist/public/js/designer.js +55 -2
  91. package/dist/public/js/forms.js +610 -28
  92. package/dist/public/js/icons.js +51 -0
  93. package/dist/public/js/inspector.js +638 -0
  94. package/dist/public/js/query.js +93 -3
  95. package/dist/public/js/schema.js +185 -52
  96. package/dist/public/js/seed.js +865 -152
  97. package/dist/routes/api/helpers.d.ts +42 -0
  98. package/dist/routes/api/helpers.js +133 -0
  99. package/dist/routes/api/helpers.js.map +1 -0
  100. package/dist/routes/api/import-export.d.ts +3 -0
  101. package/dist/routes/api/import-export.js +85 -0
  102. package/dist/routes/api/import-export.js.map +1 -0
  103. package/dist/routes/api/index.d.ts +4 -0
  104. package/dist/routes/api/index.js +37 -0
  105. package/dist/routes/api/index.js.map +1 -0
  106. package/dist/routes/api/query.d.ts +3 -0
  107. package/dist/routes/api/query.js +76 -0
  108. package/dist/routes/api/query.js.map +1 -0
  109. package/dist/routes/api/rows.d.ts +3 -0
  110. package/dist/routes/api/rows.js +373 -0
  111. package/dist/routes/api/rows.js.map +1 -0
  112. package/dist/routes/api/seed.d.ts +3 -0
  113. package/dist/routes/api/seed.js +82 -0
  114. package/dist/routes/api/seed.js.map +1 -0
  115. package/dist/routes/api/tables.d.ts +3 -0
  116. package/dist/routes/api/tables.js +160 -0
  117. package/dist/routes/api/tables.js.map +1 -0
  118. package/dist/routes/databases.d.ts +8 -11
  119. package/dist/routes/databases.js +100 -66
  120. package/dist/routes/databases.js.map +1 -1
  121. package/dist/routes/index.d.ts +3 -0
  122. package/dist/routes/index.js +20 -0
  123. package/dist/routes/index.js.map +1 -0
  124. package/dist/routes/pages.d.ts +3 -3
  125. package/dist/routes/pages.js +157 -64
  126. package/dist/routes/pages.js.map +1 -1
  127. package/dist/serverless.d.ts +40 -0
  128. package/dist/serverless.js +210 -0
  129. package/dist/serverless.js.map +1 -0
  130. package/dist/sql/generator.d.ts +7 -3
  131. package/dist/sql/generator.js +144 -7
  132. package/dist/sql/generator.js.map +1 -1
  133. package/dist/sql/index.d.ts +2 -0
  134. package/dist/sql/index.js +19 -0
  135. package/dist/sql/index.js.map +1 -0
  136. package/dist/types/api.d.ts +412 -0
  137. package/dist/types/api.js +9 -0
  138. package/dist/types/api.js.map +1 -0
  139. package/dist/utils/colors.d.ts +40 -0
  140. package/dist/utils/colors.js +64 -0
  141. package/dist/utils/colors.js.map +1 -0
  142. package/dist/{util.d.ts → utils/common.d.ts} +10 -6
  143. package/dist/{util.js → utils/common.js} +80 -13
  144. package/dist/utils/common.js.map +1 -0
  145. package/dist/utils/csv.js.map +1 -0
  146. package/dist/utils/datatype.d.ts +49 -0
  147. package/dist/utils/datatype.js +222 -0
  148. package/dist/utils/datatype.js.map +1 -0
  149. package/dist/utils/icons.d.ts +11 -0
  150. package/dist/utils/icons.js +72 -0
  151. package/dist/utils/icons.js.map +1 -0
  152. package/dist/utils/index.d.ts +4 -0
  153. package/dist/utils/index.js +21 -0
  154. package/dist/utils/index.js.map +1 -0
  155. package/dist/{logger.d.ts → utils/logger.d.ts} +1 -1
  156. package/dist/utils/logger.js +40 -0
  157. package/dist/utils/logger.js.map +1 -0
  158. package/dist/views/layouts/main.hbs +40 -11
  159. package/dist/views/pages/databases.hbs +182 -74
  160. package/dist/views/pages/designer.hbs +29 -11
  161. package/dist/views/pages/error.hbs +3 -3
  162. package/dist/views/pages/form.hbs +5 -3
  163. package/dist/views/pages/home.hbs +22 -13
  164. package/dist/views/pages/login.hbs +111 -0
  165. package/dist/views/pages/query.hbs +8 -6
  166. package/dist/views/pages/schema.hbs +41 -13
  167. package/dist/views/pages/seed.hbs +200 -54
  168. package/dist/views/pages/table.hbs +152 -72
  169. package/dist/views/partials/icon.hbs +2 -0
  170. package/dist/views/partials/navbar.hbs +69 -25
  171. package/dist/views/partials/sidebar.hbs +108 -94
  172. package/docs/API.md +144 -0
  173. package/docs/EXAMPLES.md +576 -0
  174. package/docs/SECURITY.md +265 -0
  175. package/package.json +15 -4
  176. package/dist/args.d.ts +0 -28
  177. package/dist/args.js +0 -187
  178. package/dist/args.js.map +0 -1
  179. package/dist/config.d.ts +0 -17
  180. package/dist/config.js +0 -23
  181. package/dist/config.js.map +0 -1
  182. package/dist/csv.js.map +0 -1
  183. package/dist/data/generator.d.ts +0 -86
  184. package/dist/data/generator.js +0 -1031
  185. package/dist/data/generator.js.map +0 -1
  186. package/dist/logger.js +0 -25
  187. package/dist/logger.js.map +0 -1
  188. package/dist/routes/api.d.ts +0 -9
  189. package/dist/routes/api.js +0 -848
  190. package/dist/routes/api.js.map +0 -1
  191. package/dist/test/classifier.test.d.ts +0 -1
  192. package/dist/test/classifier.test.js +0 -44
  193. package/dist/test/classifier.test.js.map +0 -1
  194. package/dist/test/csv.test.d.ts +0 -1
  195. package/dist/test/csv.test.js +0 -64
  196. package/dist/test/csv.test.js.map +0 -1
  197. package/dist/test/database.test.d.ts +0 -1
  198. package/dist/test/database.test.js +0 -402
  199. package/dist/test/database.test.js.map +0 -1
  200. package/dist/test/generator.test.d.ts +0 -1
  201. package/dist/test/generator.test.js +0 -132
  202. package/dist/test/generator.test.js.map +0 -1
  203. package/dist/test/manager.test.d.ts +0 -1
  204. package/dist/test/manager.test.js +0 -146
  205. package/dist/test/manager.test.js.map +0 -1
  206. package/dist/util.js.map +0 -1
  207. /package/dist/{csv.d.ts → utils/csv.d.ts} +0 -0
  208. /package/dist/{csv.js → utils/csv.js} +0 -0
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLogger = createLogger;
4
+ const colors_1 = require("./colors");
5
+ const LEVELS = { debug: 10, info: 20, warn: 30, error: 40 };
6
+ function formatTime() {
7
+ const d = new Date();
8
+ const pad = (n) => String(n).padStart(2, '0');
9
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
10
+ }
11
+ const BADGES = {
12
+ debug: colors_1.c.magenta('[debug]'),
13
+ info: colors_1.c.cyan('[info]'),
14
+ warn: colors_1.c.yellow('[warn]'),
15
+ error: colors_1.c.red(colors_1.c.bold('[error]')),
16
+ };
17
+ /** Minimal, color-enhanced console logger with level filtering and scoped children. */
18
+ function createLogger(level = 'info', scope = 'admindb') {
19
+ const threshold = LEVELS[level] ?? LEVELS.info;
20
+ // Clean scope name (e.g. "admindb:db:users.db" -> "db:users.db")
21
+ const cleanScope = scope === 'admindb' || scope === 'app' ? '' : scope.replace(/^admindb:/, '');
22
+ const scopeTag = cleanScope ? colors_1.c.dim(colors_1.c.cyan(`[${cleanScope}]`)) : '';
23
+ const write = (lv, args) => {
24
+ if (LEVELS[lv] < threshold)
25
+ return;
26
+ const time = colors_1.c.gray(formatTime());
27
+ const badge = BADGES[lv];
28
+ const prefix = [time, badge, scopeTag].filter(Boolean).join(' ');
29
+ // eslint-disable-next-line no-console
30
+ console.log(prefix, ...args);
31
+ };
32
+ return {
33
+ debug: (...args) => write('debug', args),
34
+ info: (...args) => write('info', args),
35
+ warn: (...args) => write('warn', args),
36
+ error: (...args) => write('error', args),
37
+ child: (s) => createLogger(level, cleanScope ? `${cleanScope}:${s}` : s),
38
+ };
39
+ }
40
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;AA4BA,oCAuBC;AAnDD,qCAA6B;AAY7B,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAEtF,SAAS,UAAU;IACjB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,MAAM,MAAM,GAA6B;IACvC,KAAK,EAAE,UAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC3B,IAAI,EAAE,UAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtB,IAAI,EAAE,UAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACxB,KAAK,EAAE,UAAC,CAAC,GAAG,CAAC,UAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;CAChC,CAAC;AAEF,uFAAuF;AACvF,SAAgB,YAAY,CAAC,QAAkB,MAAM,EAAE,KAAK,GAAG,SAAS;IACtE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC;IAE/C,iEAAiE;IACjE,MAAM,UAAU,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAChG,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,UAAC,CAAC,GAAG,CAAC,UAAC,CAAC,IAAI,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpE,MAAM,KAAK,GAAG,CAAC,EAAY,EAAE,IAAe,EAAQ,EAAE;QACpD,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS;YAAE,OAAO;QACnC,MAAM,IAAI,GAAG,UAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjE,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC;QACxC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;QACtC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;QACtC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC;QACxC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACzE,CAAC;AACJ,CAAC"}
@@ -1,5 +1,7 @@
1
+ {{!-- Layout: Main Application Wrapper (renders all pages via {{{body}}}) --}}
1
2
  <!DOCTYPE html>
2
3
  <html lang="en" data-theme="admindb">
4
+
3
5
  <head>
4
6
  <meta charset="utf-8" />
5
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -9,7 +11,14 @@
9
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
10
12
  <link rel="stylesheet" href="{{basePath}}/css/app.css" />
11
13
  <script>
12
- window.APP = { basePath: {{{json basePath}}}, readonly: {{{json readonly}}} };
14
+ window.APP = {
15
+ basePath: {{{json basePath}}},
16
+ readonly: {{{json readonly}}},
17
+ serverless: {{{json serverless}}},
18
+ dialect: {{{json dialect}}},
19
+ isSqlite: {{{json isSqlite}}},
20
+ isPostgres: {{{json isPostgres}}}
21
+ };
13
22
  // Apply the saved theme before first paint to avoid a flash.
14
23
  (function () {
15
24
  try {
@@ -18,32 +27,52 @@
18
27
  } catch (e) {}
19
28
  })();
20
29
  </script>
30
+ <script src="{{basePath}}/js/icons.js" defer></script>
21
31
  <script src="{{basePath}}/js/api.js" defer></script>
22
32
  <script src="{{basePath}}/js/app.js" defer></script>
33
+ <script src="{{basePath}}/js/inspector.js" defer></script>
34
+
23
35
  </head>
24
36
  <body class="min-h-screen bg-base-200 text-base-content">
25
37
  {{#if readonly}}
26
38
  <div class="flex items-center justify-center gap-2 bg-warning/15 px-4 py-2 text-center text-sm font-semibold text-warning">
27
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" 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>
28
- Read-only mode — this database is open without write access. All writes are disabled.
39
+ <span class="shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
40
+ {{#if serverless}}
41
+ Serverless mode active — database is open in read-only mode. Writes and schema modifications are disabled.
42
+ {{else}}
43
+ Read-only mode — this database is open without write access. All writes are disabled.
44
+ {{/if}}
29
45
  </div>
30
46
  {{/if}}
31
- <div class="drawer lg:drawer-open">
32
- <input id="sidebar-toggle" type="checkbox" class="drawer-toggle" />
33
- <div class="drawer-content flex min-h-screen flex-col">
47
+ {{#if noSidebar}}
48
+ <div class="flex min-h-screen flex-col">
34
49
  {{> navbar}}
35
50
  <main class="mx-auto w-full max-w-[1500px] flex-1 px-4 py-6 sm:px-6 lg:px-8 lg:py-8">
36
51
  {{{body}}}
37
52
  </main>
38
53
  <footer class="border-t border-base-300 px-6 py-4 text-center text-xs text-base-content/40">
39
- AdminDB{{#if version}} v{{version}}{{/if}} · a browser tool for SQLite databases
54
+ AdminDB{{#if version}} v{{version}}{{/if}} · SQLite & PostgreSQL database administration
40
55
  </footer>
41
56
  </div>
42
- <div class="drawer-side z-40">
43
- <label for="sidebar-toggle" aria-label="close sidebar" class="drawer-overlay"></label>
44
- {{> sidebar}}
57
+ {{else}}
58
+ <div class="drawer lg:drawer-open">
59
+ <input id="sidebar-toggle" type="checkbox" class="drawer-toggle" />
60
+ <div class="drawer-content flex min-h-screen flex-col">
61
+ {{> navbar}}
62
+ <main class="mx-auto w-full max-w-[1500px] flex-1 px-4 py-6 sm:px-6 lg:px-8 lg:py-8">
63
+ {{{body}}}
64
+ </main>
65
+ <footer class="border-t border-base-300 px-6 py-4 text-center text-xs text-base-content/40">
66
+ AdminDB{{#if version}} v{{version}}{{/if}} · SQLite & PostgreSQL database administration
67
+ </footer>
68
+ </div>
69
+
70
+ <div class="drawer-side z-40">
71
+ <label for="sidebar-toggle" aria-label="close sidebar" class="drawer-overlay"></label>
72
+ {{> sidebar}}
73
+ </div>
45
74
  </div>
46
- </div>
75
+ {{/if}}
47
76
  <div id="toast-container" class="pointer-events-none fixed inset-x-0 top-4 z-50 flex flex-col items-center gap-2 px-4"></div>
48
77
  </body>
49
78
  </html>
@@ -1,73 +1,85 @@
1
+ {{!-- Page: Multi-Database Manager Landing · URL: /databases (or / in manager mode) --}}
1
2
  <div class="space-y-6">
3
+
2
4
  <!-- Header -->
3
5
  <div>
4
6
  <p class="text-sm font-semibold uppercase tracking-wider text-primary">Manager</p>
5
7
  <h1 class="mt-1 text-3xl font-extrabold tracking-tight">Databases</h1>
6
- <p class="mt-1.5 text-sm text-base-content/55">Open a database to browse and edit it, or create a new one.</p>
8
+ <p class="mt-1.5 text-sm text-base-content/55">Connect to PostgreSQL databases, create SQLite files, or open existing local databases with configurable read/write access.</p>
7
9
  </div>
8
10
 
9
- <!-- New database -->
10
- <div class="app-card p-5">
11
- <div class="flex flex-wrap items-end gap-3">
12
- <div class="w-full max-w-sm">
13
- <label class="field-label" for="new-db-name">New database name</label>
14
- <input id="new-db-name" class="field-input font-mono" placeholder="e.g. analytics" autocomplete="off" spellcheck="false" />
11
+ <!-- Connect & Create Actions Grid -->
12
+ <div class="grid grid-cols-1 gap-5 lg:grid-cols-2">
13
+ <!-- Connect PostgreSQL Database -->
14
+ <div class="app-card p-5 border border-info/30 bg-info/[0.02]">
15
+ <div class="mb-3 flex items-center justify-between">
16
+ <h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-info">
17
+ {{{icon "database" class="h-4 w-4"}}}
18
+ Connect PostgreSQL
19
+ </h2>
20
+ <span class="rounded bg-info/15 px-2 py-0.5 text-[10px] font-bold text-info">Remote / Local</span>
15
21
  </div>
16
- {{#unless readonly}}
17
- <button id="create-db" type="button" class="btn btn-primary btn-sm mb-0.5 gap-1.5">
18
- <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>
19
- Create
20
- </button>
21
- {{else}}
22
- <span class="mb-1 text-sm font-medium text-warning">Read-only — creating databases is disabled.</span>
23
- {{/unless}}
22
+ <div class="space-y-3">
23
+ <div>
24
+ <label class="field-label" for="pg-conn-name">Connection Name <span class="text-base-content/40">(optional)</span></label>
25
+ <input id="pg-conn-name" class="field-input font-mono text-xs" placeholder="e.g. prod_postgres" autocomplete="off" spellcheck="false" />
26
+ </div>
27
+ <div>
28
+ <label class="field-label" for="pg-conn-uri">Connection URI <span class="chip chip-type">required</span></label>
29
+ <input id="pg-conn-uri" class="field-input font-mono text-xs" placeholder="postgresql://user:password@localhost:5432/mydb" autocomplete="off" spellcheck="false" />
30
+ </div>
31
+ <div>
32
+ <label class="flex items-center gap-2 cursor-pointer pt-0.5">
33
+ <input type="checkbox" id="pg-conn-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
34
+ <span class="text-xs font-medium text-base-content/75">Open as Read-only (block writes & schema changes)</span>
35
+ </label>
36
+ </div>
37
+ <div class="pt-1">
38
+ {{#unless readonly}}
39
+ <button id="connect-pg" type="button" class="btn btn-info btn-sm gap-1.5 w-full sm:w-auto">
40
+ {{{icon "plus" class="h-4 w-4"}}}
41
+ Connect PostgreSQL
42
+ </button>
43
+ {{else}}
44
+ <span class="text-xs font-medium text-warning">Read-only mode — connecting databases is disabled.</span>
45
+ {{/unless}}
46
+ </div>
47
+ </div>
48
+ <p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
49
+ Credentials are encrypted in-memory and sanitized in the UI. Passwords are never sent to the client.
50
+ </p>
24
51
  </div>
25
- <p class="mt-2 text-xs text-base-content/40">
26
- New databases are created in <code class="font-mono">{{dbDir}}</code>. Files already there are picked up
27
- automatically, and any explicitly configured database paths appear here too.
28
- </p>
29
- </div>
30
52
 
31
- <!-- Open an existing database file -->
32
- {{#if allowBrowse}}
33
- <div class="app-card p-5">
34
- <div class="mb-3 flex flex-wrap items-center justify-between gap-2">
35
- <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Open an existing database</h2>
36
- <span class="text-xs text-base-content/40">.db · .sqlite · .sqlite3</span>
37
- </div>
38
- <div class="flex flex-wrap items-center gap-2">
39
- <input id="fs-path" class="field-input font-mono sm:!w-96" placeholder="Absolute path to a folder, e.g. C:\data" autocomplete="off" spellcheck="false" />
40
- <button id="fs-go" type="button" class="btn btn-outline btn-sm gap-1.5">
41
- <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="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>
42
- Go
43
- </button>
44
- <button id="fs-up" type="button" class="btn btn-ghost 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="M3 10h13M3 10l4-4m-4 4l4 4" /></svg>
46
- Up
47
- </button>
53
+ <!-- Create SQLite Database -->
54
+ <div class="app-card p-5 border border-emerald-500/30 bg-emerald-500/[0.02]">
55
+ <div class="mb-3 flex items-center justify-between">
56
+ <h2 class="flex items-center gap-2 text-sm font-bold uppercase tracking-wide text-emerald-600 dark:text-emerald-400">
57
+ {{{icon "plus" class="h-4 w-4"}}}
58
+ Create SQLite Database
59
+ </h2>
60
+ <span class="rounded bg-emerald-500/15 px-2 py-0.5 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">File-based</span>
48
61
  </div>
49
- <div class="mt-3 overflow-hidden rounded-xl border border-base-300">
50
- <div id="fs-current" class="border-b border-base-200 bg-base-200/50 px-3 py-2 font-mono text-xs text-base-content/60"></div>
51
- <div id="fs-listing" class="max-h-80 divide-y divide-base-200/70 overflow-auto"></div>
62
+ <div class="space-y-3">
63
+ <div>
64
+ <label class="field-label" for="new-db-name">Database Name <span class="chip chip-type">required</span></label>
65
+ <input id="new-db-name" class="field-input font-mono text-xs" placeholder="e.g. analytics" autocomplete="off" spellcheck="false" />
66
+ </div>
67
+ <div class="pt-1">
68
+ {{#unless readonly}}
69
+ <button id="create-db" type="button" class="btn btn-primary btn-sm gap-1.5 w-full sm:w-auto">
70
+ {{{icon "plus" class="h-4 w-4"}}}
71
+ Create SQLite DB
72
+ </button>
73
+ {{else}}
74
+ <span class="text-xs font-medium text-warning">Read-only — creating databases is disabled.</span>
75
+ {{/unless}}
76
+ </div>
52
77
  </div>
53
- <p class="mt-2.5 text-xs text-base-content/45">
54
- Browse the filesystem to select an existing database; opening it adds it to the list above so you can
55
- switch between databases freely.
56
- {{#if browseRoot}}
57
- <span class="font-medium text-base-content/60">Browsing is limited to <code class="font-mono">{{browseRoot}}</code>.</span>
58
- {{/if}}
59
- <span class="font-medium text-warning">This server has no authentication — treat it like a remote filesystem &amp; database shell.</span>
78
+ <p class="mt-3 text-[11px] text-base-content/45 leading-relaxed">
79
+ Files are saved to <code class="font-mono">{{dbDir}}</code>. Any <code class="font-mono">.db</code> file dropped there is auto-discovered.
60
80
  </p>
61
81
  </div>
62
- {{else}}
63
- <div class="app-card p-5">
64
- <p class="text-sm text-base-content/60">
65
- <b class="text-base-content/80">File browsing is disabled.</b>
66
- This server was started with specific database files, so the filesystem browser is turned off — use the
67
- list of available databases below.
68
- </p>
69
- </div>
70
- {{/if}}
82
+ </div>
71
83
 
72
84
  <!-- List -->
73
85
  <div>
@@ -83,9 +95,10 @@
83
95
  <thead>
84
96
  <tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
85
97
  <th class="font-semibold">Name</th>
98
+ <th class="font-semibold">Mode</th>
86
99
  <th class="text-right font-semibold">Tables</th>
87
100
  <th class="text-right font-semibold">Size</th>
88
- <th class="font-semibold">Modified</th>
101
+ <th class="font-semibold">Status / Modified</th>
89
102
  <th class="text-right font-semibold">Actions</th>
90
103
  </tr>
91
104
  </thead>
@@ -94,31 +107,76 @@
94
107
  <tr class="group hover:bg-primary/[0.04]">
95
108
  <td>
96
109
  <a href="{{../basePath}}/{{this.id}}" class="inline-flex items-center gap-2.5">
97
- <span class="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-primary/10 text-primary transition-colors group-hover:bg-primary/20">
98
- <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>
110
+ <span class="grid h-8 w-8 shrink-0 place-items-center rounded-lg {{#if this.isPostgres}}bg-info/10 text-info group-hover:bg-info/20{{else}}bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 group-hover:bg-emerald-500/20{{/if}} transition-colors">
111
+ {{{icon "database" class="h-4 w-4"}}}
99
112
  </span>
100
113
  <span class="min-w-0">
101
- <span class="block truncate font-mono text-[13.5px] font-semibold">{{this.name}}</span>
102
- <span class="block max-w-[220px] truncate text-[11px] text-base-content/40" title="{{this.path}}">{{this.path}}</span>
114
+ <div class="flex items-center gap-1.5">
115
+ <span class="truncate font-mono text-[13.5px] font-semibold">{{this.name}}</span>
116
+ {{#if this.isPostgres}}
117
+ <span class="rounded bg-info/15 px-1.5 py-0.2 text-[10px] font-bold text-info">PostgreSQL</span>
118
+ {{else}}
119
+ <span class="rounded bg-emerald-500/15 px-1.5 py-0.2 text-[10px] font-bold text-emerald-600 dark:text-emerald-400">SQLite</span>
120
+ {{/if}}
121
+ </div>
122
+ <span class="block max-w-[260px] truncate font-mono text-[11px] text-base-content/40" title="{{this.path}}">{{this.path}}</span>
103
123
  </span>
104
124
  </a>
105
125
  </td>
126
+ <td class="align-middle">
127
+ {{#if ../readonly}}
128
+ <span class="rounded bg-warning/20 px-2 py-0.5 text-[10px] font-bold uppercase text-warning">Read-only</span>
129
+ {{else}}
130
+ <button type="button" class="js-toggle-db-mode rounded px-2 py-0.5 text-[10px] font-bold uppercase transition hover:opacity-80 {{#if this.readonly}}bg-warning/20 text-warning{{else}}bg-success/20 text-success{{/if}}"
131
+ data-id="{{this.id}}" data-readonly="{{#if this.readonly}}true{{else}}false{{/if}}" title="Click to toggle between Writable and Read-only">
132
+ {{#if this.readonly}}Read-only{{else}}Writable{{/if}} ⇄
133
+ </button>
134
+ {{/if}}
135
+ </td>
106
136
  <td class="text-right tabular-nums text-base-content/60">{{this.tables}}</td>
107
137
  <td class="text-right tabular-nums text-base-content/60">{{this.sizeLabel}}</td>
108
138
  <td class="text-[13px] text-base-content/55">{{this.modifiedLabel}}</td>
109
139
  <td class="whitespace-nowrap text-right">
110
- <div class="row-actions">
111
- <a href="{{../basePath}}/{{this.id}}" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
112
- <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 7l5 5m0 0l-5 5m5-5H6" /></svg>
140
+ <div class="row-actions">
141
+ <div class="join">
142
+ <a href="{{../basePath}}/{{this.id}}" class="btn btn-ghost btn-xs join-item gap-1 text-base-content/70 hover:text-primary">
143
+ {{{icon "arrowRight" class="h-3.5 w-3.5"}}}
113
144
  Open
114
145
  </a>
115
- {{#unless ../readonly}}
116
- <button type="button" class="btn btn-ghost btn-xs gap-1 text-error js-delete-db" data-id="{{this.id}}">
117
- <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>
146
+ <div class="dropdown dropdown-end">
147
+ <label tabindex="0" role="button" class="btn btn-ghost btn-xs join-item px-1 text-base-content/60 hover:text-base-content" title="Open options">
148
+ {{{icon "chevronDown" class="h-3 w-3"}}}
149
+ </label>
150
+ <ul tabindex="0" class="dropdown-content menu z-50 w-44 rounded-xl border border-base-300 bg-base-100 p-1.5 shadow-lift text-xs">
151
+ <li>
152
+ <a href="{{../basePath}}/{{this.id}}?readonly=0" class="flex items-center gap-1.5 text-success">
153
+ {{{icon "check" class="h-3.5 w-3.5"}}}
154
+ Open Writable
155
+ </a>
156
+ </li>
157
+ <li>
158
+ <a href="{{../basePath}}/{{this.id}}?readonly=1" class="flex items-center gap-1.5 text-warning">
159
+ {{{icon "lock" class="h-3.5 w-3.5"}}}
160
+ Open Read-only
161
+ </a>
162
+ </li>
163
+ </ul>
164
+ </div>
165
+ </div>
166
+ {{#unless ../readonly}}
167
+ {{#if this.isPostgres}}
168
+ <button type="button" class="btn btn-ghost btn-xs gap-1 text-warning js-disconnect-db" data-id="{{this.id}}" data-name="{{this.name}}" title="Disconnect this database from the manager list">
169
+ {{{icon "logout" class="h-3.5 w-3.5"}}}
170
+ Disconnect
171
+ </button>
172
+ {{else}}
173
+ <button type="button" class="btn btn-ghost btn-xs gap-1 text-error js-delete-db" data-id="{{this.id}}" title="Delete database file from disk">
174
+ {{{icon "trash" class="h-3.5 w-3.5"}}}
118
175
  Delete
119
176
  </button>
120
- {{/unless}}
121
- </div>
177
+ {{/if}}
178
+ {{/unless}}
179
+ </div>
122
180
  </td>
123
181
  </tr>
124
182
  {{/each}}
@@ -128,16 +186,66 @@
128
186
  </div>
129
187
  {{else}}
130
188
  <div class="empty-state">
131
- <span class="empty-icon">
132
- <svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7" 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>
133
- </span>
189
+ <span class="empty-icon">{{{icon "database" class="h-7 w-7"}}}</span>
134
190
  <p class="text-sm font-medium text-base-content/70">No databases yet</p>
135
191
  <p class="max-w-sm text-sm text-base-content/45">
136
- Create one above, or drop <code class="font-mono">.db</code> files into
137
- <code class="font-mono">{{dbDir}}</code> and refresh.
192
+ Connect a PostgreSQL database or create a new SQLite database above to get started.
138
193
  </p>
139
194
  </div>
140
195
  {{/if}}
141
196
  </div>
197
+
198
+ <!-- Open an existing database file -->
199
+ {{#if allowBrowse}}
200
+ <div class="app-card p-5">
201
+ <div class="mb-3 flex flex-wrap items-center justify-between gap-2">
202
+ <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Open an existing SQLite file</h2>
203
+ <span class="text-xs text-base-content/40">.db · .sqlite · .sqlite3</span>
204
+ </div>
205
+ <div class="flex flex-wrap items-center gap-2">
206
+ <input id="fs-path" class="field-input font-mono sm:!w-96" placeholder="Absolute path to a folder, e.g. C:\data" autocomplete="off" spellcheck="false" />
207
+ <button id="fs-go" type="button" class="btn btn-outline btn-sm gap-1.5">
208
+ {{{icon "search" class="h-4 w-4"}}}
209
+ Go
210
+ </button>
211
+ <button id="fs-up" type="button" class="btn btn-ghost btn-sm gap-1.5">
212
+ {{{icon "arrowUp" class="h-4 w-4"}}}
213
+ Up
214
+ </button>
215
+ </div>
216
+ <div class="mt-2">
217
+ <label class="flex items-center gap-2 cursor-pointer">
218
+ <input type="checkbox" id="fs-readonly" class="checkbox checkbox-xs checkbox-primary rounded" />
219
+ <span class="text-xs font-medium text-base-content/70">Open selected file in Read-only mode</span>
220
+ </label>
221
+ </div>
222
+ <div class="mt-3 overflow-hidden rounded-xl border border-base-300">
223
+ <div id="fs-current" class="border-b border-base-200 bg-base-200/50 px-3 py-2 font-mono text-xs text-base-content/60"></div>
224
+ <div id="fs-listing" class="max-h-80 divide-y divide-base-200/70 overflow-auto"></div>
225
+ </div>
226
+ <p class="mt-2.5 text-xs text-base-content/45">
227
+ Browse the filesystem to select an existing database; opening it adds it to the list above.
228
+ {{#if browseRoot}}
229
+ <span class="font-medium text-base-content/60">Browsing is limited to <code class="font-mono">{{browseRoot}}</code>.</span>
230
+ {{/if}}
231
+ </p>
232
+ </div>
233
+ {{/if}}
234
+
235
+ <!-- Security Responsibility Notice -->
236
+ <div class="rounded-xl border border-warning/30 bg-warning/[0.04] p-4 text-xs text-base-content/75 leading-relaxed">
237
+ <div class="flex items-start gap-2.5">
238
+ <span class="text-warning shrink-0 mt-0.5">
239
+ {{{icon "warning" class="h-4 w-4"}}}
240
+ </span>
241
+ <div>
242
+ <span class="font-bold text-warning">Security & Protection Notice:</span>
243
+ AdminDB's native authentication provides basic single-user password protection. For production environments and internet-facing networks, <strong>it is entirely your responsibility to secure this interface</strong> by placing it behind your web application's own authentication system (e.g., custom Express/Next.js auth middleware, SSO/OAuth, NextAuth), a secure VPN, or an IP-whitelisted reverse proxy with HTTPS.
244
+ </div>
245
+ </div>
246
+ </div>
247
+
142
248
  </div>
143
249
  <script src="{{basePath}}/js/databases.js" defer></script>
250
+
251
+
@@ -1,4 +1,6 @@
1
+ {{!-- Page: Visual Table Designer & Creator · URL: /designer --}}
1
2
  <div class="space-y-6">
3
+
2
4
  <!-- Header -->
3
5
  <div>
4
6
  <p class="text-sm font-semibold uppercase tracking-wider text-primary">Designer</p>
@@ -21,7 +23,7 @@
21
23
  <div class="flex flex-wrap items-center justify-between gap-2 border-b border-base-200 px-5 py-4">
22
24
  <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Columns</h2>
23
25
  <button id="add-column" type="button" class="btn btn-outline btn-sm gap-1.5">
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="M12 4v16m8-8H4" /></svg>
26
+ {{{icon "plus" class="h-4 w-4"}}}
25
27
  Add column
26
28
  </button>
27
29
  </div>
@@ -30,14 +32,15 @@
30
32
  <div class="flex flex-wrap gap-2 border-t border-base-200 px-5 py-4">
31
33
  {{#unless readonly}}
32
34
  <button id="create-table" type="button" class="btn btn-primary gap-1.5">
33
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /></svg>
35
+ {{{icon "check" class="h-4 w-4"}}}
34
36
  Create table
35
37
  </button>
36
38
  {{else}}
37
39
  <span class="text-sm font-medium text-warning">Read-only — table creation is disabled.</span>
38
40
  {{/unless}}
41
+
39
42
  <button id="copy-sql" type="button" class="btn btn-outline gap-1.5" title="Copy the preview SQL">
40
- <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="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3" /></svg>
43
+ {{{icon "copy" class="h-4 w-4"}}}
41
44
  Copy SQL
42
45
  </button>
43
46
  </div>
@@ -50,7 +53,7 @@
50
53
  <div class="flex items-center justify-between border-b border-base-200 bg-base-200/40 px-4 py-3">
51
54
  <h2 class="flex items-center gap-2 text-sm font-semibold text-base-content/60">
52
55
  <span class="grid h-5 w-5 place-items-center rounded-md bg-primary/10 text-primary">
53
- <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>
56
+ {{{icon "query" class="h-3.5 w-3.5"}}}
54
57
  </span>
55
58
  SQL preview
56
59
  </h2>
@@ -65,14 +68,29 @@
65
68
  </div>
66
69
 
67
70
  <div class="rounded-2xl border border-base-300/70 bg-base-100 p-4">
68
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wider text-base-content/45">Type guide</h3>
71
+ <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wider text-base-content/45">
72
+ {{#if isPostgres}}PostgreSQL Type Guide{{else}}SQLite Type Guide{{/if}}
73
+ </h3>
69
74
  <ul class="space-y-1.5 text-[13px] text-base-content/60">
70
- <li class="flex items-center justify-between gap-2"><span class="font-mono">TEXT</span><span class="text-base-content/40">Free-form text</span></li>
71
- <li class="flex items-center justify-between gap-2"><span class="font-mono">INTEGER</span><span class="text-base-content/40">Whole numbers</span></li>
72
- <li class="flex items-center justify-between gap-2"><span class="font-mono">REAL</span><span class="text-base-content/40">Decimal numbers</span></li>
73
- <li class="flex items-center justify-between gap-2"><span class="font-mono">BLOB</span><span class="text-base-content/40">Binary data</span></li>
74
- <li class="flex items-center justify-between gap-2"><span class="font-mono">BOOLEAN</span><span class="text-base-content/40">Stored as 0/1</span></li>
75
- <li class="flex items-center justify-between gap-2"><span class="font-mono">DATE</span><span class="text-base-content/40">Datetime + now default</span></li>
75
+ {{#if isPostgres}}
76
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">TEXT / VARCHAR</span><span class="text-base-content/40">Free-form string</span></li>
77
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">INTEGER / BIGINT</span><span class="text-base-content/40">Whole numbers</span></li>
78
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">SERIAL / BIGSERIAL</span><span class="text-base-content/40">Auto-incrementing PK</span></li>
79
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">REAL / NUMERIC</span><span class="text-base-content/40">Decimal numbers</span></li>
80
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">BYTEA</span><span class="text-base-content/40">Binary byte data</span></li>
81
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">BOOLEAN</span><span class="text-base-content/40">true / false</span></li>
82
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">TIMESTAMPTZ</span><span class="text-base-content/40">Timestamp with TZ</span></li>
83
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">JSON / JSONB</span><span class="text-base-content/40">Structured JSON</span></li>
84
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">UUID</span><span class="text-base-content/40">UUID generator</span></li>
85
+ {{else}}
86
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">TEXT</span><span class="text-base-content/40">Free-form text</span></li>
87
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">INTEGER</span><span class="text-base-content/40">Whole numbers / PK</span></li>
88
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">REAL</span><span class="text-base-content/40">Decimal numbers</span></li>
89
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">BLOB</span><span class="text-base-content/40">Binary data</span></li>
90
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">BOOLEAN</span><span class="text-base-content/40">Stored as 0/1</span></li>
91
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">DATETIME</span><span class="text-base-content/40">ISO-8601 timestamps</span></li>
92
+ <li class="flex items-center justify-between gap-2"><span class="font-mono">JSON</span><span class="text-base-content/40">JSON string/functions</span></li>
93
+ {{/if}}
76
94
  </ul>
77
95
  </div>
78
96
  </aside>
@@ -1,8 +1,8 @@
1
+ {{!-- Page: Error Display · URL: HTTP 404 / 500 Error Handlers --}}
1
2
  <div class="mx-auto mt-16 max-w-md space-y-6 text-center">
3
+
2
4
  <div class="mx-auto grid h-20 w-20 place-items-center rounded-3xl bg-error/10 text-error">
3
- <svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
4
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
5
- </svg>
5
+ {{{icon "warning" class="h-10 w-10"}}}
6
6
  </div>
7
7
  <div>
8
8
  <h1 class="text-5xl font-extrabold tracking-tight text-error">{{status}}</h1>
@@ -1,8 +1,10 @@
1
+ {{!-- Page: Row Editor & Inserter · URL: /tables/:table/rows/new or /tables/:table/rows/:id/edit --}}
1
2
  <div class="mx-auto max-w-3xl space-y-5">
3
+
2
4
  <!-- Header -->
3
5
  <div class="flex items-center gap-3">
4
6
  <a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
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"><path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
7
+ {{{icon "arrowLeft" class="h-5 w-5"}}}
6
8
  </a>
7
9
  <div>
8
10
  <h1 class="text-2xl font-bold tracking-tight">
@@ -26,7 +28,7 @@
26
28
  {{#if (eq mode 'edit')}}Update row{{else}}Insert row{{/if}}
27
29
  </button>
28
30
  <button id="row-generate" type="button" class="btn btn-outline gap-1.5">
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="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" /></svg>
31
+ {{{icon "sql" class="h-4 w-4"}}}
30
32
  Get query
31
33
  </button>
32
34
  {{else}}
@@ -46,7 +48,7 @@
46
48
  <div class="flex items-center justify-between border-b border-base-200 px-6 py-4">
47
49
  <h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-base-content/45">
48
50
  <span class="grid h-6 w-6 place-items-center rounded-md bg-primary/10 text-primary">
49
- <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="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" /></svg>
51
+ {{{icon "sql" class="h-4 w-4"}}}
50
52
  </span>
51
53
  Generated SQL
52
54
  </h2>