gloomberb 0.11.2 → 0.12.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 (531) hide show
  1. package/README.md +7 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -1
  4. package/src/api-client/auth.ts +10 -0
  5. package/src/api-client/data.ts +108 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +134 -1
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/types.ts +220 -0
  11. package/src/app/pane-runtime/index.tsx +15 -12
  12. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  13. package/src/app/pane-runtime/layout-placement.ts +13 -0
  14. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  15. package/src/app.tsx +60 -18
  16. package/src/architecture/browser-entry-graph.test.ts +96 -0
  17. package/src/brokers/profile-form.test.ts +25 -27
  18. package/src/brokers/test-broker.ts +68 -0
  19. package/src/capabilities/chart-series.ts +3 -2
  20. package/src/cli/commands/market.ts +2 -2
  21. package/src/cli/commands/plugins.ts +39 -11
  22. package/src/cli/desktop-pane-shot.ts +285 -16
  23. package/src/cli/index.ts +1 -1
  24. package/src/cli/pane-functions/capabilities.ts +61 -31
  25. package/src/cli/pane-functions/catalog.ts +16 -4
  26. package/src/cli/pane-functions/discovery.ts +1 -0
  27. package/src/cli/pane-functions/headless.test.ts +247 -0
  28. package/src/cli/pane-functions/headless.ts +423 -0
  29. package/src/cli/pane-functions/index.test.ts +9 -0
  30. package/src/cli/pane-functions/index.ts +6 -2
  31. package/src/cli/pane-functions/options.ts +27 -2
  32. package/src/cli/pane-functions/report.ts +4 -0
  33. package/src/cli/pane-functions/resolver.ts +26 -8
  34. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  35. package/src/cli/pane-functions/screenshot.ts +236 -20
  36. package/src/cli/registry.ts +0 -22
  37. package/src/cli/restore-plugins.ts +34 -0
  38. package/src/cli/result.ts +7 -10
  39. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  40. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  41. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  42. package/src/components/chart/composite/composite-chart.test.tsx +68 -20
  43. package/src/components/chart/composite/composite-chart.tsx +301 -204
  44. package/src/components/chart/composite/format.ts +8 -2
  45. package/src/components/chart/composite/interactions.test.ts +68 -102
  46. package/src/components/chart/composite/interactions.ts +214 -264
  47. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  48. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  49. package/src/components/chart/composite/scene.ts +57 -3
  50. package/src/components/chart/composite/text-renderer.ts +3 -2
  51. package/src/components/chart/composite/time-scale.ts +138 -57
  52. package/src/components/chart/composite/types.ts +25 -1
  53. package/src/components/chart/core/data.ts +9 -13
  54. package/src/components/chart/core/date-window.ts +7 -1
  55. package/src/components/chart/core/pointer.ts +3 -0
  56. package/src/components/chart/core/types.ts +0 -45
  57. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  58. package/src/components/chart/native/kitty/index.test.ts +0 -188
  59. package/src/components/chart/native/raster/crosshair.ts +6 -5
  60. package/src/components/chart/native/raster/primitives.ts +0 -23
  61. package/src/components/chart/native/renderer-selection.ts +81 -31
  62. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  63. package/src/components/chart/static/chart-surface.tsx +150 -0
  64. package/src/components/chart/static/index.ts +8 -0
  65. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  66. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  67. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  68. package/src/components/chart/static/series.ts +49 -0
  69. package/src/components/command-bar/action-runtime.ts +1 -3
  70. package/src/components/command-bar/assist/model.test.ts +17 -2
  71. package/src/components/command-bar/assist/model.ts +40 -9
  72. package/src/components/command-bar/commands/direct/index.ts +1 -1
  73. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  74. package/src/components/command-bar/commands/registry.ts +0 -11
  75. package/src/components/command-bar/helpers.test.ts +2 -2
  76. package/src/components/command-bar/helpers.ts +2 -6
  77. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  78. package/src/components/command-bar/list/badge.test.ts +54 -0
  79. package/src/components/command-bar/list/badge.ts +62 -0
  80. package/src/components/command-bar/list/model.test.ts +103 -0
  81. package/src/components/command-bar/list/model.ts +61 -4
  82. package/src/components/command-bar/list/view.test.tsx +113 -0
  83. package/src/components/command-bar/list/view.tsx +147 -131
  84. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  85. package/src/components/command-bar/panel/body.tsx +51 -65
  86. package/src/components/command-bar/panel/index.tsx +48 -13
  87. package/src/components/command-bar/panel/layout.test.ts +139 -0
  88. package/src/components/command-bar/panel/layout.ts +65 -28
  89. package/src/components/command-bar/panel/native-surface.ts +24 -0
  90. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  91. package/src/components/command-bar/panel/runtime.ts +6 -3
  92. package/src/components/command-bar/panel/state.ts +41 -7
  93. package/src/components/command-bar/panel/types.ts +7 -1
  94. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  95. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  96. package/src/components/command-bar/routes/root/results.ts +30 -28
  97. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  98. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  99. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  100. package/src/components/command-bar/routes/root/selection.ts +1 -12
  101. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  102. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  103. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  104. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  105. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  106. package/src/components/command-bar/routing/actions.ts +1 -81
  107. package/src/components/command-bar/routing/launch-request.ts +1 -1
  108. package/src/components/command-bar/routing/list-state.ts +6 -21
  109. package/src/components/command-bar/selection-runtime.ts +1 -1
  110. package/src/components/command-bar/surface/assist.test.tsx +14 -10
  111. package/src/components/command-bar/surface/environment.ts +8 -1
  112. package/src/components/command-bar/surface/index.test.tsx +84 -68
  113. package/src/components/command-bar/surface/index.tsx +33 -36
  114. package/src/components/command-bar/surface/test-harness.tsx +15 -3
  115. package/src/components/command-bar/theme-picker.tsx +43 -15
  116. package/src/components/command-bar/view-model.test.ts +53 -8
  117. package/src/components/command-bar/view-model.ts +43 -14
  118. package/src/components/command-bar/workflow/tickers.ts +1 -0
  119. package/src/components/command-bar/workflow/types.ts +1 -1
  120. package/src/components/data-table/export.test.ts +21 -0
  121. package/src/components/data-table/export.ts +21 -0
  122. package/src/components/data-table/view.test.tsx +45 -6
  123. package/src/components/data-table/view.tsx +55 -9
  124. package/src/components/index.ts +10 -2
  125. package/src/components/input-search-bar.test.tsx +36 -2
  126. package/src/components/input-search-bar.tsx +18 -1
  127. package/src/components/layout/header.test.tsx +57 -10
  128. package/src/components/layout/header.tsx +292 -149
  129. package/src/components/layout/market-summary.test.ts +81 -0
  130. package/src/components/layout/market-summary.ts +109 -0
  131. package/src/components/layout/shell/chrome.ts +96 -1
  132. package/src/components/layout/shell/index.tsx +11 -3
  133. package/src/components/layout/shell/menu.ts +9 -0
  134. package/src/components/layout/shell/pane/actions.ts +29 -0
  135. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  136. package/src/components/layout/shell/shortcuts.ts +3 -0
  137. package/src/components/layout/status-bar.test.tsx +9 -8
  138. package/src/components/layout/status-bar.tsx +85 -54
  139. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  140. package/src/components/price-sparkline/index.ts +61 -34
  141. package/src/components/price-sparkline/view.tsx +1 -1
  142. package/src/components/sign-in-gate.test.tsx +128 -0
  143. package/src/components/sign-in-gate.tsx +149 -0
  144. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  145. package/src/components/ticker/badge/list.tsx +17 -3
  146. package/src/components/ticker/list-table-view.tsx +6 -3
  147. package/src/components/ui/data-table/index.tsx +22 -4
  148. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  149. package/src/components/ui/frame.tsx +28 -0
  150. package/src/components/ui/index.ts +3 -0
  151. package/src/components/ui/native-select.tsx +20 -10
  152. package/src/components/ui/select-button.tsx +138 -0
  153. package/src/components/ui/status.tsx +2 -2
  154. package/src/components/ui/table-layout.ts +1 -1
  155. package/src/components/use-double-click-activation.ts +7 -3
  156. package/src/core/app-services.ts +3 -3
  157. package/src/data/config/chart-settings.ts +4 -4
  158. package/src/data/config/layout.ts +12 -6
  159. package/src/data/config/store/index.test.ts +97 -0
  160. package/src/data/config/store/migrations.ts +41 -0
  161. package/src/data/config/store/normalize.ts +5 -3
  162. package/src/i18n/es.ts +6 -2
  163. package/src/i18n/ja.ts +6 -2
  164. package/src/i18n/ko.ts +6 -2
  165. package/src/i18n/zh-cn.ts +6 -2
  166. package/src/i18n/zh-tw.ts +6 -2
  167. package/src/layout-marketplace/gallery-terminal.tsx +126 -96
  168. package/src/layout-marketplace/gallery.test.tsx +65 -1
  169. package/src/layout-marketplace/pane-imagery.ts +1 -0
  170. package/src/layout-marketplace/payload.test.ts +17 -0
  171. package/src/layout-marketplace/payload.ts +40 -5
  172. package/src/market-data/coordinator/index.ts +3 -2
  173. package/src/market-data/coordinator/quotes.ts +173 -66
  174. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  175. package/src/pane-settings.ts +1 -1
  176. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  177. package/src/plugins/builtin/analytics/view.tsx +1 -1
  178. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  179. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  180. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  181. package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
  182. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  183. package/src/plugins/builtin/chart-composer/settings.ts +2 -13
  184. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  185. package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
  186. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  187. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  188. package/src/plugins/builtin/composite-plugins.ts +16 -1
  189. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  190. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  191. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  192. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  193. package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
  194. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  195. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  196. package/src/plugins/builtin/earnings/index.tsx +1 -0
  197. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  198. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  199. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  200. package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
  201. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  202. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  203. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
  204. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  205. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  206. package/src/plugins/builtin/econ/index.tsx +3 -1
  207. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  208. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  209. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  210. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  211. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  212. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  213. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  214. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  215. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  216. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  217. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  218. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  219. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  220. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  221. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  222. package/src/plugins/builtin/futures/index.tsx +1 -0
  223. package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
  224. package/src/plugins/builtin/help/index.tsx +4 -0
  225. package/src/plugins/builtin/holders/index.tsx +1 -0
  226. package/src/plugins/builtin/insider/index.tsx +1 -0
  227. package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
  228. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  229. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  230. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  231. package/src/plugins/builtin/market-movers/index.tsx +1 -0
  232. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  233. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  234. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  235. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  236. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  237. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  238. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  239. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  240. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  241. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  242. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  243. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  244. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  245. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  246. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  247. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  248. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  249. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  250. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  251. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  252. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  253. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  254. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  255. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  256. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  257. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  258. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  259. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  260. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  261. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  262. package/src/plugins/builtin/options/analytics.test.ts +83 -0
  263. package/src/plugins/builtin/options/analytics.ts +110 -0
  264. package/src/plugins/builtin/options/index.tsx +18 -2
  265. package/src/plugins/builtin/options/table.ts +121 -51
  266. package/src/plugins/builtin/options/types.ts +22 -15
  267. package/src/plugins/builtin/options/view.test.tsx +53 -1
  268. package/src/plugins/builtin/options/view.tsx +92 -41
  269. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  270. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  271. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  272. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  273. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  274. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  275. package/src/plugins/builtin/plugin-module.test.ts +2 -4
  276. package/src/plugins/builtin/plugin-module.ts +9 -8
  277. package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
  278. package/src/plugins/builtin/research/index.tsx +4 -0
  279. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  280. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  281. package/src/plugins/builtin/research-search/data.ts +109 -0
  282. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  283. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  284. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  285. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  286. package/src/plugins/builtin/research-search/index.tsx +85 -0
  287. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  288. package/src/plugins/builtin/research-search/model.ts +291 -0
  289. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  290. package/src/plugins/builtin/research-search/pane.tsx +678 -0
  291. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  292. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  293. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  294. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  295. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  296. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  297. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  298. package/src/plugins/builtin/scanner/index.ts +2 -0
  299. package/src/plugins/builtin/sec/index.tsx +1 -0
  300. package/src/plugins/builtin/sectors/index.tsx +1 -0
  301. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  302. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  303. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  304. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  305. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
  306. package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  308. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  309. package/src/plugins/builtin/volatility/index.tsx +1 -1
  310. package/src/plugins/builtin/world-indices/index.tsx +1 -0
  311. package/src/plugins/builtin/world-venue-map/index.ts +27 -0
  312. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  313. package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
  314. package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
  315. package/src/plugins/builtin/world-venue-map/model.ts +268 -0
  316. package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
  317. package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
  318. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  319. package/src/plugins/bundle.test.ts +109 -0
  320. package/src/plugins/bundle.ts +139 -0
  321. package/src/plugins/catalog-backend.ts +6 -44
  322. package/src/plugins/catalog-browser.test.ts +1 -0
  323. package/src/plugins/catalog-browser.ts +12 -0
  324. package/src/plugins/catalog-manifest.test.ts +43 -0
  325. package/src/plugins/catalog-manifest.ts +92 -0
  326. package/src/plugins/catalog-ui.ts +20 -4
  327. package/src/plugins/catalog.ts +9 -2
  328. package/src/plugins/current-target.ts +28 -0
  329. package/src/plugins/host-contract.ts +37 -0
  330. package/src/plugins/host-link.ts +158 -0
  331. package/src/plugins/host-modules.ts +61 -0
  332. package/src/plugins/loader.ts +41 -22
  333. package/src/plugins/ownership.ts +1 -0
  334. package/src/plugins/prediction-markets/index.tsx +1 -0
  335. package/src/plugins/registry/context.ts +3 -0
  336. package/src/plugins/registry/contributions.ts +27 -0
  337. package/src/plugins/registry/index.test.ts +25 -0
  338. package/src/plugins/registry/index.ts +8 -0
  339. package/src/plugins/registry/pane-settings.test.ts +53 -0
  340. package/src/plugins/registry/pane-settings.ts +29 -3
  341. package/src/plugins/seed.test.ts +83 -0
  342. package/src/plugins/seed.ts +80 -0
  343. package/src/public/broker.ts +31 -0
  344. package/src/public/market-data.ts +9 -0
  345. package/src/public/pane-hooks.ts +57 -0
  346. package/src/public/public-api.test.ts +285 -0
  347. package/src/public/react.ts +62 -0
  348. package/src/public/test-support.ts +23 -0
  349. package/src/public/time-series.ts +8 -0
  350. package/src/public/utils.ts +77 -0
  351. package/src/remote/layout-helpers.ts +6 -8
  352. package/src/remote/resources.ts +2 -0
  353. package/src/remote/schema.ts +1 -0
  354. package/src/remote/semantic-tree.test.tsx +105 -0
  355. package/src/remote/semantic-tree.tsx +53 -35
  356. package/src/renderers/browser/main.tsx +6 -0
  357. package/src/renderers/browser/ui-host.tsx +11 -0
  358. package/src/renderers/cloudflare/worker.test.ts +19 -0
  359. package/src/renderers/cloudflare/worker.ts +1 -1
  360. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
  361. package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
  362. package/src/renderers/electrobun/bun/index.ts +6 -2
  363. package/src/renderers/electrobun/shared/protocol.ts +25 -0
  364. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  365. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
  366. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  367. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  368. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  369. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  370. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  371. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  372. package/src/renderers/electrobun/view/main.tsx +27 -2
  373. package/src/renderers/electrobun/view/styles.css +5 -0
  374. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  375. package/src/renderers/electrobun/view/ui-host.tsx +3 -0
  376. package/src/renderers/opentui/chart-surface.tsx +5 -1
  377. package/src/renderers/opentui/host.tsx +20 -2
  378. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  379. package/src/renderers/opentui/interaction-performance.ts +188 -0
  380. package/src/renderers/opentui/start.tsx +26 -1
  381. package/src/renderers/opentui/test-utils.tsx +13 -0
  382. package/src/renderers/opentui/toast-host.tsx +26 -2
  383. package/src/renderers/opentui/ui-host.tsx +1 -0
  384. package/src/sources/provider-router/search.test.ts +191 -0
  385. package/src/sources/provider-router/search.ts +92 -39
  386. package/src/state/app/context/index.tsx +2 -0
  387. package/src/state/app/context/selector.test.tsx +33 -1
  388. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  389. package/src/state/hooks/quote-streaming.ts +106 -30
  390. package/src/state/pane-table-export-registry.ts +50 -0
  391. package/src/theme/color-utils.ts +1 -1
  392. package/src/theme/colors.ts +50 -0
  393. package/src/theme/themes.test.ts +15 -2
  394. package/src/theme/themes.ts +19 -1
  395. package/src/tickers/search/index.test.ts +26 -0
  396. package/src/tickers/search/index.ts +42 -17
  397. package/src/tickers/search/ranking.ts +14 -0
  398. package/src/time-series/chart-data.test.ts +216 -0
  399. package/src/time-series/range.ts +12 -0
  400. package/src/time-series/resolution.test.ts +25 -26
  401. package/src/time-series/resolution.ts +44 -25
  402. package/src/time-series/resolve.ts +7 -0
  403. package/src/time-series/spec.ts +5 -5
  404. package/src/time-series/types.ts +3 -1
  405. package/src/time-series/use-chart-resolution.ts +5 -0
  406. package/src/types/config.ts +123 -3
  407. package/src/types/data-provider.ts +11 -0
  408. package/src/types/headless.ts +161 -0
  409. package/src/types/plugin.ts +104 -20
  410. package/src/ui/host.tsx +19 -1
  411. package/src/ui/index.tsx +1 -0
  412. package/src/ui/toast.tsx +8 -4
  413. package/src/utils/csv.test.ts +13 -0
  414. package/src/utils/csv.ts +37 -0
  415. package/src/utils/format.ts +35 -0
  416. package/src/utils/fuzzy-search.test.ts +94 -0
  417. package/src/utils/fuzzy-search.ts +81 -22
  418. package/src/utils/save-text-file.test.ts +24 -0
  419. package/src/utils/save-text-file.ts +36 -0
  420. package/src/utils/shortcut-labels.ts +14 -0
  421. package/src/components/chart/core/axis-format.ts +0 -157
  422. package/src/components/chart/core/index.test.ts +0 -1075
  423. package/src/components/chart/core/projection.ts +0 -357
  424. package/src/components/chart/core/render-utils.ts +0 -4
  425. package/src/components/chart/core/renderer.ts +0 -244
  426. package/src/components/chart/core/scene.ts +0 -180
  427. package/src/components/chart/core/time-axis.ts +0 -330
  428. package/src/components/chart/cursor-motion.ts +0 -47
  429. package/src/components/chart/indicators/types.ts +0 -26
  430. package/src/components/chart/market-session.ts +0 -176
  431. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  432. package/src/components/chart/multi-line/renderer.ts +0 -161
  433. package/src/components/chart/multi-line/scene.ts +0 -188
  434. package/src/components/chart/native/raster/layout.ts +0 -129
  435. package/src/components/chart/native/raster/price-chart.ts +0 -244
  436. package/src/components/chart/rendering/chart-draw.ts +0 -270
  437. package/src/components/chart/rendering/geometry.ts +0 -95
  438. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  439. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  440. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  441. package/src/components/chart/static/chart/surface.tsx +0 -358
  442. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  443. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  444. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  445. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  446. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  447. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  448. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  449. package/src/plugins/builtin/substack/api/store.ts +0 -186
  450. package/src/plugins/builtin/substack/api/types.ts +0 -42
  451. package/src/plugins/builtin/substack/api.test.ts +0 -298
  452. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  453. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  454. package/src/plugins/builtin/substack/content.ts +0 -478
  455. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  456. package/src/plugins/builtin/substack/index.tsx +0 -49
  457. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  458. package/src/plugins/builtin/substack/model.test.ts +0 -155
  459. package/src/plugins/builtin/substack/normalize.ts +0 -343
  460. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  461. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  462. package/src/plugins/builtin/substack/pane.tsx +0 -547
  463. package/src/plugins/builtin/substack/read-state.ts +0 -30
  464. package/src/plugins/builtin/substack/table.ts +0 -111
  465. package/src/plugins/builtin/substack/types.ts +0 -71
  466. package/src/plugins/builtin/substack/utils.ts +0 -131
  467. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  468. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  469. package/src/plugins/ibkr/account-cache.ts +0 -24
  470. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  471. package/src/plugins/ibkr/config.test.ts +0 -79
  472. package/src/plugins/ibkr/config.ts +0 -250
  473. package/src/plugins/ibkr/dialogs.tsx +0 -40
  474. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  475. package/src/plugins/ibkr/flex/index.ts +0 -367
  476. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  477. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  478. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  479. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  480. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  481. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  482. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  483. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  484. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  485. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  486. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  487. package/src/plugins/ibkr/gateway/history.ts +0 -120
  488. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  489. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  490. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  491. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  492. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  493. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  494. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  495. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  496. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  497. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  498. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  499. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  500. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  501. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  502. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  503. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  504. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  505. package/src/plugins/ibkr/gateway/types.ts +0 -27
  506. package/src/plugins/ibkr/index.test.tsx +0 -162
  507. package/src/plugins/ibkr/index.tsx +0 -159
  508. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  509. package/src/plugins/ibkr/instance-selection.ts +0 -36
  510. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  511. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  512. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  513. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  514. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  515. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  516. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  517. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  518. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  519. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  520. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  521. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  522. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  523. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  524. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  525. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  526. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  527. package/src/plugins/ibkr/trade/utils.ts +0 -144
  528. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  529. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  530. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  531. package/src/plugins/ibkr/trading/state.ts +0 -335
