factory_seeder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +111 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +445 -0
  5. data/app/assets/stylesheets/factory_seeder.css +637 -0
  6. data/app/controllers/factory_seeder/application_controller.rb +8 -0
  7. data/app/controllers/factory_seeder/custom_seeds_controller.rb +134 -0
  8. data/app/controllers/factory_seeder/dashboard_controller.rb +36 -0
  9. data/app/controllers/factory_seeder/factory_controller.rb +70 -0
  10. data/app/views/factory_seeder/custom_seeds/index.html.erb +51 -0
  11. data/app/views/factory_seeder/custom_seeds/show.html.erb +113 -0
  12. data/app/views/factory_seeder/dashboard/index.html.erb +99 -0
  13. data/app/views/factory_seeder/factory/index.html.erb +71 -0
  14. data/app/views/factory_seeder/factory/show.html.erb +108 -0
  15. data/app/views/factory_seeder/seeds/show.html.erb +2 -0
  16. data/app/views/layouts/factory_seeder/application.html.erb +25 -0
  17. data/bin/factory_seeder +27 -0
  18. data/config/factory_seeder.rb +24 -0
  19. data/config/routes.rb +20 -0
  20. data/lib/factory_seeder/asset_helper.rb +34 -0
  21. data/lib/factory_seeder/cli.rb +352 -0
  22. data/lib/factory_seeder/configuration.rb +32 -0
  23. data/lib/factory_seeder/custom_seed_loader.rb +39 -0
  24. data/lib/factory_seeder/engine.rb +16 -0
  25. data/lib/factory_seeder/execution_log_store.rb +48 -0
  26. data/lib/factory_seeder/factory_scanner.rb +149 -0
  27. data/lib/factory_seeder/loader.rb +26 -0
  28. data/lib/factory_seeder/rails_integration.rb +29 -0
  29. data/lib/factory_seeder/seed.rb +102 -0
  30. data/lib/factory_seeder/seed_builder.rb +67 -0
  31. data/lib/factory_seeder/seed_generator.rb +305 -0
  32. data/lib/factory_seeder/seed_manager.rb +128 -0
  33. data/lib/factory_seeder/seeder.rb +41 -0
  34. data/lib/factory_seeder/version.rb +5 -0
  35. data/lib/factory_seeder/web_interface.rb +119 -0
  36. data/lib/factory_seeder.rb +209 -0
  37. data/templates/seed_template.rb +84 -0
  38. metadata +276 -0
