cdd-cli 3.2.2 → 4.0.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 (74) hide show
  1. package/.~lock.ROADMAP.md# +1 -0
  2. package/CHANGELOG.md +51 -0
  3. package/README.es.md +198 -0
  4. package/README.md +81 -23
  5. package/ROADMAP.md +647 -0
  6. package/coverage/clover.xml +400 -519
  7. package/coverage/coverage-final.json +16 -20
  8. package/coverage/lcov-report/ContainerCreationPrompt.jsx.html +400 -0
  9. package/coverage/lcov-report/ControlsHUD.jsx.html +256 -0
  10. package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +31 -13
  11. package/coverage/lcov-report/components/PromptField.jsx.html +4 -4
  12. package/coverage/lcov-report/components/SuggestionPanel.jsx.html +37 -13
  13. package/coverage/lcov-report/components/index.html +14 -14
  14. package/coverage/lcov-report/helpers/constants.js.html +87 -33
  15. package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +40 -40
  16. package/coverage/lcov-report/helpers/dockerHubService.js.html +310 -0
  17. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +1 -1
  18. package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +1 -1
  19. package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +1 -1
  20. package/coverage/lcov-report/helpers/imageNameUtils.js.html +18 -18
  21. package/coverage/lcov-report/helpers/index.html +77 -62
  22. package/coverage/lcov-report/helpers/logger.js.html +60 -60
  23. package/coverage/lcov-report/helpers/safeCall.js.html +14 -14
  24. package/coverage/lcov-report/helpers/validationHelpers.js.html +52 -52
  25. package/coverage/lcov-report/hooks/creation/index.html +19 -19
  26. package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +4 -4
  27. package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +225 -48
  28. package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +5 -5
  29. package/coverage/lcov-report/hooks/debug/index.html +1 -1
  30. package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +7 -7
  31. package/coverage/lcov-report/hooks/index.html +15 -15
  32. package/coverage/lcov-report/hooks/navigation/index.html +1 -1
  33. package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +6 -6
  34. package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +13 -13
  35. package/coverage/lcov-report/hooks/useControls.js.html +82 -40
  36. package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +5 -5
  37. package/coverage/lcov-report/hooks/useExitHandler.js.html +6 -6
  38. package/coverage/lcov-report/index.html +38 -68
  39. package/coverage/lcov.info +742 -981
  40. package/dist/App.js +7 -1
  41. package/dist/components/ContainerCreationPrompt.js +26 -10
  42. package/dist/components/ControlsHUD.js +106 -0
  43. package/dist/components/SuggestionPanel.js +16 -7
  44. package/dist/helpers/constants.js +60 -21
  45. package/dist/helpers/dockerHubService.js +111 -0
  46. package/dist/helpers/logger.js +1 -1
  47. package/dist/hooks/creation/useContainerActions.js +22 -5
  48. package/dist/hooks/creation/useContainerCreation.js +395 -107
  49. package/dist/hooks/useContainerCommandRouter.js +1 -1
  50. package/dist/hooks/useControls.js +23 -7
  51. package/dist/index.js +7 -0
  52. package/package.json +1 -1
  53. package/src/App.jsx +6 -0
  54. package/src/components/ContainerCreationPrompt.jsx +15 -5
  55. package/src/components/ControlsHUD.jsx +66 -0
  56. package/src/components/SuggestionPanel.jsx +10 -2
  57. package/src/helpers/constants.js +38 -20
  58. package/src/helpers/dockerHubService.js +75 -0
  59. package/src/helpers/logger.js +1 -2
  60. package/src/hooks/creation/useContainerActions.js +19 -6
  61. package/src/hooks/creation/useContainerCreation.js +224 -87
  62. package/src/hooks/useContainerCommandRouter.js +1 -1
  63. package/src/hooks/useControls.js +24 -8
  64. package/src/index.js +4 -0
  65. package/test/ContainerCreationPrompt.dom.test.js +245 -0
  66. package/test/ControlsHUD.dom.test.js +125 -0
  67. package/test/SuggestionPanel.dom.test.js +30 -0
  68. package/test/constants.test.js +7 -0
  69. package/test/dockerHubService.test.js +213 -0
  70. package/test/logger.test.js +58 -0
  71. package/test/resolveImageTag.test.js +26 -0
  72. package/test/useContainerCreation.dom.test.js +306 -3
  73. package/test/useContainerCreationHub.dom.test.js +184 -0
  74. package/test/useControls.dom.test.js +212 -6
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">86.4% </span>
26
+ <span class="strong">87.4% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>89/103</span>
28
+ <span class='fraction'>118/135</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">88.63% </span>
33
+ <span class="strong">87.03% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>39/44</span>
35
+ <span class='fraction'>47/54</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">90.9% </span>
40
+ <span class="strong">91.66% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>10/11</span>
42
+ <span class='fraction'>11/12</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">87% </span>
47
+ <span class="strong">88.28% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>87/100</span>
49
+ <span class='fraction'>113/128</span>
50
50
  </div>
