@navios/commander-tui 1.3.0 → 1.5.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 (240) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/{src/__tests__/mocks/scm-mock.ts → dist/base/src/__tests__/mocks/scm-mock.d.ts} +3 -1
  3. package/dist/base/src/__tests__/mocks/scm-mock.d.ts.map +1 -0
  4. package/dist/base/src/__tests__/setup.d.ts +2 -0
  5. package/dist/base/src/__tests__/setup.d.ts.map +1 -0
  6. package/dist/base/src/__tests__/utils/factories.d.ts +67 -0
  7. package/dist/base/src/__tests__/utils/factories.d.ts.map +1 -0
  8. package/dist/base/src/__tests__/utils/render-utils.d.ts +21 -0
  9. package/dist/base/src/__tests__/utils/render-utils.d.ts.map +1 -0
  10. package/dist/base/src/__tests__/utils/test-container.d.ts +20 -0
  11. package/dist/base/src/__tests__/utils/test-container.d.ts.map +1 -0
  12. package/dist/base/src/adapters/interface.d.ts +9 -2
  13. package/dist/base/src/adapters/interface.d.ts.map +1 -1
  14. package/dist/base/src/overrides/missing-adapter.override.d.ts +10 -0
  15. package/dist/base/src/overrides/missing-adapter.override.d.ts.map +1 -1
  16. package/dist/base/src/services/index.d.ts +1 -0
  17. package/dist/base/src/services/index.d.ts.map +1 -1
  18. package/dist/base/src/services/logger.d.ts.map +1 -1
  19. package/dist/base/src/services/readline_prompt.d.ts +27 -0
  20. package/dist/base/src/services/readline_prompt.d.ts.map +1 -0
  21. package/dist/base/src/services/screen.d.ts +14 -8
  22. package/dist/base/src/services/screen.d.ts.map +1 -1
  23. package/dist/base/src/services/screen_manager.d.ts +62 -12
  24. package/dist/base/src/services/screen_manager.d.ts.map +1 -1
  25. package/dist/base/src/tokens/logger.d.ts +2 -2
  26. package/dist/base/src/types/events.types.d.ts +40 -0
  27. package/dist/base/src/types/events.types.d.ts.map +1 -0
  28. package/dist/base/src/types/index.d.ts +1 -0
  29. package/dist/base/src/types/index.d.ts.map +1 -1
  30. package/dist/base/src/types/screen.types.d.ts +28 -0
  31. package/dist/base/src/types/screen.types.d.ts.map +1 -1
  32. package/dist/base/src/utils/colors/helpers.d.ts +0 -16
  33. package/dist/base/src/utils/colors/helpers.d.ts.map +1 -1
  34. package/dist/base/src/utils/index.d.ts +2 -0
  35. package/dist/base/src/utils/index.d.ts.map +1 -1
  36. package/dist/base/src/utils/prompt.d.ts +7 -0
  37. package/dist/base/src/utils/prompt.d.ts.map +1 -0
  38. package/dist/base/src/utils/runtime.d.ts +10 -0
  39. package/dist/base/src/utils/runtime.d.ts.map +1 -0
  40. package/dist/base/src/utils/stdout-printer.d.ts +5 -0
  41. package/dist/base/src/utils/stdout-printer.d.ts.map +1 -1
  42. package/dist/base/tsconfig.base.tsbuildinfo +1 -1
  43. package/dist/base/tsconfig.tsbuildinfo +1 -0
  44. package/dist/ink/src/adapters/ink/components/file/file_log.d.ts +28 -0
  45. package/dist/ink/src/adapters/ink/components/file/file_log.d.ts.map +1 -0
  46. package/dist/ink/src/adapters/ink/components/file/index.d.ts +2 -0
  47. package/dist/ink/src/adapters/ink/components/file/index.d.ts.map +1 -0
  48. package/dist/ink/src/adapters/ink/components/filter/filter_bar.d.ts +7 -0
  49. package/dist/ink/src/adapters/ink/components/filter/filter_bar.d.ts.map +1 -0
  50. package/dist/ink/src/adapters/ink/components/filter/index.d.ts +2 -0
  51. package/dist/ink/src/adapters/ink/components/filter/index.d.ts.map +1 -0
  52. package/dist/ink/src/adapters/ink/components/help/help_overlay.d.ts +6 -0
  53. package/dist/ink/src/adapters/ink/components/help/help_overlay.d.ts.map +1 -0
  54. package/dist/ink/src/adapters/ink/components/help/index.d.ts +2 -0
  55. package/dist/ink/src/adapters/ink/components/help/index.d.ts.map +1 -0
  56. package/dist/ink/src/adapters/ink/components/index.d.ts +9 -0
  57. package/dist/ink/src/adapters/ink/components/index.d.ts.map +1 -0
  58. package/dist/ink/src/adapters/ink/components/log/index.d.ts +2 -0
  59. package/dist/ink/src/adapters/ink/components/log/index.d.ts.map +1 -0
  60. package/dist/ink/src/adapters/ink/components/log/log_message.d.ts +15 -0
  61. package/dist/ink/src/adapters/ink/components/log/log_message.d.ts.map +1 -0
  62. package/dist/ink/src/adapters/ink/components/prompt/index.d.ts +2 -0
  63. package/dist/ink/src/adapters/ink/components/prompt/index.d.ts.map +1 -0
  64. package/dist/ink/src/adapters/ink/components/prompt/prompt_renderer.d.ts +6 -0
  65. package/dist/ink/src/adapters/ink/components/prompt/prompt_renderer.d.ts.map +1 -0
  66. package/dist/ink/src/adapters/ink/components/screen/group_renderer.d.ts +14 -0
  67. package/dist/ink/src/adapters/ink/components/screen/group_renderer.d.ts.map +1 -0
  68. package/dist/ink/src/adapters/ink/components/screen/index.d.ts +7 -0
  69. package/dist/ink/src/adapters/ink/components/screen/index.d.ts.map +1 -0
  70. package/dist/ink/src/adapters/ink/components/screen/loading_message.d.ts +6 -0
  71. package/dist/ink/src/adapters/ink/components/screen/loading_message.d.ts.map +1 -0
  72. package/dist/ink/src/adapters/ink/components/screen/message_renderer.d.ts +6 -0
  73. package/dist/ink/src/adapters/ink/components/screen/message_renderer.d.ts.map +1 -0
  74. package/dist/ink/src/adapters/ink/components/screen/progress_message.d.ts +6 -0
  75. package/dist/ink/src/adapters/ink/components/screen/progress_message.d.ts.map +1 -0
  76. package/dist/ink/src/adapters/ink/components/screen/screen_bridge.d.ts +14 -0
  77. package/dist/ink/src/adapters/ink/components/screen/screen_bridge.d.ts.map +1 -0
  78. package/dist/ink/src/adapters/ink/components/screen/table_message.d.ts +6 -0
  79. package/dist/ink/src/adapters/ink/components/screen/table_message.d.ts.map +1 -0
  80. package/dist/ink/src/adapters/ink/components/screen_manager_bridge.d.ts +8 -0
  81. package/dist/ink/src/adapters/ink/components/screen_manager_bridge.d.ts.map +1 -0
  82. package/dist/ink/src/adapters/ink/components/sidebar/index.d.ts +4 -0
  83. package/dist/ink/src/adapters/ink/components/sidebar/index.d.ts.map +1 -0
  84. package/dist/ink/src/adapters/ink/components/sidebar/sidebar.d.ts +11 -0
  85. package/dist/ink/src/adapters/ink/components/sidebar/sidebar.d.ts.map +1 -0
  86. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_item.d.ts +9 -0
  87. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_item.d.ts.map +1 -0
  88. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_separator.d.ts +2 -0
  89. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_separator.d.ts.map +1 -0
  90. package/dist/ink/src/adapters/ink/context/index.d.ts +2 -0
  91. package/dist/ink/src/adapters/ink/context/index.d.ts.map +1 -0
  92. package/dist/ink/src/adapters/ink/context/logger_context.d.ts +33 -0
  93. package/dist/ink/src/adapters/ink/context/logger_context.d.ts.map +1 -0
  94. package/dist/ink/src/adapters/ink/hooks/index.d.ts +2 -0
  95. package/dist/ink/src/adapters/ink/hooks/index.d.ts.map +1 -0
  96. package/dist/ink/src/adapters/ink/hooks/use_theme.d.ts +7 -0
  97. package/dist/ink/src/adapters/ink/hooks/use_theme.d.ts.map +1 -0
  98. package/dist/ink/src/adapters/ink/index.d.ts +18 -0
  99. package/dist/ink/src/adapters/ink/index.d.ts.map +1 -0
  100. package/dist/ink/src/adapters/react-shared/hooks/index.d.ts +4 -0
  101. package/dist/ink/src/adapters/react-shared/hooks/index.d.ts.map +1 -0
  102. package/dist/ink/src/adapters/react-shared/hooks/use_filter_state.d.ts +18 -0
  103. package/dist/ink/src/adapters/react-shared/hooks/use_filter_state.d.ts.map +1 -0
  104. package/dist/ink/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts +26 -0
  105. package/dist/ink/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts.map +1 -0
  106. package/dist/ink/src/adapters/react-shared/hooks/use_manager_subscription.d.ts +7 -0
  107. package/dist/ink/src/adapters/react-shared/hooks/use_manager_subscription.d.ts.map +1 -0
  108. package/dist/ink/src/adapters/react-shared/index.d.ts +2 -0
  109. package/dist/ink/src/adapters/react-shared/index.d.ts.map +1 -0
  110. package/dist/ink/tsconfig.ink.tsbuildinfo +1 -0
  111. package/dist/react/src/adapters/react-shared/hooks/index.d.ts +4 -0
  112. package/dist/react/src/adapters/react-shared/hooks/index.d.ts.map +1 -0
  113. package/dist/react/src/adapters/react-shared/hooks/use_filter_state.d.ts +18 -0
  114. package/dist/react/src/adapters/react-shared/hooks/use_filter_state.d.ts.map +1 -0
  115. package/dist/react/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts +26 -0
  116. package/dist/react/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts.map +1 -0
  117. package/dist/react/src/adapters/react-shared/hooks/use_manager_subscription.d.ts +7 -0
  118. package/dist/react/src/adapters/react-shared/hooks/use_manager_subscription.d.ts.map +1 -0
  119. package/dist/react/src/adapters/react-shared/index.d.ts +2 -0
  120. package/dist/react/src/adapters/react-shared/index.d.ts.map +1 -0
  121. package/dist/react/tsconfig.react.tsbuildinfo +1 -1
  122. package/dist/solid/tsconfig.solid.tsbuildinfo +1 -1
  123. package/lib/index.cjs +2180 -181
  124. package/lib/index.cjs.map +1 -1
  125. package/lib/index.d.cts +3199 -277
  126. package/lib/index.d.cts.map +1 -0
  127. package/lib/index.d.mts +3199 -277
  128. package/lib/index.d.mts.map +1 -0
  129. package/lib/index.mjs +2101 -138
  130. package/lib/index.mjs.map +1 -1
  131. package/package.json +1 -31
  132. package/src/__tests__/services/logger.spec.ts +32 -0
  133. package/src/__tests__/services/screen.spec.ts +114 -101
  134. package/src/__tests__/utils/factories.ts +2 -0
  135. package/src/adapters/interface.ts +10 -2
  136. package/src/overrides/missing-adapter.override.ts +16 -6
  137. package/src/services/index.ts +1 -0
  138. package/src/services/logger.ts +7 -1
  139. package/src/services/readline_prompt.ts +194 -0
  140. package/src/services/screen.ts +108 -57
  141. package/src/services/screen_manager.ts +287 -74
  142. package/src/types/events.types.ts +84 -0
  143. package/src/types/index.ts +3 -0
  144. package/src/types/screen.types.ts +34 -0
  145. package/src/utils/colors/helpers.ts +0 -25
  146. package/src/utils/index.ts +6 -0
  147. package/src/utils/prompt.ts +18 -0
  148. package/src/utils/runtime.ts +14 -0
  149. package/src/utils/stdout-printer.ts +16 -5
  150. package/tsconfig.base.json +1 -17
  151. package/tsconfig.json +1 -6
  152. package/tsdown.config.mts +13 -70
  153. package/lib/adapters/react/index.cjs +0 -1768
  154. package/lib/adapters/react/index.cjs.map +0 -1
  155. package/lib/adapters/react/index.d.cts +0 -80
  156. package/lib/adapters/react/index.d.mts +0 -80
  157. package/lib/adapters/react/index.mjs +0 -1760
  158. package/lib/adapters/react/index.mjs.map +0 -1
  159. package/lib/adapters/solid/index.cjs +0 -3855
  160. package/lib/adapters/solid/index.cjs.map +0 -1
  161. package/lib/adapters/solid/index.d.cts +0 -74
  162. package/lib/adapters/solid/index.d.mts +0 -74
  163. package/lib/adapters/solid/index.mjs +0 -3847
  164. package/lib/adapters/solid/index.mjs.map +0 -1
  165. package/lib/filter_engine-DXqu9Vaq.cjs +0 -1836
  166. package/lib/filter_engine-DXqu9Vaq.cjs.map +0 -1
  167. package/lib/filter_engine-DmqhEhpA.mjs +0 -1609
  168. package/lib/filter_engine-DmqhEhpA.mjs.map +0 -1
  169. package/lib/interface-CTHQ08aY.d.mts +0 -699
  170. package/lib/interface-DQEIz9Mb.d.cts +0 -699
  171. package/src/__tests__/components/__snapshots__/filter_bar.spec.tsx.snap +0 -2293
  172. package/src/__tests__/components/__snapshots__/loading_message.spec.tsx.snap +0 -1414
  173. package/src/__tests__/components/__snapshots__/log_message.spec.tsx.snap +0 -3245
  174. package/src/__tests__/components/__snapshots__/progress_message.spec.tsx.snap +0 -1783
  175. package/src/__tests__/components/__snapshots__/prompt_renderer.spec.tsx.snap +0 -3203
  176. package/src/__tests__/components/__snapshots__/sidebar.spec.tsx.snap +0 -2857
  177. package/src/__tests__/components/filter_bar.spec.tsx +0 -190
  178. package/src/__tests__/components/loading_message.spec.tsx +0 -110
  179. package/src/__tests__/components/log_message.spec.tsx +0 -166
  180. package/src/__tests__/components/progress_message.spec.tsx +0 -147
  181. package/src/__tests__/components/prompt_renderer.spec.tsx +0 -274
  182. package/src/__tests__/components/sidebar.spec.tsx +0 -322
  183. package/src/__tests__/utils/render-utils.tsx +0 -39
  184. package/src/adapters/react/components/file/file_log.tsx +0 -241
  185. package/src/adapters/react/components/file/index.ts +0 -1
  186. package/src/adapters/react/components/filter/filter_bar.tsx +0 -79
  187. package/src/adapters/react/components/filter/index.ts +0 -1
  188. package/src/adapters/react/components/help/help_overlay.tsx +0 -100
  189. package/src/adapters/react/components/help/index.ts +0 -1
  190. package/src/adapters/react/components/log/index.ts +0 -1
  191. package/src/adapters/react/components/log/log_message.tsx +0 -102
  192. package/src/adapters/react/components/prompt/index.ts +0 -2
  193. package/src/adapters/react/components/prompt/prompt_renderer.tsx +0 -346
  194. package/src/adapters/react/components/screen/group_renderer.tsx +0 -64
  195. package/src/adapters/react/components/screen/index.ts +0 -6
  196. package/src/adapters/react/components/screen/loading_message.tsx +0 -43
  197. package/src/adapters/react/components/screen/message_renderer.tsx +0 -108
  198. package/src/adapters/react/components/screen/progress_message.tsx +0 -60
  199. package/src/adapters/react/components/screen/screen_bridge.tsx +0 -149
  200. package/src/adapters/react/components/screen/table_message.tsx +0 -57
  201. package/src/adapters/react/components/screen_manager_bridge.tsx +0 -245
  202. package/src/adapters/react/components/sidebar/index.ts +0 -3
  203. package/src/adapters/react/components/sidebar/sidebar.tsx +0 -102
  204. package/src/adapters/react/components/sidebar/sidebar_item.tsx +0 -50
  205. package/src/adapters/react/components/sidebar/sidebar_separator.tsx +0 -13
  206. package/src/adapters/react/context/index.ts +0 -1
  207. package/src/adapters/react/context/logger_context.tsx +0 -109
  208. package/src/adapters/react/hooks/index.ts +0 -1
  209. package/src/adapters/react/hooks/use_theme.ts +0 -12
  210. package/src/adapters/react/index.ts +0 -39
  211. package/src/adapters/solid/components/file/file_log.tsx +0 -221
  212. package/src/adapters/solid/components/file/index.ts +0 -1
  213. package/src/adapters/solid/components/filter/filter_bar.tsx +0 -84
  214. package/src/adapters/solid/components/filter/index.ts +0 -1
  215. package/src/adapters/solid/components/help/help_overlay.tsx +0 -106
  216. package/src/adapters/solid/components/help/index.ts +0 -1
  217. package/src/adapters/solid/components/log/index.ts +0 -1
  218. package/src/adapters/solid/components/log/log_message.tsx +0 -92
  219. package/src/adapters/solid/components/prompt/index.ts +0 -2
  220. package/src/adapters/solid/components/prompt/prompt_renderer.tsx +0 -350
  221. package/src/adapters/solid/components/screen/group_renderer.tsx +0 -61
  222. package/src/adapters/solid/components/screen/index.ts +0 -6
  223. package/src/adapters/solid/components/screen/loading_message.tsx +0 -39
  224. package/src/adapters/solid/components/screen/message_renderer.tsx +0 -122
  225. package/src/adapters/solid/components/screen/progress_message.tsx +0 -61
  226. package/src/adapters/solid/components/screen/screen_bridge.tsx +0 -155
  227. package/src/adapters/solid/components/screen/table_message.tsx +0 -58
  228. package/src/adapters/solid/components/screen_manager_bridge.tsx +0 -243
  229. package/src/adapters/solid/components/sidebar/index.ts +0 -3
  230. package/src/adapters/solid/components/sidebar/sidebar.tsx +0 -108
  231. package/src/adapters/solid/components/sidebar/sidebar_item.tsx +0 -55
  232. package/src/adapters/solid/components/sidebar/sidebar_separator.tsx +0 -13
  233. package/src/adapters/solid/context/index.ts +0 -2
  234. package/src/adapters/solid/context/logger_context.tsx +0 -95
  235. package/src/adapters/solid/hooks/index.ts +0 -1
  236. package/src/adapters/solid/hooks/use_theme.ts +0 -12
  237. package/src/adapters/solid/index.tsx +0 -43
  238. package/src/adapters/solid/jsx.d.ts +0 -98
  239. package/tsconfig.react.json +0 -16
  240. package/tsconfig.solid.json +0 -16
