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
@@ -0,0 +1,400 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for ContainerCreationPrompt.jsx</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="prettify.css" />
9
+ <link rel="stylesheet" href="base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="index.html">All files</a> ContainerCreationPrompt.jsx</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>8/8</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">76.47% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>13/17</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>1/1</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>8/8</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
172
+ <span class="cline-any cline-neutral">&nbsp;</span>
173
+ <span class="cline-any cline-neutral">&nbsp;</span>
174
+ <span class="cline-any cline-neutral">&nbsp;</span>
175
+ <span class="cline-any cline-neutral">&nbsp;</span>
176
+ <span class="cline-any cline-neutral">&nbsp;</span>
177
+ <span class="cline-any cline-neutral">&nbsp;</span>
178
+ <span class="cline-any cline-neutral">&nbsp;</span>
179
+ <span class="cline-any cline-neutral">&nbsp;</span>
180
+ <span class="cline-any cline-neutral">&nbsp;</span>
181
+ <span class="cline-any cline-neutral">&nbsp;</span>
182
+ <span class="cline-any cline-neutral">&nbsp;</span>
183
+ <span class="cline-any cline-neutral">&nbsp;</span>
184
+ <span class="cline-any cline-neutral">&nbsp;</span>
185
+ <span class="cline-any cline-neutral">&nbsp;</span>
186
+ <span class="cline-any cline-neutral">&nbsp;</span>
187
+ <span class="cline-any cline-neutral">&nbsp;</span>
188
+ <span class="cline-any cline-neutral">&nbsp;</span>
189
+ <span class="cline-any cline-neutral">&nbsp;</span>
190
+ <span class="cline-any cline-neutral">&nbsp;</span>
191
+ <span class="cline-any cline-neutral">&nbsp;</span>
192
+ <span class="cline-any cline-neutral">&nbsp;</span>
193
+ <span class="cline-any cline-neutral">&nbsp;</span>
194
+ <span class="cline-any cline-neutral">&nbsp;</span>
195
+ <span class="cline-any cline-neutral">&nbsp;</span>
196
+ <span class="cline-any cline-neutral">&nbsp;</span>
197
+ <span class="cline-any cline-neutral">&nbsp;</span>
198
+ <span class="cline-any cline-neutral">&nbsp;</span>
199
+ <span class="cline-any cline-neutral">&nbsp;</span>
200
+ <span class="cline-any cline-neutral">&nbsp;</span>
201
+ <span class="cline-any cline-neutral">&nbsp;</span>
202
+ <span class="cline-any cline-neutral">&nbsp;</span>
203
+ <span class="cline-any cline-neutral">&nbsp;</span>
204
+ <span class="cline-any cline-neutral">&nbsp;</span>
205
+ <span class="cline-any cline-neutral">&nbsp;</span>
206
+ <span class="cline-any cline-neutral">&nbsp;</span>
207
+ <span class="cline-any cline-neutral">&nbsp;</span>
208
+ <span class="cline-any cline-neutral">&nbsp;</span>
209
+ <span class="cline-any cline-neutral">&nbsp;</span>
210
+ <span class="cline-any cline-yes">12x</span>
211
+ <span class="cline-any cline-yes">12x</span>
212
+ <span class="cline-any cline-neutral">&nbsp;</span>
213
+ <span class="cline-any cline-neutral">&nbsp;</span>
214
+ <span class="cline-any cline-neutral">&nbsp;</span>
215
+ <span class="cline-any cline-neutral">&nbsp;</span>
216
+ <span class="cline-any cline-neutral">&nbsp;</span>
217
+ <span class="cline-any cline-neutral">&nbsp;</span>
218
+ <span class="cline-any cline-neutral">&nbsp;</span>
219
+ <span class="cline-any cline-neutral">&nbsp;</span>
220
+ <span class="cline-any cline-neutral">&nbsp;</span>
221
+ <span class="cline-any cline-neutral">&nbsp;</span>
222
+ <span class="cline-any cline-neutral">&nbsp;</span>
223
+ <span class="cline-any cline-neutral">&nbsp;</span>
224
+ <span class="cline-any cline-neutral">&nbsp;</span>
225
+ <span class="cline-any cline-neutral">&nbsp;</span>
226
+ <span class="cline-any cline-neutral">&nbsp;</span>
227
+ <span class="cline-any cline-neutral">&nbsp;</span>
228
+ <span class="cline-any cline-neutral">&nbsp;</span>
229
+ <span class="cline-any cline-neutral">&nbsp;</span>
230
+ <span class="cline-any cline-neutral">&nbsp;</span>
231
+ <span class="cline-any cline-neutral">&nbsp;</span>
232
+ <span class="cline-any cline-neutral">&nbsp;</span>
233
+ <span class="cline-any cline-yes">12x</span>
234
+ <span class="cline-any cline-yes">12x</span>
235
+ <span class="cline-any cline-yes">12x</span>
236
+ <span class="cline-any cline-yes">12x</span>
237
+ <span class="cline-any cline-yes">12x</span>
238
+ <span class="cline-any cline-neutral">&nbsp;</span>
239
+ <span class="cline-any cline-neutral">&nbsp;</span>
240
+ <span class="cline-any cline-neutral">&nbsp;</span>
241
+ <span class="cline-any cline-neutral">&nbsp;</span>
242
+ <span class="cline-any cline-neutral">&nbsp;</span>
243
+ <span class="cline-any cline-neutral">&nbsp;</span>
244
+ <span class="cline-any cline-neutral">&nbsp;</span>
245
+ <span class="cline-any cline-neutral">&nbsp;</span>
246
+ <span class="cline-any cline-neutral">&nbsp;</span>
247
+ <span class="cline-any cline-neutral">&nbsp;</span>
248
+ <span class="cline-any cline-neutral">&nbsp;</span>
249
+ <span class="cline-any cline-neutral">&nbsp;</span>
250
+ <span class="cline-any cline-neutral">&nbsp;</span>
251
+ <span class="cline-any cline-neutral">&nbsp;</span>
252
+ <span class="cline-any cline-neutral">&nbsp;</span>
253
+ <span class="cline-any cline-neutral">&nbsp;</span>
254
+ <span class="cline-any cline-neutral">&nbsp;</span>
255
+ <span class="cline-any cline-neutral">&nbsp;</span>
256
+ <span class="cline-any cline-neutral">&nbsp;</span>
257
+ <span class="cline-any cline-neutral">&nbsp;</span>
258
+ <span class="cline-any cline-neutral">&nbsp;</span>
259
+ <span class="cline-any cline-yes">1x</span>
260
+ <span class="cline-any cline-neutral">&nbsp;</span>
261
+ <span class="cline-any cline-neutral">&nbsp;</span>
262
+ <span class="cline-any cline-neutral">&nbsp;</span>
263
+ <span class="cline-any cline-neutral">&nbsp;</span>
264
+ <span class="cline-any cline-neutral">&nbsp;</span>
265
+ <span class="cline-any cline-neutral">&nbsp;</span>
266
+ <span class="cline-any cline-neutral">&nbsp;</span>
267
+ <span class="cline-any cline-neutral">&nbsp;</span>
268
+ <span class="cline-any cline-neutral">&nbsp;</span>
269
+ <span class="cline-any cline-neutral">&nbsp;</span>
270
+ <span class="cline-any cline-neutral">&nbsp;</span>
271
+ <span class="cline-any cline-neutral">&nbsp;</span>
272
+ <span class="cline-any cline-neutral">&nbsp;</span>
273
+ <span class="cline-any cline-neutral">&nbsp;</span>
274
+ <span class="cline-any cline-neutral">&nbsp;</span>
275
+ <span class="cline-any cline-neutral">&nbsp;</span>
276
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import React from 'react';
277
+ import { Box, Text } from 'ink';
278
+ import { PromptField, PromptMessage } from './PromptField.jsx';
279
+ import { SuggestionPanel } from './SuggestionPanel.jsx';
280
+ import { ControlsHUD } from './ControlsHUD.jsx';
281
+ import PropTypes from 'prop-types';
282
+ &nbsp;
283
+ /**
284
+ * Prompt UI shown when creating a new container.
285
+ * Presents a step-by-step form (image, name, ports, env) and displays
286
+ * a contextual message provided by the creation hook.
287
+ *
288
+ * @param {Object} props
289
+ * @param {number} props.step - Current step index (0..3)
290
+ * @param {string} props.imageName - Value for the image name field
291
+ * @param {string} props.containerName - Value for the container name field
292
+ * @param {string} props.portInput - Value for the ports input field
293
+ * @param {string} props.envInput - Value for the environment variables field
294
+ * @param {string} props.message - Contextual message to display (errors/hints)
295
+ * @param {string} props.messageColor - Color for the contextual message
296
+ * @param {string[]} [props.suggestions] - Autocomplete suggestions (shown only on step 0)
297
+ * @param {number} [props.selectedSuggestionIndex] - Currently focused suggestion index
298
+ * @param {number} [props.visibleOffset] - First visible suggestion offset
299
+ * @returns {JSX.Element}
300
+ */
301
+ export default function ContainerCreationPrompt(props) {
302
+ const {
303
+ step,
304
+ imageName,
305
+ containerName,
306
+ portInput,
307
+ envInput,
308
+ message,
309
+ messageColor,
310
+ suggestions = <span class="branch-0 cbranch-no" title="branch not covered" >[],</span>
311
+ selectedSuggestionIndex = <span class="branch-0 cbranch-no" title="branch not covered" >-1,</span>
312
+ visibleOffset = <span class="branch-0 cbranch-no" title="branch not covered" >0,</span>
313
+ hubResults = null,
314
+ isSearchingHub = false,
315
+ } = props;
316
+ const prompts = [
317
+ {
318
+ label: 'Name of the image to create (e.g., nginx:1.27-alpine):',
319
+ value: imageName,
320
+ required: true,
321
+ },
322
+ {
323
+ label: 'Name of the container (optional):',
324
+ value: containerName,
325
+ required: false,
326
+ },
327
+ {
328
+ label: 'Ports (optional, format 8080:80,443:443):',
329
+ value: portInput,
330
+ required: false,
331
+ },
332
+ {
333
+ label: 'Environment variables (optional, format VAR1=val1,VAR2=val2):',
334
+ value: envInput,
335
+ required: false,
336
+ },
337
+ ];
338
+ const { label, value, required } = prompts[step] || <span class="branch-1 cbranch-no" title="branch not covered" >{};</span>
339
+ const activeItems = hubResults ?? suggestions;
340
+ const showSuggestions = step === 0 &amp;&amp; (isSearchingHub || activeItems.length &gt; 0);
341
+ const hasSuggestions = (suggestions?.length &gt; 0) || (hubResults?.length &gt; 0) || isSearchingHub;
342
+ return (
343
+ &lt;Box
344
+ flexDirection="column"
345
+ borderStyle="round"
346
+ borderColor="yellow"
347
+ padding={1}
348
+ &gt;
349
+ &lt;PromptField label={label} value={value} required={required} /&gt;
350
+ {showSuggestions &amp;&amp; (
351
+ &lt;SuggestionPanel
352
+ items={activeItems}
353
+ selectedIndex={selectedSuggestionIndex}
354
+ visibleOffset={visibleOffset}
355
+ isLoading={isSearchingHub}
356
+ /&gt;
357
+ )}
358
+ &lt;PromptMessage message={message} color={messageColor} /&gt;
359
+ &lt;ControlsHUD step={step} hasSuggestions={hasSuggestions} isSearchingHub={isSearchingHub} /&gt;
360
+ &lt;/Box&gt;
361
+ );
362
+ }
363
+ &nbsp;
364
+ ContainerCreationPrompt.propTypes = {
365
+ step: PropTypes.number.isRequired,
366
+ imageName: PropTypes.string,
367
+ containerName: PropTypes.string,
368
+ portInput: PropTypes.string,
369
+ envInput: PropTypes.string,
370
+ message: PropTypes.string,
371
+ messageColor: PropTypes.string,
372
+ suggestions: PropTypes.arrayOf(PropTypes.string),
373
+ selectedSuggestionIndex: PropTypes.number,
374
+ visibleOffset: PropTypes.number,
375
+ hubResults: PropTypes.arrayOf(PropTypes.string),
376
+ isSearchingHub: PropTypes.bool,
377
+ };
378
+ &nbsp;
379
+ // Named export for test compatibility with jest ESM interop
380
+ export { ContainerCreationPrompt };
381
+ &nbsp;</pre></td></tr></table></pre>
382
+
383
+ <div class='push'></div><!-- for sticky footer -->
384
+ </div><!-- /wrapper -->
385
+ <div class='footer quiet pad2 space-top1 center small'>
386
+ Code coverage generated by
387
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
388
+ at 2026-04-27T22:13:17.603Z
389
+ </div>
390
+ <script src="prettify.js"></script>
391
+ <script>
392
+ window.onload = function () {
393
+ prettyPrint();
394
+ };
395
+ </script>
396
+ <script src="sorter.js"></script>
397
+ <script src="block-navigation.js"></script>
398
+ </body>
399
+ </html>
400
+
@@ -0,0 +1,256 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for ControlsHUD.jsx</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="prettify.css" />
9
+ <link rel="stylesheet" href="base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="index.html">All files</a> ControlsHUD.jsx</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>14/14</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">75% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>6/8</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>3/3</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>13/13</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
124
+ <span class="cline-any cline-neutral">&nbsp;</span>
125
+ <span class="cline-any cline-neutral">&nbsp;</span>
126
+ <span class="cline-any cline-neutral">&nbsp;</span>
127
+ <span class="cline-any cline-neutral">&nbsp;</span>
128
+ <span class="cline-any cline-neutral">&nbsp;</span>
129
+ <span class="cline-any cline-neutral">&nbsp;</span>
130
+ <span class="cline-any cline-neutral">&nbsp;</span>
131
+ <span class="cline-any cline-neutral">&nbsp;</span>
132
+ <span class="cline-any cline-neutral">&nbsp;</span>
133
+ <span class="cline-any cline-neutral">&nbsp;</span>
134
+ <span class="cline-any cline-neutral">&nbsp;</span>
135
+ <span class="cline-any cline-yes">21x</span>
136
+ <span class="cline-any cline-yes">15x</span>
137
+ <span class="cline-any cline-yes">8x</span>
138
+ <span class="cline-any cline-neutral">&nbsp;</span>
139
+ <span class="cline-any cline-neutral">&nbsp;</span>
140
+ <span class="cline-any cline-neutral">&nbsp;</span>
141
+ <span class="cline-any cline-neutral">&nbsp;</span>
142
+ <span class="cline-any cline-neutral">&nbsp;</span>
143
+ <span class="cline-any cline-yes">7x</span>
144
+ <span class="cline-any cline-yes">7x</span>
145
+ <span class="cline-any cline-yes">7x</span>
146
+ <span class="cline-any cline-yes">7x</span>
147
+ <span class="cline-any cline-yes">7x</span>
148
+ <span class="cline-any cline-yes">7x</span>
149
+ <span class="cline-any cline-neutral">&nbsp;</span>
150
+ <span class="cline-any cline-yes">6x</span>
151
+ <span class="cline-any cline-neutral">&nbsp;</span>
152
+ <span class="cline-any cline-neutral">&nbsp;</span>
153
+ <span class="cline-any cline-neutral">&nbsp;</span>
154
+ <span class="cline-any cline-neutral">&nbsp;</span>
155
+ <span class="cline-any cline-neutral">&nbsp;</span>
156
+ <span class="cline-any cline-neutral">&nbsp;</span>
157
+ <span class="cline-any cline-neutral">&nbsp;</span>
158
+ <span class="cline-any cline-neutral">&nbsp;</span>
159
+ <span class="cline-any cline-neutral">&nbsp;</span>
160
+ <span class="cline-any cline-neutral">&nbsp;</span>
161
+ <span class="cline-any cline-neutral">&nbsp;</span>
162
+ <span class="cline-any cline-neutral">&nbsp;</span>
163
+ <span class="cline-any cline-neutral">&nbsp;</span>
164
+ <span class="cline-any cline-neutral">&nbsp;</span>
165
+ <span class="cline-any cline-yes">15x</span>
166
+ <span class="cline-any cline-yes">15x</span>
167
+ <span class="cline-any cline-neutral">&nbsp;</span>
168
+ <span class="cline-any cline-neutral">&nbsp;</span>
169
+ <span class="cline-any cline-yes">47x</span>
170
+ <span class="cline-any cline-neutral">&nbsp;</span>
171
+ <span class="cline-any cline-neutral">&nbsp;</span>
172
+ <span class="cline-any cline-neutral">&nbsp;</span>
173
+ <span class="cline-any cline-neutral">&nbsp;</span>
174
+ <span class="cline-any cline-neutral">&nbsp;</span>
175
+ <span class="cline-any cline-neutral">&nbsp;</span>
176
+ <span class="cline-any cline-neutral">&nbsp;</span>
177
+ <span class="cline-any cline-neutral">&nbsp;</span>
178
+ <span class="cline-any cline-neutral">&nbsp;</span>
179
+ <span class="cline-any cline-neutral">&nbsp;</span>
180
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import React from 'react';
181
+ import { Box, Text } from 'ink';
182
+ &nbsp;
183
+ /**
184
+ * Returns the contextual keyboard hints for the current wizard state.
185
+ *
186
+ * @param {number} step - Current wizard step (0-3)
187
+ * @param {boolean} hasSuggestions - Whether suggestions/hub results are visible
188
+ * @param {boolean} isSearchingHub - Whether a Hub search is in progress
189
+ * @returns {{ key: string, label: string }[]}
190
+ */
191
+ function getHints(step, hasSuggestions, isSearchingHub) {
192
+ if (step === 0) {
193
+ if (hasSuggestions) {
194
+ return [
195
+ { key: '↑↓', label: 'Navigate' },
196
+ { key: 'Enter', label: 'Select' },
197
+ { key: 'Esc', label: 'Cancel' },
198
+ ];
199
+ }
200
+ const hints = [];
201
+ if (!isSearchingHub) hints.push({ key: 'Tab', label: 'Search Hub' });
202
+ hints.push({ key: '↑↓', label: 'Browse' });
203
+ hints.push({ key: 'Enter', label: 'Confirm' });
204
+ hints.push({ key: 'Esc', label: 'Cancel' });
205
+ return hints;
206
+ }
207
+ return [
208
+ { key: 'Enter', label: 'Continue' },
209
+ { key: 'Esc', label: 'Cancel' },
210
+ ];
211
+ }
212
+ &nbsp;
213
+ /**
214
+ * Displays a row of contextual keyboard shortcut hints for the active wizard step.
215
+ *
216
+ * @param {Object} props
217
+ * @param {number} props.step - Current wizard step
218
+ * @param {boolean} [props.hasSuggestions=false] - Whether suggestions/hub results are visible
219
+ * @param {boolean} [props.isSearchingHub=false] - Whether a Hub search is in progress
220
+ */
221
+ function ControlsHUD({ step, hasSuggestions = <span class="branch-0 cbranch-no" title="branch not covered" >false,</span> isSearchingHub = <span class="branch-0 cbranch-no" title="branch not covered" >false </span>}) {
222
+ const hints = getHints(step, hasSuggestions, isSearchingHub);
223
+ return (
224
+ &lt;Box flexDirection="row" columnGap={2}&gt;
225
+ {hints.map(({ key, label }) =&gt; (
226
+ &lt;Box key={key}&gt;
227
+ &lt;Text color="cyan"&gt;[{key}]&lt;/Text&gt;
228
+ &lt;Text dimColor&gt; {label}&lt;/Text&gt;
229
+ &lt;/Box&gt;
230
+ ))}
231
+ &lt;/Box&gt;
232
+ );
233
+ }
234
+ &nbsp;
235
+ export default ControlsHUD;
236
+ export { getHints, ControlsHUD };
237
+ &nbsp;</pre></td></tr></table></pre>
238
+
239
+ <div class='push'></div><!-- for sticky footer -->
240
+ </div><!-- /wrapper -->
241
+ <div class='footer quiet pad2 space-top1 center small'>
242
+ Code coverage generated by
243
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
244
+ at 2026-04-27T22:13:17.603Z
245
+ </div>
246
+ <script src="prettify.js"></script>
247
+ <script>
248
+ window.onload = function () {
249
+ prettyPrint();
250
+ };
251
+ </script>
252
+ <script src="sorter.js"></script>
253
+ <script src="block-navigation.js"></script>
254
+ </body>
255
+ </html>
256
+