51
51
 
52
52
 
@@ -303,7 +303,67 @@
303
303
  <a name='L238'></a><a href='#L238'>238</a>
304
304
  <a name='L239'></a><a href='#L239'>239</a>
305
305
  <a name='L240'></a><a href='#L240'>240</a>
306
- <a name='L241'></a><a href='#L241'>241</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
366
+ <span class="cline-any cline-neutral">&nbsp;</span>
307
367
  <span class="cline-any cline-neutral">&nbsp;</span>
308
368
  <span class="cline-any cline-neutral">&nbsp;</span>
309
369
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -330,38 +390,91 @@
330
390
  <span class="cline-any cline-neutral">&nbsp;</span>
331
391
  <span class="cline-any cline-neutral">&nbsp;</span>
332
392
  <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-yes">165x</span>
334
- <span class="cline-any cline-yes">165x</span>
335
- <span class="cline-any cline-yes">165x</span>
336
- <span class="cline-any cline-yes">165x</span>
337
- <span class="cline-any cline-yes">165x</span>
338
- <span class="cline-any cline-yes">165x</span>
339
- <span class="cline-any cline-yes">165x</span>
393
+ <span class="cline-any cline-yes">204x</span>
394
+ <span class="cline-any cline-yes">204x</span>
395
+ <span class="cline-any cline-yes">204x</span>
396
+ <span class="cline-any cline-yes">204x</span>
397
+ <span class="cline-any cline-yes">204x</span>
398
+ <span class="cline-any cline-yes">204x</span>
399
+ <span class="cline-any cline-yes">204x</span>
340
400
  <span class="cline-any cline-neutral">&nbsp;</span>
341
401
  <span class="cline-any cline-neutral">&nbsp;</span>
342
- <span class="cline-any cline-yes">165x</span>
343
- <span class="cline-any cline-yes">165x</span>
344
- <span class="cline-any cline-yes">165x</span>
402
+ <span class="cline-any cline-yes">204x</span>
403
+ <span class="cline-any cline-yes">204x</span>
404
+ <span class="cline-any cline-yes">204x</span>
345
405
  <span class="cline-any cline-neutral">&nbsp;</span>
346
406
  <span class="cline-any cline-neutral">&nbsp;</span>
407
+ <span class="cline-any cline-yes">204x</span>
408
+ <span class="cline-any cline-yes">204x</span>
347
409
  <span class="cline-any cline-neutral">&nbsp;</span>
410
+ <span class="cline-any cline-yes">204x</span>
348
411
  <span class="cline-any cline-neutral">&nbsp;</span>
349
412
  <span class="cline-any cline-neutral">&nbsp;</span>
350
413
  <span class="cline-any cline-neutral">&nbsp;</span>
351
414
  <span class="cline-any cline-neutral">&nbsp;</span>
352
415
  <span class="cline-any cline-neutral">&nbsp;</span>
