@navios/commander-tui 1.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 (348) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +275 -0
  3. package/coverage/__tests__/utils/factories.ts.html +1147 -0
  4. package/coverage/__tests__/utils/index.html +131 -0
  5. package/coverage/__tests__/utils/render-utils.tsx.html +202 -0
  6. package/coverage/base.css +224 -0
  7. package/coverage/block-navigation.js +87 -0
  8. package/coverage/clover.xml +959 -0
  9. package/coverage/components/filter/filter_bar.tsx.html +322 -0
  10. package/coverage/components/filter/index.html +116 -0
  11. package/coverage/components/log/index.html +131 -0
  12. package/coverage/components/log/index.ts.html +88 -0
  13. package/coverage/components/log/log_message.tsx.html +391 -0
  14. package/coverage/components/prompt/index.html +116 -0
  15. package/coverage/components/prompt/prompt_renderer.tsx.html +1123 -0
  16. package/coverage/components/screen/index.html +131 -0
  17. package/coverage/components/screen/loading_message.tsx.html +217 -0
  18. package/coverage/components/screen/progress_message.tsx.html +265 -0
  19. package/coverage/components/sidebar/index.html +146 -0
  20. package/coverage/components/sidebar/sidebar.tsx.html +391 -0
  21. package/coverage/components/sidebar/sidebar_item.tsx.html +235 -0
  22. package/coverage/components/sidebar/sidebar_separator.tsx.html +124 -0
  23. package/coverage/context/index.html +131 -0
  24. package/coverage/context/index.ts.html +88 -0
  25. package/coverage/context/logger_context.tsx.html +412 -0
  26. package/coverage/coverage-final.json +55 -0
  27. package/coverage/favicon.png +0 -0
  28. package/coverage/filter/filter_engine.ts.html +424 -0
  29. package/coverage/filter/index.html +116 -0
  30. package/coverage/hooks/index.html +131 -0
  31. package/coverage/hooks/index.ts.html +88 -0
  32. package/coverage/hooks/use_theme.ts.html +121 -0
  33. package/coverage/index.html +356 -0
  34. package/coverage/keyboard/index.html +116 -0
  35. package/coverage/keyboard/keyboard_manager.ts.html +784 -0
  36. package/coverage/prettify.css +1 -0
  37. package/coverage/prettify.js +2 -0
  38. package/coverage/schemas/index.html +161 -0
  39. package/coverage/schemas/index.ts.html +94 -0
  40. package/coverage/schemas/logger-options.ts.html +124 -0
  41. package/coverage/schemas/prompt-options.ts.html +112 -0
  42. package/coverage/schemas/screen-options.ts.html +127 -0
  43. package/coverage/services/index.html +146 -0
  44. package/coverage/services/logger.ts.html +1192 -0
  45. package/coverage/services/prompt.ts.html +568 -0
  46. package/coverage/services/screen.ts.html +1804 -0
  47. package/coverage/sort-arrow-sprite.png +0 -0
  48. package/coverage/sorter.js +210 -0
  49. package/coverage/themes/dark.ts.html +604 -0
  50. package/coverage/themes/high-contrast.ts.html +619 -0
  51. package/coverage/themes/index.html +176 -0
  52. package/coverage/themes/index.ts.html +97 -0
  53. package/coverage/themes/light.ts.html +601 -0
  54. package/coverage/themes/utils.ts.html +334 -0
  55. package/coverage/tokens/index.html +161 -0
  56. package/coverage/tokens/index.ts.html +94 -0
  57. package/coverage/tokens/logger.ts.html +115 -0
  58. package/coverage/tokens/prompt.ts.html +115 -0
  59. package/coverage/tokens/screen.ts.html +115 -0
  60. package/coverage/types/file.types.ts.html +265 -0
  61. package/coverage/types/filter.types.ts.html +238 -0
  62. package/coverage/types/index.html +236 -0
  63. package/coverage/types/index.ts.html +151 -0
  64. package/coverage/types/keyboard.types.ts.html +364 -0
  65. package/coverage/types/log.types.ts.html +268 -0
  66. package/coverage/types/message.types.ts.html +445 -0
  67. package/coverage/types/prompt.types.ts.html +403 -0
  68. package/coverage/types/screen.types.ts.html +451 -0
  69. package/coverage/types/theme.types.ts.html +841 -0
  70. package/coverage/utils/colors/file-colors.ts.html +112 -0
  71. package/coverage/utils/colors/helpers.ts.html +235 -0
  72. package/coverage/utils/colors/index.html +221 -0
  73. package/coverage/utils/colors/index.ts.html +145 -0
  74. package/coverage/utils/colors/log-colors.ts.html +253 -0
  75. package/coverage/utils/colors/progress-colors.ts.html +160 -0
  76. package/coverage/utils/colors/prompt-colors.ts.html +175 -0
  77. package/coverage/utils/colors/sidebar-colors.ts.html +241 -0
  78. package/coverage/utils/colors/table-colors.ts.html +118 -0
  79. package/coverage/utils/filetype.ts.html +277 -0
  80. package/coverage/utils/format.ts.html +241 -0
  81. package/coverage/utils/index.html +161 -0
  82. package/coverage/utils/index.ts.html +118 -0
  83. package/coverage/utils/stdout-printer.ts.html +523 -0
  84. package/dist/src/components/file/file_log.d.ts +35 -0
  85. package/dist/src/components/file/file_log.d.ts.map +1 -0
  86. package/dist/src/components/file/index.d.ts +2 -0
  87. package/dist/src/components/file/index.d.ts.map +1 -0
  88. package/dist/src/components/filter/filter_bar.d.ts +10 -0
  89. package/dist/src/components/filter/filter_bar.d.ts.map +1 -0
  90. package/dist/src/components/filter/index.d.ts +2 -0
  91. package/dist/src/components/filter/index.d.ts.map +1 -0
  92. package/dist/src/components/help/help_overlay.d.ts +10 -0
  93. package/dist/src/components/help/help_overlay.d.ts.map +1 -0
  94. package/dist/src/components/help/index.d.ts +2 -0
  95. package/dist/src/components/help/index.d.ts.map +1 -0
  96. package/dist/src/components/index.d.ts +27 -0
  97. package/dist/src/components/index.d.ts.map +1 -0
  98. package/dist/src/components/log/debug_log.d.ts +3 -0
  99. package/dist/src/components/log/debug_log.d.ts.map +1 -0
  100. package/dist/src/components/log/error_log.d.ts +3 -0
  101. package/dist/src/components/log/error_log.d.ts.map +1 -0
  102. package/dist/src/components/log/fatal_log.d.ts +3 -0
  103. package/dist/src/components/log/fatal_log.d.ts.map +1 -0
  104. package/dist/src/components/log/index.d.ts +9 -0
  105. package/dist/src/components/log/index.d.ts.map +1 -0
  106. package/dist/src/components/log/info_log.d.ts +3 -0
  107. package/dist/src/components/log/info_log.d.ts.map +1 -0
  108. package/dist/src/components/log/log_message.d.ts +33 -0
  109. package/dist/src/components/log/log_message.d.ts.map +1 -0
  110. package/dist/src/components/log/success_log.d.ts +3 -0
  111. package/dist/src/components/log/success_log.d.ts.map +1 -0
  112. package/dist/src/components/log/trace_log.d.ts +3 -0
  113. package/dist/src/components/log/trace_log.d.ts.map +1 -0
  114. package/dist/src/components/log/warning_log.d.ts +3 -0
  115. package/dist/src/components/log/warning_log.d.ts.map +1 -0
  116. package/dist/src/components/prompt/index.d.ts +3 -0
  117. package/dist/src/components/prompt/index.d.ts.map +1 -0
  118. package/dist/src/components/prompt/prompt_renderer.d.ts +6 -0
  119. package/dist/src/components/prompt/prompt_renderer.d.ts.map +1 -0
  120. package/dist/src/components/screen/group_renderer.d.ts +19 -0
  121. package/dist/src/components/screen/group_renderer.d.ts.map +1 -0
  122. package/dist/src/components/screen/index.d.ts +13 -0
  123. package/dist/src/components/screen/index.d.ts.map +1 -0
  124. package/dist/src/components/screen/loading_message.d.ts +6 -0
  125. package/dist/src/components/screen/loading_message.d.ts.map +1 -0
  126. package/dist/src/components/screen/message_renderer.d.ts +8 -0
  127. package/dist/src/components/screen/message_renderer.d.ts.map +1 -0
  128. package/dist/src/components/screen/progress_message.d.ts +8 -0
  129. package/dist/src/components/screen/progress_message.d.ts.map +1 -0
  130. package/dist/src/components/screen/screen_bridge.d.ts +20 -0
  131. package/dist/src/components/screen/screen_bridge.d.ts.map +1 -0
  132. package/dist/src/components/screen/table_message.d.ts +6 -0
  133. package/dist/src/components/screen/table_message.d.ts.map +1 -0
  134. package/dist/src/components/screen_manager_bridge.d.ts +11 -0
  135. package/dist/src/components/screen_manager_bridge.d.ts.map +1 -0
  136. package/dist/src/components/sidebar/index.d.ts +6 -0
  137. package/dist/src/components/sidebar/index.d.ts.map +1 -0
  138. package/dist/src/components/sidebar/sidebar.d.ts +18 -0
  139. package/dist/src/components/sidebar/sidebar.d.ts.map +1 -0
  140. package/dist/src/components/sidebar/sidebar_item.d.ts +14 -0
  141. package/dist/src/components/sidebar/sidebar_item.d.ts.map +1 -0
  142. package/dist/src/components/sidebar/sidebar_separator.d.ts +2 -0
  143. package/dist/src/components/sidebar/sidebar_separator.d.ts.map +1 -0
  144. package/dist/src/context/logger_context.d.ts +60 -0
  145. package/dist/src/context/logger_context.d.ts.map +1 -0
  146. package/dist/src/filter/filter_engine.d.ts +20 -0
  147. package/dist/src/filter/filter_engine.d.ts.map +1 -0
  148. package/dist/src/filter/index.d.ts +4 -0
  149. package/dist/src/filter/index.d.ts.map +1 -0
  150. package/dist/src/hooks/index.d.ts +2 -0
  151. package/dist/src/hooks/index.d.ts.map +1 -0
  152. package/dist/src/hooks/use_theme.d.ts +7 -0
  153. package/dist/src/hooks/use_theme.d.ts.map +1 -0
  154. package/dist/src/index.d.ts +88 -0
  155. package/dist/src/index.d.ts.map +1 -0
  156. package/dist/src/keyboard/create_bindings.d.ts +31 -0
  157. package/dist/src/keyboard/create_bindings.d.ts.map +1 -0
  158. package/dist/src/keyboard/index.d.ts +12 -0
  159. package/dist/src/keyboard/index.d.ts.map +1 -0
  160. package/dist/src/keyboard/keyboard_manager.d.ts +69 -0
  161. package/dist/src/keyboard/keyboard_manager.d.ts.map +1 -0
  162. package/dist/src/services/index.d.ts +5 -0
  163. package/dist/src/services/index.d.ts.map +1 -0
  164. package/dist/src/services/logger.d.ts +61 -0
  165. package/dist/src/services/logger.d.ts.map +1 -0
  166. package/dist/src/services/prompt.d.ts +37 -0
  167. package/dist/src/services/prompt.d.ts.map +1 -0
  168. package/dist/src/services/screen.d.ts +165 -0
  169. package/dist/src/services/screen.d.ts.map +1 -0
  170. package/dist/src/services/screen_manager.d.ts +124 -0
  171. package/dist/src/services/screen_manager.d.ts.map +1 -0
  172. package/dist/src/themes/dark.d.ts +7 -0
  173. package/dist/src/themes/dark.d.ts.map +1 -0
  174. package/dist/src/themes/high-contrast.d.ts +7 -0
  175. package/dist/src/themes/high-contrast.d.ts.map +1 -0
  176. package/dist/src/themes/index.d.ts +18 -0
  177. package/dist/src/themes/index.d.ts.map +1 -0
  178. package/dist/src/themes/light.d.ts +6 -0
  179. package/dist/src/themes/light.d.ts.map +1 -0
  180. package/dist/src/themes/utils.d.ts +22 -0
  181. package/dist/src/themes/utils.d.ts.map +1 -0
  182. package/dist/src/types/file.types.d.ts +40 -0
  183. package/dist/src/types/file.types.d.ts.map +1 -0
  184. package/dist/src/types/filter.types.d.ts +31 -0
  185. package/dist/src/types/filter.types.d.ts.map +1 -0
  186. package/dist/src/types/index.d.ts +81 -0
  187. package/dist/src/types/index.d.ts.map +1 -0
  188. package/dist/src/types/keyboard.types.d.ts +83 -0
  189. package/dist/src/types/keyboard.types.d.ts.map +1 -0
  190. package/dist/src/types/log.types.d.ts +32 -0
  191. package/dist/src/types/log.types.d.ts.map +1 -0
  192. package/dist/src/types/message.types.d.ts +91 -0
  193. package/dist/src/types/message.types.d.ts.map +1 -0
  194. package/dist/src/types/prompt.types.d.ts +89 -0
  195. package/dist/src/types/prompt.types.d.ts.map +1 -0
  196. package/dist/src/types/screen.types.d.ts +85 -0
  197. package/dist/src/types/screen.types.d.ts.map +1 -0
  198. package/dist/src/types/theme.types.d.ts +216 -0
  199. package/dist/src/types/theme.types.d.ts.map +1 -0
  200. package/dist/src/utils/colors/file-colors.d.ts +10 -0
  201. package/dist/src/utils/colors/file-colors.d.ts.map +1 -0
  202. package/dist/src/utils/colors/helpers.d.ts +29 -0
  203. package/dist/src/utils/colors/helpers.d.ts.map +1 -0
  204. package/dist/src/utils/colors/index.d.ts +13 -0
  205. package/dist/src/utils/colors/index.d.ts.map +1 -0
  206. package/dist/src/utils/colors/log-colors.d.ts +15 -0
  207. package/dist/src/utils/colors/log-colors.d.ts.map +1 -0
  208. package/dist/src/utils/colors/progress-colors.d.ts +25 -0
  209. package/dist/src/utils/colors/progress-colors.d.ts.map +1 -0
  210. package/dist/src/utils/colors/prompt-colors.d.ts +22 -0
  211. package/dist/src/utils/colors/prompt-colors.d.ts.map +1 -0
  212. package/dist/src/utils/colors/sidebar-colors.d.ts +50 -0
  213. package/dist/src/utils/colors/sidebar-colors.d.ts.map +1 -0
  214. package/dist/src/utils/colors/table-colors.d.ts +12 -0
  215. package/dist/src/utils/colors/table-colors.d.ts.map +1 -0
  216. package/dist/src/utils/filetype.d.ts +19 -0
  217. package/dist/src/utils/filetype.d.ts.map +1 -0
  218. package/dist/src/utils/format.d.ts +9 -0
  219. package/dist/src/utils/format.d.ts.map +1 -0
  220. package/dist/src/utils/index.d.ts +20 -0
  221. package/dist/src/utils/index.d.ts.map +1 -0
  222. package/dist/src/utils/stdout-printer.d.ts +10 -0
  223. package/dist/src/utils/stdout-printer.d.ts.map +1 -0
  224. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  225. package/dist/tsconfig.tsbuildinfo +1 -0
  226. package/dist/tsdown.config.d.mts +5 -0
  227. package/dist/tsdown.config.d.mts.map +1 -0
  228. package/dist/vitest.config.d.mts +3 -0
  229. package/dist/vitest.config.d.mts.map +1 -0
  230. package/lib/index.cjs +6349 -0
  231. package/lib/index.cjs.map +1 -0
  232. package/lib/index.d.cts +1720 -0
  233. package/lib/index.d.cts.map +1 -0
  234. package/lib/index.d.mts +1720 -0
  235. package/lib/index.d.mts.map +1 -0
  236. package/lib/index.mjs +6264 -0
  237. package/lib/index.mjs.map +1 -0
  238. package/lib/screen_manager_bridge-BpDgVu3e.cjs +3357 -0
  239. package/lib/screen_manager_bridge-BpDgVu3e.cjs.map +1 -0
  240. package/lib/screen_manager_bridge-CkV7637i.cjs +3 -0
  241. package/lib/screen_manager_bridge-DN2J6_k1.mjs +3 -0
  242. package/lib/screen_manager_bridge-Dfg4QUrl.mjs +3034 -0
  243. package/lib/screen_manager_bridge-Dfg4QUrl.mjs.map +1 -0
  244. package/package.json +43 -0
  245. package/project.json +60 -0
  246. package/src/__tests__/components/__snapshots__/filter_bar.spec.tsx.snap +2245 -0
  247. package/src/__tests__/components/__snapshots__/loading_message.spec.tsx.snap +1382 -0
  248. package/src/__tests__/components/__snapshots__/log_message.spec.tsx.snap +3169 -0
  249. package/src/__tests__/components/__snapshots__/progress_message.spec.tsx.snap +1743 -0
  250. package/src/__tests__/components/__snapshots__/prompt_renderer.spec.tsx.snap +3135 -0
  251. package/src/__tests__/components/__snapshots__/sidebar.spec.tsx.snap +2617 -0
  252. package/src/__tests__/components/filter_bar.spec.tsx +190 -0
  253. package/src/__tests__/components/loading_message.spec.tsx +110 -0
  254. package/src/__tests__/components/log_message.spec.tsx +166 -0
  255. package/src/__tests__/components/progress_message.spec.tsx +147 -0
  256. package/src/__tests__/components/prompt_renderer.spec.tsx +274 -0
  257. package/src/__tests__/components/sidebar.spec.tsx +305 -0
  258. package/src/__tests__/filter/filter_engine.spec.ts +325 -0
  259. package/src/__tests__/keyboard/keyboard_manager.spec.ts +557 -0
  260. package/src/__tests__/mocks/scm-mock.ts +5 -0
  261. package/src/__tests__/services/logger.spec.ts +630 -0
  262. package/src/__tests__/services/prompt.spec.ts +411 -0
  263. package/src/__tests__/services/screen.spec.ts +721 -0
  264. package/src/__tests__/setup.ts +43 -0
  265. package/src/__tests__/utils/factories.ts +354 -0
  266. package/src/__tests__/utils/filetype.spec.ts +195 -0
  267. package/src/__tests__/utils/format.spec.ts +178 -0
  268. package/src/__tests__/utils/render-utils.tsx +39 -0
  269. package/src/__tests__/utils/test-container.ts +48 -0
  270. package/src/components/file/file_log.tsx +241 -0
  271. package/src/components/file/index.ts +1 -0
  272. package/src/components/filter/filter_bar.tsx +79 -0
  273. package/src/components/filter/index.ts +1 -0
  274. package/src/components/help/help_overlay.tsx +100 -0
  275. package/src/components/help/index.ts +1 -0
  276. package/src/components/index.ts +15 -0
  277. package/src/components/log/index.ts +1 -0
  278. package/src/components/log/log_message.tsx +102 -0
  279. package/src/components/prompt/index.ts +2 -0
  280. package/src/components/prompt/prompt_renderer.tsx +346 -0
  281. package/src/components/screen/group_renderer.tsx +64 -0
  282. package/src/components/screen/index.ts +6 -0
  283. package/src/components/screen/loading_message.tsx +44 -0
  284. package/src/components/screen/message_renderer.tsx +108 -0
  285. package/src/components/screen/progress_message.tsx +60 -0
  286. package/src/components/screen/screen_bridge.tsx +149 -0
  287. package/src/components/screen/table_message.tsx +57 -0
  288. package/src/components/screen_manager_bridge.tsx +245 -0
  289. package/src/components/sidebar/index.ts +3 -0
  290. package/src/components/sidebar/sidebar.tsx +102 -0
  291. package/src/components/sidebar/sidebar_item.tsx +50 -0
  292. package/src/components/sidebar/sidebar_separator.tsx +13 -0
  293. package/src/context/index.ts +1 -0
  294. package/src/context/logger_context.tsx +109 -0
  295. package/src/factories/index.ts +1 -0
  296. package/src/factories/screen.factory.ts +22 -0
  297. package/src/filter/filter_engine.ts +113 -0
  298. package/src/filter/index.ts +1 -0
  299. package/src/hooks/index.ts +1 -0
  300. package/src/hooks/use_theme.ts +12 -0
  301. package/src/index.ts +64 -0
  302. package/src/keyboard/create_bindings.ts +457 -0
  303. package/src/keyboard/index.ts +2 -0
  304. package/src/keyboard/keyboard_manager.ts +233 -0
  305. package/src/overrides/console.logger.override.ts +61 -0
  306. package/src/overrides/index.ts +1 -0
  307. package/src/schemas/index.ts +3 -0
  308. package/src/schemas/logger-options.ts +13 -0
  309. package/src/schemas/prompt-options.ts +9 -0
  310. package/src/schemas/screen-options.ts +14 -0
  311. package/src/services/index.ts +4 -0
  312. package/src/services/logger.ts +369 -0
  313. package/src/services/prompt.ts +169 -0
  314. package/src/services/screen.ts +590 -0
  315. package/src/services/screen_manager.tsx +390 -0
  316. package/src/themes/dark.ts +173 -0
  317. package/src/themes/high-contrast.ts +178 -0
  318. package/src/themes/index.ts +4 -0
  319. package/src/themes/light.ts +172 -0
  320. package/src/themes/utils.ts +83 -0
  321. package/src/tokens/index.ts +3 -0
  322. package/src/tokens/logger.ts +10 -0
  323. package/src/tokens/prompt.ts +10 -0
  324. package/src/tokens/screen.ts +10 -0
  325. package/src/types/file.types.ts +60 -0
  326. package/src/types/filter.types.ts +51 -0
  327. package/src/types/index.ts +22 -0
  328. package/src/types/keyboard.types.ts +93 -0
  329. package/src/types/log.types.ts +61 -0
  330. package/src/types/message.types.ts +120 -0
  331. package/src/types/prompt.types.ts +106 -0
  332. package/src/types/screen.types.ts +124 -0
  333. package/src/types/theme.types.ts +252 -0
  334. package/src/utils/colors/file-colors.ts +9 -0
  335. package/src/utils/colors/helpers.ts +50 -0
  336. package/src/utils/colors/index.ts +20 -0
  337. package/src/utils/colors/log-colors.ts +56 -0
  338. package/src/utils/colors/progress-colors.ts +25 -0
  339. package/src/utils/colors/prompt-colors.ts +30 -0
  340. package/src/utils/colors/sidebar-colors.ts +52 -0
  341. package/src/utils/colors/table-colors.ts +11 -0
  342. package/src/utils/filetype.ts +64 -0
  343. package/src/utils/format.ts +52 -0
  344. package/src/utils/index.ts +11 -0
  345. package/src/utils/stdout-printer.ts +255 -0
  346. package/tsconfig.json +14 -0
  347. package/tsdown.config.mts +34 -0
  348. package/vitest.config.mts +10 -0