@@ -1,155 +0,0 @@
1
- import { TextAttributes } from '@opentui/core'
2
- import { createSignal, createEffect, createMemo, For, Show, onCleanup } from 'solid-js'
3
-
4
- import { useTheme } from '../../hooks/index.ts'
5
- import { PromptRenderer } from '../prompt/index.ts'
6
-
7
- import type { ScreenInstance } from '../../../../services/index.ts'
8
- import type { MessageData } from '../../../../types/index.ts'
9
-
10
- import { GroupRenderer } from './group_renderer.tsx'
11
- import { MessageRenderer } from './message_renderer.tsx'
12
-
13
- export interface ScreenBridgeProps {
14
- screen: ScreenInstance
15
- focused: boolean
16
- /** Pre-filtered messages (if filtering is active) */
17
- filteredMessages?: MessageData[]
18
- /** Whether any filter is currently active */
19
- isFiltering?: boolean
20
- /** Total message count (before filtering) */
21
- totalMessages?: number
22
- }
23
-
24
- // Helper to process messages and organize them into groups
25
- interface ProcessedMessage {
26
- type: 'single' | 'group'
27
- message?: MessageData
28
- label?: string
29
- messages?: MessageData[]
30
- }
31
-
32
- function processMessagesIntoGroups(messages: MessageData[]): ProcessedMessage[] {
33
- const result: ProcessedMessage[] = []
34
- let i = 0
35
-
36
- while (i < messages.length) {
37
- const msg = messages[i]!
38
-
39
- if (msg.type === 'group' && !msg.isEnd) {
40
- // Start of a group - collect all messages until groupEnd
41
- const groupLabel = msg.label
42
- const groupMessages: MessageData[] = []
43
- i++ // Move past the group start
44
-
45
- while (i < messages.length) {
46
- const innerMsg = messages[i]!
47
- if (innerMsg.type === 'group' && innerMsg.isEnd) {
48
- i++ // Move past the group end
49
- break
50
- }
51
- groupMessages.push(innerMsg)
52
- i++
53
- }
54
-
55
- result.push({
56
- type: 'group',
57
- label: groupLabel,
58
- messages: groupMessages,
59
- })
60
- } else if (msg.type === 'group' && msg.isEnd) {
61
- // Stray group end - skip it
62
- i++
63
- } else {
64
- // Regular message
65
- result.push({ type: 'single', message: msg })
66
- i++
67
- }
68
- }
69
-
70
- return result
71
- }
72
-
73
- export function ScreenBridge(props: ScreenBridgeProps) {
74
- const theme = useTheme()
75
- const [version, setVersion] = createSignal(0)
76
-
77
- // Subscribe to screen changes
78
- createEffect(() => {
79
- const unsub = props.screen.onChange(() => setVersion((v) => v + 1))
80
- onCleanup(() => unsub())
81
- })
82
-
83
- // Use filtered messages if provided, otherwise get from screen
84
- const messages = createMemo(() => {
85
- version() // Track version for reactivity
86
- return props.filteredMessages ?? props.screen.getMessages()
87
- })
88
-
89
- const activePrompt = createMemo(() => {
90
- version() // Track version for reactivity
91
- return props.screen.getActivePrompt()
92
- })
93
-
94
- const processedMessages = createMemo(() => processMessagesIntoGroups(messages()))
95
-
96
- // Calculate filter stats
97
- const filteredCount = () => messages().length
98
- const total = () => props.totalMessages ?? messages().length
99
- const showFilterStatus = () => props.isFiltering && filteredCount() !== total()
100
-
101
- return (
102
- <box flexDirection="column" flexGrow={1}>
103
- {/* Screen header */}
104
- <box
105
- backgroundColor={theme.header.background}
106
- borderColor={props.focused ? theme.sidebar.focusBorder : theme.header.border}
107
- border={['bottom']}
108
- paddingLeft={1}
109
- paddingRight={1}
110
- flexDirection="row"
111
- justifyContent="space-between"
112
- >
113
- <text fg={theme.header.text} attributes={TextAttributes.BOLD}>
114
- {props.screen.getName()}
115
- </text>
116
- <Show when={showFilterStatus()}>
117
- <text fg={theme.sidebar.textDim}>
118
- {filteredCount()}/{total()} messages
119
- </text>
120
- </Show>
121
- </box>
122
-
123
- {/* Scrollable content area */}
124
- <scrollbox
125
- flexGrow={1}
126
- scrollY
127
- stickyScroll
128
- stickyStart="bottom"
129
- contentOptions={{
130
- paddingLeft: 1,
131
- paddingRight: 1,
132
- paddingTop: 1,
133
- paddingBottom: 1,
134
- gap: 1,
135
- }}
136
- >
137
- <For each={processedMessages()}>
138
- {(item) => (
139
- <Show
140
- when={item.type === 'group'}
141
- fallback={<MessageRenderer message={item.message!} />}
142
- >
143
- <GroupRenderer label={item.label!} messages={item.messages!} />
144
- </Show>
145
- )}
146
- </For>
147
-
148
- {/* Render active prompt at the end of messages */}
149
- <Show when={activePrompt()}>
150
- <PromptRenderer prompt={activePrompt()!} />
151
- </Show>
152
- </scrollbox>
153
- </box>
154
- )
155
- }
@@ -1,58 +0,0 @@
1
- import { TextAttributes } from '@opentui/core'
2
- import { For, Show, createMemo } from 'solid-js'
3
-
4
- import { TABLE_COLORS } from '../../../../utils/index.ts'
5
-
6
- import type { TableMessageData } from '../../../../types/index.ts'
7
-
8
- export interface TableMessageProps {
9
- message: TableMessageData
10
- }
11
-
12
- export function TableMessage(props: TableMessageProps) {
13
- // Calculate column widths
14
- const colWidths = createMemo(() =>
15
- props.message.headers.map((h, i) => {
16
- const headerLen = h.length
17
- const maxRowLen =
18
- props.message.rows.length > 0
19
- ? Math.max(...props.message.rows.map((r) => (r[i] ?? '').length))
20
- : 0
21
- return Math.max(headerLen, maxRowLen)
22
- }),
23
- )
24
-
25
- const pad = (str: string, width: number) => str.padEnd(width)
26
-
27
- const headerRow = createMemo(() =>
28
- props.message.headers.map((h, i) => pad(h, colWidths()[i] ?? 0)).join(' │ '),
29
- )
30
-
31
- const separator = createMemo(() => colWidths().map((w) => '─'.repeat(w)).join('─┼─'))
32
-
33
- const dataRows = createMemo(() =>
34
- props.message.rows.map((row) => row.map((cell, i) => pad(cell, colWidths()[i] ?? 0)).join(' │ ')),
35
- )
36
-
37
- return (
38
- <box
39
- flexDirection="column"
40
- border={['left']}
41
- borderColor={TABLE_COLORS.border}
42
- backgroundColor={TABLE_COLORS.background}
43
- paddingLeft={1}
44
- paddingRight={1}
45
- >
46
- <Show when={props.message.title}>
47
- <text fg={TABLE_COLORS.title} attributes={TextAttributes.BOLD}>
48
- {props.message.title}
49
- </text>
50
- </Show>
51
- <text fg={TABLE_COLORS.headerText} attributes={TextAttributes.BOLD}>
52
- {headerRow()}
53
- </text>
54
- <text fg={TABLE_COLORS.separator}>{separator()}</text>
55
- <For each={dataRows()}>{(row) => <text fg={TABLE_COLORS.cellText}>{row}</text>}</For>
56
- </box>
57
- )
58
- }
@@ -1,243 +0,0 @@
1
- import { useKeyboard } from '@opentui/solid'
2
- import { createSignal, createEffect, createMemo, onCleanup, Show } from 'solid-js'
3
-
4
- import { LoggerProvider } from '../context/index.ts'
5
- import { FilterEngine } from '../../../filter/index.ts'
6
- import { KeyboardManager, createDefaultBindings, handlePrintableInput } from '../../../keyboard/index.ts'
7
- import {
8
- ALL_LOG_LEVELS,
9
- createDefaultFilterState,
10
- hasActiveFilter,
11
- type FilterState,
12
- type KeyboardContext,
13
- type Theme,
14
- } from '../../../types/index.ts'
15
-
16
- import type { ScreenManagerInstance } from '../../../services/index.ts'
17
-
18
- import { FilterBar } from './filter/filter_bar.tsx'
19
- import { HelpOverlay } from './help/help_overlay.tsx'
20
- import { ScreenBridge } from './screen/screen_bridge.tsx'
21
- import { Sidebar } from './sidebar/sidebar.tsx'
22
-
23
- export interface ScreenManagerBridgeProps {
24
- manager: ScreenManagerInstance
25
- theme?: Theme
26
- }
27
-
28
- export function ScreenManagerBridge(props: ScreenManagerBridgeProps) {
29
- const [version, setVersion] = createSignal(0)
30
- const [showHelp, setShowHelp] = createSignal(false)
31
- const [filter, setFilter] = createSignal<FilterState>(createDefaultFilterState())
32
-
33
- // Subscribe to manager changes
34
- createEffect(() => {
35
- const unsub = props.manager.onChange(() => setVersion((v) => v + 1))
36
- onCleanup(() => unsub())
37
- })
38
-
39
- // Helper functions for keyboard bindings
40
- const getActiveScreen = () => props.manager.getActiveScreen()
41
-
42
- const toggleHelp = () => {
43
- setShowHelp((prev) => !prev)
44
- }
45
-
46
- const toggleFilter = () => {
47
- setFilter((prev) => ({
48
- ...prev,
49
- isVisible: !prev.isVisible,
50
- focusedField: 'search',
51
- }))
52
- }
53
-
54
- const closeFilter = () => {
55
- setFilter((prev) => ({ ...prev, isVisible: false }))
56
- }
57
-
58
- const filterAppendChar = (char: string) => {
59
- setFilter((prev) => ({
60
- ...prev,
61
- searchQuery: prev.searchQuery + char,
62
- }))
63
- }
64
-
65
- const filterDeleteChar = () => {
66
- setFilter((prev) => ({
67
- ...prev,
68
- searchQuery: prev.searchQuery.slice(0, -1),
69
- }))
70
- }
71
-
72
- const filterToggleLevel = (index: number) => {
73
- setFilter((prev) => {
74
- const level = ALL_LOG_LEVELS[index]
75
- if (!level) return prev
76
-
77
- const newLevels = new Set(prev.enabledLevels)
78
- if (newLevels.has(level)) {
79
- newLevels.delete(level)
80
- } else {
81
- newLevels.add(level)
82
- }
83
-
84
- return { ...prev, enabledLevels: newLevels }
85
- })
86
- }
87
-
88
- const filterCycleField = () => {
89
- setFilter((prev) => ({
90
- ...prev,
91
- focusedField: prev.focusedField === 'search' ? 'levels' : 'search',
92
- }))
93
- }
94
-
95
- // Create keyboard manager with bindings
96
- const keyboardManager = createMemo(() => {
97
- const km = new KeyboardManager()
98
- const bindings = createDefaultBindings({
99
- manager: props.manager,
100
- getActiveScreen,
101
- toggleHelp,
102
- toggleFilter,
103
- closeFilter,
104
- filterAppendChar,
105
- filterDeleteChar,
106
- filterToggleLevel,
107
- filterCycleField,
108
- })
109
- km.addBindings(bindings)
110
- return km
111
- })
112
-
113
- // Keyboard handler
114
- const handleKeyboard = (key: { name: string; ctrl?: boolean; meta?: boolean; sequence?: string }) => {
115
- const screens = props.manager.getScreens()
116
- const activeScreen = props.manager.getActiveScreen()
117
-
118
- const context: KeyboardContext = {
119
- hasSidebar: screens.length > 1,
120
- focusArea: props.manager.focusArea,
121
- hasPrompt: activeScreen?.hasActivePrompt() ?? false,
122
- inInputMode: activeScreen?.isPromptInInputMode() ?? false,
123
- isFilterActive: filter().isVisible,
124
- isHelpVisible: showHelp(),
125
- }
126
-
127
- // Try keyboard manager first
128
- if (keyboardManager().handleKey(key, context)) {
129
- return
130
- }
131
-
132
- // Handle printable characters (for input mode and filter)
133
- handlePrintableInput(key, context, {
134
- manager: props.manager,
135
- getActiveScreen,
136
- toggleHelp,
137
- toggleFilter,
138
- closeFilter,
139
- filterAppendChar,
140
- filterDeleteChar,
141
- filterToggleLevel,
142
- filterCycleField,
143
- })
144
- }
145
-
146
- // Handle keyboard input
147
- useKeyboard(handleKeyboard)
148
-
149
- // Derived state
150
- const screens = () => {
151
- version() // Track for reactivity
152
- return props.manager.getScreens()
153
- }
154
-
155
- const activeScreen = () => {
156
- version() // Track for reactivity
157
- return props.manager.getActiveScreen()
158
- }
159
-
160
- const activeScreenId = () => activeScreen()?.getId() ?? screens()[0]?.getId() ?? ''
161
- const bindOptions = () => props.manager.getBindOptions()
162
- const hasSidebar = () => screens().length > 1
163
-
164
- // Subscribe to active screen version for level counts
165
- const [activeScreenVersion, setActiveScreenVersion] = createSignal(0)
166
-
167
- createEffect(() => {
168
- const screen = activeScreen()
169
- if (screen) {
170
- const unsub = screen.onChange(() => setActiveScreenVersion((v) => v + 1))
171
- onCleanup(() => unsub())
172
- }
173
- })
174
-
175
- // Get level counts for filter bar
176
- const levelCounts = createMemo(() => {
177
- activeScreenVersion() // Track for reactivity
178
- const screen = activeScreen()
179
- if (!screen) {
180
- return {
181
- verbose: 0,
182
- debug: 0,
183
- log: 0,
184
- warn: 0,
185
- error: 0,
186
- fatal: 0,
187
- }
188
- }
189
- return FilterEngine.countByLevel(screen.getMessages())
190
- })
191
-
192
- // Filter messages for the active screen
193
- const filteredMessages = createMemo(() => {
194
- activeScreenVersion() // Track for reactivity
195
- const screen = activeScreen()
196
- if (!screen) return []
197
- return FilterEngine.filterMessages(screen.getMessages(), filter())
198
- })
199
-
200
- const isFiltering = createMemo(() => hasActiveFilter(filter()))
201
-
202
- return (
203
- <LoggerProvider theme={props.theme}>
204
- <box flexDirection="row" flexGrow={1}>
205
- {/* Sidebar */}
206
- <Show when={hasSidebar()}>
207
- <Sidebar
208
- screens={screens()}
209
- selectedIndex={props.manager.selectedIndex}
210
- activeScreenId={activeScreenId()}
211
- focused={props.manager.focusArea === 'sidebar'}
212
- width={bindOptions().sidebarWidth ?? 25}
213
- title={bindOptions().sidebarTitle ?? 'Screens'}
214
- />
215
- </Show>
216
-
217
- {/* Main content area */}
218
- <box flexDirection="column" flexGrow={1}>
219
- {/* Filter bar */}
220
- <Show when={filter().isVisible}>
221
- <FilterBar filter={filter()} levelCounts={levelCounts()} />
222
- </Show>
223
-
224
- {/* Screen content */}
225
- <Show when={activeScreen()}>
226
- <ScreenBridge
227
- screen={activeScreen()!}
228
- focused={props.manager.focusArea === 'content'}
229
- filteredMessages={filteredMessages()}
230
- isFiltering={isFiltering()}
231
- totalMessages={activeScreen()!.getMessages().length}
232
- />
233
- </Show>
234
- </box>
235
-
236
- {/* Help overlay */}
237
- <Show when={showHelp()}>
238
- <HelpOverlay bindings={keyboardManager().getBindingsForHelp()} />
239
- </Show>
240
- </box>
241
- </LoggerProvider>
242
- )
243
- }
@@ -1,3 +0,0 @@
1
- export * from './sidebar.tsx'
2
- export * from './sidebar_item.tsx'
3
- export * from './sidebar_separator.tsx'
@@ -1,108 +0,0 @@
1
- import { TextAttributes } from '@opentui/core'
2
- import { For, Show, createMemo } from 'solid-js'
3
-
4
- import { useTheme } from '../../hooks/index.ts'
5
-
6
- import type { ScreenInstance } from '../../../../services/index.ts'
7
-
8
- import { SidebarItem } from './sidebar_item.tsx'
9
- import { SidebarSeparator } from './sidebar_separator.tsx'
10
-
11
- export interface SidebarProps {
12
- screens: ScreenInstance[]
13
- selectedIndex: number
14
- activeScreenId: string
15
- focused: boolean
16
- width: number
17
- title: string
18
- }
19
-
20
- export function Sidebar(props: SidebarProps) {
21
- const theme = useTheme()
22
-
23
- // Separate screens: only "pending" status on top, everything else below
24
- const pendingScreens = createMemo(() => {
25
- const result: { screen: ScreenInstance; originalIndex: number }[] = []
26
- props.screens.forEach((screen, index) => {
27
- if (screen.getStatus() === 'pending') {
28
- result.push({ screen, originalIndex: index })
29
- }
30
- })
31
- return result
32
- })
33
-
34
- const otherScreens = createMemo(() => {
35
- const result: { screen: ScreenInstance; originalIndex: number }[] = []
36
- props.screens.forEach((screen, index) => {
37
- if (screen.getStatus() !== 'pending') {
38
- result.push({ screen, originalIndex: index })
39
- }
40
- })
41
- return result
42
- })
43
-
44
- const hasPending = () => pendingScreens().length > 0
45
- const hasOther = () => otherScreens().length > 0
46
- const showSeparator = () => hasPending() && hasOther()
47
-
48
- return (
49
- <box
50
- flexDirection="column"
51
- width={props.width}
52
- borderColor={props.focused ? theme.sidebar.focusBorder : theme.sidebar.border}
53
- border={['right']}
54
- >
55
- {/* Sidebar header */}
56
- <box
57
- backgroundColor={theme.header.background}
58
- paddingLeft={1}
59
- paddingRight={1}
60
- borderColor={theme.header.border}
61
- border={['bottom']}
62
- >
63
- <text fg={theme.header.text} attributes={TextAttributes.BOLD}>
64
- {props.title}
65
- </text>
66
- </box>
67
-
68
- {/* Screen list */}
69
- <scrollbox scrollY stickyScroll={false} flexGrow={1} contentOptions={{ flexGrow: 1 }}>
70
- <box flexDirection="column">
71
- {/* Pending screens (active work) */}
72
- <For each={pendingScreens()}>
73
- {({ screen, originalIndex }) => (
74
- <SidebarItem
75
- screen={screen}
76
- isSelected={originalIndex === props.selectedIndex}
77
- isActive={screen.getId() === props.activeScreenId}
78
- focused={props.focused}
79
- />
80
- )}
81
- </For>
82
-
83
- {/* Separator between pending and other screens */}
84
- <Show when={showSeparator()}>
85
- <SidebarSeparator />
86
- </Show>
87
-
88
- {/* Other screens (waiting, success, fail) */}
89
- <For each={otherScreens()}>
90
- {({ screen, originalIndex }) => (
91
- <SidebarItem
92
- screen={screen}
93
- isSelected={originalIndex === props.selectedIndex}
94
- isActive={screen.getId() === props.activeScreenId}
95
- focused={props.focused}
96
- />
97
- )}
98
- </For>
99
- </box>
100
- </scrollbox>
101
-
102
- {/* Footer with keybindings hint */}
103
- <box paddingLeft={1} paddingRight={1} borderColor={theme.sidebar.border} border={['top']}>
104
- <text fg={theme.sidebar.text}>q: exit | Tab: focus | ?: help</text>
105
- </box>
106
- </box>
107
- )
108
- }
@@ -1,55 +0,0 @@
1
- import { TextAttributes } from '@opentui/core'
2
- import { Show } from 'solid-js'
3
-
4
- import { useTheme } from '../../hooks/index.ts'
5
-
6
- import type { ScreenInstance } from '../../../../services/index.ts'
7
-
8
- export interface SidebarItemProps {
9
- screen: ScreenInstance
10
- isSelected: boolean
11
- isActive: boolean
12
- focused: boolean
13
- }
14
-
15
- export function SidebarItem(props: SidebarItemProps) {
16
- const theme = useTheme()
17
- const status = () => props.screen.getStatus()
18
- const statusIndicator = () => theme.statusIndicators[status()]
19
-
20
- // Determine background color based on state
21
- const backgroundColor = () => {
22
- if (props.isSelected && props.focused) {
23
- return theme.sidebar.selectedBackground
24
- } else if (props.isActive) {
25
- return theme.sidebar.selectedBackground + '80'
26
- }
27
- return undefined
28
- }
29
-
30
- return (
31
- <box flexDirection="row" paddingLeft={1} paddingRight={1} backgroundColor={backgroundColor()}>
32
- {/* Selection indicator */}
33
- <text fg={props.isSelected && props.focused ? theme.sidebar.focusBorder : 'transparent'}>
34
- {'>'}{' '}
35
- </text>
36
-
37
- {/* Status indicator */}
38
- <text fg={statusIndicator().color}>{statusIndicator().icon} </text>
39
-
40
- {/* Screen name */}
41
- <text fg={props.isActive ? theme.sidebar.text : theme.sidebar.textDim} flexGrow={1}>
42
- {props.screen.getName()}
43
- </text>
44
-
45
- {/* Badge if present */}
46
- <Show when={props.screen.getBadgeCount() > 0}>
47
- <box backgroundColor={theme.sidebar.badge} paddingLeft={1} paddingRight={1}>
48
- <text fg={theme.colors.foreground} attributes={TextAttributes.BOLD}>
49
- {props.screen.getBadgeCount() > 99 ? '99+' : props.screen.getBadgeCount()}
50
- </text>
51
- </box>
52
- </Show>
53
- </box>
54
- )
55
- }
@@ -1,13 +0,0 @@
1
- import { useTheme } from '../../hooks/index.ts'
2
-
3
- export function SidebarSeparator() {
4
- const theme = useTheme()
5
-
6
- return (
7
- <box flexDirection="row" paddingTop={1}>
8
- <box flexGrow={1} />
9
- <text fg={theme.separator.line}>· · ·</text>
10
- <box flexGrow={1} />
11
- </box>
12
- )
13
- }
@@ -1,2 +0,0 @@
1
- export { LoggerProvider, useLoggerContext } from './logger_context.tsx'
2
- export type { LoggerProviderProps } from './logger_context.tsx'