@@ -0,0 +1,109 @@
1
+ import { useEffect, useState } from "react";
2
+ import { priceColor } from "../../theme/colors";
3
+ import { useThemeColors } from "../../theme/theme-context";
4
+ import { useAppActive } from "../../state/app/activity";
5
+ import { useAppSelector } from "../../state/app/context";
6
+ import { selectBaseCurrency } from "../../state/selectors-ui";
7
+ import { getSharedMarketDataCoordinator } from "../../market-data/coordinator";
8
+ import { t } from "../../i18n";
9
+ import { useQuoteEntry, useResolvedEntryValue } from "../../market-data/hooks";
10
+ import { formatPercentRaw } from "../../utils/format";
11
+ import { formatMarketPrice } from "../../market-data/market/format";
12
+ import { getActiveQuoteDisplay, marketStateColor, marketStateCountdown, marketStateLabel } from "../../market-data/market/status";
13
+
14
+ const SPY_REFRESH_MS = 5 * 60_000; // 5 min
15
+
16
+ export interface MarketSummary {
17
+ baseCurrency: string;
18
+ marketColor: string;
19
+ /** Market state with its countdown, when the state has one. */
20
+ marketLabel: string;
21
+ /** Market state alone, for a header too narrow for the countdown. */
22
+ marketLabelShort: string;
23
+ spyColor: string;
24
+ spyText: string;
25
+ }
26
+
27
+ export interface MarketSummaryFit {
28
+ showBaseCurrency: boolean;
29
+ showCountdown: boolean;
30
+ showState: boolean;
31
+ showSpy: boolean;
32
+ }
33
+
34
+ /**
35
+ * Picks which parts of the cluster survive at a given width, ordered by how
36
+ * much each can still change: SPY first, then the market-state label, then the
37
+ * base currency, then the countdown suffix that widens the label. A narrowing
38
+ * header therefore sheds the countdown, then the currency, then the state, and
39
+ * keeps SPY longest. `countdownWidth` is what the suffix adds to the label.
40
+ */
41
+ export function resolveMarketSummaryFit(options: {
42
+ available: number;
43
+ baseCurrencyWidth: number;
44
+ countdownWidth: number;
45
+ spyWidth: number;
46
+ stateWidth: number;
47
+ }): MarketSummaryFit {
48
+ let remaining = options.available;
49
+ const take = (width: number): boolean => {
50
+ if (width <= 0 || width > remaining) return false;
51
+ remaining -= width;
52
+ return true;
53
+ };
54
+ const showSpy = take(options.spyWidth);
55
+ const showState = take(options.stateWidth);
56
+ const showBaseCurrency = take(options.baseCurrencyWidth);
57
+ const showCountdown = showState && take(options.countdownWidth);
58
+ return { showBaseCurrency, showCountdown, showState, showSpy };
59
+ }
60
+
61
+ export function useMarketSummary(): MarketSummary {
62
+ const colors = useThemeColors();
63
+ const appActive = useAppActive();
64
+ const baseCurrency = useAppSelector(selectBaseCurrency);
65
+ const spyQuoteEntry = useQuoteEntry("SPY", null);
66
+ const spyQuote = useResolvedEntryValue(spyQuoteEntry);
67
+ const mktState = spyQuote?.marketState;
68
+ const [now, setNow] = useState(Date.now());
69
+
70
+ useEffect(() => {
71
+ if (!appActive || (mktState !== "PRE" && mktState !== "REGULAR")) return;
72
+ setNow(Date.now());
73
+ const id = setInterval(() => setNow(Date.now()), 1_000);
74
+ return () => clearInterval(id);
75
+ }, [appActive, mktState]);
76
+
77
+ useEffect(() => {
78
+ if (!appActive) return;
79
+ const coordinator = getSharedMarketDataCoordinator();
80
+ if (!coordinator) return;
81
+ const fetchSpy = async () => {
82
+ await coordinator.loadQuote({ symbol: "SPY" }).catch(() => {});
83
+ };
84
+ fetchSpy();
85
+ const id = setInterval(fetchSpy, SPY_REFRESH_MS);
86
+ return () => { clearInterval(id); };
87
+ }, [appActive]);
88
+
89
+ const activeSpyQuote = getActiveQuoteDisplay(spyQuote);
90
+ const spyColor = activeSpyQuote ? priceColor(activeSpyQuote.change, colors) : colors.textDim;
91
+ const spyText = activeSpyQuote
92
+ ? `SPY ${formatMarketPrice(activeSpyQuote.price, { assetCategory: "ETF" })} ${formatPercentRaw(activeSpyQuote.changePercent)}`
93
+ : "SPY —";
94
+
95
+ const mktCountdown = mktState ? marketStateCountdown(mktState, now) : null;
96
+ const marketLabelShort = mktState ? t(marketStateLabel(mktState)) : "";
97
+ const marketLabel = marketLabelShort && mktCountdown
98
+ ? `${marketLabelShort} · ${mktCountdown}`
99
+ : marketLabelShort;
100
+
101
+ return {
102
+ baseCurrency,
103
+ marketColor: mktState ? marketStateColor(mktState, colors) : colors.textDim,
104
+ marketLabel,
105
+ marketLabelShort,
106
+ spyColor,
107
+ spyText,
108
+ };
109
+ }
@@ -1,8 +1,103 @@
1
- import { TITLEBAR_OVERLAY_HEIGHT_PX } from "../titlebar-overlay";
1
+ import { TITLEBAR_OVERLAY_HEIGHT_PX, getTitlebarLeadingInset } from "../titlebar-overlay";
2
2
 