353
- <span class="cline-any cline-yes">22x</span>
354
- <span class="cline-any cline-yes">22x</span>
355
- <span class="cline-any cline-yes">22x</span>
356
- <span class="cline-any cline-yes">22x</span>
416
+ <span class="cline-any cline-neutral">&nbsp;</span>
417
+ <span class="cline-any cline-neutral">&nbsp;</span>
418
+ <span class="cline-any cline-neutral">&nbsp;</span>
419
+ <span class="cline-any cline-neutral">&nbsp;</span>
420
+ <span class="cline-any cline-neutral">&nbsp;</span>
421
+ <span class="cline-any cline-yes">28x</span>
422
+ <span class="cline-any cline-yes">28x</span>
423
+ <span class="cline-any cline-yes">28x</span>
424
+ <span class="cline-any cline-yes">28x</span>
425
+ <span class="cline-any cline-neutral">&nbsp;</span>
426
+ <span class="cline-any cline-yes">28x</span>
427
+ <span class="cline-any cline-yes">28x</span>
428
+ <span class="cline-any cline-yes">28x</span>
429
+ <span class="cline-any cline-yes">28x</span>
357
430
  <span class="cline-any cline-yes">1x</span>
358
431
  <span class="cline-any cline-yes">1x</span>
359
432
  <span class="cline-any cline-neutral">&nbsp;</span>
360
- <span class="cline-any cline-yes">21x</span>
361
- <span class="cline-any cline-yes">21x</span>
362
- <span class="cline-any cline-yes">420x</span>
433
+ <span class="cline-any cline-yes">27x</span>
434
+ <span class="cline-any cline-yes">27x</span>
435
+ <span class="cline-any cline-yes">540x</span>
436
+ <span class="cline-any cline-neutral">&nbsp;</span>
437
+ <span class="cline-any cline-yes">27x</span>
438
+ <span class="cline-any cline-neutral">&nbsp;</span>
439
+ <span class="cline-any cline-neutral">&nbsp;</span>
440
+ <span class="cline-any cline-neutral">&nbsp;</span>
441
+ <span class="cline-any cline-neutral">&nbsp;</span>
442
+ <span class="cline-any cline-neutral">&nbsp;</span>
443
+ <span class="cline-any cline-neutral">&nbsp;</span>
444
+ <span class="cline-any cline-neutral">&nbsp;</span>
445
+ <span class="cline-any cline-neutral">&nbsp;</span>
446
+ <span class="cline-any cline-yes">6x</span>
447
+ <span class="cline-any cline-yes">6x</span>
448
+ <span class="cline-any cline-yes">5x</span>
449
+ <span class="cline-any cline-neutral">&nbsp;</span>
450
+ <span class="cline-any cline-neutral">&nbsp;</span>
451
+ <span class="cline-any cline-neutral">&nbsp;</span>
452
+ <span class="cline-any cline-yes">4x</span>
453
+ <span class="cline-any cline-neutral">&nbsp;</span>
454
+ <span class="cline-any cline-yes">4x</span>
455
+ <span class="cline-any cline-yes">4x</span>
456
+ <span class="cline-any cline-neutral">&nbsp;</span>
457
+ <span class="cline-any cline-yes">4x</span>
458
+ <span class="cline-any cline-yes">4x</span>
459
+ <span class="cline-any cline-neutral">&nbsp;</span>
460
+ <span class="cline-any cline-yes">4x</span>
461
+ <span class="cline-any cline-yes">4x</span>
462
+ <span class="cline-any cline-yes">4x</span>
463
+ <span class="cline-any cline-neutral">&nbsp;</span>
464
+ <span class="cline-any cline-yes">4x</span>
465
+ <span class="cline-any cline-yes">4x</span>
466
+ <span class="cline-any cline-neutral">&nbsp;</span>
467
+ <span class="cline-any cline-yes">4x</span>
468
+ <span class="cline-any cline-yes">3x</span>
469
+ <span class="cline-any cline-neutral">&nbsp;</span>
470
+ <span class="cline-any cline-no">&nbsp;</span>
471
+ <span class="cline-any cline-neutral">&nbsp;</span>
472
+ <span class="cline-any cline-no">&nbsp;</span>
473
+ <span class="cline-any cline-neutral">&nbsp;</span>
474
+ <span class="cline-any cline-yes">4x</span>
475
+ <span class="cline-any cline-yes">3x</span>
476
+ <span class="cline-any cline-neutral">&nbsp;</span>
363
477
  <span class="cline-any cline-neutral">&nbsp;</span>