@@ -0,0 +1,274 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { PromptRenderer } from '../../components/prompt/prompt_renderer.tsx'
4
+ import {
5
+ createChoicePrompt,
6
+ createConfirmPrompt,
7
+ createInputPrompt,
8
+ createMultiChoicePrompt,
9
+ STABLE_TIMESTAMP,
10
+ } from '../utils/factories.ts'
11
+ import { wrapWithContext } from '../utils/render-utils.tsx'
12
+
13
+ describe('PromptRenderer', () => {
14
+ describe('choice prompt', () => {
15
+ it('should render choice prompt with options', () => {
16
+ const prompt = createChoicePrompt({
17
+ question: 'Select an option',
18
+ choices: [
19
+ { label: 'Option A', value: 'a' },
20
+ { label: 'Option B', value: 'b' },
21
+ { label: 'Option C', value: 'c' },
22
+ ],
23
+ selectedIndex: 0,
24
+ })
25
+
26
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
27
+
28
+ expect(component).toMatchSnapshot()
29
+ })
30
+
31
+ it('should render selected option highlighted', () => {
32
+ const prompt = createChoicePrompt({
33
+ question: 'Choose wisely',
34
+ choices: [
35
+ { label: 'First', value: '1' },
36
+ { label: 'Second', value: '2' },
37
+ { label: 'Third', value: '3' },
38
+ ],
39
+ selectedIndex: 1,
40
+ })
41
+
42
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
43
+
44
+ expect(component).toMatchSnapshot()
45
+ })
46
+
47
+ it('should render choice with input mode', () => {
48
+ const prompt = createChoicePrompt({
49
+ question: 'Select or type',
50
+ choices: [
51
+ { label: 'Option A', value: 'a' },
52
+ { label: 'Other', value: 'other', input: true },
53
+ ],
54
+ selectedIndex: 1,
55
+ inputMode: true,
56
+ inputValue: 'custom value',
57
+ })
58
+
59
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
60
+
61
+ expect(component).toMatchSnapshot()
62
+ })
63
+
64
+ it('should render choice with timeout', () => {
65
+ const prompt = createChoicePrompt({
66
+ question: 'Quick! Select one',
67
+ choices: [{ label: 'Default', value: 'default' }],
68
+ timeout: 10000,
69
+ timeoutStarted: STABLE_TIMESTAMP.getTime() - 5000, // 5 seconds elapsed from stable timestamp
70
+ })
71
+
72
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
73
+
74
+ expect(component).toMatchSnapshot()
75
+ })
76
+
77
+ it('should render resolved choice prompt', () => {
78
+ const prompt = createChoicePrompt({
79
+ question: 'Already answered',
80
+ choices: [
81
+ { label: 'Yes', value: 'yes' },
82
+ { label: 'No', value: 'no' },
83
+ ],
84
+ selectedIndex: 0,
85
+ resolved: true,
86
+ resolvedValue: 'yes',
87
+ })
88
+
89
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
90
+
91
+ expect(component).toMatchSnapshot()
92
+ })
93
+ })
94
+
95
+ describe('confirm prompt', () => {
96
+ it('should render confirm prompt (Yes/No)', () => {
97
+ const prompt = createConfirmPrompt({
98
+ question: 'Are you sure?',
99
+ confirmText: 'Yes',
100
+ cancelText: 'No',
101
+ selectedValue: true,
102
+ })
103
+
104
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
105
+
106
+ expect(component).toMatchSnapshot()
107
+ })
108
+
109
+ it('should render with No selected', () => {
110
+ const prompt = createConfirmPrompt({
111
+ question: 'Continue?',
112
+ confirmText: 'Yes',
113
+ cancelText: 'No',
114
+ selectedValue: false,
115
+ })
116
+
117
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
118
+
119
+ expect(component).toMatchSnapshot()
120
+ })
121
+
122
+ it('should render with custom button labels', () => {
123
+ const prompt = createConfirmPrompt({
124
+ question: 'Delete this file?',
125
+ confirmText: 'Delete',
126
+ cancelText: 'Keep',
127
+ selectedValue: true,
128
+ })
129
+
130
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
131
+
132
+ expect(component).toMatchSnapshot()
133
+ })
134
+
135
+ it('should render resolved confirm prompt', () => {
136
+ const prompt = createConfirmPrompt({
137
+ question: 'Already confirmed',
138
+ resolved: true,
139
+ resolvedValue: true,
140
+ })
141
+
142
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
143
+
144
+ expect(component).toMatchSnapshot()
145
+ })
146
+ })
147
+
148
+ describe('input prompt', () => {
149
+ it('should render input prompt with placeholder', () => {
150
+ const prompt = createInputPrompt({
151
+ question: 'Enter your name',
152
+ placeholder: 'John Doe',
153
+ value: '',
154
+ })
155
+
156
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
157
+
158
+ expect(component).toMatchSnapshot()
159
+ })
160
+
161
+ it('should render input with entered value', () => {
162
+ const prompt = createInputPrompt({
163
+ question: 'Enter your email',
164
+ placeholder: 'user@example.com',
165
+ value: 'test@test.com',
166
+ })
167
+
168
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
169
+
170
+ expect(component).toMatchSnapshot()
171
+ })
172
+
173
+ it('should render resolved input prompt', () => {
174
+ const prompt = createInputPrompt({
175
+ question: 'Already answered',
176
+ value: 'My answer',
177
+ resolved: true,
178
+ resolvedValue: 'My answer',
179
+ })
180
+
181
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
182
+
183
+ expect(component).toMatchSnapshot()
184
+ })
185
+ })
186
+
187
+ describe('multiChoice prompt', () => {
188
+ it('should render multiChoice with checkboxes', () => {
189
+ const prompt = createMultiChoicePrompt({
190
+ question: 'Select all that apply',
191
+ choices: [
192
+ { label: 'Option A', value: 'a' },
193
+ { label: 'Option B', value: 'b' },
194
+ { label: 'Option C', value: 'c' },
195
+ ],
196
+ selectedIndices: new Set(),
197
+ focusedIndex: 0,
198
+ })
199
+
200
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
201
+
202
+ expect(component).toMatchSnapshot()
203
+ })
204
+
205
+ it('should render with some options selected', () => {
206
+ const prompt = createMultiChoicePrompt({
207
+ question: 'Choose features',
208
+ choices: [
209
+ { label: 'Feature A', value: 'a' },
210
+ { label: 'Feature B', value: 'b' },
211
+ { label: 'Feature C', value: 'c' },
212
+ ],
213
+ selectedIndices: new Set([0, 2]),
214
+ focusedIndex: 1,
215
+ })
216
+
217
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
218
+
219
+ expect(component).toMatchSnapshot()
220
+ })
221
+
222
+ it('should show selection count', () => {
223
+ const prompt = createMultiChoicePrompt({
224
+ question: 'Select up to 3',
225
+ choices: [
226
+ { label: 'A', value: 'a' },
227
+ { label: 'B', value: 'b' },
228
+ { label: 'C', value: 'c' },
229
+ { label: 'D', value: 'd' },
230
+ ],
231
+ selectedIndices: new Set([0, 2]),
232
+ maxSelect: 3,
233
+ })
234
+
235
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
236
+
237
+ expect(component).toMatchSnapshot()
238
+ })
239
+
240
+ it('should show minSelect warning when not met', () => {
241
+ const prompt = createMultiChoicePrompt({
242
+ question: 'Select at least 2',
243
+ choices: [
244
+ { label: 'A', value: 'a' },
245
+ { label: 'B', value: 'b' },
246
+ { label: 'C', value: 'c' },
247
+ ],
248
+ selectedIndices: new Set([0]), // Only 1 selected
249
+ minSelect: 2,
250
+ })
251
+
252
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
253
+
254
+ expect(component).toMatchSnapshot()
255
+ })
256
+
257
+ it('should render resolved multiChoice prompt', () => {
258
+ const prompt = createMultiChoicePrompt({
259
+ question: 'Already selected',
260
+ choices: [
261
+ { label: 'A', value: 'a' },
262
+ { label: 'B', value: 'b' },
263
+ ],
264
+ selectedIndices: new Set([0, 1]),
265
+ resolved: true,
266
+ resolvedValues: ['a', 'b'],
267
+ })
268
+
269
+ const component = wrapWithContext(<PromptRenderer prompt={prompt} />)
270
+
271
+ expect(component).toMatchSnapshot()
272
+ })
273
+ })
274
+ })
@@ -0,0 +1,305 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ import { Sidebar } from '../../components/sidebar/sidebar.tsx'
4
+ import { wrapWithContext } from '../utils/render-utils.tsx'
5
+
6
+ import type { ScreenInstance } from '../../services/screen.ts'
7
+ import type { ScreenStatus } from '../../types/index.ts'
8
+
9
+ // Create mock ScreenInstance
10
+ function createMockScreen(overrides: {
11
+ id?: string
12
+ name?: string
13
+ icon?: string
14
+ badgeCount?: number
15
+ status?: ScreenStatus
16
+ }): ScreenInstance {
17
+ return {
18
+ getId: vi.fn(() => overrides.id ?? 'screen-1'),
19
+ getName: vi.fn(() => overrides.name ?? 'Test Screen'),
20
+ getIcon: vi.fn(() => overrides.icon),
21
+ getBadgeCount: vi.fn(() => overrides.badgeCount ?? 0),
22
+ getStatus: vi.fn(() => overrides.status ?? 'pending'),
23
+ isHidden: vi.fn(() => false),
24
+ } as unknown as ScreenInstance
25
+ }
26
+
27
+ describe('Sidebar', () => {
28
+ describe('screen list', () => {
29
+ it('should render screen list', () => {
30
+ const screens = [
31
+ createMockScreen({ id: '1', name: 'Screen 1' }),
32
+ createMockScreen({ id: '2', name: 'Screen 2' }),
33
+ createMockScreen({ id: '3', name: 'Screen 3' }),
34
+ ]
35
+
36
+ const component = wrapWithContext(
37
+ <Sidebar
38
+ screens={screens}
39
+ selectedIndex={0}
40
+ activeScreenId="1"
41
+ focused={true}
42
+ width={30}
43
+ title="Screens"
44
+ />,
45
+ )
46
+
47
+ expect(component).toMatchSnapshot()
48
+ })
49
+
50
+ it('should render active screen highlighted', () => {
51
+ const screens = [
52
+ createMockScreen({ id: '1', name: 'Screen 1' }),
53
+ createMockScreen({ id: '2', name: 'Screen 2' }),
54
+ ]
55
+
56
+ const component = wrapWithContext(
57
+ <Sidebar
58
+ screens={screens}
59
+ selectedIndex={1}
60
+ activeScreenId="2"
61
+ focused={true}
62
+ width={30}
63
+ title="Screens"
64
+ />,
65
+ )
66
+
67
+ expect(component).toMatchSnapshot()
68
+ })
69
+ })
70
+
71
+ describe('pending vs completed screens', () => {
72
+ it('should separate pending from other screens', () => {
73
+ const screens = [
74
+ createMockScreen({ id: '1', name: 'Pending 1', status: 'pending' }),
75
+ createMockScreen({ id: '2', name: 'Success', status: 'success' }),
76
+ createMockScreen({ id: '3', name: 'Pending 2', status: 'pending' }),
77
+ createMockScreen({ id: '4', name: 'Failed', status: 'fail' }),
78
+ ]
79
+
80
+ const component = wrapWithContext(
81
+ <Sidebar
82
+ screens={screens}
83
+ selectedIndex={0}
84
+ activeScreenId="1"
85
+ focused={true}
86
+ width={30}
87
+ title="Tasks"
88
+ />,
89
+ )
90
+
91
+ expect(component).toMatchSnapshot()
92
+ })
93
+
94
+ it('should show separator between pending and completed', () => {
95
+ const screens = [
96
+ createMockScreen({ id: '1', name: 'Active Task', status: 'pending' }),
97
+ createMockScreen({ id: '2', name: 'Completed Task', status: 'success' }),
98
+ ]
99
+
100
+ const component = wrapWithContext(
101
+ <Sidebar
102
+ screens={screens}
103
+ selectedIndex={0}
104
+ activeScreenId="1"
105
+ focused={true}
106
+ width={30}
107
+ title="Tasks"
108
+ />,
109
+ )
110
+
111
+ expect(component).toMatchSnapshot()
112
+ })
113
+
114
+ it('should not show separator if no mix', () => {
115
+ const screens = [
116
+ createMockScreen({ id: '1', name: 'Task 1', status: 'pending' }),
117
+ createMockScreen({ id: '2', name: 'Task 2', status: 'pending' }),
118
+ ]
119
+
120
+ const component = wrapWithContext(
121
+ <Sidebar
122
+ screens={screens}
123
+ selectedIndex={0}
124
+ activeScreenId="1"
125
+ focused={true}
126
+ width={30}
127
+ title="Tasks"
128
+ />,
129
+ )
130
+
131
+ expect(component).toMatchSnapshot()
132
+ })
133
+ })
134
+
135
+ describe('status indicators', () => {
136
+ it('should render waiting status', () => {
137
+ const screens = [createMockScreen({ id: '1', name: 'Waiting', status: 'waiting' })]
138
+
139
+ const component = wrapWithContext(
140
+ <Sidebar
141
+ screens={screens}
142
+ selectedIndex={0}
143
+ activeScreenId="1"
144
+ focused={true}
145
+ width={30}
146
+ title="Screens"
147
+ />,
148
+ )
149
+
150
+ expect(component).toMatchSnapshot()
151
+ })
152
+
153
+ it('should render pending status', () => {
154
+ const screens = [createMockScreen({ id: '1', name: 'In Progress', status: 'pending' })]
155
+
156
+ const component = wrapWithContext(
157
+ <Sidebar
158
+ screens={screens}
159
+ selectedIndex={0}
160
+ activeScreenId="1"
161
+ focused={true}
162
+ width={30}
163
+ title="Screens"
164
+ />,
165
+ )
166
+
167
+ expect(component).toMatchSnapshot()
168
+ })
169
+
170
+ it('should render success status', () => {
171
+ const screens = [createMockScreen({ id: '1', name: 'Completed', status: 'success' })]
172
+
173
+ const component = wrapWithContext(
174
+ <Sidebar
175
+ screens={screens}
176
+ selectedIndex={0}
177
+ activeScreenId="1"
178
+ focused={true}
179
+ width={30}
180
+ title="Screens"
181
+ />,
182
+ )
183
+
184
+ expect(component).toMatchSnapshot()
185
+ })
186
+
187
+ it('should render fail status', () => {
188
+ const screens = [createMockScreen({ id: '1', name: 'Failed', status: 'fail' })]
189
+
190
+ const component = wrapWithContext(
191
+ <Sidebar
192
+ screens={screens}
193
+ selectedIndex={0}
194
+ activeScreenId="1"
195
+ focused={true}
196
+ width={30}
197
+ title="Screens"
198
+ />,
199
+ )
200
+
201
+ expect(component).toMatchSnapshot()
202
+ })
203
+ })
204
+
205
+ describe('badge counts', () => {
206
+ it('should render badge counts', () => {
207
+ const screens = [
208
+ createMockScreen({ id: '1', name: 'Messages', badgeCount: 5 }),
209
+ createMockScreen({ id: '2', name: 'Notifications', badgeCount: 12 }),
210
+ createMockScreen({ id: '3', name: 'Empty', badgeCount: 0 }),
211
+ ]
212
+
213
+ const component = wrapWithContext(
214
+ <Sidebar
215
+ screens={screens}
216
+ selectedIndex={0}
217
+ activeScreenId="1"
218
+ focused={true}
219
+ width={30}
220
+ title="Screens"
221
+ />,
222
+ )
223
+
224
+ expect(component).toMatchSnapshot()
225
+ })
226
+ })
227
+
228
+ describe('icons', () => {
229
+ it('should render icons', () => {
230
+ const screens = [
231
+ createMockScreen({ id: '1', name: 'Build', icon: '๐Ÿ”จ' }),
232
+ createMockScreen({ id: '2', name: 'Test', icon: '๐Ÿงช' }),
233
+ createMockScreen({ id: '3', name: 'Deploy', icon: '๐Ÿš€' }),
234
+ ]
235
+
236
+ const component = wrapWithContext(
237
+ <Sidebar
238
+ screens={screens}
239
+ selectedIndex={0}
240
+ activeScreenId="1"
241
+ focused={true}
242
+ width={30}
243
+ title="Pipeline"
244
+ />,
245
+ )
246
+
247
+ expect(component).toMatchSnapshot()
248
+ })
249
+ })
250
+
251
+ describe('focus state', () => {
252
+ it('should render focused state', () => {
253
+ const screens = [createMockScreen({ id: '1', name: 'Test' })]
254
+
255
+ const component = wrapWithContext(
256
+ <Sidebar
257
+ screens={screens}
258
+ selectedIndex={0}
259
+ activeScreenId="1"
260
+ focused={true}
261
+ width={30}
262
+ title="Screens"
263
+ />,
264
+ )
265
+
266
+ expect(component).toMatchSnapshot()
267
+ })
268
+
269
+ it('should render unfocused state', () => {
270
+ const screens = [createMockScreen({ id: '1', name: 'Test' })]
271
+
272
+ const component = wrapWithContext(
273
+ <Sidebar
274
+ screens={screens}
275
+ selectedIndex={0}
276
+ activeScreenId="1"
277
+ focused={false}
278
+ width={30}
279
+ title="Screens"
280
+ />,
281
+ )
282
+
283
+ expect(component).toMatchSnapshot()
284
+ })
285
+ })
286
+
287
+ describe('title', () => {
288
+ it('should render custom title', () => {
289
+ const screens = [createMockScreen({ id: '1', name: 'Test' })]
290
+
291
+ const component = wrapWithContext(
292
+ <Sidebar
293
+ screens={screens}
294
+ selectedIndex={0}
295
+ activeScreenId="1"
296
+ focused={true}
297
+ width={30}
298
+ title="Custom Title"
299
+ />,
300
+ )
301
+
302
+ expect(component).toMatchSnapshot()
303
+ })
304
+ })
305
+ })