3
3
  export const DEFAULT_HEADER_HEIGHT = 1;
4
4
 
5
+ const HEADER_PROMPT_MIN_WIDTH = 10;
6
+ /** Columns the header keeps free right of the prompt for the update status. */
7
+ const HEADER_PROMPT_UPDATE_COLUMNS = 14;
8
+ /**
9
+ * Width the prompt holds before the market cluster is offered anything. Above
10
+ * the command surface minimum so a mid-size window does not hand the cluster a
11
+ * whole tier and leave the sheet sitting on its floor.
12
+ */
13
+ const HEADER_PROMPT_COMFORT_WIDTH = 48;
14
+ /** Narrowest command surface, by host: a document snippet still reads here. */
15
+ const COMMAND_SURFACE_MIN_WIDTH = { native: 46, terminal: 42 };
16
+
17
+ /**
18
+ * The market cluster's reserve at the header's right edge, widest first. Each
19
+ * step is the worst case for what it shows, so a ticking countdown or a longer
20
+ * state label can never push the cluster past its columns:
21
+ *
22
+ * 42 PRE-MKT · 5h 30m SPY 1,234.56 -10.60% USD
23
+ * 31 the state label and SPY
24
+ * 21 SPY alone
25
+ *
26
+ * Steps rather than a share of the window: a reserve of, say, 18 columns is
27
+ * too narrow for anything and would waste all 18. There is deliberately no
28
+ * step for "everything but the countdown", which would cost the sheet eleven
29
+ * columns to add the base currency, the one value here that barely moves.
30
+ */
31
+ const HEADER_MARKET_TIERS = [42, 31, 21] as const;
32
+
33
+ /**
34
+ * Update status is transient, so on a narrow header it gives most of its
35
+ * reserve back rather than shortening the placeholder that has to sell the
36
+ * command bar to a first-time user.
37
+ */
38
+ function headerPromptUpdateColumns(termWidth: number): number {
39
+ return Math.min(HEADER_PROMPT_UPDATE_COLUMNS, Math.max(4, Math.floor(termWidth * 0.12)));
40
+ }
41
+
42
+ /**
43
+ * Columns the market cluster gets, from the terminal width alone: a reserve
44
+ * that tracked the quote would resize the prompt every time SPY ticked.
45
+ */
46
+ function headerMarketColumns(termWidth: number, left: number, updateColumns: number): number {
47
+ const spare = termWidth - left - updateColumns - HEADER_PROMPT_COMFORT_WIDTH;
48
+ return HEADER_MARKET_TIERS.find((tier) => tier <= spare) ?? 0;
49
+ }
50
+
5
51
  export function resolveAppHeaderHeightCells(options: { titleBarOverlay?: boolean; cellHeightPx?: number }): number {
6
52
  if (!options.titleBarOverlay || !options.cellHeightPx || options.cellHeightPx <= 0) return DEFAULT_HEADER_HEIGHT;
7
53
  return TITLEBAR_OVERLAY_HEIGHT_PX / options.cellHeightPx;
8
54
  }