364
- <span class="cline-any cline-yes">21x</span>
365
478
  <span class="cline-any cline-neutral">&nbsp;</span>
366
479
  <span class="cline-any cline-neutral">&nbsp;</span>
367
480
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -401,18 +514,20 @@
401
514
  <span class="cline-any cline-neutral">&nbsp;</span>
402
515
  <span class="cline-any cline-neutral">&nbsp;</span>
403
516
  <span class="cline-any cline-neutral">&nbsp;</span>
404
- <span class="cline-any cline-yes">39x</span>
405
- <span class="cline-any cline-yes">14x</span>
517
+ <span class="cline-any cline-yes">43x</span>
518
+ <span class="cline-any cline-yes">18x</span>
406
519
  <span class="cline-any cline-yes">1x</span>
407
520
  <span class="cline-any cline-yes">1x</span>
408
521
  <span class="cline-any cline-yes">1x</span>
409
522
  <span class="cline-any cline-neutral">&nbsp;</span>
410
- <span class="cline-any cline-yes">13x</span>
411
- <span class="cline-any cline-yes">13x</span>
523
+ <span class="cline-any cline-yes">17x</span>
524
+ <span class="cline-any cline-yes">17x</span>
525
+ <span class="cline-any cline-yes">17x</span>
526
+ <span class="cline-any cline-yes">17x</span>
412
527
  <span class="cline-any cline-neutral">&nbsp;</span>
413
528
  <span class="cline-any cline-neutral">&nbsp;</span>
414
- <span class="cline-any cline-yes">13x</span>
415
- <span class="cline-any cline-yes">13x</span>
529
+ <span class="cline-any cline-yes">17x</span>
530
+ <span class="cline-any cline-yes">17x</span>
416
531
  <span class="cline-any cline-neutral">&nbsp;</span>
417
532
  <span class="cline-any cline-yes">25x</span>
418
533
  <span class="cline-any cline-yes">9x</span>
@@ -505,19 +620,22 @@
505
620
  <span class="cline-any cline-neutral">&nbsp;</span>
506
621
  <span class="cline-any cline-neutral">&nbsp;</span>
507
622
  <span class="cline-any cline-neutral">&nbsp;</span>
508
- <span class="cline-any cline-yes">8x</span>
509
- <span class="cline-any cline-yes">8x</span>
510
- <span class="cline-any cline-yes">8x</span>
511
- <span class="cline-any cline-yes">8x</span>
512
- <span class="cline-any cline-yes">8x</span>
513
- <span class="cline-any cline-yes">8x</span>
514
- <span class="cline-any cline-yes">8x</span>
515
- <span class="cline-any cline-yes">8x</span>
516
- <span class="cline-any cline-yes">8x</span>
517
- <span class="cline-any cline-yes">8x</span>
623
+ <span class="cline-any cline-yes">12x</span>
624
+ <span class="cline-any cline-yes">12x</span>
625
+ <span class="cline-any cline-yes">12x</span>
626
+ <span class="cline-any cline-yes">12x</span>
627
+ <span class="cline-any cline-yes">12x</span>
628
+ <span class="cline-any cline-yes">12x</span>
629
+ <span class="cline-any cline-yes">12x</span>
630
+ <span class="cline-any cline-yes">12x</span>
631
+ <span class="cline-any cline-yes">12x</span>
632
+ <span class="cline-any cline-yes">12x</span>
633
+ <span class="cline-any cline-neutral">&nbsp;</span>
634
+ <span class="cline-any cline-neutral">&nbsp;</span>
635
+ <span class="cline-any cline-yes">204x</span>
636
+ <span class="cline-any cline-neutral">&nbsp;</span>
518
637
  <span class="cline-any cline-neutral">&nbsp;</span>
