admindb 2.2.1 → 2.3.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 +368 -364
- package/dist/app.js +25 -16
- package/dist/auth/config.d.ts +1 -1
- package/dist/auth/config.js +18 -30
- package/dist/auth/crypto.js +11 -21
- package/dist/auth/middleware.js +9 -16
- package/dist/auth/routes.js +9 -15
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +20 -29
- package/dist/cli/config.d.ts +1 -1
- package/dist/cli/config.js +15 -18
- package/dist/cli/runner.js +13 -13
- package/dist/data/chain.d.ts +1 -1
- package/dist/data/chain.js +40 -617
- package/dist/data/datasets.d.ts +1 -1
- package/dist/data/datasets.js +43 -1
- package/dist/data/detector.js +45 -21
- package/dist/data/engine.d.ts +1 -1
- package/dist/data/engine.js +483 -142
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +8 -0
- package/dist/data/prng.d.ts +1 -0
- package/dist/data/prng.js +73 -0
- package/dist/data/registry.d.ts +1 -0
- package/dist/data/registry.js +805 -0
- package/dist/data/schema-graph.d.ts +1 -0
- package/dist/data/schema-graph.js +210 -0
- package/dist/data/strategies.d.ts +1 -1
- package/dist/data/strategies.js +44 -283
- package/dist/data/templates.d.ts +1 -0
- package/dist/data/templates.js +134 -0
- package/dist/data/types.d.ts +1 -1
- package/dist/data/validator.d.ts +1 -0
- package/dist/data/validator.js +160 -0
- package/dist/db/database.js +9 -14
- package/dist/db/export.js +32 -55
- package/dist/db/filters.d.ts +1 -1
- package/dist/db/filters.js +15 -38
- package/dist/db/introspection.js +4 -7
- package/dist/db/manager.d.ts +1 -1
- package/dist/db/manager.js +48 -53
- package/dist/db/migrations.js +7 -14
- package/dist/db/postgres.js +30 -78
- package/dist/index.d.ts +1 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/inspector.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/seed.js +1 -1
- package/dist/routes/api/erd.js +3 -8
- package/dist/routes/api/helpers.d.ts +1 -1
- package/dist/routes/api/helpers.js +75 -25
- package/dist/routes/api/import-export.js +1 -2
- package/dist/routes/api/query.js +2 -6
- package/dist/routes/api/rows.js +4 -8
- package/dist/routes/api/seed.js +35 -21
- package/dist/routes/api/tables.js +15 -30
- package/dist/routes/databases.js +8 -26
- package/dist/routes/pages.js +67 -18
- package/dist/serverless.js +31 -44
- package/dist/sql/generator.d.ts +1 -1
- package/dist/sql/generator.js +35 -109
- package/dist/types/api.d.ts +1 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +45 -85
- package/dist/utils/csv.d.ts +1 -1
- package/dist/utils/csv.js +11 -17
- package/dist/utils/datatype.js +46 -60
- package/dist/utils/icons.js +8 -8
- package/dist/views/layouts/main.hbs +1 -87
- package/dist/views/pages/databases.hbs +1 -233
- package/dist/views/pages/designer.hbs +1 -89
- package/dist/views/pages/erd.hbs +1 -1241
- package/dist/views/pages/error.hbs +1 -10
- package/dist/views/pages/form.hbs +1 -59
- package/dist/views/pages/home.hbs +1 -220
- package/dist/views/pages/info.hbs +1 -107
- package/dist/views/pages/login.hbs +1 -98
- package/dist/views/pages/query.hbs +1 -129
- package/dist/views/pages/schema.hbs +1 -298
- package/dist/views/pages/seed-select.hbs +251 -0
- package/dist/views/pages/seed.hbs +256 -414
- package/dist/views/pages/table.hbs +1 -327
- package/dist/views/partials/navbar.hbs +1 -83
- package/dist/views/partials/sidebar.hbs +1 -129
- package/docs/API.md +149 -149
- package/docs/EXAMPLES.md +579 -579
- package/docs/SECURITY.md +265 -265
- package/package.json +80 -79
|
@@ -1,465 +1,307 @@
|
|
|
1
|
-
<div class="
|
|
2
|
-
<div class="flex items-center gap-4">
|
|
3
|
-
<
|
|
4
|
-
{{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<div class="
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
1
|
+
<div class="space-y-4 pb-20">
|
|
2
|
+
<div class="app-card p-3.5 flex flex-wrap items-center justify-between gap-4">
|
|
3
|
+
<div class="flex items-center gap-3 min-w-0">
|
|
4
|
+
<a href="{{basePath}}/seed" class="btn btn-sm btn-ghost btn-square text-base-content/70 hover:text-base-content" title="Choose table & mode">
|
|
5
|
+
{{{icon "arrowLeft" class="h-4 w-4"}}}
|
|
6
|
+
</a>
|
|
7
|
+
<div class="h-4 w-px bg-base-300"></div>
|
|
8
|
+
<div class="flex items-center gap-2 flex-wrap">
|
|
9
|
+
<a href="{{basePath}}/seed" class="text-xs font-semibold text-base-content/50 hover:text-primary transition-colors">Seed Data</a>
|
|
10
|
+
<span class="text-xs text-base-content/30">/</span>
|
|
11
|
+
{{#if allTables.length}}
|
|
12
|
+
<div class="dropdown dropdown-bottom">
|
|
13
|
+
<label tabindex="0" class="btn btn-xs btn-ghost gap-1 font-mono font-bold text-xs" title="Switch table">
|
|
14
|
+
<span>{{table}}</span>
|
|
15
|
+
{{{icon "chevronDown" class="h-3 w-3 opacity-60"}}}
|
|
16
|
+
</label>
|
|
17
|
+
<ul tabindex="0" class="dropdown-content z-30 menu p-1 shadow-lg bg-base-100 border border-base-300 rounded-box w-52 max-h-60 overflow-y-auto">
|
|
18
|
+
{{#each allTables}}
|
|
19
|
+
<li>
|
|
20
|
+
<a href="{{../basePath}}/seed/{{this}}" class="{{#if (eq this ../table)}}active font-bold{{/if}} font-mono text-xs">
|
|
21
|
+
{{{icon "table" class="h-3.5 w-3.5"}}}
|
|
22
|
+
{{this}}
|
|
23
|
+
</a>
|
|
24
|
+
</li>
|
|
25
|
+
{{/each}}
|
|
26
|
+
</ul>
|
|
14
27
|
</div>
|
|
28
|
+
{{else}}
|
|
29
|
+
<span class="font-mono font-bold text-sm text-base-content">{{table}}</span>
|
|
30
|
+
{{/if}}
|
|
31
|
+
<span class="badge badge-sm badge-ghost font-mono text-[11px] text-base-content/60">{{colCount}} cols</span>
|
|
32
|
+
{{#if dialect}}
|
|
33
|
+
<span class="badge badge-sm badge-outline font-mono text-[10px] uppercase text-base-content/50">{{dialect}}</span>
|
|
34
|
+
{{/if}}
|
|
15
35
|
</div>
|
|
16
36
|
</div>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<span
|
|
26
|
-
|
|
27
|
-
</div>
|
|
28
|
-
<span class="text-xs font-semibold text-primary">Choose Mode</span>
|
|
37
|
+
<div class="flex items-center gap-2.5 flex-wrap">
|
|
38
|
+
<div class="seed-mode-segment">
|
|
39
|
+
<button type="button" id="btn-select-single" class="seed-mode-btn {{#unless isChainMode}}active{{/unless}}">
|
|
40
|
+
{{{icon "table" class="h-3.5 w-3.5"}}}
|
|
41
|
+
<span>Single Table</span>
|
|
42
|
+
</button>
|
|
43
|
+
<button type="button" id="btn-select-chain" class="seed-mode-btn {{#if isChainMode}}active{{/if}}">
|
|
44
|
+
{{{icon "diagram" class="h-3.5 w-3.5"}}}
|
|
45
|
+
<span>ER Chain</span>
|
|
46
|
+
</button>
|
|
29
47
|
</div>
|
|
30
|
-
<div
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
48
|
+
<div class="h-4 w-px bg-base-300 hidden sm:block"></div>
|
|
49
|
+
<div class="flex items-center gap-1.5" title="Numeric seed for deterministic generation">
|
|
50
|
+
<div class="relative">
|
|
51
|
+
<input id="plan-seed-input" type="number" placeholder="Seed (auto)"
|
|
52
|
+
class="field-input w-28 font-mono text-xs !py-1 pl-2.5 pr-6" />
|
|
53
|
+
<span class="absolute right-2 top-1/2 -translate-y-1/2 text-[10px] font-mono text-base-content/40">#</span>
|
|
34
54
|
</div>
|
|
35
|
-
<
|
|
55
|
+
<button type="button" id="btn-random-seed" class="btn btn-sm btn-ghost btn-square text-base-content/70 hover:text-base-content" title="Roll random seed">
|
|
56
|
+
{{{icon "refresh" class="h-3.5 w-3.5"}}}
|
|
57
|
+
</button>
|
|
36
58
|
</div>
|
|
37
|
-
<div
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
<div class="h-4 w-px bg-base-300 hidden sm:block"></div>
|
|
60
|
+
<div class="flex items-center gap-1">
|
|
61
|
+
<button type="button" id="btn-profiles-modal" class="btn btn-sm btn-ghost gap-1.5 text-xs text-base-content/80 hover:text-base-content" title="Manage seed profiles">
|
|
62
|
+
{{{icon "book" class="h-3.5 w-3.5 text-primary"}}}
|
|
63
|
+
<span class="hidden md:inline">Profiles</span>
|
|
64
|
+
</button>
|
|
65
|
+
<button type="button" id="btn-export-plan-json" class="btn btn-sm btn-ghost btn-square text-base-content/70 hover:text-base-content" title="Export generation plan JSON">
|
|
66
|
+
{{{icon "download" class="h-3.5 w-3.5"}}}
|
|
67
|
+
</button>
|
|
68
|
+
<label for="input-import-plan-json" class="btn btn-sm btn-ghost btn-square text-base-content/70 hover:text-base-content cursor-pointer" title="Import generation plan JSON">
|
|
69
|
+
{{{icon "upload" class="h-3.5 w-3.5"}}}
|
|
70
|
+
<input type="file" id="input-import-plan-json" accept=".json" class="hidden" />
|
|
71
|
+
</label>
|
|
43
72
|
</div>
|
|
73
|
+
<div class="h-4 w-px bg-base-300 hidden sm:block"></div>
|
|
74
|
+
<button id="seed-insert" type="button" class="btn btn-primary btn-sm gap-2 font-bold px-4 shadow-sm">
|
|
75
|
+
{{{icon "play" class="h-3.5 w-3.5"}}}
|
|
76
|
+
<span>Execute Seed</span>
|
|
77
|
+
</button>
|
|
44
78
|
</div>
|
|
45
79
|
</div>
|
|
46
|
-
<div id="step-content-1" class="
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
<div id="step-content-1" class="hidden">
|
|
81
|
+
<button id="btn-next-1" class="hidden"></button>
|
|
82
|
+
</div>
|
|
83
|
+
<div id="step-content-2" class="contents">
|
|
84
|
+
<button id="btn-prev-2" class="hidden"></button>
|
|
85
|
+
<button id="btn-next-2" class="hidden"></button>
|
|
86
|
+
</div>
|
|
87
|
+
<div id="step-content-3" class="contents">
|
|
88
|
+
<button id="btn-prev-3" class="hidden"></button>
|
|
89
|
+
</div>
|
|
90
|
+
<div id="step-nav-1" class="hidden"><div class="seed-step-circle"><span class="seed-step-num"></span><span class="seed-step-check"></span></div></div>
|
|
91
|
+
<div id="step-nav-2" class="hidden"><div class="seed-step-circle"><span class="seed-step-num"></span><span class="seed-step-check"></span></div></div>
|
|
92
|
+
<div id="step-nav-3" class="hidden"><div class="seed-step-circle"><span class="seed-step-num"></span><span class="seed-step-check"></span></div></div>
|
|
93
|
+
<div id="wizard-progress-bar" class="hidden"></div>
|
|
94
|
+
<div class="grid grid-cols-1 xl:grid-cols-12 gap-4 items-start">
|
|
95
|
+
<div class="xl:col-span-7 space-y-4">
|
|
96
|
+
<div id="config-single" class="{{#if isChainMode}}hidden{{/if}} space-y-4">
|
|
97
|
+
<div class="app-card p-3.5 flex flex-wrap items-center justify-between gap-4">
|
|
98
|
+
<div class="flex items-center gap-3">
|
|
99
|
+
<div class="flex items-center">
|
|
100
|
+
<button type="button" id="seed-count-dec" class="btn btn-xs btn-outline rounded-r-none border-r-0 px-2.5 font-mono text-sm hover:bg-primary hover:text-primary-content hover:border-primary">−</button>
|
|
101
|
+
<input id="seed-count" type="number" value="10" min="1" max="{{maxRows}}"
|
|
102
|
+
class="field-input !rounded-none border-x-0 !py-0.5 font-mono w-20 font-bold text-xs text-center [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" />
|
|
103
|
+
<button type="button" id="seed-count-inc" class="btn btn-xs btn-outline rounded-l-none border-l-0 px-2.5 font-mono text-sm hover:bg-primary hover:text-primary-content hover:border-primary">+</button>
|
|
104
|
+
</div>
|
|
105
|
+
<span class="text-[11px] uppercase font-bold text-base-content/50">Rows</span>
|
|
106
|
+
<div class="h-4 w-px bg-base-200 hidden sm:block"></div>
|
|
107
|
+
<div class="flex gap-1 flex-wrap">
|
|
108
|
+
{{#each quickCounts}}
|
|
109
|
+
<button type="button" class="preset-pill btn btn-xs btn-ghost border border-base-300 font-mono text-[11px] px-2" data-count="{{this}}">{{this}}</button>
|
|
110
|
+
{{/each}}
|
|
53
111
|
</div>
|
|
54
112
|
</div>
|
|
55
|
-
<div class="
|
|
56
|
-
<
|
|
57
|
-
<
|
|
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>
|
|
113
|
+
<div class="flex items-center gap-2 w-full sm:w-auto">
|
|
114
|
+
<input type="text" id="seed-col-search" placeholder="Filter columns…" class="field-input text-xs !py-1 w-full sm:w-48" />
|
|
115
|
+
<span id="col-count-badge" class="badge badge-sm badge-ghost font-mono text-[11px] shrink-0">{{colCount}} cols</span>
|
|
61
116
|
</div>
|
|
62
117
|
</div>
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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>
|
|
118
|
+
<div class="app-card p-4 space-y-3">
|
|
119
|
+
<div class="flex items-center justify-between pb-2 border-b border-base-200">
|
|
120
|
+
<span class="text-xs font-bold uppercase tracking-wider text-base-content/70">Columns Specification</span>
|
|
121
|
+
<span class="text-[11px] text-base-content/40">Select generator strategy & customize parameters per column</span>
|
|
91
122
|
</div>
|
|
92
|
-
<div
|
|
93
|
-
<div class="w-2.5 h-2.5 rounded-full bg-secondary scale-0 transition-transform duration-200 seed-mode-dot"></div>
|
|
123
|
+
<div id="seed-columns" class="space-y-2.5">
|
|
94
124
|
</div>
|
|
95
125
|
</div>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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"}}}
|
|
119
|
-
</button>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
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>
|
|
126
|
+
</div>
|
|
127
|
+
<div id="config-chain" class="{{#unless isChainMode}}hidden{{/unless}} space-y-4">
|
|
128
|
+
<div class="app-card p-3.5 flex flex-wrap items-center justify-between gap-4">
|
|
129
|
+
<div class="flex items-center gap-3">
|
|
130
|
+
<label class="text-xs font-bold text-base-content/70">Graph Scope:</label>
|
|
131
|
+
<select id="chain-scope" class="field-select !py-1 text-xs font-semibold w-52">
|
|
132
|
+
<option value="chain">Connected Relational Chain</option>
|
|
133
|
+
<option value="ancestors">Upstream Parents Only</option>
|
|
134
|
+
<option value="descendants">Downstream Children Only</option>
|
|
135
|
+
<option value="all">Entire Database (All Tables)</option>
|
|
136
|
+
</select>
|
|
136
137
|
</div>
|
|
137
|
-
<div class="flex items-
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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>
|
|
138
|
+
<div class="flex items-center gap-2">
|
|
139
|
+
<span class="text-xs font-bold text-base-content/70">Scale:</span>
|
|
140
|
+
<div class="join">
|
|
141
|
+
<button type="button" class="chain-scale-btn btn btn-xs join-item font-mono" data-scale="0.5">0.5×</button>
|
|
142
|
+
<button type="button" class="chain-scale-btn btn btn-xs join-item btn-neutral font-mono" data-scale="1">1×</button>
|
|
143
|
+
<button type="button" class="chain-scale-btn btn btn-xs join-item font-mono" data-scale="2">2×</button>
|
|
144
|
+
<button type="button" class="chain-scale-btn btn btn-xs join-item font-mono" data-scale="5">5×</button>
|
|
150
145
|
</div>
|
|
146
|
+
<span id="chain-summary-badge" class="badge badge-sm badge-primary font-mono font-bold ml-2">0 Tables</span>
|
|
151
147
|
</div>
|
|
152
148
|
</div>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
<div class="app-card p-4 space-y-3">
|
|
150
|
+
<div class="flex items-center justify-between pb-2 border-b border-base-200">
|
|
151
|
+
<span class="text-xs font-bold uppercase tracking-wider text-base-content/70">Topological Execution Pipeline</span>
|
|
152
|
+
<span class="text-[11px] text-base-content/40">Dependencies ordered upstream-first</span>
|
|
153
|
+
</div>
|
|
154
|
+
<div id="chain-pipeline-container" class="space-y-2.5">
|
|
155
|
+
</div>
|
|
160
156
|
</div>
|
|
161
157
|
</div>
|
|
158
|
+
<details class="app-card group">
|
|
159
|
+
<summary class="p-3.5 flex items-center justify-between cursor-pointer list-none select-none text-xs font-bold text-base-content/70 hover:text-base-content">
|
|
160
|
+
<div class="flex items-center gap-2">
|
|
161
|
+
{{{icon "settings" class="h-3.5 w-3.5"}}}
|
|
162
|
+
<span>Advanced Execution Options</span>
|
|
163
|
+
</div>
|
|
164
|
+
<span class="text-xs text-base-content/40 group-open:rotate-180 transition-transform">▼</span>
|
|
165
|
+
</summary>
|
|
166
|
+
<div class="p-3.5 pt-0 border-t border-base-200/80 mt-1 flex flex-wrap items-center gap-6 text-xs">
|
|
167
|
+
<label class="cursor-pointer flex items-center gap-2 select-none group">
|
|
168
|
+
<input id="plan-transaction-opt" type="checkbox" checked class="checkbox checkbox-primary checkbox-xs" />
|
|
169
|
+
<span class="font-medium text-base-content/80 group-hover:text-base-content">Wrap in Transaction (BEGIN ... COMMIT)</span>
|
|
170
|
+
</label>
|
|
171
|
+
<label class="cursor-pointer flex items-center gap-2 select-none group">
|
|
172
|
+
<input id="plan-rollback-opt" type="checkbox" checked class="checkbox checkbox-primary checkbox-xs" />
|
|
173
|
+
<span class="font-medium text-base-content/80 group-hover:text-base-content">Atomic Rollback on Error</span>
|
|
174
|
+
</label>
|
|
175
|
+
<label class="cursor-pointer flex items-center gap-2 select-none group">
|
|
176
|
+
<input id="seed-truncate" type="checkbox" class="checkbox checkbox-error checkbox-xs" />
|
|
177
|
+
<span class="font-medium text-error/90 group-hover:text-error">Clear tables before inserting (Truncate)</span>
|
|
178
|
+
</label>
|
|
179
|
+
</div>
|
|
180
|
+
</details>
|
|
162
181
|
</div>
|
|
163
|
-
<div
|
|
164
|
-
<div class="app-card p-5">
|
|
165
|
-
<div class="flex
|
|
166
|
-
<div>
|
|
167
|
-
<
|
|
168
|
-
<
|
|
169
|
-
<option value="chain">Full Connected Chain</option>
|
|
170
|
-
<option value="ancestors">Parents Only</option>
|
|
171
|
-
<option value="descendants">Children Only</option>
|
|
172
|
-
</select>
|
|
182
|
+
<div class="xl:col-span-5 space-y-4 xl:sticky xl:top-4">
|
|
183
|
+
<div id="validation-report-card" class="app-card p-3.5 space-y-2">
|
|
184
|
+
<div class="flex items-center justify-between">
|
|
185
|
+
<div id="validation-summary-pill" class="flex items-center gap-2">
|
|
186
|
+
<span id="validation-status-dot" class="w-2 h-2 rounded-full bg-success"></span>
|
|
187
|
+
<span id="validation-status-text" class="text-xs font-mono font-bold text-base-content">Plan Ready</span>
|
|
173
188
|
</div>
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</div>
|
|
189
|
+
<span id="validation-summary-chip" class="badge badge-sm badge-success font-mono text-[10px] font-bold">All Checks Passed</span>
|
|
190
|
+
</div>
|
|
191
|
+
<div id="validation-issues-list" class="space-y-1.5 text-xs">
|
|
192
|
+
<div class="flex items-center gap-2 text-success font-medium text-[11px]">
|
|
193
|
+
{{{icon "check" class="h-3.5 w-3.5 shrink-0"}}}
|
|
194
|
+
<span>Primary key & constraint strategies valid</span>
|
|
181
195
|
</div>
|
|
182
196
|
</div>
|
|
183
197
|
</div>
|
|
184
|
-
<div class="app-card
|
|
185
|
-
<div class="flex items-center justify-between
|
|
186
|
-
<div>
|
|
187
|
-
<
|
|
188
|
-
<
|
|
198
|
+
<div class="app-card overflow-hidden">
|
|
199
|
+
<div class="flex items-center justify-between p-3 border-b border-base-200 bg-base-100 gap-2 flex-wrap">
|
|
200
|
+
<div class="join">
|
|
201
|
+
<button type="button" id="preview-tab-grid" class="btn btn-xs join-item btn-active font-bold">Table Preview</button>
|
|
202
|
+
<button type="button" id="preview-tab-sql" class="btn btn-xs join-item font-bold">SQL Script</button>
|
|
189
203
|
</div>
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
<span
|
|
204
|
+
<button id="seed-refresh-preview" type="button" class="btn btn-xs btn-ghost gap-1 text-xs text-base-content/70 hover:text-primary">
|
|
205
|
+
{{{icon "refresh" class="h-3 w-3"}}}
|
|
206
|
+
<span>Refresh</span>
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
<div id="seed-chain-table-tabs" class="tabs tabs-bordered flex-nowrap w-full overflow-x-auto hidden px-3 py-1 bg-base-200/40 border-b border-base-200 text-xs"></div>
|
|
210
|
+
<div id="preview-view-grid">
|
|
211
|
+
<div class="overflow-x-auto max-h-[440px]">
|
|
212
|
+
<table class="table table-zebra table-pin-rows table-xs w-full">
|
|
213
|
+
<thead id="seed-preview-thead" class="bg-base-200/90 text-[10px] uppercase font-mono tracking-wider text-base-content/70 backdrop-blur sticky top-0 z-10"></thead>
|
|
214
|
+
<tbody id="seed-preview-tbody" class="font-mono text-[11px]">
|
|
215
|
+
<tr>
|
|
216
|
+
<td colspan="100" class="text-center py-12 opacity-50">
|
|
217
|
+
<div class="flex flex-col items-center gap-2">
|
|
218
|
+
<span class="loading loading-spinner loading-sm text-primary"></span>
|
|
219
|
+
<span class="text-xs">Generating preview…</span>
|
|
220
|
+
</div>
|
|
221
|
+
</td>
|
|
222
|
+
</tr>
|
|
223
|
+
</tbody>
|
|
224
|
+
</table>
|
|
193
225
|
</div>
|
|
194
226
|
</div>
|
|
195
|
-
<div id="
|
|
227
|
+
<div id="preview-view-sql" class="hidden p-3 bg-base-200/20 space-y-2">
|
|
228
|
+
<div class="flex items-center justify-between">
|
|
229
|
+
<span class="text-[11px] font-mono text-base-content/50 uppercase font-bold">Generated SQL (Preview)</span>
|
|
230
|
+
<button type="button" id="btn-copy-sql" class="btn btn-xs btn-outline gap-1 text-[11px]">
|
|
231
|
+
{{{icon "copy" class="h-3 w-3"}}}
|
|
232
|
+
<span>Copy SQL</span>
|
|
233
|
+
</button>
|
|
234
|
+
</div>
|
|
235
|
+
<pre id="preview-sql-code" class="bg-neutral text-neutral-content p-3.5 rounded-lg font-mono text-xs overflow-x-auto max-h-[380px] border border-base-300 leading-relaxed"></pre>
|
|
196
236
|
</div>
|
|
197
237
|
</div>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
</
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
{{{icon "arrowRight" class="h-4 w-4"}}}
|
|
207
|
-
</button>
|
|
238
|
+
<div id="seed-truncate-banner" class="hidden p-3 rounded-lg bg-error/10 border border-error/20 flex items-center gap-2.5">
|
|
239
|
+
<span class="text-error shrink-0">{{{icon "warning" class="h-4 w-4"}}}</span>
|
|
240
|
+
<p class="text-xs font-bold text-error">
|
|
241
|
+
Destructive Action: Existing table rows will be truncated before seeding.
|
|
242
|
+
</p>
|
|
243
|
+
</div>
|
|
244
|
+
<div id="seed-execute-bar" class="hidden"></div>
|
|
245
|
+
<div id="seed-feedback" class="hidden"></div>
|
|
208
246
|
</div>
|
|
209
247
|
</div>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
</
|
|
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
|
|
220
|
-
</button>
|
|
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>
|
|
248
|
+
</div>
|
|
249
|
+
<dialog id="seed-profiles-dialog" class="modal">
|
|
250
|
+
<div class="modal-box p-0 overflow-hidden max-w-lg rounded-2xl border border-base-200 shadow-xl">
|
|
251
|
+
<div class="px-5 py-4 bg-base-200/50 border-b border-base-200 flex items-center justify-between">
|
|
252
|
+
<div class="flex items-center gap-2.5">
|
|
253
|
+
{{{icon "book" class="h-4 w-4 text-primary"}}}
|
|
254
|
+
<h3 class="font-bold text-sm text-base-content">Seed Profiles & Presets</h3>
|
|
242
255
|
</div>
|
|
256
|
+
<button type="button" class="btn btn-xs btn-circle btn-ghost" id="btn-close-profiles">✕</button>
|
|
243
257
|
</div>
|
|
244
|
-
<div
|
|
245
|
-
<div
|
|
246
|
-
<
|
|
247
|
-
<
|
|
248
|
-
<
|
|
249
|
-
|
|
258
|
+
<div class="p-5 space-y-4 text-xs">
|
|
259
|
+
<div>
|
|
260
|
+
<h4 class="font-bold text-[10px] uppercase tracking-wider text-base-content/50 mb-2">Quick Blueprints</h4>
|
|
261
|
+
<div class="grid grid-cols-3 gap-2">
|
|
262
|
+
<button type="button" class="btn-preset-profile btn btn-xs btn-outline font-mono" data-preset="smoke">⚡ Smoke (10)</button>
|
|
263
|
+
<button type="button" class="btn-preset-profile btn btn-xs btn-outline font-mono" data-preset="realistic">🌱 Standard (100)</button>
|
|
264
|
+
<button type="button" class="btn-preset-profile btn btn-xs btn-outline font-mono" data-preset="stress">🚀 Stress (1000)</button>
|
|
265
|
+
</div>
|
|
250
266
|
</div>
|
|
251
|
-
<div class="
|
|
252
|
-
<
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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>
|
|
267
|
+
<div class="p-3 rounded-lg bg-base-200/40 border border-base-300 space-y-2">
|
|
268
|
+
<h4 class="font-bold text-[10px] uppercase tracking-wider text-base-content/60">Save Current Configuration</h4>
|
|
269
|
+
<div class="flex gap-2">
|
|
270
|
+
<input id="profile-name-input" type="text" placeholder="Profile name (e.g. Test Dataset)"
|
|
271
|
+
class="field-input flex-1 text-xs !py-1 font-medium" />
|
|
272
|
+
<button type="button" id="btn-save-profile" class="btn btn-xs btn-primary px-3 font-bold">Save</button>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
<div>
|
|
276
|
+
<h4 class="font-bold text-[10px] uppercase tracking-wider text-base-content/50 mb-1.5">Saved Profiles</h4>
|
|
277
|
+
<div id="profiles-list-container" class="space-y-1.5 max-h-48 overflow-y-auto pr-1">
|
|
278
|
+
<div class="py-4 text-center text-xs text-base-content/40">No saved profiles yet.</div>
|
|
268
279
|
</div>
|
|
269
280
|
</div>
|
|
270
281
|
</div>
|
|
271
|
-
<div id="seed-feedback" class="hidden"></div>
|
|
272
282
|
</div>
|
|
273
|
-
</
|
|
283
|
+
<form method="dialog" class="modal-backdrop bg-base-300/60 backdrop-blur-sm"><button>close</button></form>
|
|
284
|
+
</dialog>
|
|
274
285
|
<dialog id="seed-truncate-dialog" class="modal">
|
|
275
|
-
<div class="modal-box p-0 overflow-hidden max-w-md">
|
|
276
|
-
<div class="px-
|
|
277
|
-
<
|
|
278
|
-
|
|
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>
|
|
285
|
-
</div>
|
|
286
|
+
<div class="modal-box p-0 overflow-hidden max-w-md rounded-2xl border border-error/20 shadow-xl">
|
|
287
|
+
<div class="px-5 py-4 bg-error/5 border-b border-error/15 flex items-center gap-2.5">
|
|
288
|
+
<span class="text-error">{{{icon "warning" class="h-5 w-5"}}}</span>
|
|
289
|
+
<h3 class="font-bold text-sm text-error">Confirm Truncate Action</h3>
|
|
286
290
|
</div>
|
|
287
|
-
<div class="
|
|
288
|
-
<p
|
|
289
|
-
You have
|
|
290
|
-
This will <strong>permanently delete all existing rows</strong> in the affected tables.
|
|
291
|
+
<div class="p-5 space-y-3 text-xs text-base-content/80 leading-relaxed">
|
|
292
|
+
<p>
|
|
293
|
+
You have enabled <strong class="text-error">Clear tables before inserting</strong>. All existing records in affected tables will be permanently deleted in reverse topological order before new rows are inserted.
|
|
291
294
|
</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
295
|
</div>
|
|
310
|
-
<div class="px-
|
|
311
|
-
<button type="button" class="btn btn-ghost" id="seed-truncate-cancel">Cancel</button>
|
|
312
|
-
<button type="button" class="btn btn-error gap-
|
|
313
|
-
{{{icon "warning" class="h-
|
|
314
|
-
Yes,
|
|
296
|
+
<div class="px-5 pb-4 flex items-center justify-end gap-2">
|
|
297
|
+
<button type="button" class="btn btn-ghost btn-xs" id="seed-truncate-cancel">Cancel</button>
|
|
298
|
+
<button type="button" class="btn btn-error btn-xs font-bold gap-1.5" id="seed-truncate-confirm">
|
|
299
|
+
{{{icon "warning" class="h-3.5 w-3.5"}}}
|
|
300
|
+
<span>Yes, Truncate & Seed</span>
|
|
315
301
|
</button>
|
|
316
302
|
</div>
|
|
317
303
|
</div>
|
|
318
|
-
<form method="dialog" class="modal-backdrop bg-base-300/
|
|
304
|
+
<form method="dialog" class="modal-backdrop bg-base-300/60 backdrop-blur-sm"><button>close</button></form>
|
|
319
305
|
</dialog>
|
|
320
306
|
<script id="seed-config" type="application/json">{{{json seedConfig}}}</script>
|
|
321
307
|
<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>
|