admindb 2.1.1 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -12
- package/dist/app.js +230 -1
- package/dist/auth/config.js +121 -1
- package/dist/auth/crypto.js +108 -1
- package/dist/auth/index.js +21 -1
- package/dist/auth/middleware.js +85 -1
- package/dist/auth/routes.js +70 -1
- package/dist/auth/types.js +7 -1
- package/dist/cli/args.js +320 -1
- package/dist/cli/config.js +128 -1
- package/dist/cli/index.js +20 -1
- package/dist/cli/runner.js +211 -1
- package/dist/cli.js +4 -1
- package/dist/data/chain.d.ts +1 -0
- package/dist/data/chain.js +707 -0
- package/dist/data/datasets.js +129 -1
- package/dist/data/detector.d.ts +1 -1
- package/dist/data/detector.js +511 -1
- package/dist/data/engine.d.ts +1 -1
- package/dist/data/engine.js +245 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +22 -1
- package/dist/data/strategies.d.ts +1 -1
- package/dist/data/strategies.js +339 -1
- package/dist/data/types.d.ts +1 -1
- package/dist/data/types.js +5 -1
- package/dist/db/database.d.ts +1 -1
- package/dist/db/database.js +477 -1
- package/dist/db/export.d.ts +1 -1
- package/dist/db/export.js +90 -1
- package/dist/db/filters.js +142 -1
- package/dist/db/index.js +24 -1
- package/dist/db/introspection.js +167 -1
- package/dist/db/manager.js +351 -1
- package/dist/db/migrations.js +107 -1
- package/dist/db/postgres.d.ts +1 -1
- package/dist/db/postgres.js +735 -1
- package/dist/db/types.d.ts +1 -1
- package/dist/db/types.js +6 -1
- package/dist/index.js +52 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/api.js +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/common.js +1 -0
- package/dist/public/js/databases.js +1 -1
- package/dist/public/js/designer.js +1 -1
- package/dist/public/js/forms.js +1 -1
- package/dist/public/js/home.js +1 -0
- package/dist/public/js/inspector.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/schema.js +1 -1
- package/dist/public/js/seed.js +1 -1
- package/dist/routes/api/erd.d.ts +1 -0
- package/dist/routes/api/erd.js +50 -0
- package/dist/routes/api/helpers.d.ts +1 -1
- package/dist/routes/api/helpers.js +163 -1
- package/dist/routes/api/import-export.js +83 -1
- package/dist/routes/api/index.js +48 -1
- package/dist/routes/api/query.js +78 -1
- package/dist/routes/api/rows.js +362 -1
- package/dist/routes/api/seed.js +153 -1
- package/dist/routes/api/tables.js +231 -1
- package/dist/routes/databases.js +228 -1
- package/dist/routes/index.js +19 -1
- package/dist/routes/pages.js +397 -1
- package/dist/serverless.js +174 -1
- package/dist/sql/classifier.js +24 -1
- package/dist/sql/error-analyzer.d.ts +1 -0
- package/dist/sql/error-analyzer.js +550 -0
- package/dist/sql/generator.js +319 -1
- package/dist/sql/index.js +18 -1
- package/dist/types/api.js +2 -1
- package/dist/utils/colors.js +54 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +225 -1
- package/dist/utils/csv.js +67 -1
- package/dist/utils/datatype.js +181 -1
- package/dist/utils/icons.js +81 -1
- package/dist/utils/index.js +20 -1
- package/dist/utils/logger.js +36 -1
- package/dist/views/layouts/main.hbs +14 -1
- package/dist/views/pages/erd.hbs +1241 -0
- package/dist/views/pages/home.hbs +98 -2
- package/dist/views/pages/info.hbs +107 -0
- package/dist/views/pages/query.hbs +54 -12
- package/dist/views/pages/seed.hbs +435 -171
- package/dist/views/partials/sidebar.hbs +12 -0
- package/docs/API.md +6 -1
- package/docs/EXAMPLES.md +3 -0
- package/package.json +5 -4
- package/dist/public/js/icons.js +0 -1
|
@@ -1,201 +1,465 @@
|
|
|
1
|
-
<div class="space-y-
|
|
2
|
-
<div class="flex
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<div>
|
|
8
|
-
<div class="
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
<div class="max-w-5xl mx-auto space-y-8 pb-24">
|
|
2
|
+
<div class="flex items-center gap-4">
|
|
3
|
+
<a href="{{basePath}}/tables/{{table}}" class="btn btn-circle btn-ghost bg-base-200 hover:bg-base-300 transition-colors">
|
|
4
|
+
{{{icon "arrowLeft" class="h-5 w-5"}}}
|
|
5
|
+
</a>
|
|
6
|
+
<div class="flex-1 min-w-0">
|
|
7
|
+
<div class="flex items-center gap-3 flex-wrap">
|
|
8
|
+
<div class="p-2 rounded-xl bg-gradient-to-br from-primary/20 to-secondary/20 text-primary shadow-soft">
|
|
9
|
+
{{{icon "seed" class="h-6 w-6"}}}
|
|
10
|
+
</div>
|
|
11
|
+
<div>
|
|
12
|
+
<h1 class="text-2xl font-bold font-mono tracking-tight">Seed Generator <span class="text-primary">{{table}}</span></h1>
|
|
13
|
+
<p class="text-sm text-base-content/50 mt-0.5">Generate realistic mock data in three easy steps.</p>
|
|
14
|
+
</div>
|
|
14
15
|
</div>
|
|
15
16
|
</div>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{{{icon "chevronDown" class="h-3.5 w-3.5 opacity-60"}}}
|
|
22
|
-
</button>
|
|
23
|
-
<ul tabindex="0" class="dropdown-content z-20 menu p-2 shadow-lg bg-base-100 rounded-xl w-56 border border-base-200 text-xs">
|
|
24
|
-
<li><button type="button" id="preset-realistic" class="py-2">✨ Realistic Mock Data</button></li>
|
|
25
|
-
<li><button type="button" id="preset-minimal" class="py-2">⚡ Minimal (Required Only)</button></li>
|
|
26
|
-
<li><button type="button" id="preset-sparse" class="py-2">🎲 Sparse (30% Nullables)</button></li>
|
|
27
|
-
<li><button type="button" id="preset-numbered" class="py-2">🔢 Sequential & Numbered</button></li>
|
|
28
|
-
<li class="border-t border-base-200 my-1"></li>
|
|
29
|
-
<li><button type="button" id="seed-export-config" class="py-2">💾 Export Plan as JSON</button></li>
|
|
30
|
-
<li><button type="button" id="seed-import-config" class="py-2">📥 Import Plan JSON…</button></li>
|
|
31
|
-
</ul>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="app-card p-4">
|
|
19
|
+
<div class="flex items-center justify-between relative">
|
|
20
|
+
<div class="absolute left-0 right-0 top-1/2 -translate-y-1/2 h-0.5 bg-base-300 mx-16 z-0">
|
|
21
|
+
<div id="wizard-progress-bar" class="h-full bg-gradient-to-r from-primary to-secondary transition-all duration-500 ease-out" style="width: 0%"></div>
|
|
32
22
|
</div>
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
<div id="step-nav-1" class="seed-step relative z-10 flex flex-col items-center gap-2 cursor-pointer group">
|
|
24
|
+
<div class="seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-primary border-primary text-primary-content shadow-[0_0_12px_rgba(109,93,246,0.4)]">
|
|
25
|
+
<span class="seed-step-num">1</span>
|
|
26
|
+
<span class="seed-step-check hidden">{{{icon "check" class="h-4 w-4"}}}</span>
|
|
27
|
+
</div>
|
|
28
|
+
<span class="text-xs font-semibold text-primary">Choose Mode</span>
|
|
29
|
+
</div>
|
|
30
|
+
<div id="step-nav-2" class="seed-step relative z-10 flex flex-col items-center gap-2 cursor-pointer group">
|
|
31
|
+
<div class="seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-base-200 border-base-300 text-base-content/40">
|
|
32
|
+
<span class="seed-step-num">2</span>
|
|
33
|
+
<span class="seed-step-check hidden">{{{icon "check" class="h-4 w-4"}}}</span>
|
|
34
|
+
</div>
|
|
35
|
+
<span class="text-xs font-semibold text-base-content/40">Configure</span>
|
|
36
|
+
</div>
|
|
37
|
+
<div id="step-nav-3" class="seed-step relative z-10 flex flex-col items-center gap-2 cursor-pointer group">
|
|
38
|
+
<div class="seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-base-200 border-base-300 text-base-content/40">
|
|
39
|
+
<span class="seed-step-num">3</span>
|
|
40
|
+
<span class="seed-step-check hidden">{{{icon "check" class="h-4 w-4"}}}</span>
|
|
41
|
+
</div>
|
|
42
|
+
<span class="text-xs font-semibold text-base-content/40">Preview & Run</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div id="step-content-1" class="space-y-6">
|
|
47
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
48
|
+
<button id="btn-select-single" class="seed-mode-card app-card p-6 text-left group transition-all duration-200 border-2 border-transparent hover:border-primary/40 hover:-translate-y-0.5">
|
|
49
|
+
<div class="flex items-start gap-4 mb-5">
|
|
50
|
+
<div class="relative shrink-0">
|
|
51
|
+
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-primary/20 to-primary/5 flex items-center justify-center text-primary group-hover:scale-110 transition-transform duration-200 shadow-soft">
|
|
52
|
+
{{{icon "table" class="h-7 w-7"}}}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="min-w-0">
|
|
56
|
+
<h3 class="text-lg font-bold leading-tight">Single Table</h3>
|
|
57
|
+
<p class="text-xs text-base-content/50 mt-1">Generate data for this table only</p>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="ml-auto shrink-0 w-5 h-5 rounded-full border-2 border-base-300 transition-all duration-200 seed-mode-radio flex items-center justify-center">
|
|
60
|
+
<div class="w-2.5 h-2.5 rounded-full bg-primary scale-0 transition-transform duration-200 seed-mode-dot"></div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<p class="text-sm text-base-content/60 leading-relaxed mb-5">
|
|
64
|
+
Manually control mock values for each column with full strategy control.
|
|
65
|
+
</p>
|
|
66
|
+
<ul class="space-y-1.5">
|
|
67
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
68
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
69
|
+
Manual column strategies (fixed, list, pattern, etc.)
|
|
70
|
+
</li>
|
|
71
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
72
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
73
|
+
Live sample value preview per column
|
|
74
|
+
</li>
|
|
75
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
76
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
77
|
+
Up to 5,000 rows in one pass
|
|
78
|
+
</li>
|
|
79
|
+
</ul>
|
|
80
|
+
</button>
|
|
81
|
+
<button id="btn-select-chain" class="seed-mode-card app-card p-6 text-left group transition-all duration-200 border-2 border-transparent hover:border-secondary/40 hover:-translate-y-0.5">
|
|
82
|
+
<div class="flex items-start gap-4 mb-5">
|
|
83
|
+
<div class="relative shrink-0">
|
|
84
|
+
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-secondary/20 to-secondary/5 flex items-center justify-center text-secondary group-hover:scale-110 transition-transform duration-200 shadow-soft">
|
|
85
|
+
{{{icon "diagram" class="h-7 w-7"}}}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="min-w-0">
|
|
89
|
+
<h3 class="text-lg font-bold leading-tight">ER Relational Chain</h3>
|
|
90
|
+
<p class="text-xs text-base-content/50 mt-1">Synchronized relational seeding</p>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="ml-auto shrink-0 w-5 h-5 rounded-full border-2 border-base-300 transition-all duration-200 seed-mode-radio flex items-center justify-center">
|
|
93
|
+
<div class="w-2.5 h-2.5 rounded-full bg-secondary scale-0 transition-transform duration-200 seed-mode-dot"></div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<p class="text-sm text-base-content/60 leading-relaxed mb-5">
|
|
97
|
+
Builds a dependency graph and inserts parent records before children to prevent FK errors.
|
|
98
|
+
</p>
|
|
99
|
+
<ul class="space-y-1.5">
|
|
100
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
101
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
102
|
+
Auto FK dependency resolution
|
|
103
|
+
</li>
|
|
104
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
105
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
106
|
+
Topologically-ordered execution pipeline
|
|
107
|
+
</li>
|
|
108
|
+
<li class="flex items-center gap-2 text-xs text-base-content/60">
|
|
109
|
+
<span class="w-4 h-4 rounded-full bg-success/15 text-success flex items-center justify-center shrink-0">{{{icon "check" class="h-2.5 w-2.5"}}}</span>
|
|
110
|
+
Configurable per-table row counts
|
|
111
|
+
</li>
|
|
112
|
+
</ul>
|
|
113
|
+
</button>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="flex justify-end pt-2">
|
|
116
|
+
<button id="btn-next-1" class="btn btn-primary gap-2 px-8 transition-all duration-200" disabled>
|
|
117
|
+
Next Step
|
|
118
|
+
{{{icon "arrowRight" class="h-4 w-4"}}}
|
|
36
119
|
</button>
|
|
37
|
-
{{#unless readonly}}
|
|
38
|
-
<button id="seed-insert" type="button" class="btn btn-primary btn-sm gap-1.5 shadow-sm">
|
|
39
|
-
{{{icon "plus" class="h-4 w-4"}}}
|
|
40
|
-
Insert Rows
|
|
41
|
-
</button>
|
|
42
|
-
{{else}}
|
|
43
|
-
<span class="inline-flex items-center gap-1.5 text-xs font-medium text-warning bg-warning/10 px-2.5 py-1.5 rounded-lg">
|
|
44
|
-
{{{icon "lock" class="h-4 w-4"}}}
|
|
45
|
-
Read-only database
|
|
46
|
-
</span>
|
|
47
|
-
{{/unless}}
|
|
48
120
|
</div>
|
|
49
121
|
</div>
|
|
50
|
-
<div
|
|
51
|
-
<div class="
|
|
52
|
-
<div class="
|
|
53
|
-
<
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
122
|
+
<div id="step-content-2" class="hidden space-y-6">
|
|
123
|
+
<div id="config-single" class="hidden space-y-5">
|
|
124
|
+
<div class="app-card p-5">
|
|
125
|
+
<div class="flex flex-wrap gap-6 items-end justify-between">
|
|
126
|
+
<div class="flex items-end gap-4">
|
|
127
|
+
<div>
|
|
128
|
+
<label class="block text-xs font-bold uppercase tracking-wider text-base-content/50 mb-2">Rows to Generate</label>
|
|
129
|
+
<div class="flex items-center gap-0">
|
|
130
|
+
<button type="button" id="seed-count-dec" class="btn btn-sm btn-outline rounded-r-none border-r-0 px-3 font-mono text-lg leading-none hover:bg-primary hover:text-primary-content hover:border-primary transition-colors">−</button>
|
|
131
|
+
<input id="seed-count" type="number" value="10" min="1" max="5000"
|
|
132
|
+
class="field-input !rounded-none border-x-0 !py-1.5 font-mono w-24 font-bold text-lg text-center [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" />
|
|
133
|
+
<button type="button" id="seed-count-inc" class="btn btn-sm btn-outline rounded-l-none border-l-0 px-3 font-mono text-lg leading-none hover:bg-primary hover:text-primary-content hover:border-primary transition-colors">+</button>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="flex items-end gap-3">
|
|
138
|
+
<div>
|
|
139
|
+
<span class="block text-xs font-bold uppercase tracking-wider text-base-content/50 mb-2">Quick Presets</span>
|
|
140
|
+
<div class="flex gap-2">
|
|
141
|
+
<button type="button" class="preset-pill btn btn-sm btn-outline rounded-full gap-1.5" id="preset-realistic" data-count="50">
|
|
142
|
+
<span class="w-1.5 h-1.5 rounded-full bg-success"></span>
|
|
143
|
+
Realistic
|
|
144
|
+
</button>
|
|
145
|
+
<button type="button" class="preset-pill btn btn-sm btn-outline rounded-full gap-1.5" id="preset-minimal" data-count="5">
|
|
146
|
+
<span class="w-1.5 h-1.5 rounded-full bg-info"></span>
|
|
147
|
+
Minimal
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
63
151
|
</div>
|
|
64
152
|
</div>
|
|
65
153
|
</div>
|
|
66
|
-
<div class="
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
</span>
|
|
74
|
-
<input id="seed-search" type="text" placeholder="Search column by name or type..." class="field-input pl-9 text-xs" />
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
<div class="lg:col-span-4 flex flex-col justify-end space-y-2">
|
|
78
|
-
{{#unless readonly}}
|
|
79
|
-
<label class="cursor-pointer flex items-center gap-2 text-xs font-medium text-base-content/80 hover:text-base-content transition-colors">
|
|
80
|
-
<input id="seed-truncate" type="checkbox" class="checkbox checkbox-xs checkbox-error rounded" />
|
|
81
|
-
<span class="flex items-center gap-1 text-error/90">
|
|
82
|
-
{{{icon "trash" class="h-3.5 w-3.5"}}}
|
|
83
|
-
Clear table before inserting (DELETE all rows)
|
|
84
|
-
</span>
|
|
85
|
-
</label>
|
|
86
|
-
{{/unless}}
|
|
87
|
-
<p class="text-[11px] text-base-content/45 leading-tight">Rows are inserted in a single atomic transaction. Any constraint failure safely rolls back.</p>
|
|
154
|
+
<div class="app-card p-6">
|
|
155
|
+
<div class="flex items-center justify-between mb-5">
|
|
156
|
+
<h3 class="text-base font-bold">Column Strategies</h3>
|
|
157
|
+
<span class="badge badge-ghost text-xs">Configure per column</span>
|
|
158
|
+
</div>
|
|
159
|
+
<div id="seed-columns" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
160
|
+
</div>
|
|
88
161
|
</div>
|
|
89
162
|
</div>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
</
|
|
163
|
+
<div id="config-chain" class="hidden space-y-5">
|
|
164
|
+
<div class="app-card p-5">
|
|
165
|
+
<div class="flex flex-wrap gap-6 items-end justify-between">
|
|
166
|
+
<div>
|
|
167
|
+
<label class="block text-xs font-bold uppercase tracking-wider text-base-content/50 mb-2">Scope</label>
|
|
168
|
+
<select id="chain-scope" class="field-select !py-1.5 w-64 font-medium">
|
|
169
|
+
<option value="chain">Full Connected Chain</option>
|
|
170
|
+
<option value="ancestors">Parents Only</option>
|
|
171
|
+
<option value="descendants">Children Only</option>
|
|
172
|
+
</select>
|
|
173
|
+
</div>
|
|
174
|
+
<div>
|
|
175
|
+
<span class="block text-xs font-bold uppercase tracking-wider text-base-content/50 mb-2">Scale Multiplier</span>
|
|
176
|
+
<div class="join shadow-soft">
|
|
177
|
+
<button type="button" class="chain-scale-btn btn btn-sm join-item font-mono" data-scale="0.5">0.5×</button>
|
|
178
|
+
<button type="button" class="chain-scale-btn btn btn-sm join-item btn-neutral font-mono" data-scale="1">1×</button>
|
|
179
|
+
<button type="button" class="chain-scale-btn btn btn-sm join-item font-mono" data-scale="2">2×</button>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
<div class="app-card p-6">
|
|
185
|
+
<div class="flex items-center justify-between mb-5 pb-4 border-b border-base-200">
|
|
186
|
+
<div>
|
|
187
|
+
<h3 class="text-base font-bold">Execution Pipeline</h3>
|
|
188
|
+
<p class="text-xs text-base-content/50 mt-0.5">Tables are inserted in topological order</p>
|
|
189
|
+
</div>
|
|
190
|
+
<div class="flex items-center gap-2">
|
|
191
|
+
<div class="w-2 h-2 rounded-full bg-success animate-pulse"></div>
|
|
192
|
+
<span id="chain-summary-badge" class="badge badge-primary font-bold">0 Tables</span>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<div id="chain-pipeline-container" class="space-y-3">
|
|
196
|
+
</div>
|
|
110
197
|
</div>
|
|
111
198
|
</div>
|
|
112
|
-
<div
|
|
113
|
-
|
|
114
|
-
|
|
199
|
+
<div class="flex justify-between pt-2">
|
|
200
|
+
<button id="btn-prev-2" type="button" class="btn btn-ghost gap-2 px-6">
|
|
201
|
+
{{{icon "arrowLeft" class="h-4 w-4"}}}
|
|
202
|
+
Back
|
|
203
|
+
</button>
|
|
204
|
+
<button id="btn-next-2" type="button" class="btn btn-primary gap-2 px-8">
|
|
205
|
+
Preview Data
|
|
206
|
+
{{{icon "arrowRight" class="h-4 w-4"}}}
|
|
207
|
+
</button>
|
|
115
208
|
</div>
|
|
116
209
|
</div>
|
|
117
|
-
<div id="
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<
|
|
123
|
-
{{{icon "table" class="h-3.5 w-3.5"}}}
|
|
124
|
-
Table Preview
|
|
125
|
-
</button>
|
|
126
|
-
<button id="tab-sql-view" type="button" class="tab tab-sm font-medium gap-1.5">
|
|
127
|
-
{{{icon "sql" class="h-3.5 w-3.5"}}}
|
|
128
|
-
SQL Statements
|
|
129
|
-
</button>
|
|
210
|
+
<div id="step-content-3" class="hidden space-y-5">
|
|
211
|
+
<div class="app-card overflow-hidden">
|
|
212
|
+
<div class="flex items-center justify-between px-6 pt-5 pb-4 border-b border-base-200">
|
|
213
|
+
<div>
|
|
214
|
+
<h3 class="text-base font-bold">Data Preview</h3>
|
|
215
|
+
<p class="text-xs text-base-content/50 mt-0.5">Sample of what will be inserted</p>
|
|
130
216
|
</div>
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<button id="seed-export-csv" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
|
|
135
|
-
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
136
|
-
Export CSV
|
|
137
|
-
</button>
|
|
138
|
-
<button id="seed-export-json" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
|
|
139
|
-
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
140
|
-
Export JSON
|
|
141
|
-
</button>
|
|
142
|
-
<button id="seed-copy-sql" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
|
|
143
|
-
{{{icon "copy" class="h-3.5 w-3.5"}}}
|
|
144
|
-
Copy SQL
|
|
145
|
-
</button>
|
|
146
|
-
<button id="seed-download-sql" type="button" class="btn btn-ghost btn-xs gap-1 text-base-content/70 hover:text-primary">
|
|
147
|
-
{{{icon "export" class="h-3.5 w-3.5"}}}
|
|
148
|
-
Download .sql
|
|
217
|
+
<button id="seed-refresh-preview" type="button" class="btn btn-sm btn-ghost gap-1.5 hover:bg-primary/10 hover:text-primary transition-colors">
|
|
218
|
+
{{{icon "refresh" class="h-4 w-4"}}}
|
|
219
|
+
Regenerate
|
|
149
220
|
</button>
|
|
150
221
|
</div>
|
|
222
|
+
<div class="w-full overflow-x-auto border-b border-base-200 bg-base-200/30">
|
|
223
|
+
<div id="seed-chain-table-tabs" class="tabs tabs-bordered flex-nowrap w-max min-w-full hidden px-4"></div>
|
|
224
|
+
</div>
|
|
225
|
+
<div class="px-4 pt-3 pb-1 flex items-center justify-between">
|
|
226
|
+
<span id="seed-row-count-badge" class="text-xs text-base-content/40 font-mono"></span>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="overflow-x-auto max-h-[460px] shadow-inner">
|
|
229
|
+
<table class="table table-zebra table-pin-rows table-sm w-full">
|
|
230
|
+
<thead id="seed-preview-thead" class="bg-base-200/80 text-[10px] uppercase tracking-widest font-bold text-base-content/60 backdrop-blur sticky top-0 z-10"></thead>
|
|
231
|
+
<tbody id="seed-preview-tbody" class="font-mono text-[11px] leading-relaxed">
|
|
232
|
+
<tr>
|
|
233
|
+
<td colspan="100" class="text-center py-16 opacity-40">
|
|
234
|
+
<div class="flex flex-col items-center gap-3">
|
|
235
|
+
<span class="loading loading-spinner loading-md"></span>
|
|
236
|
+
<span class="text-xs">Generating preview…</span>
|
|
237
|
+
</div>
|
|
238
|
+
</td>
|
|
239
|
+
</tr>
|
|
240
|
+
</tbody>
|
|
241
|
+
</table>
|
|
242
|
+
</div>
|
|
151
243
|
</div>
|
|
152
|
-
<div id="seed-
|
|
153
|
-
<
|
|
154
|
-
<
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<
|
|
244
|
+
<div id="seed-execute-bar" class="app-card overflow-hidden transition-all duration-300">
|
|
245
|
+
<div id="seed-truncate-banner" class="hidden px-6 py-3 bg-error/10 border-b border-error/20 flex items-center gap-3">
|
|
246
|
+
<span class="text-error shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
|
|
247
|
+
<p class="text-xs font-semibold text-error/80">
|
|
248
|
+
<strong>Destructive action:</strong> Existing rows will be permanently deleted before new data is inserted.
|
|
249
|
+
</p>
|
|
250
|
+
</div>
|
|
251
|
+
<div class="flex flex-wrap items-center justify-between gap-4 p-5">
|
|
252
|
+
<button id="btn-prev-3" type="button" class="btn btn-ghost gap-2 px-5">
|
|
253
|
+
{{{icon "arrowLeft" class="h-4 w-4"}}}
|
|
254
|
+
Back to Config
|
|
255
|
+
</button>
|
|
256
|
+
<div class="flex items-center gap-5">
|
|
257
|
+
<label class="cursor-pointer flex items-center gap-2.5 group select-none" for="seed-truncate">
|
|
258
|
+
<input id="seed-truncate" type="checkbox" class="checkbox checkbox-error checkbox-sm" />
|
|
259
|
+
<span class="text-sm font-semibold text-base-content/70 group-hover:text-error transition-colors">
|
|
260
|
+
Clear tables first
|
|
261
|
+
</span>
|
|
262
|
+
</label>
|
|
263
|
+
<button id="seed-insert" type="button"
|
|
264
|
+
class="btn btn-primary btn-lg gap-2 px-10 shadow-lg hover:shadow-primary/30 hover:shadow-xl transition-all duration-200 hover:scale-[1.02] active:scale-100">
|
|
265
|
+
{{{icon "play" class="h-5 w-5"}}}
|
|
266
|
+
Execute Seed
|
|
267
|
+
</button>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
160
270
|
</div>
|
|
271
|
+
<div id="seed-feedback" class="hidden"></div>
|
|
161
272
|
</div>
|
|
162
273
|
</div>
|
|
163
|
-
<dialog id="seed-config-dialog" class="modal">
|
|
164
|
-
<div class="modal-box app-card max-w-lg">
|
|
165
|
-
<h3 id="seed-config-dialog-title" class="text-base font-bold">Seed Plan Configuration</h3>
|
|
166
|
-
<p class="mt-1 text-xs text-base-content/60">Export or paste a JSON configuration for column generator settings.</p>
|
|
167
|
-
<textarea id="seed-config-textarea" rows="12" class="field-input mt-3 w-full font-mono text-xs" spellcheck="false"></textarea>
|
|
168
|
-
<div class="mt-4 flex justify-end gap-2">
|
|
169
|
-
<button id="seed-config-dialog-cancel" type="button" class="btn btn-ghost btn-sm">Close</button>
|
|
170
|
-
<button id="seed-config-dialog-apply" type="button" class="btn btn-primary btn-sm">Apply Configuration</button>
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
<form method="dialog" class="modal-backdrop">
|
|
174
|
-
<button>close</button>
|
|
175
|
-
</form>
|
|
176
|
-
</dialog>
|
|
177
274
|
<dialog id="seed-truncate-dialog" class="modal">
|
|
178
|
-
<div class="modal-box
|
|
179
|
-
<div class="
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<
|
|
185
|
-
|
|
275
|
+
<div class="modal-box p-0 overflow-hidden max-w-md">
|
|
276
|
+
<div class="px-6 pt-6 pb-4 bg-error/5 border-b border-error/15">
|
|
277
|
+
<div class="flex items-center gap-3">
|
|
278
|
+
<div class="w-10 h-10 rounded-xl bg-error/15 flex items-center justify-center text-error shrink-0">
|
|
279
|
+
{{{icon "warning" class="h-5 w-5"}}}
|
|
280
|
+
</div>
|
|
281
|
+
<div>
|
|
282
|
+
<h3 class="font-bold text-lg text-error leading-tight">Confirm Destructive Action</h3>
|
|
283
|
+
<p class="text-xs text-base-content/50 mt-0.5">This operation cannot be undone</p>
|
|
284
|
+
</div>
|
|
186
285
|
</div>
|
|
187
286
|
</div>
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<
|
|
287
|
+
<div class="px-6 py-5 space-y-4">
|
|
288
|
+
<p class="text-sm text-base-content/80 leading-relaxed">
|
|
289
|
+
You have selected to <strong class="text-error">clear the tables</strong> before generating mock data.
|
|
290
|
+
This will <strong>permanently delete all existing rows</strong> in the affected tables.
|
|
291
|
+
</p>
|
|
292
|
+
<div class="rounded-xl bg-base-200 border border-base-300 p-4">
|
|
293
|
+
<p class="text-xs font-bold uppercase tracking-wider text-base-content/40 mb-2">What will happen</p>
|
|
294
|
+
<ul class="space-y-1.5">
|
|
295
|
+
<li class="flex items-center gap-2 text-xs text-base-content/70">
|
|
296
|
+
<span class="text-error">{{{icon "warning" class="h-3.5 w-3.5"}}}</span>
|
|
297
|
+
All existing rows will be truncated
|
|
298
|
+
</li>
|
|
299
|
+
<li class="flex items-center gap-2 text-xs text-base-content/70">
|
|
300
|
+
<span class="text-primary">{{{icon "play" class="h-3.5 w-3.5"}}}</span>
|
|
301
|
+
New mock data will be inserted
|
|
302
|
+
</li>
|
|
303
|
+
<li class="flex items-center gap-2 text-xs text-base-content/70">
|
|
304
|
+
<span class="text-error">{{{icon "warning" class="h-3.5 w-3.5"}}}</span>
|
|
305
|
+
This action is irreversible
|
|
306
|
+
</li>
|
|
307
|
+
</ul>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
<div class="px-6 pb-6 flex items-center justify-end gap-3">
|
|
311
|
+
<button type="button" class="btn btn-ghost" id="seed-truncate-cancel">Cancel</button>
|
|
312
|
+
<button type="button" class="btn btn-error gap-2" id="seed-truncate-confirm">
|
|
313
|
+
{{{icon "warning" class="h-4 w-4"}}}
|
|
314
|
+
Yes, Delete & Seed
|
|
315
|
+
</button>
|
|
194
316
|
</div>
|
|
195
317
|
</div>
|
|
196
|
-
<form method="dialog" class="modal-backdrop">
|
|
197
|
-
<button>close</button>
|
|
198
|
-
</form>
|
|
318
|
+
<form method="dialog" class="modal-backdrop bg-base-300/80 backdrop-blur-sm"><button>close</button></form>
|
|
199
319
|
</dialog>
|
|
200
320
|
<script id="seed-config" type="application/json">{{{json seedConfig}}}</script>
|
|
201
321
|
<script src="{{basePath}}/js/seed.js" defer></script>
|
|
322
|
+
<script>
|
|
323
|
+
(function () {
|
|
324
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
325
|
+
// +/- count buttons
|
|
326
|
+
var countInput = document.getElementById('seed-count');
|
|
327
|
+
var decBtn = document.getElementById('seed-count-dec');
|
|
328
|
+
var incBtn = document.getElementById('seed-count-inc');
|
|
329
|
+
if (decBtn && incBtn && countInput) {
|
|
330
|
+
decBtn.addEventListener('click', function () {
|
|
331
|
+
var v = Math.max(1, (parseInt(countInput.value, 10) || 10) - 1);
|
|
332
|
+
countInput.value = v;
|
|
333
|
+
countInput.dispatchEvent(new Event('input'));
|
|
334
|
+
});
|
|
335
|
+
incBtn.addEventListener('click', function () {
|
|
336
|
+
var v = Math.min(5000, (parseInt(countInput.value, 10) || 10) + 1);
|
|
337
|
+
countInput.value = v;
|
|
338
|
+
countInput.dispatchEvent(new Event('input'));
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
// Preset pills: sync count
|
|
342
|
+
document.querySelectorAll('.preset-pill').forEach(function (pill) {
|
|
343
|
+
pill.addEventListener('click', function () {
|
|
344
|
+
document.querySelectorAll('.preset-pill').forEach(function (p) {
|
|
345
|
+
p.classList.remove('btn-primary', 'btn-secondary');
|
|
346
|
+
p.classList.add('btn-outline');
|
|
347
|
+
});
|
|
348
|
+
pill.classList.remove('btn-outline');
|
|
349
|
+
pill.classList.add('btn-primary');
|
|
350
|
+
if (countInput && pill.dataset.count) {
|
|
351
|
+
countInput.value = pill.dataset.count;
|
|
352
|
+
countInput.dispatchEvent(new Event('input'));
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
// Truncate checkbox → warning banner toggle
|
|
357
|
+
var truncateChk = document.getElementById('seed-truncate');
|
|
358
|
+
var truncateBanner = document.getElementById('seed-truncate-banner');
|
|
359
|
+
if (truncateChk && truncateBanner) {
|
|
360
|
+
truncateChk.addEventListener('change', function () {
|
|
361
|
+
if (truncateChk.checked) {
|
|
362
|
+
truncateBanner.classList.remove('hidden');
|
|
363
|
+
truncateBanner.classList.add('flex');
|
|
364
|
+
} else {
|
|
365
|
+
truncateBanner.classList.add('hidden');
|
|
366
|
+
truncateBanner.classList.remove('flex');
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
// Wizard progress bar + step label color sync (mirrors seed.js goToStep)
|
|
371
|
+
var progressBar = document.getElementById('wizard-progress-bar');
|
|
372
|
+
var stepNavEls = [
|
|
373
|
+
document.getElementById('step-nav-1'),
|
|
374
|
+
document.getElementById('step-nav-2'),
|
|
375
|
+
document.getElementById('step-nav-3')
|
|
376
|
+
];
|
|
377
|
+
function syncStepStyles(activeStep) {
|
|
378
|
+
var pct = { 1: '0%', 2: '50%', 3: '100%' };
|
|
379
|
+
if (progressBar) progressBar.style.width = pct[activeStep] || '0%';
|
|
380
|
+
stepNavEls.forEach(function (el, i) {
|
|
381
|
+
if (!el) return;
|
|
382
|
+
var stepNum = i + 1;
|
|
383
|
+
var circle = el.querySelector('.seed-step-circle');
|
|
384
|
+
var numSpan = el.querySelector('.seed-step-num');
|
|
385
|
+
var checkSpan = el.querySelector('.seed-step-check');
|
|
386
|
+
var label = el.querySelector('span:last-child');
|
|
387
|
+
if (stepNum < activeStep) {
|
|
388
|
+
// Completed
|
|
389
|
+
circle.className = 'seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-success border-success text-success-content';
|
|
390
|
+
if (numSpan) numSpan.classList.add('hidden');
|
|
391
|
+
if (checkSpan) checkSpan.classList.remove('hidden');
|
|
392
|
+
if (label) label.className = 'text-xs font-semibold text-success';
|
|
393
|
+
} else if (stepNum === activeStep) {
|
|
394
|
+
// Active
|
|
395
|
+
circle.className = 'seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-primary border-primary text-primary-content shadow-[0_0_12px_rgba(109,93,246,0.4)]';
|
|
396
|
+
if (numSpan) numSpan.classList.remove('hidden');
|
|
397
|
+
if (checkSpan) checkSpan.classList.add('hidden');
|
|
398
|
+
if (label) label.className = 'text-xs font-semibold text-primary';
|
|
399
|
+
} else {
|
|
400
|
+
// Inactive
|
|
401
|
+
circle.className = 'seed-step-circle w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300 bg-base-200 border-base-300 text-base-content/40';
|
|
402
|
+
if (numSpan) numSpan.classList.remove('hidden');
|
|
403
|
+
if (checkSpan) checkSpan.classList.add('hidden');
|
|
404
|
+
if (label) label.className = 'text-xs font-semibold text-base-content/40';
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
// Patch seed.js goToStep to also sync our UI
|
|
409
|
+
var origGoToStep = window._seedGoToStep;
|
|
410
|
+
// We'll observe mutation / use a MutationObserver on step content visibility
|
|
411
|
+
var observer = new MutationObserver(function () {
|
|
412
|
+
var contents = [
|
|
413
|
+
document.getElementById('step-content-1'),
|
|
414
|
+
document.getElementById('step-content-2'),
|
|
415
|
+
document.getElementById('step-content-3')
|
|
416
|
+
];
|
|
417
|
+
for (var i = 0; i < contents.length; i++) {
|
|
418
|
+
if (contents[i] && !contents[i].classList.contains('hidden')) {
|
|
419
|
+
syncStepStyles(i + 1);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
['step-content-1', 'step-content-2', 'step-content-3'].forEach(function (id) {
|
|
425
|
+
var el = document.getElementById(id);
|
|
426
|
+
if (el) observer.observe(el, { attributes: true, attributeFilter: ['class'] });
|
|
427
|
+
});
|
|
428
|
+
// Initial sync
|
|
429
|
+
syncStepStyles(1);
|
|
430
|
+
// Mode card radio dot sync (complement seed.js selectMode)
|
|
431
|
+
var btnSingle = document.getElementById('btn-select-single');
|
|
432
|
+
var btnChain = document.getElementById('btn-select-chain');
|
|
433
|
+
function syncModeCards(selected) {
|
|
434
|
+
[btnSingle, btnChain].forEach(function (btn) {
|
|
435
|
+
if (!btn) return;
|
|
436
|
+
var radio = btn.querySelector('.seed-mode-radio');
|
|
437
|
+
var dot = btn.querySelector('.seed-mode-dot');
|
|
438
|
+
var isSelected = btn === selected;
|
|
439
|
+
if (radio) radio.classList.toggle('border-primary', isSelected && btn === btnSingle);
|
|
440
|
+
if (radio) radio.classList.toggle('border-secondary', isSelected && btn === btnChain);
|
|
441
|
+
if (radio) radio.classList.toggle('border-base-300', !isSelected);
|
|
442
|
+
if (dot) dot.classList.toggle('scale-100', isSelected);
|
|
443
|
+
if (dot) dot.classList.toggle('scale-0', !isSelected);
|
|
444
|
+
btn.classList.toggle('seed-mode-card--selected-single', isSelected && btn === btnSingle);
|
|
445
|
+
btn.classList.toggle('seed-mode-card--selected-chain', isSelected && btn === btnChain);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
if (btnSingle) btnSingle.addEventListener('click', function () { syncModeCards(btnSingle); });
|
|
449
|
+
if (btnChain) btnChain.addEventListener('click', function () { syncModeCards(btnChain); });
|
|
450
|
+
// Row count badge updater for step 3
|
|
451
|
+
var origTbody = document.getElementById('seed-preview-tbody');
|
|
452
|
+
if (origTbody) {
|
|
453
|
+
var rowObserver = new MutationObserver(function () {
|
|
454
|
+
var badge = document.getElementById('seed-row-count-badge');
|
|
455
|
+
if (!badge) return;
|
|
456
|
+
var rows = origTbody.querySelectorAll('tr');
|
|
457
|
+
var isPlaceholder = origTbody.querySelector('td[colspan]');
|
|
458
|
+
if (isPlaceholder) { badge.textContent = ''; return; }
|
|
459
|
+
badge.textContent = rows.length + ' row' + (rows.length !== 1 ? 's' : '') + ' generated';
|
|
460
|
+
});
|
|
461
|
+
rowObserver.observe(origTbody, { childList: true, subtree: true });
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
})();
|
|
465
|
+
</script>
|