@@ -0,0 +1,637 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap');
2
+
3
+ :root {
4
+ --background: #080b11;
5
+ --foreground: #eef3ff;
6
+ --card: #0f1424;
7
+ --card-border: #1c2037;
8
+ --border: #1e2439;
9
+ --muted: #8ea0c3;
10
+ --primary: #2bd1ff;
11
+ --accent: #ff3cb7;
12
+ --success: #5ef7ba;
13
+ --warning: #facc15;
14
+ --destructive: #ff6b6b;
15
+ --radius-lg: 1rem;
16
+ --radius-md: 0.75rem;
17
+ }
18
+
19
+ *, *::before, *::after {
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ body {
24
+ margin: 0;
25
+ font-family: 'JetBrains Mono', 'Space Grotesk', system-ui, sans-serif;
26
+ background: var(--background);
27
+ color: var(--foreground);
28
+ min-height: 100vh;
29
+ }
30
+
31
+ .app-header {
32
+ position: sticky;
33
+ top: 0;
34
+ z-index: 10;
35
+ backdrop-filter: blur(14px);
36
+ background: linear-gradient(135deg, rgba(7, 8, 15, 0.95), rgba(16, 20, 36, 0.9));
37
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
38
+ padding: 1rem 2rem;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: space-between;
42
+ }
43
+
44
+ .app-header__title {
45
+ font-family: 'Space Grotesk', sans-serif;
46
+ font-size: 1.25rem;
47
+ letter-spacing: 0.4em;
48
+ text-transform: uppercase;
49
+ }
50
+
51
+ .app-header__tagline {
52
+ font-size: 0.9rem;
53
+ color: var(--muted);
54
+ }
55
+
56
+ .app-header__link {
57
+ color: var(--foreground);
58
+ text-decoration: none;
59
+ font-size: 0.85rem;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.2em;
62
+ }
63
+
64
+ .page-shell {
65
+ position: relative;
66
+ min-height: 100vh;
67
+ overflow: hidden;
68
+ background: radial-gradient(circle at top right, rgba(43, 209, 255, 0.2), transparent 40%),
69
+ radial-gradient(circle at bottom left, rgba(255, 60, 183, 0.15), transparent 45%),
70
+ var(--background);
71
+ }
72
+
73
+ .scanlines,
74
+ .grid-background {
75
+ position: absolute;
76
+ inset: 0;
77
+ pointer-events: none;
78
+ z-index: 0;
79
+ }
80
+
81
+ .scanlines::after {
82
+ content: '';
83
+ position: absolute;
84
+ inset: 0;
85
+ background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(255, 255, 255, 0.05) 2px, rgba(255, 255, 255, 0.05) 4px);
86
+ mix-blend-mode: screen;
87
+ }
88
+
89
+ .grid-background::after {
90
+ content: '';
91
+ position: absolute;
92
+ inset: 0;
93
+ background-image: linear-gradient(0deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
94
+ linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
95
+ background-size: 80px 80px;
96
+ }
97
+
98
+ .page-content {
99
+ position: relative;
100
+ z-index: 5;
101
+ padding: 2rem 1.5rem 4rem;
102
+ max-width: 1200px;
103
+ margin: 0 auto;
104
+ }
105
+
106
+ .hero {
107
+ text-align: center;
108
+ margin-bottom: 3rem;
109
+ }
110
+
111
+ .hero__icon {
112
+ font-size: 3rem;
113
+ color: var(--primary);
114
+ margin-bottom: 0.5rem;
115
+ animation: pulse 6s linear infinite;
116
+ }
117
+
118
+ @keyframes pulse {
119
+ 0%,
120
+ 100% {
121
+ text-shadow: 0 0 8px rgba(43, 209, 255, 0.7);
122
+ }
123
+ 50% {
124
+ text-shadow: 0 0 30px rgba(43, 209, 255, 0.2);
125
+ }
126
+ }
127
+
128
+ .hero__title {
129
+ font-size: clamp(2rem, 3vw, 3.5rem);
130
+ letter-spacing: 0.4em;
131
+ text-transform: uppercase;
132
+ margin-bottom: 1rem;
133
+ }
134
+
135
+ .hero__subtitle {
136
+ color: var(--muted);
137
+ font-size: 1rem;
138
+ max-width: 600px;
139
+ margin: 0 auto 1.5rem;
140
+ }
141
+
142
+ .hero__flair {
143
+ display: flex;
144
+ justify-content: center;
145
+ gap: 0.5rem;
146
+ color: var(--muted);
147
+ font-size: 0.8rem;
148
+ }
149
+
150
+ .stat-row {
151
+ display: grid;
152
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
153
+ gap: 1rem;
154
+ margin-bottom: 2.5rem;
155
+ }
156
+
157
+ .stat-card {
158
+ background: rgba(255, 255, 255, 0.02);
159
+ border: 1px solid rgba(255, 255, 255, 0.08);
160
+ border-radius: var(--radius-md);
161
+ padding: 1.25rem;
162
+ min-height: 100px;
163
+ display: flex;
164
+ flex-direction: column;
165
+ justify-content: center;
166
+ gap: 0.35rem;
167
+ }
168
+
169
+ .stat-card__value {
170
+ font-size: 1.8rem;
171
+ font-weight: 600;
172
+ }
173
+
174
+ .stat-card__label {
175
+ color: var(--muted);
176
+ font-size: 0.8rem;
177
+ }
178
+
179
+ .mode-grid {
180
+ display: grid;
181
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
182
+ gap: 1.5rem;
183
+ }
184
+
185
+ .mode-card {
186
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0));
187
+ border: 1px solid rgba(255, 255, 255, 0.1);
188
+ border-radius: var(--radius-lg);
189
+ padding: 1.5rem;
190
+ position: relative;
191
+ overflow: hidden;
192
+ min-height: 320px;
193
+ }
194
+
195
+ .mode-card::after {
196
+ content: '';
197
+ position: absolute;
198
+ inset: 0;
199
+ border-radius: inherit;
200
+ border: 1px solid rgba(255, 255, 255, 0.02);
201
+ pointer-events: none;
202
+ }
203
+
204
+ .mode-card__header {
205
+ display: flex;
206
+ align-items: center;
207
+ margin-bottom: 1rem;
208
+ gap: 0.5rem;
209
+ }
210
+
211
+ .mode-card__title {
212
+ font-size: 1.5rem;
213
+ font-weight: 600;
214
+ text-transform: uppercase;
215
+ letter-spacing: 0.2em;
216
+ }
217
+
218
+ .mode-card__description {
219
+ color: var(--muted);
220
+ font-size: 0.9rem;
221
+ margin-bottom: 1.5rem;
222
+ }
223
+
224
+ .mode-card__tags {
225
+ display: flex;
226
+ flex-wrap: wrap;
227
+ gap: 0.5rem;
228
+ margin-bottom: 1.5rem;
229
+ }
230
+
231
+ .mode-card__tag {
232
+ border-radius: 999px;
233
+ padding: 0.35rem 0.85rem;
234
+ font-size: 0.7rem;
235
+ border: 1px solid rgba(255, 255, 255, 0.16);
236
+ color: var(--muted);
237
+ text-transform: uppercase;
238
+ letter-spacing: 0.15em;
239
+ }
240
+
241
+ .mode-card__actions {
242
+ margin-top: auto;
243
+ }
244
+
245
+ .btn,
246
+ .btn-primary,
247
+ .btn-accent,
248
+ .btn-destructive {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ justify-content: center;
252
+ gap: 0.35rem;
253
+ padding: 0.9rem 1.5rem;
254
+ border-radius: var(--radius-md);
255
+ border: 1px solid transparent;
256
+ text-transform: uppercase;
257
+ font-size: 0.8rem;
258
+ letter-spacing: 0.3em;
259
+ font-weight: 600;
260
+ color: var(--foreground);
261
+ text-decoration: none;
262
+ cursor: pointer;
263
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
264
+ }
265
+
266
+ .btn-primary {
267
+ background: linear-gradient(135deg, rgba(43, 209, 255, 0.2), rgba(43, 209, 255, 0.05));
268
+ border-color: rgba(43, 209, 255, 0.6);
269
+ box-shadow: 0 0 12px rgba(43, 209, 255, 0.3);
270
+ }
271
+
272
+ .btn-accent {
273
+ background: linear-gradient(135deg, rgba(255, 60, 183, 0.3), rgba(255, 60, 183, 0.05));
274
+ border-color: rgba(255, 60, 183, 0.7);
275
+ box-shadow: 0 0 12px rgba(255, 60, 183, 0.25);
276
+ }
277
+
278
+ .btn-destructive {
279
+ background: linear-gradient(135deg, rgba(255, 107, 107, 0.3), rgba(255, 107, 107, 0.05));
280
+ border-color: rgba(255, 107, 107, 0.6);
281
+ }
282
+
283
+ .btn:hover {
284
+ transform: translateY(-2px);
285
+ }
286
+
287
+ .section-title {
288
+ font-size: 1.3rem;
289
+ letter-spacing: 0.15em;
290
+ text-transform: uppercase;
291
+ margin-bottom: 1rem;
292
+ }
293
+
294
+ .alert-message {
295
+ margin-bottom: 1rem;
296
+ padding: 1rem 1.25rem;
297
+ border-radius: var(--radius-md);
298
+ background: rgba(255, 255, 255, 0.06);
299
+ border: 1px solid rgba(255, 255, 255, 0.05);
300
+ }
301
+
302
+ .alert-message--success {
303
+ border-color: rgba(94, 247, 186, 0.6);
304
+ }
305
+
306
+ .alert-message--error {
307
+ border-color: rgba(255, 107, 107, 0.6);
308
+ }
309
+
310
+ .alert-message--info {
311
+ border-color: rgba(43, 209, 255, 0.6);
312
+ }
313
+
314
+ .factories-grid {
315
+ display: grid;
316
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
317
+ gap: 1.25rem;
318
+ }
319
+
320
+ .factory-card {
321
+ background: linear-gradient(160deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0));
322
+ border: 1px solid var(--card-border);
323
+ border-radius: var(--radius-lg);
324
+ padding: 1.5rem;
325
+ min-height: 300px;
326
+ display: flex;
327
+ flex-direction: column;
328
+ gap: 0.75rem;
329
+ }
330
+
331
+ .factory-card__header {
332
+ display: flex;
333
+ justify-content: space-between;
334
+ align-items: center;
335
+ }
336
+
337
+ .factory-card__title {
338
+ font-size: 1.2rem;
339
+ font-weight: 600;
340
+ text-transform: uppercase;
341
+ }
342
+
343
+ .factory-card__meta {
344
+ color: var(--muted);
345
+ font-size: 0.85rem;
346
+ }
347
+
348
+ .factory-card__description {
349
+ color: var(--muted);
350
+ font-size: 0.9rem;
351
+ line-height: 1.4;
352
+ flex: 1;
353
+ }
354
+
355
+ .factory-card__badges {
356
+ display: flex;
357
+ flex-wrap: wrap;
358
+ gap: 0.35rem;
359
+ }
360
+
361
+ .trait-pill,
362
+ .assoc-pill {
363
+ padding: 0.25rem 0.75rem;
364
+ border-radius: 999px;
365
+ font-size: 0.7rem;
366
+ text-transform: uppercase;
367
+ letter-spacing: 0.2em;
368
+ background: rgba(255, 255, 255, 0.06);
369
+ border: 1px solid rgba(255, 255, 255, 0.08);
370
+ }
371
+
372
+ .factory-card__footer {
373
+ margin-top: 1rem;
374
+ }
375
+
376
+ .factory-card__footer .btn {
377
+ width: 100%;
378
+ }
379
+
380
+ .factory-show-grid {
381
+ display: grid;
382
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
383
+ gap: 1.5rem;
384
+ }
385
+
386
+ .panel {
387
+ background: var(--card);
388
+ border: 1px solid var(--card-border);
389
+ border-radius: var(--radius-lg);
390
+ padding: 1.5rem;
391
+ position: relative;
392
+ overflow: hidden;
393
+ }
394
+
395
+ .panel::after {
396
+ content: '';
397
+ position: absolute;
398
+ inset: 0;
399
+ border-radius: inherit;
400
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.02), transparent);
401
+ pointer-events: none;
402
+ }
403
+
404
+ .panel__header {
405
+ display: flex;
406
+ align-items: center;
407
+ justify-content: space-between;
408
+ margin-bottom: 1rem;
409
+ }
410
+
411
+ .panel__title {
412
+ font-size: 1.1rem;
413
+ letter-spacing: 0.2em;
414
+ }
415
+
416
+ .panel__body {
417
+ display: flex;
418
+ flex-direction: column;
419
+ gap: 1rem;
420
+ }
421
+
422
+ .form-group {
423
+ display: flex;
424
+ flex-direction: column;
425
+ gap: 0.3rem;
426
+ }
427
+
428
+ .form-group label {
429
+ font-size: 0.75rem;
430
+ letter-spacing: 0.2em;
431
+ text-transform: uppercase;
432
+ color: var(--muted);
433
+ }
434
+
435
+ .trait-grid {
436
+ display: flex;
437
+ flex-wrap: wrap;
438
+ gap: 0.5rem;
439
+ }
440
+
441
+ .trait-checkbox {
442
+ display: inline-flex;
443
+ align-items: center;
444
+ gap: 0.35rem;
445
+ padding: 0.45rem 0.75rem;
446
+ border-radius: var(--radius-md);
447
+ border: 1px solid rgba(255, 255, 255, 0.08);
448
+ background: rgba(255, 255, 255, 0.02);
449
+ font-size: 0.75rem;
450
+ letter-spacing: 0.2em;
451
+ text-transform: uppercase;
452
+ }
453
+
454
+ .trait-checkbox input {
455
+ accent-color: var(--primary);
456
+ }
457
+
458
+ .attribute-grid {
459
+ display: grid;
460
+ gap: 0.65rem;
461
+ }
462
+
463
+ .attribute-row {
464
+ display: flex;
465
+ flex-direction: column;
466
+ gap: 0.3rem;
467
+ }
468
+
469
+ .required {
470
+ color: var(--destructive);
471
+ margin-left: 0.25rem;
472
+ }
473
+
474
+ .factory-card__label {
475
+ letter-spacing: 0.2em;
476
+ text-transform: uppercase;
477
+ font-size: 0.55rem;
478
+ color: var(--muted);
479
+ }
480
+
481
+ .form-control {
482
+ background: rgba(255, 255, 255, 0.02);
483
+ border: 1px solid rgba(255, 255, 255, 0.1);
484
+ padding: 0.75rem 1rem;
485
+ border-radius: var(--radius-md);
486
+ color: var(--foreground);
487
+ }
488
+
489
+ .console {
490
+ background: rgba(0, 0, 0, 0.3);
491
+ border-radius: var(--radius-lg);
492
+ border: 1px solid rgba(255, 255, 255, 0.08);
493
+ min-height: 320px;
494
+ display: flex;
495
+ flex-direction: column;
496
+ }
497
+
498
+ .console__header {
499
+ padding: 1rem 1.25rem;
500
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
501
+ display: flex;
502
+ align-items: center;
503
+ gap: 0.5rem;
504
+ }
505
+
506
+ .console__body {
507
+ flex: 1;
508
+ padding: 1rem 1.25rem;
509
+ overflow: auto;
510
+ font-size: 0.85rem;
511
+ line-height: 1.5;
512
+ }
513
+
514
+ .console-log {
515
+ margin-bottom: 0.5rem;
516
+ }
517
+
518
+ .console-log span {
519
+ color: rgba(255, 255, 255, 0.5);
520
+ margin-right: 0.5rem;
521
+ }
522
+
523
+ .console-log--info {
524
+ color: var(--foreground);
525
+ }
526
+
527
+ .console-log--success {
528
+ color: var(--success);
529
+ }
530
+
531
+ .console-log--warning {
532
+ color: var(--warning);
533
+ }
534
+
535
+ .console-log--danger {
536
+ color: var(--destructive);
537
+ }
538
+
539
+ .console-log--error {
540
+ color: var(--destructive);
541
+ }
542
+
543
+ .seed-grid {
544
+ display: grid;
545
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
546
+ gap: 1.25rem;
547
+ }
548
+
549
+ .seed-card {
550
+ background: rgba(255, 255, 255, 0.02);
551
+ border: 1px solid rgba(255, 255, 255, 0.08);
552
+ border-radius: var(--radius-lg);
553
+ padding: 1.5rem;
554
+ display: flex;
555
+ flex-direction: column;
556
+ gap: 0.75rem;
557
+ }
558
+
559
+ .seed-card__header {
560
+ display: flex;
561
+ justify-content: space-between;
562
+ align-items: center;
563
+ }
564
+
565
+ .seed-card__title {
566
+ font-size: 1.2rem;
567
+ font-weight: 600;
568
+ }
569
+
570
+ .seed-card__description {
571
+ color: var(--muted);
572
+ font-size: 0.9rem;
573
+ }
574
+
575
+ .seed-card__tags {
576
+ display: flex;
577
+ flex-wrap: wrap;
578
+ gap: 0.35rem;
579
+ }
580
+
581
+ .seed-card__tag {
582
+ padding: 0.3rem 0.7rem;
583
+ border-radius: 999px;
584
+ border: 1px solid rgba(255, 255, 255, 0.15);
585
+ font-size: 0.7rem;
586
+ text-transform: uppercase;
587
+ letter-spacing: 0.2em;
588
+ }
589
+
590
+ .seed-card__actions {
591
+ margin-top: auto;
592
+ }
593
+
594
+ .seed-detail {
595
+ display: flex;
596
+ flex-direction: column;
597
+ gap: 1rem;
598
+ }
599
+
600
+ .seed-detail__hero {
601
+ border: 1px solid rgba(255, 255, 255, 0.1);
602
+ border-radius: var(--radius-lg);
603
+ padding: 1.5rem;
604
+ background: rgba(255, 255, 255, 0.03);
605
+ }
606
+
607
+ .seed-detail__title {
608
+ font-size: 1.5rem;
609
+ letter-spacing: 0.3em;
610
+ }
611
+
612
+ .seed-detail__subtitle {
613
+ color: var(--muted);
614
+ font-size: 0.9rem;
615
+ }
616
+
617
+ .seed-detail-form {
618
+ display: grid;
619
+ gap: 1rem;
620
+ }
621
+
622
+ .seed-detail-form .form-actions {
623
+ margin-top: 1rem;
624
+ }
625
+
626
+ @media (max-width: 768px) {
627
+ .page-content {
628
+ padding: 1.5rem;
629
+ }
630
+
631
+ .mode-card,
632
+ .factory-card,
633
+ .panel,
634
+ .seed-card {
635
+ min-height: auto;
636
+ }
637
+ }
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FactorySeeder
4
+ class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+ layout 'factory_seeder/application'
7
+ end
8
+ end