admindb 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +368 -335
  2. package/dist/app.js +227 -1
  3. package/dist/auth/config.d.ts +1 -1
  4. package/dist/auth/config.js +109 -1
  5. package/dist/auth/crypto.js +98 -1
  6. package/dist/auth/index.js +21 -1
  7. package/dist/auth/middleware.js +78 -1
  8. package/dist/auth/routes.js +64 -1
  9. package/dist/auth/types.js +7 -1
  10. package/dist/cli/args.d.ts +1 -1
  11. package/dist/cli/args.js +309 -1
  12. package/dist/cli/config.js +118 -1
  13. package/dist/cli/index.js +20 -1
  14. package/dist/cli/runner.js +208 -1
  15. package/dist/cli.js +4 -1
  16. package/dist/data/chain.d.ts +1 -0
  17. package/dist/data/chain.js +130 -0
  18. package/dist/data/datasets.d.ts +1 -1
  19. package/dist/data/datasets.js +171 -1
  20. package/dist/data/detector.d.ts +1 -1
  21. package/dist/data/detector.js +535 -1
  22. package/dist/data/engine.d.ts +1 -1
  23. package/dist/data/engine.js +586 -1
  24. package/dist/data/index.d.ts +1 -1
  25. package/dist/data/index.js +30 -1
  26. package/dist/data/prng.d.ts +1 -0
  27. package/dist/data/prng.js +73 -0
  28. package/dist/data/registry.d.ts +1 -0
  29. package/dist/data/registry.js +805 -0
  30. package/dist/data/schema-graph.d.ts +1 -0
  31. package/dist/data/schema-graph.js +210 -0
  32. package/dist/data/strategies.d.ts +1 -1
  33. package/dist/data/strategies.js +100 -1
  34. package/dist/data/templates.d.ts +1 -0
  35. package/dist/data/templates.js +134 -0
  36. package/dist/data/types.d.ts +1 -1
  37. package/dist/data/types.js +5 -1
  38. package/dist/data/validator.d.ts +1 -0
  39. package/dist/data/validator.js +160 -0
  40. package/dist/db/database.d.ts +1 -1
  41. package/dist/db/database.js +472 -1
  42. package/dist/db/export.d.ts +1 -1
  43. package/dist/db/export.js +67 -1
  44. package/dist/db/filters.d.ts +1 -1
  45. package/dist/db/filters.js +119 -1
  46. package/dist/db/index.js +24 -1
  47. package/dist/db/introspection.js +164 -1
  48. package/dist/db/manager.js +327 -1
  49. package/dist/db/migrations.js +100 -1
  50. package/dist/db/postgres.d.ts +1 -1
  51. package/dist/db/postgres.js +687 -1
  52. package/dist/db/types.d.ts +1 -1
  53. package/dist/db/types.js +6 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.js +52 -1
  56. package/dist/public/css/app.css +1 -1
  57. package/dist/public/js/api.js +1 -1
  58. package/dist/public/js/browse.js +1 -1
  59. package/dist/public/js/common.js +1 -0
  60. package/dist/public/js/databases.js +1 -1
  61. package/dist/public/js/designer.js +1 -1
  62. package/dist/public/js/forms.js +1 -1
  63. package/dist/public/js/home.js +1 -0
  64. package/dist/public/js/inspector.js +1 -1
  65. package/dist/public/js/query.js +1 -1
  66. package/dist/public/js/schema.js +1 -1
  67. package/dist/public/js/seed.js +1 -1
  68. package/dist/routes/api/erd.d.ts +1 -0
  69. package/dist/routes/api/erd.js +45 -0
  70. package/dist/routes/api/helpers.d.ts +1 -1
  71. package/dist/routes/api/helpers.js +213 -1
  72. package/dist/routes/api/import-export.js +82 -1
  73. package/dist/routes/api/index.js +48 -1
  74. package/dist/routes/api/query.js +74 -1
  75. package/dist/routes/api/rows.js +358 -1
  76. package/dist/routes/api/seed.js +167 -1
  77. package/dist/routes/api/tables.js +216 -1
  78. package/dist/routes/databases.js +210 -1
  79. package/dist/routes/index.js +19 -1
  80. package/dist/routes/pages.js +446 -1
  81. package/dist/serverless.js +149 -1
  82. package/dist/sql/classifier.js +24 -1
  83. package/dist/sql/error-analyzer.d.ts +1 -0
  84. package/dist/sql/error-analyzer.js +550 -0
  85. package/dist/sql/generator.d.ts +1 -1
  86. package/dist/sql/generator.js +245 -1
  87. package/dist/sql/index.js +18 -1
  88. package/dist/types/api.d.ts +1 -1
  89. package/dist/types/api.js +2 -1
  90. package/dist/utils/colors.js +54 -1
  91. package/dist/utils/common.d.ts +1 -1
  92. package/dist/utils/common.js +185 -1
  93. package/dist/utils/csv.d.ts +1 -1
  94. package/dist/utils/csv.js +61 -1
  95. package/dist/utils/datatype.js +167 -1
  96. package/dist/utils/icons.js +81 -1
  97. package/dist/utils/index.js +20 -1
  98. package/dist/utils/logger.js +36 -1
  99. package/dist/views/layouts/main.hbs +1 -74
  100. package/dist/views/pages/databases.hbs +1 -233
  101. package/dist/views/pages/designer.hbs +1 -89
  102. package/dist/views/pages/erd.hbs +1 -0
  103. package/dist/views/pages/error.hbs +1 -10
  104. package/dist/views/pages/form.hbs +1 -59
  105. package/dist/views/pages/home.hbs +1 -124
  106. package/dist/views/pages/info.hbs +1 -0
  107. package/dist/views/pages/login.hbs +1 -98
  108. package/dist/views/pages/query.hbs +1 -87
  109. package/dist/views/pages/schema.hbs +1 -298
  110. package/dist/views/pages/seed-select.hbs +251 -0
  111. package/dist/views/pages/seed.hbs +273 -167
  112. package/dist/views/pages/table.hbs +1 -327
  113. package/dist/views/partials/navbar.hbs +1 -83
  114. package/dist/views/partials/sidebar.hbs +1 -117
  115. package/docs/API.md +149 -144
  116. package/docs/EXAMPLES.md +579 -576
  117. package/docs/SECURITY.md +265 -265
  118. package/package.json +79 -78
  119. package/dist/public/js/icons.js +0 -1