55
+
56
+ /**
57
+ * Width shared by the header prompt and the command sheet that drops out of
58
+ * it, so the sheet reads as the prompt expanding downward. A fraction of the
59
+ * window so the update status and the Help pill keep their place, capped where
60
+ * a document snippet still has room but a label does not run past where the
61
+ * eye goes.
62
+ */
63
+ export function resolveCommandSurfaceWidth(options: { termWidth: number; nativePaneChrome?: boolean }): number {
64
+ const { termWidth } = options;
65
+ return options.nativePaneChrome
66
+ ? Math.max(COMMAND_SURFACE_MIN_WIDTH.native, Math.min(104, termWidth - 10, Math.floor(termWidth * 0.64)))
67
+ : Math.max(COMMAND_SURFACE_MIN_WIDTH.terminal, Math.min(96, termWidth - 8, Math.floor(termWidth * 0.68)));
68
+ }
69
+
70
+ export interface HeaderPromptGeometry {
71
+ /** Column the prompt starts at. */
72
+ left: number;
73
+ width: number;
74
+ /** Columns held at the header's right edge for the market cluster. */
75
+ marketColumns: number;
76
+ }
77
+
78
+ /**
79
+ * Geometry of the always-visible command prompt in the header. While the
80
+ * command bar is open the same prompt hosts its input, so the geometry never
81
+ * changes underneath the user.
82
+ */
83
+ export function resolveHeaderPromptGeometry(options: {
84
+ termWidth: number;
85
+ nativePaneChrome?: boolean;
86
+ nativeWindowChrome?: boolean;
87
+ titleBarOverlay?: boolean;
88
+ }): HeaderPromptGeometry {
89
+ const { nativePaneChrome, termWidth, titleBarOverlay } = options;
90
+ const nativeWindowChrome = options.nativeWindowChrome ?? titleBarOverlay;
91
+ const leadingInset = titleBarOverlay && nativeWindowChrome ? getTitlebarLeadingInset() : 0;
92
+ const left = leadingInset + 1;
93
+ const updateColumns = headerPromptUpdateColumns(termWidth);
94
+ const marketColumns = headerMarketColumns(termWidth, left, updateColumns);
95
+ const width = Math.max(
96
+ HEADER_PROMPT_MIN_WIDTH,
97
+ Math.min(
98
+ resolveCommandSurfaceWidth({ nativePaneChrome, termWidth }),
99
+ termWidth - left - updateColumns - marketColumns,
100
+ ),
101
+ );
102
+ return { left, width, marketColumns };
103
+ }
@@ -30,9 +30,10 @@ import {
30
30
  selectStatusBarVisible,
31
31
  } from "../../../state/selectors-ui";