519
638
  <span class="cline-any cline-neutral">&nbsp;</span>
520
- <span class="cline-any cline-yes">165x</span>
521
639
  <span class="cline-any cline-neutral">&nbsp;</span>
522
640
  <span class="cline-any cline-neutral">&nbsp;</span>
523
641
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -543,13 +661,14 @@
543
661
  <span class="cline-any cline-neutral">&nbsp;</span>
544
662
  <span class="cline-any cline-neutral">&nbsp;</span>
545
663
  <span class="cline-any cline-neutral">&nbsp;</span>
546
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState } from 'react';
664
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState, useRef } from 'react';
547
665
  import {
548
666
  validatePorts,
549
667
  validateEnvVars,
550
668
  } from '../../helpers/validationHelpers.js';
551
- import { IMAGE_PROFILES } from '../../helpers/constants.js';
669
+ import { IMAGE_PROFILES, resolveImageTag } from '../../helpers/constants.js';
552
670
  import { safeCall } from '../../helpers/safeCall.js';
671
+ import { searchDockerHub, formatHubResult } from '../../helpers/dockerHubService.js';
553
672
  &nbsp;
554
673
  const MAX_VISIBLE = 6;
555
674
  &nbsp;
@@ -582,14 +701,27 @@ export function useContainerCreation({
582
701
  const [suggestions, setSuggestions] = useState([]);
583
702
  const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1);
584
703
  const [visibleOffset, setVisibleOffset] = useState(0);
704
+ &nbsp;
705
+ // Docker Hub search state
706
+ const [isSearchingHub, setIsSearchingHub] = useState(false);
707
+ const [hubResults, setHubResults] = useState(null);
708
+ // Tracks active request: { controller: AbortController|null, requestId: number }
709
+ const activeHubRequestRef = useRef({ controller: null, requestId: 0 });
585
710
  &nbsp;
586
711
  /**
587
712
  * Updates the image name input and recalculates autocomplete suggestions.
588
713
  * Resets selectedSuggestionIndex to -1 on every keystroke.
714
+ * Also aborts any in-flight Hub search and clears Hub results.
589
715
  *
590
716
  * @param {string} value - New raw image name typed by user
591
717
  */
592
718
  function updateImageInput(value) {
719
+ // Abort any in-flight Hub search and clear its state
720
+ activeHubRequestRef.current.controller?.abort();
721
+ activeHubRequestRef.current.requestId += 1;
722
+ setIsSearchingHub(false);
723
+ setHubResults(null);
724
+ &nbsp;
593
725
  setImageName(value);
594
726
  setSelectedSuggestionIndex(-1);
595
727
  setVisibleOffset(0);
@@ -603,6 +735,46 @@ export function useContainerCreation({
603
735
  );
604
736
  setSuggestions(matches);
605
737
  }
738
+ &nbsp;
739
+ /**
740
+ * Triggers a Docker Hub search for the current imageName.
741
+ * Guards: imageName must be non-empty; no concurrent search allowed.
742
+ * Uses AbortController + requestId to handle race conditions.
743
+ */
744
+ async function triggerHubSearch() {
745
+ const query = imageName.trim();
746
+ if (!query) return;
747
+ if (isSearchingHub) return;
748
+ &nbsp;
749
+ // Abort previous request (should already be aborted from updateImageInput,
750
+ // but guard here too)
751
+ activeHubRequestRef.current.controller?.abort();
752
+ &nbsp;
753
+ const requestId = activeHubRequestRef.current.requestId + 1;
754
+ activeHubRequestRef.current.requestId = requestId;
755
+ &nbsp;
756
+ const controller = new AbortController();
757
+ activeHubRequestRef.current.controller = controller;
758
+ &nbsp;
759
+ setIsSearchingHub(true);
760
+ setSelectedSuggestionIndex(-1);
761
+ setVisibleOffset(0);
762
+ &nbsp;
763
+ try {
764
+ const results = await searchDockerHub(query, { signal: controller.signal });
765
+ // Ignore stale responses
766
+ if (activeHubRequestRef.current.requestId !== requestId) return;
767
+ setHubResults(results.map(formatHubResult));
768
+ } catch (err) {
769
+ <span class="cstat-no" title="statement not covered" > if (activeHubRequestRef.current.requestId !== requestId) <span class="cstat-no" title="statement not covered" >return;</span></span>
770
+ // Silence AbortError; for all other errors fall back to static suggestions
771
+ <span class="cstat-no" title="statement not covered" > setHubResults(null);</span>
772
+ } finally {
773
+ if (activeHubRequestRef.current.requestId === requestId) {
774
+ setIsSearchingHub(false);
775
+ }
776
+ }
777
+ }
606
778
  &nbsp;
607
779
  /**
608
780
  * Moves the suggestion selection up (-1) or down (+1).
@@ -631,7 +803,7 @@ export function useContainerCreation({
631
803
  function applyFocusedSuggestion() {
632
804
  <span class="missing-if-branch" title="if path not taken" >I</span>if (selectedSuggestionIndex &lt; 0 || selectedSuggestionIndex &gt;= suggestions.length) <span class="cstat-no" title="statement not covered" >return;</span>
633
805
  const chosen = suggestions[selectedSuggestionIndex];
634
- setImageName(chosen);
806
+ setImageName(resolveImageTag(chosen, imageProfiles));
635
807
  setSuggestions([]);
636
808
  setSelectedSuggestionIndex(-1);
637
809
  setVisibleOffset(0);
@@ -647,6 +819,8 @@ export function useContainerCreation({
647
819
  setMessageColor('red');
648
820
  return;
649
821
  }
822
+ const resolved = resolveImageTag(imageName, imageProfiles);
823
+ setImageName(resolved);
650
824
  setStep(1);
651
825
  setMessage(
652
826
  'Optional: Enter container name or leave empty and press Enter'
@@ -775,7 +949,10 @@ export function useContainerCreation({
775
949
  suggestions,
776
950
  selectedSuggestionIndex,
777
951
  visibleOffset,
952
+ isSearchingHub,
953
+ hubResults,
778
954
  updateImageInput,
955
+ triggerHubSearch,
779
956
  moveSuggestionSelection,
780
957
  applyFocusedSuggestion,
781
958
  nextStep,
@@ -790,7 +967,7 @@ export function useContainerCreation({
790
967
  <div class='footer quiet pad2 space-top1 center small'>
791
968
  Code coverage generated by
792
969
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
793
- at 2026-04-27T20:17:25.625Z
970
+ at 2026-04-27T22:13:21.150Z
794
971
  </div>
795
972
  <script src="../../prettify.js"></script>
796
973
  <script>
@@ -131,9 +131,9 @@
131
131
  <span class="cline-any cline-neutral">&nbsp;</span>
132
132
  <span class="cline-any cline-neutral">&nbsp;</span>
133
133
  <span class="cline-any cline-neutral">&nbsp;</span>
134
- <span class="cline-any cline-yes">84x</span>
135
- <span class="cline-any cline-yes">84x</span>
136
- <span class="cline-any cline-yes">84x</span>
134
+ <span class="cline-any cline-yes">96x</span>
135
+ <span class="cline-any cline-yes">96x</span>
136
+ <span class="cline-any cline-yes">96x</span>
137
137
  <span class="cline-any cline-neutral">&nbsp;</span>
138
138
  <span class="cline-any cline-neutral">&nbsp;</span>
139
139
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -155,7 +155,7 @@
155
155
  <span class="cline-any cline-neutral">&nbsp;</span>
156
156
  <span class="cline-any cline-neutral">&nbsp;</span>
157
157
  <span class="cline-any cline-neutral">&nbsp;</span>
158
- <span class="cline-any cline-yes">84x</span>
158
+ <span class="cline-any cline-yes">96x</span>
159
159
  <span class="cline-any cline-neutral">&nbsp;</span>
160
160
  <span class="cline-any cline-neutral">&nbsp;</span>
161
161
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -223,7 +223,7 @@ export function useLogsViewer() {
223
223
  <div class='footer quiet pad2 space-top1 center small'>
224
224
  Code coverage generated by
225
225
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
226
- at 2026-04-27T20:17:25.625Z
226
+ at 2026-04-27T22:13:21.150Z
227
227
  </div>
228
228
  <script src="../../prettify.js"></script>
229
229
  <script>
@@ -101,7 +101,7 @@
101
101
  <div class='footer quiet pad2 space-top1 center small'>
102
102
  Code coverage generated by
103
103
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2026-04-27T20:17:25.625Z
104
+ at 2026-04-27T22:13:21.150Z
105
105
  </div>
106
106
  <script src="../../prettify.js"></script>
107
107
  <script>
@@ -101,11 +101,11 @@
101
101
  <span class="cline-any cline-neutral">&nbsp;</span>
102
102
  <span class="cline-any cline-neutral">&nbsp;</span>
103
103
  <span class="cline-any cline-neutral">&nbsp;</span>
104
- <span class="cline-any cline-yes">84x</span>
105
- <span class="cline-any cline-yes">84x</span>
104
+ <span class="cline-any cline-yes">96x</span>
105
+ <span class="cline-any cline-yes">96x</span>
106
106
  <span class="cline-any cline-neutral">&nbsp;</span>
107
- <span class="cline-any cline-yes">84x</span>
108
- <span class="cline-any cline-yes">16x</span>
107
+ <span class="cline-any cline-yes">96x</span>
108
+ <span class="cline-any cline-yes">20x</span>
109
109
  <span class="cline-any cline-no">&nbsp;</span>
110
110
  <span class="cline-any cline-no">&nbsp;</span>
111
111
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -126,10 +126,10 @@
126
126
  <span class="cline-any cline-no">&nbsp;</span>
127
127
  <span class="cline-any cline-neutral">&nbsp;</span>
128
128
  <span class="cline-any cline-neutral">&nbsp;</span>
129
- <span class="cline-any cline-yes">16x</span>
129
+ <span class="cline-any cline-yes">20x</span>
130
130
  <span class="cline-any cline-neutral">&nbsp;</span>
131
131
  <span class="cline-any cline-neutral">&nbsp;</span>
132
- <span class="cline-any cline-yes">84x</span>
132
+ <span class="cline-any cline-yes">96x</span>
133
133
  <span class="cline-any cline-neutral">&nbsp;</span>
134
134
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState, useEffect } from 'react';
135
135
  import { logger } from '../../helpers/logger.js';
@@ -172,7 +172,7 @@ export function useDebugLogs() {
172
172
  <div class='footer quiet pad2 space-top1 center small'>
173
173
  Code coverage generated by
174
174
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
175
- at 2026-04-27T20:17:25.625Z
175
+ at 2026-04-27T22:13:21.150Z
176
176
  </div>
177
177
  <script src="../../prettify.js"></script>
178
178
  <script>
@@ -23,16 +23,16 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">46.59% </span>
26
+ <span class="strong">48.63% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>82/176</span>
28
+ <span class='fraction'>89/183</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">43.8% </span>
33
+ <span class="strong">50% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>53/121</span>
35
+ <span class='fraction'>68/136</span>
36
36
  </div>
37
37
 
38
38
 
@@ -44,9 +44,9 @@
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">48.8% </span>
47
+ <span class="strong">50.85% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>82/168</span>
49
+ <span class='fraction'>89/175</span>
50
50
  </div>
51
51
 
52
52
 
@@ -95,17 +95,17 @@
95
95
 
96
96
  <tr>
97
97
  <td class="file medium" data-value="useControls.js"><a href="useControls.js.html">useControls.js</a></td>
98
- <td data-value="56.48" class="pic medium">
99
- <div class="chart"><div class="cover-fill" style="width: 56%"></div><div class="cover-empty" style="width: 44%"></div></div>
98
+ <td data-value="59.13" class="pic medium">
99
+ <div class="chart"><div class="cover-fill" style="width: 59%"></div><div class="cover-empty" style="width: 41%"></div></div>
100
100
  </td>
101
- <td data-value="56.48" class="pct medium">56.48%</td>
102
- <td data-value="108" class="abs medium">61/108</td>
103
- <td data-value="61.33" class="pct medium">61.33%</td>
104
- <td data-value="75" class="abs medium">46/75</td>
101
+ <td data-value="59.13" class="pct medium">59.13%</td>
102
+ <td data-value="115" class="abs medium">68/115</td>
103
+ <td data-value="67.77" class="pct medium">67.77%</td>
104
+ <td data-value="90" class="abs medium">61/90</td>
105
105
  <td data-value="26.08" class="pct low">26.08%</td>
106
106
  <td data-value="23" class="abs low">6/23</td>
107
- <td data-value="60.39" class="pct medium">60.39%</td>
108
- <td data-value="101" class="abs medium">61/101</td>
107
+ <td data-value="62.96" class="pct medium">62.96%</td>
108
+ <td data-value="108" class="abs medium">68/108</td>
109
109
  </tr>
110
110
 
111
111
  <tr>
@@ -146,7 +146,7 @@
146
146
  <div class='footer quiet pad2 space-top1 center small'>
147
147
  Code coverage generated by
148
148
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
149
- at 2026-04-27T20:17:25.625Z
149
+ at 2026-04-27T22:13:21.150Z
150
150
  </div>
151
151
  <script src="../prettify.js"></script>
152
152
  <script>
@@ -101,7 +101,7 @@
101
101
  <div class='footer quiet pad2 space-top1 center small'>
102
102
  Code coverage generated by
103
103
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2026-04-27T20:17:25.625Z
104
+ at 2026-04-27T22:13:21.150Z
105
105
  </div>
106
106
  <script src="../../prettify.js"></script>
107
107
  <script>
@@ -94,12 +94,12 @@
94
94
  <a name='L29'></a><a href='#L29'>29</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
95
95
  <span class="cline-any cline-neutral">&nbsp;</span>
96
96
  <span class="cline-any cline-neutral">&nbsp;</span>
97
- <span class="cline-any cline-yes">84x</span>
97
+ <span class="cline-any cline-yes">96x</span>
98
98
  <span class="cline-any cline-neutral">&nbsp;</span>
99
- <span class="cline-any cline-yes">84x</span>
99
+ <span class="cline-any cline-yes">96x</span>
100
100
  <span class="cline-any cline-neutral">&nbsp;</span>
101
- <span class="cline-any cline-yes">8x</span>
102
- <span class="cline-any cline-yes">8x</span>
101
+ <span class="cline-any cline-yes">12x</span>
102
+ <span class="cline-any cline-yes">12x</span>
103
103
  <span class="cline-any cline-neutral">&nbsp;</span>
104
104
  <span class="cline-any cline-neutral">&nbsp;</span>
105
105
  <span class="cline-any cline-no">&nbsp;</span>
@@ -117,7 +117,7 @@
117
117
  <span class="cline-any cline-neutral">&nbsp;</span>
118
118
  <span class="cline-any cline-neutral">&nbsp;</span>
119
119
  <span class="cline-any cline-neutral">&nbsp;</span>
120
- <span class="cline-any cline-yes">84x</span>
120
+ <span class="cline-any cline-yes">96x</span>
121
121
  <span class="cline-any cline-neutral">&nbsp;</span>
122
122
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { useState, useCallback } from 'react';
123
123
  &nbsp;
@@ -154,7 +154,7 @@ export function useContainerSelection(total) {
154
154
  <div class='footer quiet pad2 space-top1 center small'>
155
155
  Code coverage generated by
156
156
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
157
- at 2026-04-27T20:17:25.625Z
157
+ at 2026-04-27T22:13:21.150Z
158
158
  </div>
159
159
  <script src="../../prettify.js"></script>
160
160
  <script>