@@ -1,10 +1 @@
1
- <div class="mx-auto mt-16 max-w-md space-y-6 text-center">
2
- <div class="mx-auto grid h-20 w-20 place-items-center rounded-3xl bg-error/10 text-error">
3
- {{{icon "warning" class="h-10 w-10"}}}
4
- </div>
5
- <div>
6
- <h1 class="text-5xl font-extrabold tracking-tight text-error">{{status}}</h1>
7
- <p class="mt-2 text-base-content/60">{{error}}</p>
8
- </div>
9
- <a href="{{basePath}}/" class="btn btn-primary">Back to home</a>
10
- </div>
1
+ <div class="mx-auto mt-16 max-w-md space-y-6 text-center">
11
2
  <div class="mx-auto grid h-20 w-20 place-items-center rounded-3xl bg-error/10 text-error">
12
3
  {{{icon "warning" class="h-10 w-10"}}}
13
4
  </div>
14
5
  <div>
15
6
  <h1 class="text-5xl font-extrabold tracking-tight text-error">{{status}}</h1>
16
7
  <p class="mt-2 text-base-content/60">{{error}}</p>
17
8
  </div>
18
9
  <a href="{{basePath}}/" class="btn btn-primary">Back to home</a>
@@ -1,59 +1 @@
1
- <div class="mx-auto max-w-3xl space-y-5">
2
- <div class="flex items-center gap-3">
3
- <a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
4
- {{{icon "arrowLeft" class="h-5 w-5"}}}
5
- </a>
6
- <div>
7
- <h1 class="text-2xl font-bold tracking-tight">
8
- {{#if (eq mode 'edit')}}Edit row{{else}}New row{{/if}}
9
- <span class="text-base-content/40">in</span> <span class="font-mono text-primary">{{table}}</span>
10
- </h1>
11
- <p class="text-sm text-base-content/55">{{infoSummary}}</p>
12
- </div>
13
- </div>
14
- <div class="app-card">
15
- <div class="border-b border-base-200 px-6 py-4">
16
- <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Row fields</h2>
17
- </div>
18
- <div class="p-6">
19
- <div id="row-fields" class="grid grid-cols-1 gap-x-6 gap-y-5 md:grid-cols-2"></div>
20
- <div id="form-error" class="hidden"></div>
21
- <div class="mt-6 flex flex-wrap items-center gap-2 border-t border-base-200 pt-5">
22
- {{#unless readonly}}
23
- <button id="row-submit" type="button" class="btn btn-primary">
24
- {{#if (eq mode 'edit')}}Update row{{else}}Insert row{{/if}}
25
- </button>
26
- <button id="row-generate" type="button" class="btn btn-outline gap-1.5">
27
- {{{icon "sql" class="h-4 w-4"}}}
28
- Get query
29
- </button>
30
- {{else}}
31
- <span class="text-sm font-medium text-warning">This database is read-only — rows cannot be {{#if (eq mode 'edit')}}updated{{else}}inserted{{/if}}.</span>
32
- {{/unless}}
33
- <a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost">Cancel</a>
34
- </div>
35
- <p class="mt-3 text-xs text-base-content/40">
36
- Columns with defaults are pre-filled from the schema. Empty fields are treated as "not set" (DB defaults
37
- apply). <code class="font-mono">0</code> is a valid value. "Get query" only previews the SQL — it never executes.
38
- </p>
39
- </div>
40
- </div>
41
- <div id="generated-sql" class="hidden">
42
- <div class="app-card">
43
- <div class="flex items-center justify-between border-b border-base-200 px-6 py-4">
44
- <h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-base-content/45">
45
- <span class="grid h-6 w-6 place-items-center rounded-md bg-primary/10 text-primary">
46
- {{{icon "sql" class="h-4 w-4"}}}
47
- </span>
48
- Generated SQL
49
- </h2>
50
- <button id="copy-sql" type="button" class="btn btn-ghost btn-xs gap-1">Copy</button>
51
- </div>
52
- <div class="p-4">
53
- <pre class="code-panel"><code id="generated-sql-code"></code></pre>
54
- </div>
55
- </div>
56
- </div>
57
- </div>
58
- <script id="form-config" type="application/json">{{{json config}}}</script>
59
- <script src="{{basePath}}/js/forms.js" defer></script>
1
+ <div class="mx-auto max-w-3xl space-y-5">
60
2
  <div class="page-header">
61
3
  <div class="page-header-row">
62
4
  <div class="flex items-center gap-3">
63
5
  <a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost btn-sm" aria-label="Back to table">
64
6
  {{{icon "arrowLeft" class="h-4 w-4"}}}
65
7
  </a>
66
8
  <div>
67
9
  <div class="page-pretitle">{{#if (eq mode 'edit')}}Record Editor{{else}}Record Inserter{{/if}}</div>
68
10
  <h1 class="page-title text-xl sm:text-2xl">
69
11
  {{#if (eq mode 'edit')}}Edit row{{else}}New row{{/if}}
70
12
  <span class="text-base-content/40 font-normal">in</span> <span class="font-mono text-primary">{{table}}</span>
71
13
  </h1>
72
14
  <p class="text-xs text-base-content/55 mt-0.5">{{infoSummary}}</p>
73
15
  </div>
74
16
  </div>
75
17
  </div>
76
18
  </div>
77
19
  <div class="app-card">
78
20
  <div class="border-b border-base-200 px-6 py-4">
79
21
  <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Row fields</h2>
80
22
  </div>
81
23
  <div class="p-6">
82
24
  <div id="row-fields" class="grid grid-cols-1 gap-x-6 gap-y-5 md:grid-cols-2"></div>
83
25
  <div id="form-error" class="hidden"></div>
84
26
  <div class="mt-6 flex flex-wrap items-center gap-2 border-t border-base-200 pt-5">
85
27
  {{#unless readonly}}
86
28
  <button id="row-submit" type="button" class="btn btn-primary">
87
29
  {{#if (eq mode 'edit')}}Update row{{else}}Insert row{{/if}}
88
30
  </button>
89
31
  <button id="row-generate" type="button" class="btn btn-outline gap-1.5">
90
32
  {{{icon "sql" class="h-4 w-4"}}}
91
33
  Get query
92
34
  </button>
93
35
  {{else}}
94
36
  <span class="text-sm font-medium text-warning">This database is read-only — rows cannot be {{#if (eq mode 'edit')}}updated{{else}}inserted{{/if}}.</span>
95
37
  {{/unless}}
96
38
  <a href="{{basePath}}/tables/{{table}}" class="btn btn-ghost">Cancel</a>
97
39
  </div>
98
40
  <p class="mt-3 text-xs text-base-content/40">
99
41
  Columns with defaults are pre-filled from the schema. Empty fields are treated as "not set" (DB defaults
100
42
  apply). <code class="font-mono">0</code> is a valid value. "Get query" only previews the SQL — it never executes.
101
43
  </p>
102
44
  </div>
103
45
  </div>
104
46
  <div id="generated-sql" class="hidden">
105
47
  <div class="app-card">
106
48
  <div class="flex items-center justify-between border-b border-base-200 px-6 py-4">
107
49
  <h2 class="flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-base-content/45">
108
50
  <span class="grid h-6 w-6 place-items-center rounded-md bg-primary/10 text-primary">
109
51
  {{{icon "sql" class="h-4 w-4"}}}
110
52
  </span>
111
53
  Generated SQL
112
54
  </h2>
113
55
  <button id="copy-sql" type="button" class="btn btn-ghost btn-xs gap-1">Copy</button>
114
56
  </div>
115
57
  <div class="p-4">
116
58
  <pre class="code-panel"><code id="generated-sql-code"></code></pre>
117
59
  </div>
118
60
  </div>
119
61
  </div>
@@ -1,124 +1 @@
1
- <div class="space-y-8">
2
- <div class="flex flex-wrap items-end justify-between gap-4">
3
- <div>
4
- <p class="text-sm font-semibold uppercase tracking-wider text-primary">Overview</p>
5
- <h1 class="mt-1 text-3xl font-extrabold tracking-tight">Database</h1>
6
- <p class="mt-1.5 text-sm text-base-content/55">Browse, edit, and query the connected database from your browser.</p>
7
- </div>
8
- <div class="flex gap-2">
9
- <a href="{{basePath}}/query" class="btn btn-ghost btn-sm gap-1.5">
10
- {{{icon "query" class="h-4 w-4"}}}
11
- Query
12
- </a>
13
- {{#unless readonly}}
14
- <a href="{{basePath}}/designer" class="btn btn-primary btn-sm gap-1.5">
15
- {{{icon "plus" class="h-4 w-4"}}}
16
- New table
17
- </a>
18
- {{/unless}}
19
- </div>
20
- </div>
21
- <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
22
- <div class="stat-card">
23
- <span class="stat-icon bg-primary/10 text-primary">
24
- {{{icon "table" class="h-6 w-6"}}}
25
- </span>
26
- <div>
27
- <div class="text-2xl font-extrabold tabular-nums">{{tables.length}}</div>
28
- <div class="text-[13px] text-base-content/50">Tables</div>
29
- </div>
30
- </div>
31
- <div class="stat-card">
32
- <span class="stat-icon bg-secondary/10 text-secondary">
33
- {{{icon "stats" class="h-6 w-6"}}}
34
- </span>
35
- <div>
36
- <div class="text-2xl font-extrabold tabular-nums">{{totalRows}}</div>
37
- <div class="text-[13px] text-base-content/50">Total rows</div>
38
- </div>
39
- </div>
40
- <div class="stat-card">
41
- <span class="stat-icon bg-accent/10 text-accent">
42
- {{{icon "seed" class="h-6 w-6"}}}
43
- </span>
44
- <div>
45
- <div class="text-2xl font-extrabold tabular-nums">{{savedQueries}}</div>
46
- <div class="text-[13px] text-base-content/50">Saved queries</div>
47
- </div>
48
- </div>
49
- <div class="stat-card">
50
- <span class="stat-icon {{#if isPostgres}}bg-info/10 text-info{{else}}bg-emerald-500/10 text-emerald-500{{/if}}">
51
- {{{icon "database" class="h-6 w-6"}}}
52
- </span>
53
- <div>
54
- <div class="flex items-center gap-1.5">
55
- <span class="text-xl font-extrabold">{{dialectName}}</span>
56
- {{#if readonly}}
57
- <span class="rounded bg-warning/20 px-1.5 py-0.5 text-[10px] font-bold uppercase text-warning">Read-only</span>
58
- {{else}}
59
- <span class="rounded bg-success/20 px-1.5 py-0.5 text-[10px] font-bold uppercase text-success">Writable</span>
60
- {{/if}}
61
- </div>
62
- <div class="truncate font-mono text-xs text-base-content/50" title="{{dbPath}}">{{dbPath}}</div>
63
- </div>
64
- </div>
65
- </div>
66
- <div>
67
- <div class="mb-3 flex items-center justify-between">
68
- <h2 class="text-lg font-bold">Tables</h2>
69
- <span class="text-sm text-base-content/45">{{tables.length}} total</span>
70
- </div>
71
- {{#if tables.length}}
72
- <div class="app-card overflow-hidden">
73
- <div class="overflow-x-auto">
74
- <table class="table table-sm">
75
- <thead>
76
- <tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
77
- <th class="font-semibold">Table</th>
78
- <th class="text-right font-semibold">Columns</th>
79
- <th class="text-right font-semibold">Rows</th>
80
- <th class="text-right font-semibold">Actions</th>
81
- </tr>
82
- </thead>
83
- <tbody>
84
- {{#each tables}}
85
- <tr class="group hover:bg-base-200/50">
86
- <td>
87
- <a href="{{../basePath}}/tables/{{this}}" class="inline-flex items-center gap-2.5 font-medium">
88
- <span class="grid h-8 w-8 place-items-center rounded-lg bg-primary/10 text-primary transition-colors group-hover:bg-primary/20">
89
- {{{icon "table" class="h-4 w-4"}}}
90
- </span>
91
- <span class="font-mono text-[13.5px]">{{this}}</span>
92
- </a>
93
- </td>
94
- <td class="text-right tabular-nums text-base-content/60">{{lookup ../cols this}}</td>
95
- <td class="text-right tabular-nums text-base-content/60">{{lookup ../counts this}}</td>
96
- <td class="text-right">
97
- <a href="{{../basePath}}/tables/{{this}}" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
98
- Browse
99
- {{{icon "arrowRight" class="h-3.5 w-3.5"}}}
100
- </a>
101
- </td>
102
- </tr>
103
- {{/each}}
104
- </tbody>
105
- </table>
106
- </div>
107
- </div>
108
- {{else}}
109
- <div class="empty-state">
110
- <span class="empty-icon">
111
- {{{icon "table" class="h-7 w-7"}}}
112
- </span>
113
- <p class="text-sm font-medium text-base-content/70">No tables yet</p>
114
- <p class="max-w-sm text-sm text-base-content/45">Create one with the table designer, or run a SQL statement in the query editor to get started.</p>
115
- <div class="mt-2 flex gap-2">
116
- {{#unless readonly}}
117
- <a href="{{basePath}}/designer" class="btn btn-primary btn-sm">New table</a>
118
- {{/unless}}
119
- <a href="{{basePath}}/query" class="btn btn-outline btn-sm">Query editor</a>
120
- </div>
121
- </div>
122
- {{/if}}
123
- </div>
124
- </div>
1
+ <div class="space-y-8">
125
2
  <div class="page-header">
126
3
  <div class="page-header-row">
127
4
  <div>
128
5
  <div class="page-pretitle">Overview</div>
129
6
  <h1 class="page-title">Database</h1>
130
7
  <p class="mt-0.5 text-xs text-base-content/60">Browse, edit, and query the connected database from your browser.</p>
131
8
  </div>
132
9
  <div class="page-actions">
133
10
  <a href="{{basePath}}/query" class="btn btn-ghost btn-sm gap-1.5">
134
11
  {{{icon "query" class="h-4 w-4"}}}
135
12
  Query
136
13
  </a>
137
14
  {{#unless readonly}}
138
15
  <a href="{{basePath}}/designer" class="btn btn-primary btn-sm gap-1.5">
139
16
  {{{icon "plus" class="h-4 w-4"}}}
140
17
  New table
141
18
  </a>
142
19
  {{/unless}}
143
20
  </div>
144
21
  </div>
145
22
  </div>
146
23
  <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
147
24
  <div class="stat-card">
148
25
  <span class="stat-icon bg-primary/10 text-primary">
149
26
  {{{icon "table" class="h-6 w-6"}}}
150
27
  </span>
151
28
  <div>
152
29
  <div class="text-2xl font-extrabold tabular-nums">{{tables.length}}</div>
153
30
  <div class="text-[13px] text-base-content/50">Tables</div>
154
31
  </div>
155
32
  </div>
156
33
  <div class="stat-card">
157
34
  <span class="stat-icon bg-secondary/10 text-secondary">
158
35
  {{{icon "stats" class="h-6 w-6"}}}
159
36
  </span>
160
37
  <div>
161
38
  <div class="text-2xl font-extrabold tabular-nums">{{totalRows}}</div>
162
39
  <div class="text-[13px] text-base-content/50">Total rows</div>
163
40
  </div>
164
41
  </div>
165
42
  <div class="stat-card">
166
43
  <span class="stat-icon bg-accent/10 text-accent">
167
44
  {{{icon "seed" class="h-6 w-6"}}}
168
45
  </span>
169
46
  <div>
170
47
  <div class="text-2xl font-extrabold tabular-nums">{{savedQueries}}</div>
171
48
  <div class="text-[13px] text-base-content/50">Saved queries</div>
172
49
  </div>
173
50
  </div>
174
51
  <div class="stat-card">
175
52
  <span class="stat-icon {{#if isPostgres}}bg-info/10 text-info{{else}}bg-emerald-500/10 text-emerald-500{{/if}}">
176
53
  {{{icon "database" class="h-6 w-6"}}}
177
54
  </span>
178
55
  <div>
179
56
  <div class="flex items-center gap-1.5">
180
57
  <span class="text-xl font-extrabold">{{dialectName}}</span>
181
58
  {{#if readonly}}
182
59
  <span class="rounded bg-warning/20 px-1.5 py-0.5 text-[10px] font-bold uppercase text-warning">Read-only</span>
183
60
  {{else}}
184
61
  <span class="rounded bg-success/20 px-1.5 py-0.5 text-[10px] font-bold uppercase text-success">Writable</span>
185
62
  {{/if}}
186
63
  </div>
187
64
  <div class="truncate font-mono text-xs text-base-content/50" title="{{dbPath}}">{{dbPath}}</div>
188
65
  </div>
189
66
  </div>
190
67
  </div>
191
68
  <div>
192
69
  <div class="mb-3 flex items-center justify-between">
193
70
  <h2 class="text-lg font-bold">Tables</h2>
194
71
  <span class="text-sm text-base-content/45">{{tables.length}} total</span>
195
72
  </div>
196
73
  {{#if tables.length}}
197
74
  {{#unless readonly}}
198
75
  <div id="home-bulk-toolbar"
199
76
  style="max-height: 0; overflow: hidden; transition: max-height 0.22s cubic-bezier(0.4,0,0.2,1), opacity 0.18s ease; opacity: 0;"
200
77
  aria-hidden="true">
201
78
  <div class="mb-3 flex flex-wrap items-center gap-3 rounded-xl border border-base-300 bg-base-100 px-4 py-3 shadow-soft">
202
79
  <span id="home-bulk-count"
203
80
  class="inline-flex items-center gap-1.5 rounded-full bg-primary/10 px-3 py-1 text-xs font-bold text-primary">
204
81
  <span id="home-bulk-count-num">0</span> selected
205
82
  </span>
206
83
  <div class="h-4 w-px bg-base-300"></div>
207
84
  <div class="dropdown dropdown-bottom" id="home-dd-clear">
208
85
  <button tabindex="0" id="home-btn-clear"
209
86
  class="btn btn-sm btn-warning gap-1.5 font-semibold">
210
87
  {{{icon "refresh" class="h-3.5 w-3.5"}}}
211
88
  Clear Rows
212
89
  {{{icon "chevronDown" class="h-3 w-3 opacity-60"}}}
213
90
  </button>
214
91
  <ul tabindex="0"
215
92
  class="dropdown-content menu bg-base-100 rounded-xl border border-base-300 shadow-lift z-30 mt-1 w-64 p-2 text-sm">
216
93
  <li>
217
94
  <button id="home-clear-normal" class="flex items-start gap-2.5 rounded-lg px-3 py-2.5 hover:bg-base-200 text-left w-full">
218
95
  <span class="mt-0.5 text-warning shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
219
96
  <span>
220
97
  <span class="block font-semibold">Clear rows</span>
221
98
  <span class="block text-xs text-base-content/50">Deletes all rows; fails if FK references exist</span>
222
99
  </span>
223
100
  </button>
224
101
  </li>
225
102
  <li>
226
103
  <button id="home-clear-force" class="flex items-start gap-2.5 rounded-lg px-3 py-2.5 hover:bg-error/10 text-left w-full text-error">
227
104
  <span class="mt-0.5 shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
228
105
  <span>
229
106
  <span class="block font-semibold">Force Clear <span class="text-[10px] font-bold uppercase tracking-wide rounded bg-error/15 px-1 py-0.5 ml-1">ignore FK</span></span>
230
107
  <span class="block text-xs text-error/60">Disables FK checks; deletes regardless of references</span>
231
108
  </span>
232
109
  </button>
233
110
  </li>
234
111
  </ul>
235
112
  </div>
236
113
  <div class="dropdown dropdown-bottom" id="home-dd-drop">
237
114
  <button tabindex="0" id="home-btn-drop"
238
115
  class="btn btn-sm btn-error gap-1.5 font-semibold text-white">
239
116
  {{{icon "warning" class="h-3.5 w-3.5"}}}
240
117
  Drop Tables
241
118
  {{{icon "chevronDown" class="h-3 w-3 opacity-60"}}}
242
119
  </button>
243
120
  <ul tabindex="0"
244
121
  class="dropdown-content menu bg-base-100 rounded-xl border border-base-300 shadow-lift z-30 mt-1 w-64 p-2 text-sm">
245
122
  <li>
246
123
  <button id="home-drop-normal" class="flex items-start gap-2.5 rounded-lg px-3 py-2.5 hover:bg-base-200 text-left w-full">
247
124
  <span class="mt-0.5 text-error shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
248
125
  <span>
249
126
  <span class="block font-semibold">Drop tables</span>
250
127
  <span class="block text-xs text-base-content/50">Permanently deletes tables and all data</span>
251
128
  </span>
252
129
  </button>
253
130
  </li>
254
131
  <li>
255
132
  <button id="home-drop-force" class="flex items-start gap-2.5 rounded-lg px-3 py-2.5 hover:bg-error/10 text-left w-full text-error">
256
133
  <span class="mt-0.5 shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
257
134
  <span>
258
135
  <span class="block font-semibold">Force Drop <span class="text-[10px] font-bold uppercase tracking-wide rounded bg-error/15 px-1 py-0.5 ml-1">ignore FK</span></span>
259
136
  <span class="block text-xs text-error/60">Drops with FK checks disabled; cascades on Postgres</span>
260
137
  </span>
261
138
  </button>
262
139
  </li>
263
140
  </ul>
264
141
  </div>
265
142
  <div class="ml-auto">
266
143
  <button id="home-bulk-deselect"
267
144
  class="btn btn-ghost btn-sm gap-1 text-base-content/50 hover:text-base-content">
268
145
  {{{icon "x" class="h-3.5 w-3.5"}}}
269
146
  Deselect all
270
147
  </button>
271
148
  </div>
272
149
  </div>
273
150
  </div>
274
151
  {{/unless}}
275
152
  <div class="app-card overflow-hidden">
276
153
  <div class="overflow-x-auto">
277
154
  <table class="table table-sm" id="home-tables-table">
278
155
  <thead>
279
156
  <tr class="bg-base-200/70 text-xs uppercase tracking-wide text-base-content/50">
280
157
  {{#unless readonly}}
281
158
  <th class="w-10">
282
159
  <input type="checkbox" id="home-select-all"
283
160
  class="checkbox checkbox-sm checkbox-primary"
284
161
  title="Select all tables" />
285
162
  </th>
286
163
  {{/unless}}
287
164
  <th class="font-semibold">Table</th>
288
165
  <th class="text-right font-semibold">Columns</th>
289
166
  <th class="text-right font-semibold">Rows</th>
290
167
  <th class="text-right font-semibold">Actions</th>
291
168
  </tr>
292
169
  </thead>
293
170
  <tbody>
294
171
  {{#each tables}}
295
172
  <tr class="group hover:bg-base-200/50 home-table-row" data-table="{{this}}">
296
173
  {{#unless ../readonly}}
297
174
  <td class="w-10">
298
175
  <input type="checkbox"
299
176
  class="checkbox checkbox-sm checkbox-primary home-table-checkbox"
300
177
  data-table="{{this}}"
301
178
  title="Select {{this}}" />
302
179
  </td>
303
180
  {{/unless}}
304
181
  <td>
305
182
  <a href="{{../basePath}}/tables/{{this}}" class="inline-flex items-center gap-2.5 font-medium">
306
183
  <span class="grid h-8 w-8 place-items-center rounded-lg bg-primary/10 text-primary transition-colors group-hover:bg-primary/20">
307
184
  {{{icon "table" class="h-4 w-4"}}}
308
185
  </span>
309
186
  <span class="font-mono text-[13.5px]">{{this}}</span>
310
187
  </a>
311
188
  </td>
312
189
  <td class="text-right tabular-nums text-base-content/60">{{lookup ../cols this}}</td>
313
190
  <td class="text-right tabular-nums text-base-content/60">{{lookup ../counts this}}</td>
314
191
  <td class="text-right">
315
192
  <a href="{{../basePath}}/tables/{{this}}" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
316
193
  Browse
317
194
  {{{icon "arrowRight" class="h-3.5 w-3.5"}}}
318
195
  </a>
319
196
  </td>
320
197
  </tr>
321
198
  {{/each}}
322
199
  </tbody>
323
200
  </table>
324
201
  </div>
325
202
  </div>
326
203
  {{else}}
327
204
  <div class="empty-state">
328
205
  <span class="empty-icon">
329
206
  {{{icon "table" class="h-7 w-7"}}}
330
207
  </span>
331
208
  <p class="text-sm font-medium text-base-content/70">No tables yet</p>
332
209
  <p class="max-w-sm text-sm text-base-content/45">Create one with the table designer, or run a SQL statement in the query editor to get started.</p>
333
210
  <div class="mt-2 flex gap-2">
334
211
  {{#unless readonly}}
335
212
  <a href="{{basePath}}/designer" class="btn btn-primary btn-sm">New table</a>
336
213
  {{/unless}}
337
214
  <a href="{{basePath}}/query" class="btn btn-outline btn-sm">Query editor</a>
338
215
  </div>
339
216
  </div>
340
217
  {{/if}}
341
218
  </div>
@@ -0,0 +1 @@
1
+ <div class="space-y-6">
2
  <div class="page-header">
1
3
  <div class="page-header-row">
2
4
  <div>
3
5
  <div class="page-pretitle">{{dialect}} Database</div>
4
6
  <h1 class="page-title">Info & Settings</h1>
5
7
  <p class="mt-0.5 text-xs text-base-content/60">Database configuration, settings, and schema DDL overview.</p>
6
8
  </div>
7
9
  </div>
8
10
  </div>
9
11
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
10
12
  <div class="lg:col-span-1 space-y-6">
11
13
  {{#if isDefaultPassword}}
12
14
  <div class="alert alert-warning text-xs shadow-xs rounded-2xl border border-warning/30 p-3.5">
13
15
  {{{icon "warning" class="h-5 w-5 shrink-0 text-warning"}}}
14
16
  <div>
15
17
  <div class="font-bold text-sm">Default Password in Use</div>
16
18
  <div class="text-base-content/80 mt-0.5 leading-relaxed">Console is running with default password (<code class="font-mono font-semibold">admin</code>). Run <code class="font-mono font-semibold">npm run generatehash</code> and set <code class="font-mono font-semibold">ADMINDB_PASSWORD</code>.</div>
17
19
  </div>
18
20
  </div>
19
21
  {{/if}}
20
22
  <div class="app-card overflow-hidden">
21
23
  <div class="border-b border-base-200 bg-base-200/40 px-4 py-3">
22
24
  <h2 class="text-sm font-bold uppercase tracking-wider text-base-content/80">Settings / Configuration</h2>
23
25
  </div>
24
26
  <div class="p-0">
25
27
  <table class="table table-sm w-full">
26
28
  <tbody>
27
29
  {{#each settings}}
28
30
  <tr class="hover:bg-base-200/20">
29
31
  <td class="font-medium text-base-content/70 w-1/2">{{@key}}</td>
30
32
  <td class="font-mono text-xs">{{this}}</td>
31
33
  </tr>
32
34
  {{else}}
33
35
  <tr>
34
36
  <td colspan="2" class="p-4 text-center text-sm text-base-content/40">No settings available</td>
35
37
  </tr>
36
38
  {{/each}}
37
39
  </tbody>
38
40
  </table>
39
41
  </div>
40
42
  </div>
41
43
  </div>
42
44
  <div class="lg:col-span-2 space-y-6">
43
45
  <div class="app-card overflow-hidden flex flex-col h-[75vh]">
44
46
  <div class="border-b border-base-200 bg-base-200/40 px-4 py-3 flex items-center justify-between">
45
47
  <div class="flex items-center gap-3">
46
48
  <h2 class="text-sm font-bold uppercase tracking-wider text-base-content/80">Schema DDL</h2>
47
49
  <span class="badge badge-sm badge-ghost font-mono text-[10px] uppercase font-bold">{{dialect}}</span>
48
50
  </div>
49
51
  <button id="btn-copy-ddl" class="btn btn-sm btn-ghost gap-1.5" disabled>
50
52
  {{{icon "copy" class="h-4 w-4"}}}
51
53
  Copy
52
54
  </button>
53
55
  </div>
54
56
  <div class="bg-base-300 p-4 overflow-y-auto flex-1 relative">
55
57
  <div id="ddl-loader" class="absolute inset-0 flex flex-col items-center justify-center text-base-content/50 gap-3">
56
58
  {{{icon "spinner" class="h-6 w-6 animate-spin text-primary"}}}
57
59
  <p class="text-sm font-medium">Extracting schema definitions...</p>
58
60
  </div>
59
61
  <div id="ddl-error" class="hidden absolute inset-0 flex flex-col items-center justify-center text-error gap-3 bg-base-300">
60
62
  {{{icon "error" class="h-8 w-8"}}}
61
63
  <p class="text-sm font-medium">Failed to load schema.</p>
62
64
  </div>
63
65
  <pre id="ddl-container" class="hidden m-0 h-full"><code class="language-sql text-sm text-base-content/80 whitespace-pre-wrap"></code></pre>
64
66
  </div>
65
67
  </div>
66
68
  </div>
67
69
  </div>
68
70
  document.addEventListener('DOMContentLoaded', async () => {
69
71
  const loader = document.getElementById('ddl-loader');
70
72
  const container = document.getElementById('ddl-container');
71
73
  const codeBlock = container.querySelector('code');
72
74
  const btnCopy = document.getElementById('btn-copy-ddl');
73
75
  const errorBox = document.getElementById('ddl-error');
74
76
  try {
75
77
  const res = await fetch('{{basePath}}/api/info/ddl');
76
78
  const json = await res.json();
77
79
  loader.classList.add('hidden');
78
80
  if (json.success && json.data) {
79
81
  if (window.Utils && window.Utils.highlightSql) {
80
82
  codeBlock.innerHTML = window.Utils.highlightSql(json.data);
81
83
  } else {
82
84
  codeBlock.textContent = json.data;
83
85
  }
84
86
  container.classList.remove('hidden');
85
87
  btnCopy.disabled = false;
86
88
  btnCopy.addEventListener('click', async () => {
87
89
  try {
88
90
  await navigator.clipboard.writeText(json.data);
89
91
  const originalText = btnCopy.innerHTML;
90
92
  btnCopy.innerHTML = `{{{icon "check" class="h-4 w-4"}}} Copied!`;
91
93
  btnCopy.classList.add('text-success');
92
94
  setTimeout(() => {
93
95
  btnCopy.innerHTML = originalText;
94
96
  btnCopy.classList.remove('text-success');
95
97
  }, 2000);
96
98
  } catch (err) {
97
99
  console.error('Failed to copy', err);
98
100
  }
99
101
  });
100
102
  } else {
101
103
  if (json.success && !json.data) {
102
104
  codeBlock.textContent = '-- No tables defined in the database.';
103
105
  container.classList.remove('hidden');
104
106
  } else {
105
107
  throw new Error(json.error || 'Failed to fetch DDL');
106
108
  }
107
109
  }
108
110
  } catch (err) {
109
111
  loader.classList.add('hidden');
110
112
  errorBox.classList.remove('hidden');
111
113
  errorBox.querySelector('p').textContent = err.message || 'Failed to load schema.';
112
114
  }
113
115
  });