32
32
  import { useThemeColors } from "../../../theme/theme-context";
33
+ import { tf } from "../../../i18n";
33
34
  import { getPaneDisplayTitle } from "../pane/title";
34
35
  import type { PaneHeaderQuickSetting } from "../pane/header";
35
- import { getShortcutDisplayMode } from "../../../utils/shortcut-labels";
36
+ import { formatCommandBarShortcut, getShortcutDisplayMode } from "../../../utils/shortcut-labels";
36
37
  import {
37
38
  actionMenuWidth,
38
39
  menuForPane,
@@ -257,10 +258,13 @@ export function Shell({
257
258
  });
258
259
 
259
260
  const {
261
+ canExportPaneCsv,
260
262
  closeAllFloatingPanes,
261
263
  closeFocusedPane,
262
264
  copyFocusedPaneScreenshot,
263
265
  copyPaneScreenshot,
266
+ exportFocusedPaneCsv,
267
+ exportPaneCsv,
264
268
  gridlockVisiblePanes,
265
269
  handleFloatingClose,
266
270
  openFocusedPaneSettings,
@@ -474,6 +478,7 @@ export function Shell({
474
478
  closeAllFloatingPanes,
475
479
  closeFocusedPane,
476
480
  copyFocusedPaneScreenshot,
481
+ exportFocusedPaneCsv,
477
482
  focusedPaneId,
478
483
  gridlockVisiblePanes,
479
484
  hasActiveDrag,
@@ -526,6 +531,7 @@ export function Shell({
526
531
  state: titleState,
527
532
  persistLayout,
528
533
  }),
534
+ canExportPaneCsv(paneId) ? exportPaneCsv : undefined,
529
535
  );
530
536
  void showContextMenu(context, items, event).then((shown) => {
531
537
  if (shown) return;
@@ -549,7 +555,7 @@ export function Shell({
549
555
  items: fallbackItems,
550
556
  });
551
557
  });
552
- }, [contentHeight, copyPaneScreenshot, desktopWindowBridge, focusPane, getPaneTitle, nativePaneChrome, openPaneSettings, paneMap, paneState, persistLayout, pluginRegistry, publicSharing, rendererHost.copyPngImage, sharePane, shortcutDisplayMode, showContextMenu, titleState, visibleLayout, width]);
558
+ }, [canExportPaneCsv, contentHeight, copyPaneScreenshot, desktopWindowBridge, exportPaneCsv, focusPane, getPaneTitle, nativePaneChrome, openPaneSettings, paneMap, paneState, persistLayout, pluginRegistry, publicSharing, rendererHost.copyPngImage, sharePane, shortcutDisplayMode, showContextMenu, titleState, visibleLayout, width]);
553
559
 
