admindb 2.4.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/dist/app.js +48 -25
- package/dist/core/context.d.ts +1 -0
- package/dist/core/context.js +2 -0
- package/dist/core/diff/data-differ.d.ts +1 -0
- package/dist/core/diff/data-differ.js +243 -0
- package/dist/core/diff/patch-generator.d.ts +1 -0
- package/dist/core/diff/patch-generator.js +77 -0
- package/dist/core/diff/schema-differ.d.ts +1 -0
- package/dist/core/diff/schema-differ.js +229 -0
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/errors.js +39 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +20 -0
- package/dist/core/result.d.ts +1 -0
- package/dist/core/result.js +10 -0
- package/dist/core/router.d.ts +1 -0
- package/dist/core/router.js +37 -0
- package/dist/core/transfer/dialect-mapper.d.ts +1 -0
- package/dist/core/transfer/dialect-mapper.js +303 -0
- package/dist/core/transfer/masking.d.ts +1 -0
- package/dist/core/transfer/masking.js +49 -0
- package/dist/core/transfer/sync-engine.d.ts +1 -0
- package/dist/core/transfer/sync-engine.js +234 -0
- package/dist/core/transfer/topological-sort.d.ts +1 -0
- package/dist/core/transfer/topological-sort.js +55 -0
- package/dist/data/chain.js +1 -1
- package/dist/data/engine.js +1 -1
- package/dist/db/database.d.ts +1 -1
- package/dist/db/database.js +9 -31
- package/dist/db/dialects/index.d.ts +1 -0
- package/dist/db/dialects/index.js +58 -0
- package/dist/db/dialects/postgres/ddl.d.ts +1 -0
- package/dist/db/dialects/postgres/ddl.js +107 -0
- package/dist/db/dialects/postgres/dialect.d.ts +1 -0
- package/dist/db/dialects/postgres/dialect.js +28 -0
- package/dist/db/dialects/postgres/introspector.d.ts +1 -0
- package/dist/db/dialects/postgres/introspector.js +265 -0
- package/dist/db/dialects/postgres/types.d.ts +1 -0
- package/dist/db/dialects/postgres/types.js +83 -0
- package/dist/db/dialects/sqlite/ddl.d.ts +1 -0
- package/dist/db/dialects/sqlite/ddl.js +244 -0
- package/dist/db/dialects/sqlite/dialect.d.ts +1 -0
- package/dist/db/dialects/sqlite/dialect.js +25 -0
- package/dist/db/dialects/sqlite/introspector.d.ts +1 -0
- package/dist/db/dialects/sqlite/introspector.js +217 -0
- package/dist/db/dialects/sqlite/types.d.ts +1 -0
- package/dist/db/dialects/sqlite/types.js +69 -0
- package/dist/db/dialects/types.d.ts +1 -0
- package/dist/db/dialects/types.js +15 -0
- package/dist/db/export.js +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/manager.d.ts +1 -1
- package/dist/db/manager.js +101 -21
- package/dist/db/postgres.d.ts +1 -1
- package/dist/db/postgres.js +20 -284
- package/dist/db/types.d.ts +1 -1
- package/dist/db/types.js +0 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -1
- package/dist/modules/databases/databases.routes.d.ts +1 -0
- package/dist/modules/databases/databases.routes.js +150 -0
- package/dist/modules/databases/databases.service.d.ts +1 -0
- package/dist/modules/databases/databases.service.js +134 -0
- package/dist/modules/databases/index.d.ts +1 -0
- package/dist/{routes → modules/databases}/index.js +2 -3
- package/dist/modules/erd/erd.routes.d.ts +1 -0
- package/dist/modules/erd/erd.routes.js +32 -0
- package/dist/modules/erd/erd.service.d.ts +1 -0
- package/dist/modules/erd/erd.service.js +39 -0
- package/dist/modules/erd/index.d.ts +1 -0
- package/dist/modules/erd/index.js +18 -0
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/index.js +70 -0
- package/dist/modules/query/index.d.ts +1 -0
- package/dist/modules/query/index.js +18 -0
- package/dist/modules/query/query.routes.d.ts +1 -0
- package/dist/modules/query/query.routes.js +54 -0
- package/dist/modules/query/query.service.d.ts +1 -0
- package/dist/modules/query/query.service.js +95 -0
- package/dist/modules/rows/blob.helper.d.ts +1 -0
- package/dist/modules/rows/blob.helper.js +40 -0
- package/dist/modules/rows/display.helper.d.ts +1 -0
- package/dist/modules/rows/display.helper.js +73 -0
- package/dist/modules/rows/index.d.ts +1 -0
- package/dist/modules/rows/index.js +20 -0
- package/dist/modules/rows/rows.routes.d.ts +1 -0
- package/dist/modules/rows/rows.routes.js +555 -0
- package/dist/modules/rows/rows.service.d.ts +1 -0
- package/dist/modules/rows/rows.service.js +433 -0
- package/dist/modules/schema/index.d.ts +1 -0
- package/dist/modules/schema/index.js +18 -0
- package/dist/modules/schema/schema.routes.d.ts +1 -0
- package/dist/modules/schema/schema.routes.js +171 -0
- package/dist/modules/schema/schema.service.d.ts +1 -0
- package/dist/modules/schema/schema.service.js +58 -0
- package/dist/modules/search/index.d.ts +1 -0
- package/dist/modules/search/index.js +19 -0
- package/dist/modules/search/search.routes.d.ts +1 -0
- package/dist/modules/search/search.routes.js +38 -0
- package/dist/modules/search/search.service.d.ts +1 -0
- package/dist/modules/search/search.service.js +458 -0
- package/dist/modules/search/search.types.d.ts +1 -0
- package/dist/modules/search/search.types.js +2 -0
- package/dist/modules/seed/index.d.ts +1 -0
- package/dist/modules/seed/index.js +18 -0
- package/dist/modules/seed/seed.routes.d.ts +1 -0
- package/dist/modules/seed/seed.routes.js +212 -0
- package/dist/modules/seed/seed.service.d.ts +1 -0
- package/dist/{routes/api/helpers.js → modules/seed/seed.service.js} +86 -109
- package/dist/modules/sync/index.d.ts +1 -0
- package/dist/modules/sync/index.js +18 -0
- package/dist/modules/sync/sync.routes.d.ts +1 -0
- package/dist/modules/sync/sync.routes.js +135 -0
- package/dist/modules/sync/sync.service.d.ts +1 -0
- package/dist/modules/sync/sync.service.js +41 -0
- package/dist/modules/tables/index.d.ts +1 -0
- package/dist/modules/tables/index.js +18 -0
- package/dist/modules/tables/tables.routes.d.ts +1 -0
- package/dist/modules/tables/tables.routes.js +194 -0
- package/dist/modules/tables/tables.service.d.ts +1 -0
- package/dist/modules/tables/tables.service.js +218 -0
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/search.js +1 -0
- package/dist/public/js/sync.js +1 -0
- package/dist/types/api.d.ts +1 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +1 -3
- package/dist/utils/icons.js +3 -0
- package/dist/utils/stream.d.ts +1 -0
- package/dist/utils/stream.js +131 -0
- package/dist/views/layouts/main.hbs +1 -1
- package/dist/views/pages/error.hbs +10 -1
- package/dist/views/pages/home.hbs +1 -1
- package/dist/views/pages/query.hbs +1 -1
- package/dist/views/pages/seed-select.hbs +1 -252
- package/dist/views/pages/seed.hbs +1 -307
- package/dist/views/pages/sync.hbs +409 -0
- package/dist/views/pages/table.hbs +1 -1
- package/dist/views/partials/navbar.hbs +1 -1
- package/dist/views/partials/sidebar.hbs +1 -1
- package/docs/API.md +4 -17
- package/docs/EXAMPLES.md +579 -579
- package/docs/SECURITY.md +265 -265
- package/package.json +10 -9
- package/dist/db/introspection.d.ts +0 -1
- package/dist/db/introspection.js +0 -164
- package/dist/routes/api/erd.d.ts +0 -1
- package/dist/routes/api/erd.js +0 -45
- package/dist/routes/api/helpers.d.ts +0 -1
- package/dist/routes/api/import-export.d.ts +0 -1
- package/dist/routes/api/import-export.js +0 -84
- package/dist/routes/api/index.d.ts +0 -1
- package/dist/routes/api/index.js +0 -55
- package/dist/routes/api/query.d.ts +0 -1
- package/dist/routes/api/query.js +0 -77
- package/dist/routes/api/rows.d.ts +0 -1
- package/dist/routes/api/rows.js +0 -373
- package/dist/routes/api/seed.d.ts +0 -1
- package/dist/routes/api/seed.js +0 -180
- package/dist/routes/api/tables.d.ts +0 -1
- package/dist/routes/api/tables.js +0 -230
- package/dist/routes/databases.d.ts +0 -1
- package/dist/routes/databases.js +0 -212
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/pages.d.ts +0 -1
- package/dist/routes/pages.js +0 -540
|
@@ -1,252 +1 @@
|
|
|
1
|
-
<div class="space-y-6 max-w-5xl mx-auto pb-16">
|
|
2
|
-
<div class="page-header">
|
|
3
|
-
<div class="page-header-row">
|
|
4
|
-
<div>
|
|
5
|
-
<div class="page-pretitle">Developer Tools</div>
|
|
6
|
-
<h1 class="page-title">Seed Data Generator</h1>
|
|
7
|
-
<p class="mt-0.5 text-xs text-base-content/60">
|
|
8
|
-
Generate realistic mock datasets with column heuristics or populate complete relational entity graphs.
|
|
9
|
-
</p>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
{{#if hasTables}}
|
|
14
|
-
<div class="grid gap-6 lg:grid-cols-[1fr_380px]">
|
|
15
|
-
<div class="space-y-4">
|
|
16
|
-
<div class="app-card overflow-hidden">
|
|
17
|
-
<div class="p-4 sm:p-5 border-b border-base-200 bg-base-200/30 flex flex-wrap items-center justify-between gap-3">
|
|
18
|
-
<div>
|
|
19
|
-
<h2 class="text-sm font-bold text-base-content flex items-center gap-2">
|
|
20
|
-
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/15 text-primary text-xs font-bold font-mono">1</span>
|
|
21
|
-
Choose Target Table
|
|
22
|
-
</h2>
|
|
23
|
-
<p class="text-[11px] text-base-content/50 mt-0.5">Select the root table to generate rows for.</p>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="w-full sm:w-56">
|
|
26
|
-
<div class="relative">
|
|
27
|
-
<span class="pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-base-content/40">
|
|
28
|
-
{{{icon "search" class="h-3.5 w-3.5"}}}
|
|
29
|
-
</span>
|
|
30
|
-
<input id="table-search-input" type="text" placeholder="Filter tables…" autocomplete="off"
|
|
31
|
-
class="field-input text-xs !py-1 !pl-8 w-full" />
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
<div id="table-cards-list" class="p-3 sm:p-4 space-y-2 max-h-[480px] overflow-y-auto">
|
|
36
|
-
{{#each (or seedTables tables)}}
|
|
37
|
-
<label class="table-option-card block cursor-pointer select-none rounded-xl border p-3 transition-all {{#if (eq this.name ../defaultTable)}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
38
|
-
data-table="{{this.name}}">
|
|
39
|
-
<div class="flex items-center justify-between gap-3">
|
|
40
|
-
<div class="flex items-center gap-3 min-w-0">
|
|
41
|
-
<input type="radio" name="selected_table" value="{{this.name}}" class="radio radio-primary radio-xs"
|
|
42
|
-
{{#if (eq this.name ../defaultTable)}}checked{{/if}} />
|
|
43
|
-
<div class="min-w-0">
|
|
44
|
-
<div class="font-mono font-bold text-sm text-base-content truncate flex items-center gap-2">
|
|
45
|
-
{{{icon "table" class="h-3.5 w-3.5 text-base-content/50 shrink-0"}}}
|
|
46
|
-
<span>{{this.name}}</span>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="flex items-center gap-2 mt-0.5 text-[11px] text-base-content/50">
|
|
49
|
-
<span>{{this.cols}} cols</span>
|
|
50
|
-
<span>·</span>
|
|
51
|
-
<span>{{this.rowCount}} existing rows</span>
|
|
52
|
-
{{#if this.fks}}
|
|
53
|
-
<span>·</span>
|
|
54
|
-
<span class="text-amber-500 font-medium">{{this.fks}} FK refs</span>
|
|
55
|
-
{{/if}}
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
<div class="flex items-center gap-1 shrink-0">
|
|
60
|
-
<button type="button" class="btn btn-ghost btn-xs text-[11px] text-base-content/70 hover:text-primary quick-seed-btn"
|
|
61
|
-
data-table="{{this.name}}" data-mode="single" title="Seed this table directly">
|
|
62
|
-
Single
|
|
63
|
-
</button>
|
|
64
|
-
<button type="button" class="btn btn-ghost btn-xs text-[11px] text-emerald-600 hover:text-emerald-500 quick-seed-btn"
|
|
65
|
-
data-table="{{this.name}}" data-mode="chain" title="Seed relational ER chain directly">
|
|
66
|
-
ER Chain
|
|
67
|
-
</button>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</label>
|
|
71
|
-
{{/each}}
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
<div class="space-y-4 lg:sticky lg:top-20 self-start">
|
|
76
|
-
<div class="app-card overflow-hidden">
|
|
77
|
-
<div class="p-4 border-b border-base-200 bg-base-200/30">
|
|
78
|
-
<h2 class="text-sm font-bold text-base-content flex items-center gap-2">
|
|
79
|
-
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/15 text-primary text-xs font-bold font-mono">2</span>
|
|
80
|
-
Choose Generation Mode
|
|
81
|
-
</h2>
|
|
82
|
-
<p class="text-[11px] text-base-content/50 mt-0.5">Select how rows should be populated.</p>
|
|
83
|
-
</div>
|
|
84
|
-
<div class="p-3.5 space-y-2.5">
|
|
85
|
-
<label class="mode-option-card block cursor-pointer select-none rounded-xl border p-3.5 transition-all {{#if (eq defaultMode 'single')}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
86
|
-
data-mode="single">
|
|
87
|
-
<div class="flex items-start gap-3">
|
|
88
|
-
<input type="radio" name="selected_mode" value="single" class="radio radio-primary radio-xs mt-0.5"
|
|
89
|
-
{{#if (eq defaultMode 'single')}}checked{{/if}} />
|
|
90
|
-
<div class="space-y-1">
|
|
91
|
-
<div class="flex items-center gap-2">
|
|
92
|
-
<span class="font-bold text-xs text-base-content">Single Table Seeder</span>
|
|
93
|
-
<span class="badge badge-xs badge-ghost text-[10px] font-mono">Standalone</span>
|
|
94
|
-
</div>
|
|
95
|
-
<p class="text-[11px] text-base-content/60 leading-relaxed">
|
|
96
|
-
Generates realistic rows for the selected table with automated column heuristics (names, emails, dates, addresses, UUIDs) and live formula templates.
|
|
97
|
-
</p>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
</label>
|
|
101
|
-
<label class="mode-option-card block cursor-pointer select-none rounded-xl border p-3.5 transition-all {{#if (eq defaultMode 'chain')}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
102
|
-
data-mode="chain">
|
|
103
|
-
<div class="flex items-start gap-3">
|
|
104
|
-
<input type="radio" name="selected_mode" value="chain" class="radio radio-primary radio-xs mt-0.5"
|
|
105
|
-
{{#if (eq defaultMode 'chain')}}checked{{/if}} />
|
|
106
|
-
<div class="space-y-1">
|
|
107
|
-
<div class="flex items-center gap-2">
|
|
108
|
-
<span class="font-bold text-xs text-base-content">Relational ER Chain Seeder</span>
|
|
109
|
-
<span class="badge badge-xs badge-outline badge-success text-[10px] font-mono">Full Graph</span>
|
|
110
|
-
</div>
|
|
111
|
-
<p class="text-[11px] text-base-content/60 leading-relaxed">
|
|
112
|
-
Analyzes schema graph foreign keys and seeds related parent & child entities in topological order to guarantee full relational integrity.
|
|
113
|
-
</p>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
</label>
|
|
117
|
-
</div>
|
|
118
|
-
<div class="p-3.5 border-t border-base-200 bg-base-200/20">
|
|
119
|
-
<button id="btn-launch-seed" type="button" class="btn btn-primary btn-sm w-full gap-2 font-bold shadow-sm">
|
|
120
|
-
{{{icon "seed" class="h-4 w-4"}}}
|
|
121
|
-
<span id="launch-btn-label">Open Seed Generator</span>
|
|
122
|
-
{{{icon "arrowRight" class="h-3.5 w-3.5"}}}
|
|
123
|
-
</button>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="p-3.5 rounded-xl bg-base-200/50 border border-base-300 text-xs space-y-1 text-base-content/70">
|
|
127
|
-
<div class="font-semibold text-base-content flex items-center gap-1.5 text-[11px]">
|
|
128
|
-
{{{icon "info" class="h-3.5 w-3.5 text-primary"}}}
|
|
129
|
-
Deterministic Generation
|
|
130
|
-
</div>
|
|
131
|
-
<p class="text-[11px] leading-relaxed text-base-content/60">
|
|
132
|
-
You can specify an exact numeric seed for deterministic reproducible data, or import/export seed profiles.
|
|
133
|
-
</p>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
{{else}}
|
|
138
|
-
<div class="empty-state">
|
|
139
|
-
<span class="empty-icon">{{{icon "table" class="h-7 w-7"}}}</span>
|
|
140
|
-
<p class="text-sm font-medium text-base-content/70">No tables available in the database</p>
|
|
141
|
-
<p class="text-xs text-base-content/50 mt-1 max-w-sm">Create a table using the visual designer or run SQL migrations before generating seed data.</p>
|
|
142
|
-
<div class="mt-4 flex gap-2">
|
|
143
|
-
<a href="{{basePath}}/designer/{{encodeUri dbId}}" class="btn btn-primary btn-sm gap-1.5">
|
|
144
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
145
|
-
Create table
|
|
146
|
-
</a>
|
|
147
|
-
<a href="{{basePath}}/query/{{encodeUri dbId}}" class="btn btn-outline btn-sm gap-1.5">
|
|
148
|
-
{{{icon "query" class="h-4 w-4"}}}
|
|
149
|
-
Query editor
|
|
150
|
-
</a>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
{{/if}}
|
|
154
|
-
</div>
|
|
155
|
-
<script>
|
|
156
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
157
|
-
const BASE = '{{basePath}}';
|
|
158
|
-
const DB_ID = '{{dbId}}';
|
|
159
|
-
let selectedTable = '{{defaultTable}}';
|
|
160
|
-
let selectedMode = '{{defaultMode}}' || 'single';
|
|
161
|
-
const tableCards = document.querySelectorAll('.table-option-card');
|
|
162
|
-
const modeCards = document.querySelectorAll('.mode-option-card');
|
|
163
|
-
const launchBtn = document.getElementById('btn-launch-seed');
|
|
164
|
-
const launchLabel = document.getElementById('launch-btn-label');
|
|
165
|
-
const searchInput = document.getElementById('table-search-input');
|
|
166
|
-
function updateLaunchLabel() {
|
|
167
|
-
if (launchLabel) {
|
|
168
|
-
launchLabel.textContent = selectedTable
|
|
169
|
-
? `Seed "${selectedTable}" (${selectedMode === 'chain' ? 'ER Chain' : 'Single Table'})`
|
|
170
|
-
: 'Open Seed Generator';
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function setSelectedTable(tableName) {
|
|
174
|
-
selectedTable = tableName;
|
|
175
|
-
tableCards.forEach(card => {
|
|
176
|
-
const isMatch = card.dataset.table === tableName;
|
|
177
|
-
const radio = card.querySelector('input[type="radio"]');
|
|
178
|
-
if (radio) radio.checked = isMatch;
|
|
179
|
-
if (isMatch) {
|
|
180
|
-
card.classList.add('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
181
|
-
card.classList.remove('border-base-200', 'bg-base-100');
|
|
182
|
-
} else {
|
|
183
|
-
card.classList.remove('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
184
|
-
card.classList.add('border-base-200', 'bg-base-100');
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
updateLaunchLabel();
|
|
188
|
-
}
|
|
189
|
-
function setSelectedMode(mode) {
|
|
190
|
-
selectedMode = mode;
|
|
191
|
-
modeCards.forEach(card => {
|
|
192
|
-
const isMatch = card.dataset.mode === mode;
|
|
193
|
-
const radio = card.querySelector('input[type="radio"]');
|
|
194
|
-
if (radio) radio.checked = isMatch;
|
|
195
|
-
if (isMatch) {
|
|
196
|
-
card.classList.add('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
197
|
-
card.classList.remove('border-base-200', 'bg-base-100');
|
|
198
|
-
} else {
|
|
199
|
-
card.classList.remove('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
200
|
-
card.classList.add('border-base-200', 'bg-base-100');
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
updateLaunchLabel();
|
|
204
|
-
}
|
|
205
|
-
tableCards.forEach(card => {
|
|
206
|
-
card.addEventListener('click', (e) => {
|
|
207
|
-
if (e.target.closest('.quick-seed-btn')) return;
|
|
208
|
-
const table = card.dataset.table;
|
|
209
|
-
if (table) setSelectedTable(table);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
modeCards.forEach(card => {
|
|
213
|
-
card.addEventListener('click', () => {
|
|
214
|
-
const mode = card.dataset.mode;
|
|
215
|
-
if (mode) setSelectedMode(mode);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
// Direct quick-seed buttons
|
|
219
|
-
document.querySelectorAll('.quick-seed-btn').forEach(btn => {
|
|
220
|
-
btn.addEventListener('click', (e) => {
|
|
221
|
-
e.stopPropagation();
|
|
222
|
-
const table = btn.dataset.table;
|
|
223
|
-
const mode = btn.dataset.mode || 'single';
|
|
224
|
-
if (table) {
|
|
225
|
-
window.location.href = `${BASE}/seed/${encodeURIComponent(DB_ID)}/${encodeURIComponent(table)}?mode=${encodeURIComponent(mode)}`;
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
// Launch button
|
|
230
|
-
if (launchBtn) {
|
|
231
|
-
launchBtn.addEventListener('click', () => {
|
|
232
|
-
if (!selectedTable) return;
|
|
233
|
-
window.location.href = `${BASE}/seed/${encodeURIComponent(DB_ID)}/${encodeURIComponent(selectedTable)}?mode=${encodeURIComponent(selectedMode)}`;
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
// Real-time table search filter
|
|
237
|
-
if (searchInput) {
|
|
238
|
-
searchInput.addEventListener('input', () => {
|
|
239
|
-
const q = searchInput.value.trim().toLowerCase();
|
|
240
|
-
tableCards.forEach(card => {
|
|
241
|
-
const name = (card.dataset.table || '').toLowerCase();
|
|
242
|
-
if (!q || name.includes(q)) {
|
|
243
|
-
card.classList.remove('hidden');
|
|
244
|
-
} else {
|
|
245
|
-
card.classList.add('hidden');
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
updateLaunchLabel();
|
|
251
|
-
});
|
|
252
|
-
</script>
|
|
1
|
+
<div class="space-y-6 max-w-5xl mx-auto pb-16">
|
|
253
2
|
<div class="page-header">
|
|
254
3
|
<div class="page-header-row">
|
|
255
4
|
<div>
|
|
256
5
|
<div class="page-pretitle">Developer Tools</div>
|
|
257
6
|
<h1 class="page-title">Seed Data Generator</h1>
|
|
258
7
|
<p class="mt-0.5 text-xs text-base-content/60">
|
|
259
8
|
Generate realistic mock datasets with column heuristics or populate complete relational entity graphs.
|
|
260
9
|
</p>
|
|
261
10
|
</div>
|
|
262
11
|
</div>
|
|
263
12
|
</div>
|
|
264
13
|
{{#if hasTables}}
|
|
265
14
|
<div class="grid gap-6 lg:grid-cols-[1fr_380px]">
|
|
266
15
|
<div class="space-y-4">
|
|
267
16
|
<div class="app-card overflow-hidden">
|
|
268
17
|
<div class="p-4 sm:p-5 border-b border-base-200 bg-base-200/30 flex flex-wrap items-center justify-between gap-3">
|
|
269
18
|
<div>
|
|
270
19
|
<h2 class="text-sm font-bold text-base-content flex items-center gap-2">
|
|
271
20
|
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/15 text-primary text-xs font-bold font-mono">1</span>
|
|
272
21
|
Choose Target Table
|
|
273
22
|
</h2>
|
|
274
23
|
<p class="text-[11px] text-base-content/50 mt-0.5">Select the root table to generate rows for.</p>
|
|
275
24
|
</div>
|
|
276
25
|
<div class="w-full sm:w-56">
|
|
277
26
|
<div class="relative">
|
|
278
27
|
<span class="pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-base-content/40">
|
|
279
28
|
{{{icon "search" class="h-3.5 w-3.5"}}}
|
|
280
29
|
</span>
|
|
281
30
|
<input id="table-search-input" type="text" placeholder="Filter tables…" autocomplete="off"
|
|
282
31
|
class="field-input text-xs !py-1 !pl-8 w-full" />
|
|
283
32
|
</div>
|
|
284
33
|
</div>
|
|
285
34
|
</div>
|
|
286
35
|
<div id="table-cards-list" class="p-3 sm:p-4 space-y-2 max-h-[480px] overflow-y-auto">
|
|
287
36
|
{{#each (or seedTables tables)}}
|
|
288
37
|
<label class="table-option-card block cursor-pointer select-none rounded-xl border p-3 transition-all {{#if (eq this.name ../defaultTable)}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
289
38
|
data-table="{{this.name}}">
|
|
290
39
|
<div class="flex items-center justify-between gap-3">
|
|
291
40
|
<div class="flex items-center gap-3 min-w-0">
|
|
292
41
|
<input type="radio" name="selected_table" value="{{this.name}}" class="radio radio-primary radio-xs"
|
|
293
42
|
{{#if (eq this.name ../defaultTable)}}checked{{/if}} />
|
|
294
43
|
<div class="min-w-0">
|
|
295
44
|
<div class="font-mono font-bold text-sm text-base-content truncate flex items-center gap-2">
|
|
296
45
|
{{{icon "table" class="h-3.5 w-3.5 text-base-content/50 shrink-0"}}}
|
|
297
46
|
<span>{{this.name}}</span>
|
|
298
47
|
</div>
|
|
299
48
|
<div class="flex items-center gap-2 mt-0.5 text-[11px] text-base-content/50">
|
|
300
49
|
<span>{{this.cols}} cols</span>
|
|
301
50
|
<span>·</span>
|
|
302
51
|
<span>{{this.rowCount}} existing rows</span>
|
|
303
52
|
{{#if this.fks}}
|
|
304
53
|
<span>·</span>
|
|
305
54
|
<span class="text-amber-500 font-medium">{{this.fks}} FK refs</span>
|
|
306
55
|
{{/if}}
|
|
307
56
|
</div>
|
|
308
57
|
</div>
|
|
309
58
|
</div>
|
|
310
59
|
<div class="flex items-center gap-1 shrink-0">
|
|
311
60
|
<button type="button" class="btn btn-ghost btn-xs text-[11px] text-base-content/70 hover:text-primary quick-seed-btn"
|
|
312
61
|
data-table="{{this.name}}" data-mode="single" title="Seed this table directly">
|
|
313
62
|
Single
|
|
314
63
|
</button>
|
|
315
64
|
<button type="button" class="btn btn-ghost btn-xs text-[11px] text-emerald-600 hover:text-emerald-500 quick-seed-btn"
|
|
316
65
|
data-table="{{this.name}}" data-mode="chain" title="Seed relational ER chain directly">
|
|
317
66
|
ER Chain
|
|
318
67
|
</button>
|
|
319
68
|
</div>
|
|
320
69
|
</div>
|
|
321
70
|
</label>
|
|
322
71
|
{{/each}}
|
|
323
72
|
</div>
|
|
324
73
|
</div>
|
|
325
74
|
</div>
|
|
326
75
|
<div class="space-y-4 lg:sticky lg:top-20 self-start">
|
|
327
76
|
<div class="app-card overflow-hidden">
|
|
328
77
|
<div class="p-4 border-b border-base-200 bg-base-200/30">
|
|
329
78
|
<h2 class="text-sm font-bold text-base-content flex items-center gap-2">
|
|
330
79
|
<span class="grid h-5 w-5 place-items-center rounded-md bg-primary/15 text-primary text-xs font-bold font-mono">2</span>
|
|
331
80
|
Choose Generation Mode
|
|
332
81
|
</h2>
|
|
333
82
|
<p class="text-[11px] text-base-content/50 mt-0.5">Select how rows should be populated.</p>
|
|
334
83
|
</div>
|
|
335
84
|
<div class="p-3.5 space-y-2.5">
|
|
336
85
|
<label class="mode-option-card block cursor-pointer select-none rounded-xl border p-3.5 transition-all {{#if (eq defaultMode 'single')}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
337
86
|
data-mode="single">
|
|
338
87
|
<div class="flex items-start gap-3">
|
|
339
88
|
<input type="radio" name="selected_mode" value="single" class="radio radio-primary radio-xs mt-0.5"
|
|
340
89
|
{{#if (eq defaultMode 'single')}}checked{{/if}} />
|
|
341
90
|
<div class="space-y-1">
|
|
342
91
|
<div class="flex items-center gap-2">
|
|
343
92
|
<span class="font-bold text-xs text-base-content">Single Table Seeder</span>
|
|
344
93
|
<span class="badge badge-xs badge-ghost text-[10px] font-mono">Standalone</span>
|
|
345
94
|
</div>
|
|
346
95
|
<p class="text-[11px] text-base-content/60 leading-relaxed">
|
|
347
96
|
Generates realistic rows for the selected table with automated column heuristics (names, emails, dates, addresses, UUIDs) and live formula templates.
|
|
348
97
|
</p>
|
|
349
98
|
</div>
|
|
350
99
|
</div>
|
|
351
100
|
</label>
|
|
352
101
|
<label class="mode-option-card block cursor-pointer select-none rounded-xl border p-3.5 transition-all {{#if (eq defaultMode 'chain')}}border-primary bg-primary/[0.04] shadow-sm{{else}}border-base-200 bg-base-100 hover:border-base-300 hover:bg-base-200/40{{/if}}"
|
|
353
102
|
data-mode="chain">
|
|
354
103
|
<div class="flex items-start gap-3">
|
|
355
104
|
<input type="radio" name="selected_mode" value="chain" class="radio radio-primary radio-xs mt-0.5"
|
|
356
105
|
{{#if (eq defaultMode 'chain')}}checked{{/if}} />
|
|
357
106
|
<div class="space-y-1">
|
|
358
107
|
<div class="flex items-center gap-2">
|
|
359
108
|
<span class="font-bold text-xs text-base-content">Relational ER Chain Seeder</span>
|
|
360
109
|
<span class="badge badge-xs badge-outline badge-success text-[10px] font-mono">Full Graph</span>
|
|
361
110
|
</div>
|
|
362
111
|
<p class="text-[11px] text-base-content/60 leading-relaxed">
|
|
363
112
|
Analyzes schema graph foreign keys and seeds related parent & child entities in topological order to guarantee full relational integrity.
|
|
364
113
|
</p>
|
|
365
114
|
</div>
|
|
366
115
|
</div>
|
|
367
116
|
</label>
|
|
368
117
|
</div>
|
|
369
118
|
<div class="p-3.5 border-t border-base-200 bg-base-200/20">
|
|
370
119
|
<button id="btn-launch-seed" type="button" class="btn btn-primary btn-sm w-full gap-2 font-bold shadow-sm">
|
|
371
120
|
{{{icon "seed" class="h-4 w-4"}}}
|
|
372
121
|
<span id="launch-btn-label">Open Seed Generator</span>
|
|
373
122
|
{{{icon "arrowRight" class="h-3.5 w-3.5"}}}
|
|
374
123
|
</button>
|
|
375
124
|
</div>
|
|
376
125
|
</div>
|
|
377
126
|
<div class="p-3.5 rounded-xl bg-base-200/50 border border-base-300 text-xs space-y-1 text-base-content/70">
|
|
378
127
|
<div class="font-semibold text-base-content flex items-center gap-1.5 text-[11px]">
|
|
379
128
|
{{{icon "info" class="h-3.5 w-3.5 text-primary"}}}
|
|
380
129
|
Deterministic Generation
|
|
381
130
|
</div>
|
|
382
131
|
<p class="text-[11px] leading-relaxed text-base-content/60">
|
|
383
132
|
You can specify an exact numeric seed for deterministic reproducible data, or import/export seed profiles.
|
|
384
133
|
</p>
|
|
385
134
|
</div>
|
|
386
135
|
</div>
|
|
387
136
|
</div>
|
|
388
137
|
{{else}}
|
|
389
138
|
<div class="empty-state">
|
|
390
139
|
<span class="empty-icon">{{{icon "table" class="h-7 w-7"}}}</span>
|
|
391
140
|
<p class="text-sm font-medium text-base-content/70">No tables available in the database</p>
|
|
392
141
|
<p class="text-xs text-base-content/50 mt-1 max-w-sm">Create a table using the visual designer or run SQL migrations before generating seed data.</p>
|
|
393
142
|
<div class="mt-4 flex gap-2">
|
|
394
143
|
<a href="{{basePath}}/designer/{{encodeUri dbId}}" class="btn btn-primary btn-sm gap-1.5">
|
|
395
144
|
{{{icon "plus" class="h-4 w-4"}}}
|
|
396
145
|
Create table
|
|
397
146
|
</a>
|
|
398
147
|
<a href="{{basePath}}/query/{{encodeUri dbId}}" class="btn btn-outline btn-sm gap-1.5">
|
|
399
148
|
{{{icon "query" class="h-4 w-4"}}}
|
|
400
149
|
Query editor
|
|
401
150
|
</a>
|
|
402
151
|
</div>
|
|
403
152
|
</div>
|
|
404
153
|
{{/if}}
|
|
405
154
|
const BASE = '{{basePath}}';
|
|
406
155
|
const DB_ID = '{{dbId}}';
|
|
407
156
|
let selectedTable = '{{defaultTable}}';
|
|
408
157
|
let selectedMode = '{{defaultMode}}' || 'single';
|
|
409
158
|
const tableCards = document.querySelectorAll('.table-option-card');
|
|
410
159
|
const modeCards = document.querySelectorAll('.mode-option-card');
|
|
411
160
|
const launchBtn = document.getElementById('btn-launch-seed');
|
|
412
161
|
const launchLabel = document.getElementById('launch-btn-label');
|
|
413
162
|
const searchInput = document.getElementById('table-search-input');
|
|
414
163
|
function updateLaunchLabel() {
|
|
415
164
|
if (launchLabel) {
|
|
416
165
|
launchLabel.textContent = selectedTable
|
|
417
166
|
? `Seed "${selectedTable}" (${selectedMode === 'chain' ? 'ER Chain' : 'Single Table'})`
|
|
418
167
|
: 'Open Seed Generator';
|
|
419
168
|
}
|
|
420
169
|
}
|
|
421
170
|
function setSelectedTable(tableName) {
|
|
422
171
|
selectedTable = tableName;
|
|
423
172
|
tableCards.forEach(card => {
|
|
424
173
|
const isMatch = card.dataset.table === tableName;
|
|
425
174
|
const radio = card.querySelector('input[type="radio"]');
|
|
426
175
|
if (radio) radio.checked = isMatch;
|
|
427
176
|
if (isMatch) {
|
|
428
177
|
card.classList.add('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
429
178
|
card.classList.remove('border-base-200', 'bg-base-100');
|
|
430
179
|
} else {
|
|
431
180
|
card.classList.remove('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
432
181
|
card.classList.add('border-base-200', 'bg-base-100');
|
|
433
182
|
}
|
|
434
183
|
});
|
|
435
184
|
updateLaunchLabel();
|
|
436
185
|
}
|
|
437
186
|
function setSelectedMode(mode) {
|
|
438
187
|
selectedMode = mode;
|
|
439
188
|
modeCards.forEach(card => {
|
|
440
189
|
const isMatch = card.dataset.mode === mode;
|
|
441
190
|
const radio = card.querySelector('input[type="radio"]');
|
|
442
191
|
if (radio) radio.checked = isMatch;
|
|
443
192
|
if (isMatch) {
|
|
444
193
|
card.classList.add('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
445
194
|
card.classList.remove('border-base-200', 'bg-base-100');
|
|
446
195
|
} else {
|
|
447
196
|
card.classList.remove('border-primary', 'bg-primary/[0.04]', 'shadow-sm');
|
|
448
197
|
card.classList.add('border-base-200', 'bg-base-100');
|
|
449
198
|
}
|
|
450
199
|
});
|
|
451
200
|
updateLaunchLabel();
|
|
452
201
|
}
|
|
453
202
|
tableCards.forEach(card => {
|
|
454
203
|
card.addEventListener('click', (e) => {
|
|
455
204
|
if (e.target.closest('.quick-seed-btn')) return;
|
|
456
205
|
const table = card.dataset.table;
|
|
457
206
|
if (table) setSelectedTable(table);
|
|
458
207
|
});
|
|
459
208
|
});
|
|
460
209
|
modeCards.forEach(card => {
|
|
461
210
|
card.addEventListener('click', () => {
|
|
462
211
|
const mode = card.dataset.mode;
|
|
463
212
|
if (mode) setSelectedMode(mode);
|
|
464
213
|
});
|
|
465
214
|
});
|
|
466
215
|
// Direct quick-seed buttons
|
|
467
216
|
document.querySelectorAll('.quick-seed-btn').forEach(btn => {
|
|
468
217
|
btn.addEventListener('click', (e) => {
|
|
469
218
|
e.stopPropagation();
|
|
470
219
|
const table = btn.dataset.table;
|
|
471
220
|
const mode = btn.dataset.mode || 'single';
|
|
472
221
|
if (table) {
|
|
473
222
|
window.location.href = `${BASE}/seed/${encodeURIComponent(DB_ID)}/${encodeURIComponent(table)}?mode=${encodeURIComponent(mode)}`;
|
|
474
223
|
}
|
|
475
224
|
});
|
|
476
225
|
});
|
|
477
226
|
// Launch button
|
|
478
227
|
if (launchBtn) {
|
|
479
228
|
launchBtn.addEventListener('click', () => {
|
|
480
229
|
if (!selectedTable) return;
|
|
481
230
|
window.location.href = `${BASE}/seed/${encodeURIComponent(DB_ID)}/${encodeURIComponent(selectedTable)}?mode=${encodeURIComponent(selectedMode)}`;
|
|
482
231
|
});
|
|
483
232
|
}
|
|
484
233
|
// Real-time table search filter
|
|
485
234
|
if (searchInput) {
|
|
486
235
|
searchInput.addEventListener('input', () => {
|
|
487
236
|
const q = searchInput.value.trim().toLowerCase();
|
|
488
237
|
tableCards.forEach(card => {
|
|
489
238
|
const name = (card.dataset.table || '').toLowerCase();
|
|
490
239
|
if (!q || name.includes(q)) {
|
|
491
240
|
card.classList.remove('hidden');
|
|
492
241
|
} else {
|
|
493
242
|
card.classList.add('hidden');
|
|
494
243
|
}
|
|
495
244
|
});
|
|
496
245
|
});
|
|
497
246
|
}
|
|
498
247
|
updateLaunchLabel();
|