554
560
  const {
555
561
  handleFloatingCloseMouseDown,
@@ -632,7 +638,9 @@ export function Shell({
632
638
  <Box flexDirection="column" alignItems="center">
633
639
  <AsciiText text="Gloomberb" font="wordmark" color={colors.textMuted} />
634
640
  <Box height={1} />
635
- <Text fg={colors.textDim}>Ctrl+P to get started.</Text>
641
+ <Text fg={colors.textDim}>
642
+ {tf("{shortcut} to get started.", { shortcut: formatCommandBarShortcut(shortcutDisplayMode) })}
643
+ </Text>
636
644
  </Box>
637
645
  </Box>
638
646
 
@@ -34,6 +34,7 @@ export function menuForPane(
34
34
  copyPaneScreenshot?: (paneId: string) => void | Promise<void>,
35
35
  sharePane?: () => void | Promise<void>,
36
36
  linkItems: ContextMenuItem[] = [],
37
+ exportPaneCsv?: (paneId: string) => void | Promise<void>,
37
38
  ): ContextMenuItem[] {
38
39
  const baseActions: ContextMenuItem[] = [];
39
40
  if (pluginRegistry.hasPaneSettings(pane.instance.instanceId)) {
@@ -60,6 +61,14 @@ export function menuForPane(
60
61
  onSelect: () => copyPaneScreenshot(pane.instance.instanceId),
61
62
  });
62
63
  }
64
+ if (exportPaneCsv) {
65
+ baseActions.push({
66
+ id: "export-csv",
67
+ label: "Export CSV",
68
+ accelerator: PANE_MANAGEMENT_ACCELERATORS.exportCsv,
69
+ onSelect: () => exportPaneCsv(pane.instance.instanceId),
70
+ });
71
+ }
63
72
 
64
73
  if (pane.floating) {
65
74
  baseActions.push({
@@ -13,6 +13,10 @@ import type { PluginRegistry } from "../../../../plugins/registry";
13
13
  import type { LayoutConfig } from "../../../../types/config";
14
14
  import type { RendererHost } from "../../../../ui";
15
15
  import { capturePaneScreenshotPngBase64 } from "../../../../utils/dom-screenshot";
16
+ import {
17
+ exportPaneTableCsv,
18
+ hasPaneTableExporter,
19
+ } from "../../../../state/pane-table-export-registry";
16
20
 
17
21
  function removedFocusRestoreOptions(
18
22
  layout: LayoutConfig,
@@ -75,6 +79,28 @@ export function useShellPaneActions({
75
79
  }
76
80
  }, [closePaneMenu, pluginRegistry, rendererHost]);
77
81
 
82
+ const canExportPaneCsv = useCallback((paneId: string) => {
83
+ const pane = paneMap.get(paneId);
84
+ return pane?.def.tableExport === true && hasPaneTableExporter(paneId);
85
+ }, [paneMap]);
86
+
87
+ const exportPaneCsv = useCallback(async (paneId: string) => {
88
+ closePaneMenu();
89
+ const pane = paneMap.get(paneId);
90
+ if (!pane) return;
91
+ await exportPaneTableCsv(
92
+ paneId,
93
+ pane.instance.title ?? pane.def.name,
94
+ pluginRegistry.notify,
95
+ );
96
+ }, [closePaneMenu, paneMap, pluginRegistry]);
97
+
98
+ const exportFocusedPaneCsv = useCallback(() => {
99
+ if (!focusedPaneId || !canExportPaneCsv(focusedPaneId)) return false;
100
+ void exportPaneCsv(focusedPaneId);
101
+ return true;
102
+ }, [canExportPaneCsv, exportPaneCsv, focusedPaneId]);
103
+
78
104
  const closeFocusedPane = useCallback(() => {
79
105
  if (!focusedPaneId || !isPaneInLayout(visibleLayout, focusedPaneId)) return false;
80
106
  const nextLayout = removePane(visibleLayout, focusedPaneId);
@@ -132,10 +158,13 @@ export function useShellPaneActions({
132
158
  }, [focusedPaneId, persistLayout, previousFocusedPaneId, visibleLayout]);
133
159
 
134
160
  return {
161
+ canExportPaneCsv,
135
162
  closeAllFloatingPanes,
136
163
  closeFocusedPane,
137
164
  copyFocusedPaneScreenshot,
138
165
  copyPaneScreenshot,
166
+ exportFocusedPaneCsv,
167
+ exportPaneCsv,
139
168
  gridlockVisiblePanes,
140
169
  handleFloatingClose,
141
170
  openFocusedPaneSettings,
@@ -16,6 +16,7 @@ interface ShellPaneManagementShortcutOptions {
16
16
  closeAllFloatingPanes(): boolean;
17
17
  closeFocusedPane(): boolean;
18
18
  copyFocusedPaneScreenshot(): boolean;
19
+ exportFocusedPaneCsv(): boolean;
19
20
  focusedPaneId: string | null;
20
21
  gridlockVisiblePanes(): boolean;
21
22
  hasActiveDrag(): boolean;
@@ -35,6 +36,7 @@ export function useShellPaneManagementShortcuts({
35
36
  closeAllFloatingPanes,
36
37
  closeFocusedPane,
37
38
  copyFocusedPaneScreenshot,
39
+ exportFocusedPaneCsv,
38
40
  focusedPaneId,
39
41
  gridlockVisiblePanes,
40
42
  hasActiveDrag,
@@ -121,6 +123,9 @@ export function useShellPaneManagementShortcuts({
121
123
  case "copy-screenshot":
122
124
  handled = copyFocusedPaneScreenshot();
123
125
  break;
126
+ case "export-csv":
127
+ handled = exportFocusedPaneCsv();
128
+ break;
124
129
  case "share":
125
130
  handled = shareFocusedPane();
126
131
  break;
@@ -6,6 +6,7 @@ export const PANE_MANAGEMENT_ACCELERATORS = {
6
6
  toggleFloating: "CmdOrCtrl+Shift+D",
7
7
  popOut: "CmdOrCtrl+Shift+O",
8
8
  copyScreenshot: "CmdOrCtrl+Shift+C",
9
+ exportCsv: "CmdOrCtrl+Shift+E",
9
10
  share: "CmdOrCtrl+Shift+S",
10
11
  close: "CmdOrCtrl+W",
11
12
  closeAllFloating: "CmdOrCtrl+Alt+W",
@@ -21,6 +22,7 @@ export type PaneManagementShortcut =
21
22
  | "toggle-floating"
22
23
  | "pop-out"
23
24
  | "copy-screenshot"
25
+ | "export-csv"
24
26
  | "share"
25
27
  | "close"
26
28
  | "close-all-floating"
@@ -41,6 +43,7 @@ export function resolvePaneManagementShortcut(
41
43
  if (!shifted && name === ",") return "settings";
42
44
  if (!shifted || event.alt) return null;
43
45
  if (name === "c") return "copy-screenshot";
46
+ if (name === "e") return "export-csv";
44
47
  if (name === "s") return "share";
45
48
  if (name === "d") return "toggle-floating";
46
49
  if (name === "f") return "toggle-fullscreen";
@@ -4,6 +4,7 @@ import { AppContext, createInitialState } from "../../state/app/context";
4
4
  import { cloneLayout, createDefaultConfig, createPaneInstance, type LayoutConfig } from "../../types/config";
5
5
  import type { AppNotificationRequest } from "../../types/plugin";
6
6
  import { StatusBar } from "./status-bar";
7
+ import { VERSION } from "../../version";
7
8
  import { getDockedPaneIds } from "../../plugins/pane-manager";
8
9
  import { setSharedRegistryForTests } from "../../plugins/registry";
9
10
  import { act, useEffect, useState } from "react";
@@ -51,18 +52,18 @@ describe("StatusBar", () => {
51
52
  return null;
52
53
  }
53
54
 
54
- test("opens the command bar from the shortcut hint", async () => {
55
+ test("opens the current version changelog from the version chip", async () => {
55
56
  const config = createDefaultConfig("/tmp/gloomberb-test");
56
57
  config.layouts = [{ name: "Home", layout: cloneLayout(config.layout) }];
57
58
  const state = {
58
59
  ...createInitialState(config),
59
60
  statusBarVisible: true,
60
61
  };
61
- const actions: Array<{ type: string; open?: boolean; query?: string }> = [];
62
+ let openedVersion = "";
62
63
 
63
64
  testSetup = await testRender(
64
- <AppContext value={{ state, dispatch: (action) => actions.push(action as { type: string; open?: boolean; query?: string }) }}>
65
- <StatusBar />
65
+ <AppContext value={{ state, dispatch: () => {} }}>
66
+ <StatusBar onOpenChangelog={(version) => { openedVersion = version; }} />
66
67
  </AppContext>,
67
68
  { width: 120, height: 1 },
68
69
  );
@@ -70,13 +71,13 @@ describe("StatusBar", () => {
70
71
  await testSetup.renderOnce();
71
72
 
72
73
  const frame = testSetup.captureCharFrame();
73
- const hintX = frame.split("\n")[0]?.indexOf("Ctrl+P") ?? -1;
74
- expect(hintX).toBeGreaterThanOrEqual(0);
74
+ const versionX = frame.split("\n")[0]?.indexOf(`v${VERSION}`) ?? -1;
75
+ expect(versionX).toBeGreaterThanOrEqual(0);
75
76
 
76
- await testSetup.mockMouse.click(hintX + 1, 0);
77
+ await testSetup.mockMouse.click(versionX + 1, 0);
77
78
  await testSetup.renderOnce();
78
79
 
79
- expect(actions).toContainEqual({ type: "SET_COMMAND_BAR", open: true, query: "" });
80
+ expect(openedVersion).toBe(VERSION);
80
81
  });
81
82
 
82
83
  test("shows a transient focus layout tab without replacing saved layouts", async () => {