gloomberb 0.16.0 → 0.16.2

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 (691) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +44 -11
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +5 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/members.ts +26 -0
  10. package/src/api-client/paths.ts +30 -1
  11. package/src/api-client/perps.ts +41 -0
  12. package/src/api-client/request.ts +5 -2
  13. package/src/api-client/types.ts +9 -1
  14. package/src/app/global-shortcuts.ts +14 -6
  15. package/src/app/keybindings/actions.ts +1 -1
  16. package/src/app/runtime/update.ts +38 -2
  17. package/src/app.tsx +10 -6
  18. package/src/brokers/account-cache.ts +24 -0
  19. package/src/cli/commands/command-utils.ts +8 -0
  20. package/src/cli/commands/crypto-hints.ts +75 -0
  21. package/src/cli/commands/market.ts +414 -106
  22. package/src/cli/commands/overview.ts +77 -32
  23. package/src/cli/commands/ticker.ts +101 -43
  24. package/src/cli/desktop-pane-shot.ts +34 -4
  25. package/src/cli/freshness.ts +61 -0
  26. package/src/cli/help.ts +1 -0
  27. package/src/cli/helpers.ts +4 -8
  28. package/src/cli/index.ts +12 -2
  29. package/src/cli/listing-arg.ts +321 -0
  30. package/src/cli/pane-functions/access-gate.ts +42 -0
  31. package/src/cli/pane-functions/catalog.ts +28 -1
  32. package/src/cli/pane-functions/data.ts +3 -1
  33. package/src/cli/pane-functions/dom.ts +20 -2
  34. package/src/cli/pane-functions/freshness.ts +400 -0
  35. package/src/cli/pane-functions/function-help.ts +36 -22
  36. package/src/cli/pane-functions/headless.ts +39 -11
  37. package/src/cli/pane-functions/index.ts +15 -4
  38. package/src/cli/pane-functions/options.ts +3 -0
  39. package/src/cli/pane-functions/report.ts +4 -0
  40. package/src/cli/pane-functions/resolver.ts +35 -7
  41. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  42. package/src/cli/pane-functions/screenshot.ts +7 -3
  43. package/src/cli/result.ts +41 -27
  44. package/src/cli/ticker-resolution.ts +7 -5
  45. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  46. package/src/components/chart/composite/drawing-store.ts +59 -0
  47. package/src/components/chart/composite/legend.tsx +319 -0
  48. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  49. package/src/components/chart/composite/panel-gestures.ts +59 -0
  50. package/src/components/chart/composite/panel-labels.ts +107 -0
  51. package/src/components/chart/composite/panel-surface.tsx +876 -0
  52. package/src/components/chart/composite/tool-catalog.ts +98 -0
  53. package/src/components/chart/composite/toolbar.tsx +186 -0
  54. package/src/components/chart/composite/tools.ts +8 -0
  55. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  56. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  57. package/src/components/command-bar/commands/collection.ts +5 -1
  58. package/src/components/command-bar/list/model.ts +5 -0
  59. package/src/components/command-bar/list/view.tsx +16 -3
  60. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  61. package/src/components/command-bar/routes/root/command-items.ts +9 -2
  62. package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
  63. package/src/components/command-bar/routes/root/provider-search.ts +19 -5
  64. package/src/components/command-bar/routes/root/runtime.ts +14 -5
  65. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  66. package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
  67. package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
  68. package/src/components/command-bar/routing/actions.ts +2 -0
  69. package/src/components/command-bar/selection-runtime.ts +38 -0
  70. package/src/components/command-bar/surface/index.tsx +7 -2
  71. package/src/components/command-bar/workflow/ops.ts +1 -1
  72. package/src/components/command-bar/workflow/tickers.ts +6 -0
  73. package/src/components/data-table/view.tsx +29 -10
  74. package/src/components/feedback-dialog.tsx +2 -1
  75. package/src/components/form-modal/field-row.tsx +2 -2
  76. package/src/components/index.ts +2 -2
  77. package/src/components/layout/detached-pane-shell.tsx +6 -3
  78. package/src/components/layout/floating-pane.tsx +6 -0
  79. package/src/components/layout/header.tsx +24 -7
  80. package/src/components/layout/missing-pane.tsx +2 -2
  81. package/src/components/layout/pane/content.tsx +23 -10
  82. package/src/components/layout/pane/error-boundary.tsx +103 -0
  83. package/src/components/layout/pane/footer/registration.tsx +68 -23
  84. package/src/components/layout/pane/header.tsx +61 -28
  85. package/src/components/layout/pane/index.tsx +6 -0
  86. package/src/components/layout/pane/title.ts +31 -7
  87. package/src/components/layout/shell/drag/index.ts +6 -5
  88. package/src/components/layout/shell/drag/runtime.ts +3 -0
  89. package/src/components/layout/shell/index.tsx +6 -0
  90. package/src/components/layout/shell/menu.ts +2 -1
  91. package/src/components/layout/shell/pane/actions.ts +2 -1
  92. package/src/components/layout/shell/pane/layers.tsx +29 -10
  93. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
  94. package/src/components/layout/shell/ticker-link-menu.ts +23 -9
  95. package/src/components/metric-treemap/heat-surface.tsx +745 -0
  96. package/src/components/metric-treemap/heat-tiles.ts +228 -0
  97. package/src/components/metric-treemap/index.tsx +2 -0
  98. package/src/components/metric-treemap/layout.ts +8 -0
  99. package/src/components/metric-treemap/scene.ts +432 -0
  100. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  101. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  102. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  103. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  104. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  105. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
  106. package/src/components/ticker/list-table-view.tsx +13 -1
  107. package/src/components/toggle-list.tsx +38 -12
  108. package/src/components/ui/country-flag-art.tsx +449 -0
  109. package/src/components/ui/country-flag.tsx +41 -0
  110. package/src/components/ui/data-table/types.ts +13 -0
  111. package/src/components/ui/fields.tsx +8 -0
  112. package/src/components/ui/icon.tsx +2 -0
  113. package/src/components/ui/index.ts +4 -0
  114. package/src/components/ui/multi-select/dialog.tsx +108 -22
  115. package/src/components/ui/range-track.tsx +53 -0
  116. package/src/components/ui/status.tsx +8 -2
  117. package/src/components/ui/tabs.tsx +11 -4
  118. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  119. package/src/core/state/app/types.ts +10 -1
  120. package/src/data/config/store/normalize.ts +17 -1
  121. package/src/i18n/es.ts +24 -4
  122. package/src/i18n/ja.ts +24 -4
  123. package/src/i18n/ko.ts +24 -4
  124. package/src/i18n/zh-cn.ts +24 -4
  125. package/src/i18n/zh-tw.ts +24 -4
  126. package/src/layout/ticker-navigation.ts +28 -2
  127. package/src/market-data/coordinator/chart.ts +1 -1
  128. package/src/market-data/coordinator/quotes.ts +23 -4
  129. package/src/market-data/fx-closes.ts +72 -0
  130. package/src/market-data/market/freshness.ts +78 -6
  131. package/src/market-data/market/session-close-note.ts +57 -0
  132. package/src/market-data/market/status.ts +151 -0
  133. package/src/market-data/published-apac-sessions.ts +66 -0
  134. package/src/market-data/quotes/contributions.ts +8 -0
  135. package/src/market-data/quotes/freshness.ts +36 -0
  136. package/src/market-data/quotes/resolution.ts +24 -8
  137. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  138. package/src/market-data/quotes/time.ts +16 -0
  139. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  140. package/src/plugins/builtin/alerts/cli.ts +10 -5
  141. package/src/plugins/builtin/alerts/index.tsx +1 -0
  142. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  143. package/src/plugins/builtin/analytics/risk-client.ts +330 -79
  144. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  145. package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
  146. package/src/plugins/builtin/analytics/risk-math.ts +33 -13
  147. package/src/plugins/builtin/analytics/risk-model.ts +282 -64
  148. package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
  149. package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
  150. package/src/plugins/builtin/attention/headless.ts +6 -4
  151. package/src/plugins/builtin/attention/index.tsx +1 -1
  152. package/src/plugins/builtin/attention/pane.tsx +1 -1
  153. package/src/plugins/builtin/awards/headless.ts +1 -0
  154. package/src/plugins/builtin/awards/pane.tsx +1 -1
  155. package/src/plugins/builtin/backtest/headless.ts +1 -0
  156. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  157. package/src/plugins/builtin/buildout/cells.tsx +15 -12
  158. package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
  159. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  160. package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
  161. package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
  162. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
  163. package/src/plugins/builtin/buildout/index.tsx +1 -0
  164. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  165. package/src/plugins/builtin/catalysts/index.tsx +2 -2
  166. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  167. package/src/plugins/builtin/cds/headless.ts +2 -0
  168. package/src/plugins/builtin/cds/index.tsx +1 -0
  169. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  170. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  171. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  172. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  173. package/src/plugins/builtin/chat/channels.ts +19 -3
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  175. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  176. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  177. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  178. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  179. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  180. package/src/plugins/builtin/chat/index.tsx +1 -0
  181. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  182. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  183. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  184. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  185. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  186. package/src/plugins/builtin/chat/message/types.ts +14 -2
  187. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  188. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  189. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  190. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  191. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  192. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  193. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  194. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  195. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  196. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  197. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  198. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  199. package/src/plugins/builtin/correlation/compute.ts +59 -16
  200. package/src/plugins/builtin/correlation/geo.ts +34 -0
  201. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  202. package/src/plugins/builtin/correlation/headless.ts +42 -8
  203. package/src/plugins/builtin/correlation/history.ts +2 -0
  204. package/src/plugins/builtin/correlation/index.tsx +68 -14
  205. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  206. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  207. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  208. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  209. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  210. package/src/plugins/builtin/correlation/settings.ts +1 -1
  211. package/src/plugins/builtin/cot/headless.ts +6 -3
  212. package/src/plugins/builtin/cot/index.tsx +3 -3
  213. package/src/plugins/builtin/cot/model.ts +36 -3
  214. package/src/plugins/builtin/cpi/headless.ts +4 -0
  215. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  216. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  217. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  218. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  219. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  220. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  221. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  222. package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
  223. package/src/plugins/builtin/dividend-yield/client.ts +4 -2
  224. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  225. package/src/plugins/builtin/doe/headless.ts +7 -0
  226. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  227. package/src/plugins/builtin/earnings/client.ts +2 -2
  228. package/src/plugins/builtin/earnings/headless.ts +5 -0
  229. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  230. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  231. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  232. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  233. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  234. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  235. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  236. package/src/plugins/builtin/econ/index.tsx +1 -0
  237. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  238. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  239. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  240. package/src/plugins/builtin/executives/index.tsx +1 -0
  241. package/src/plugins/builtin/exposure/headless.ts +3 -1
  242. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  243. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  244. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  245. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  246. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  247. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  248. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  249. package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
  250. package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
  251. package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
  252. package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
  253. package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
  254. package/src/plugins/builtin/gpu/headless.ts +7 -3
  255. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  256. package/src/plugins/builtin/gpu/model.ts +27 -1
  257. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  258. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  259. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  260. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  261. package/src/plugins/builtin/holders/headless.ts +139 -5
  262. package/src/plugins/builtin/holders/index.tsx +10 -3
  263. package/src/plugins/builtin/holders/pane.tsx +20 -3
  264. package/src/plugins/builtin/holders/report-header.ts +95 -0
  265. package/src/plugins/builtin/holders/table-model.ts +20 -5
  266. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  267. package/src/plugins/builtin/holders/types.ts +2 -1
  268. package/src/plugins/builtin/insider/headless.ts +2 -0
  269. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  270. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  271. package/src/plugins/builtin/jobs/headless.ts +1 -0
  272. package/src/plugins/builtin/jobs/index.tsx +1 -0
  273. package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  275. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  276. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  277. package/src/plugins/builtin/market-heatmap/data.ts +30 -2
  278. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  279. package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
  280. package/src/plugins/builtin/market-heatmap/live.ts +88 -0
  281. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  282. package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
  283. package/src/plugins/builtin/market-movers/client.ts +3 -2
  284. package/src/plugins/builtin/market-movers/headless.ts +10 -1
  285. package/src/plugins/builtin/market-movers/screener.ts +18 -5
  286. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  287. package/src/plugins/builtin/members/client.ts +53 -0
  288. package/src/plugins/builtin/members/headless.ts +35 -0
  289. package/src/plugins/builtin/members/index.tsx +20 -0
  290. package/src/plugins/builtin/members/model.ts +68 -0
  291. package/src/plugins/builtin/members/pane.tsx +175 -0
  292. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  293. package/src/plugins/builtin/mna/headless.ts +1 -0
  294. package/src/plugins/builtin/mna/index.tsx +2 -1
  295. package/src/plugins/builtin/mna/pane.tsx +5 -2
  296. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  297. package/src/plugins/builtin/news/headless.ts +2 -0
  298. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  299. package/src/plugins/builtin/notes/cli.ts +14 -6
  300. package/src/plugins/builtin/notes/index.tsx +1 -0
  301. package/src/plugins/builtin/openfda/index.tsx +1 -0
  302. package/src/plugins/builtin/options/index.tsx +2 -1
  303. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  304. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  305. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  306. package/src/plugins/builtin/pe-band/client.ts +74 -2
  307. package/src/plugins/builtin/pe-band/headless.ts +26 -8
  308. package/src/plugins/builtin/pe-band/model.ts +102 -22
  309. package/src/plugins/builtin/pe-band/pane.tsx +34 -16
  310. package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
  311. package/src/plugins/builtin/perps/client.ts +66 -5
  312. package/src/plugins/builtin/perps/equity-identity.ts +16 -0
  313. package/src/plugins/builtin/perps/equity-row.tsx +6 -4
  314. package/src/plugins/builtin/perps/headless.ts +144 -16
  315. package/src/plugins/builtin/perps/index.tsx +6 -6
  316. package/src/plugins/builtin/perps/model.ts +189 -12
  317. package/src/plugins/builtin/perps/pane.tsx +248 -47
  318. package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
  319. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
  320. package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
  321. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  322. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  323. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  324. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  325. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  326. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  327. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  328. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  329. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  330. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  331. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  332. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  333. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  334. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  335. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
  336. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
  337. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  338. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  339. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  340. package/src/plugins/builtin/power/headless.ts +3 -1
  341. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  342. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  343. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  344. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  345. package/src/plugins/builtin/research/events-headless.ts +2 -0
  346. package/src/plugins/builtin/research/headless.ts +2 -0
  347. package/src/plugins/builtin/research/index.tsx +1 -0
  348. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  349. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  350. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  351. package/src/plugins/builtin/research-search/index.tsx +1 -0
  352. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  353. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  354. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  355. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  356. package/src/plugins/builtin/scanner/headless.ts +14 -0
  357. package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
  358. package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
  359. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  360. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  361. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  362. package/src/plugins/builtin/sec/forms.ts +12 -0
  363. package/src/plugins/builtin/sec/headless.ts +2 -0
  364. package/src/plugins/builtin/sectors/client.ts +1 -0
  365. package/src/plugins/builtin/sectors/headless.ts +9 -1
  366. package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
  367. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  368. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  369. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  370. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  371. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  372. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  373. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  374. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  375. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  376. package/src/plugins/builtin/social-mentions/index.tsx +1 -1
  377. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  378. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  379. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  380. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  381. package/src/plugins/builtin/themes/headless.ts +3 -0
  382. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  383. package/src/plugins/builtin/thirteenf/index.tsx +2 -1
  384. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  385. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  386. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  387. package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
  388. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  389. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
  390. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  391. package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
  392. package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
  393. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
  394. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
  395. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  396. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  397. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  398. package/src/plugins/builtin/volatility/headless.ts +6 -1
  399. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  400. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  401. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  402. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  403. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  404. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  405. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  406. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  407. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  408. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  409. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  410. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  411. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  412. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  413. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  414. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  415. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  416. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  417. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  418. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  564. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  565. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  566. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  567. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  568. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  569. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  570. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  571. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  572. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  573. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  574. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  575. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  576. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  577. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  578. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  579. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  580. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  581. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  582. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  583. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  584. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  585. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  586. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  587. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  588. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  589. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  590. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  591. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  592. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  593. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  594. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  595. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  596. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  597. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  598. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  599. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  600. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  601. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  602. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  603. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  604. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  605. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  606. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  607. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  608. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  609. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  610. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  611. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  612. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  613. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  614. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  615. package/src/plugins/catalog-browser.ts +2 -0
  616. package/src/plugins/catalog-manifest.ts +1 -0
  617. package/src/plugins/catalog-ui.ts +3 -1
  618. package/src/plugins/catalog.ts +1 -1
  619. package/src/plugins/host-link.ts +33 -1
  620. package/src/plugins/installer.ts +48 -12
  621. package/src/plugins/loader.ts +30 -3
  622. package/src/plugins/manager-node.ts +15 -5
  623. package/src/plugins/registry/index.ts +1 -1
  624. package/src/plugins/registry/pane-settings.ts +26 -7
  625. package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
  626. package/src/renderers/dom/build-assets.ts +81 -3
  627. package/src/renderers/dom/data-table/row.tsx +52 -16
  628. package/src/renderers/dom/desktop/controls.tsx +7 -3
  629. package/src/renderers/dom/desktop/icons.tsx +1 -0
  630. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  631. package/src/renderers/dom/desktop/popover.tsx +73 -14
  632. package/src/renderers/dom/host/box.tsx +69 -26
  633. package/src/renderers/dom/host/input.tsx +14 -3
  634. package/src/renderers/dom/host/tabs.tsx +37 -1
  635. package/src/renderers/dom/styles.css +41 -7
  636. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  638. package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
  639. package/src/renderers/electrobun/bun/index.ts +73 -6
  640. package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
  641. package/src/renderers/electrobun/shared/protocol.ts +3 -0
  642. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  643. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
  644. package/src/renderers/electrobun/view/main.tsx +7 -1
  645. package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
  646. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  647. package/src/renderers/electrobun/view/update-host.ts +45 -21
  648. package/src/renderers/opentui/host.tsx +5 -0
  649. package/src/sources/gloomberb-cloud/index.ts +25 -4
  650. package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
  651. package/src/sources/provider-router/cached-routes.ts +4 -1
  652. package/src/sources/provider-router/financials.ts +11 -8
  653. package/src/sources/provider-router/history.ts +15 -10
  654. package/src/sources/sec-registrant.ts +75 -0
  655. package/src/state/app/context/index.tsx +24 -8
  656. package/src/state/hooks/quote-streaming.ts +41 -26
  657. package/src/sync/core-contributors.ts +4 -0
  658. package/src/telemetry/benign-window-error.ts +7 -0
  659. package/src/telemetry/crash-reports-dom.ts +2 -0
  660. package/src/telemetry/crash-reports.ts +4 -1
  661. package/src/test-support/cli-context.ts +10 -2
  662. package/src/test-support/daily-nav.ts +25 -0
  663. package/src/theme/heat-colors.ts +357 -2
  664. package/src/tickers/instrument-kind.ts +34 -7
  665. package/src/tickers/search/asset-classes.ts +24 -9
  666. package/src/tickers/search/index.ts +44 -11
  667. package/src/tickers/search/ranking.ts +23 -3
  668. package/src/time-series/resolve.ts +1 -1
  669. package/src/time-series/use-chart-resolution.ts +1 -1
  670. package/src/types/context-menu.ts +6 -0
  671. package/src/types/data-provider.ts +2 -0
  672. package/src/types/financials.ts +5 -0
  673. package/src/types/headless.ts +79 -2
  674. package/src/types/plugin.ts +38 -6
  675. package/src/types/ticker.ts +15 -0
  676. package/src/ui/context-menu.tsx +1 -0
  677. package/src/ui/host.tsx +16 -0
  678. package/src/updater/index.ts +38 -13
  679. package/src/utils/async-deadline.ts +21 -0
  680. package/src/utils/cli-output.ts +5 -1
  681. package/src/utils/crypto-pair.ts +41 -0
  682. package/src/utils/currency-units.ts +14 -0
  683. package/src/utils/depositary-receipt.ts +26 -0
  684. package/src/utils/exchanges.ts +72 -0
  685. package/src/utils/fire-and-forget.ts +24 -0
  686. package/src/utils/format.ts +13 -0
  687. package/src/utils/price-earnings.ts +70 -3
  688. package/src/utils/price-history.ts +58 -13
  689. package/src/utils/rpc-timeout-error.ts +27 -0
  690. package/src/utils/sec.ts +13 -1
  691. package/src/utils/utc-time.ts +79 -0
@@ -1,30 +1,43 @@
1
1
  import { useEffect, useMemo, useRef, useState } from "react";
2
- import { Button, DialogFrame, ListView, TextField, type ListViewItem } from "../../../../components/ui";
2
+ import { Button, DialogFrame, Icon, ListView, TextField, type ListViewItem } from "../../../../components/ui";
3
+ import { stepListCursor } from "../../../../components/ui/list-view";
3
4
  import { modalSurfaceStyle } from "../../../../components/ui/frame";
4
5
  import { useShortcut } from "../../../../react/input";
5
6
  import { colors, hoverBg } from "../../../../theme/colors";
6
7
  import { t } from "../../../../i18n";
7
8
  import { Box, Text, TextAttributes, useUiCapabilities, type InputRenderable } from "../../../../ui";
8
- import type { ChatUserSummary } from "../../../../api-client";
9
+ import type { ChatChannel, ChatUserSummary } from "../../../../api-client";
9
10
  import { isPlainKey } from "../../../../utils/keyboard";
10
- import { truncateWithEllipsis } from "../../../../utils/text-wrap";
11
+ import { truncateWithEllipsis, wrapTextLines } from "../../../../utils/text-wrap";
11
12
  import {
12
13
  hasOnlyDmUsernameArgs,
13
14
  parseDmUsernames,
14
15
  } from "../channels";
16
+ import {
17
+ describeConversationStartError,
18
+ directMessageAvailability,
19
+ knownConversationRefusal,
20
+ type DirectMessageAvailability,
21
+ } from "../direct-messages";
15
22
 
16
23
  const MAX_RECENT_USERS = 6;
17
24
  const MIN_DIALOG_WIDTH = 32;
18
25
  const MAX_DIALOG_WIDTH = 52;
19
- const DIALOG_HEIGHT = 13;
20
- /** Rows around the list: border, title, field, label, action row. */
21
- const DIALOG_CHROME_ROWS = 7;
26
+ const START_BUTTON_WIDTH = 7;
27
+ /** An error gets two lines in the terminal before it is cut. */
28
+ const MAX_STATUS_ROWS = 2;
29
+ /** Terminal rows around the list and the status line: border, title and its spacer, field, list header. */
30
+ const TERMINAL_CHROME_ROWS = 6;
22
31
  /** The key line under the dialog, with its spacer. */
23
- const DIALOG_KEYS_ROWS = 2;
32
+ const TERMINAL_KEYS_ROWS = 2;
33
+ /** The desktop list row, as tall as the multi-select dialog's. */
34
+ const DESKTOP_ROW_HEIGHT = 1.35;
35
+ const ELLIPSIS_STYLE = { minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } as const;
24
36
 
25
37
  interface DmUserCandidate {
26
38
  username: string;
27
39
  displayName: string;
40
+ availability: DirectMessageAvailability;
28
41
  }
29
42
 
30
43
  function normalizeUsername(value: string | null | undefined): string {
@@ -36,18 +49,26 @@ function currentTokenQuery(value: string): string {
36
49
  return normalizeUsername(token);
37
50
  }
38
51
 
52
+ /**
53
+ * Everyone the chat has seen but you, by username. A user whose settings
54
+ * refuse a DM from you carries that reason, so the list can show it before
55
+ * anything is sent; one you already share a DM with opens it.
56
+ */
39
57
  function candidateUsers(
40
- userByUsername: Map<string, ChatUserSummary>,
58
+ userByUsername: ReadonlyMap<string, ChatUserSummary>,
41
59
  currentUserId: string | null | undefined,
60
+ channels: readonly ChatChannel[],
42
61
  ): DmUserCandidate[] {
43
62
  const candidates = new Map<string, DmUserCandidate>();
44
63
  for (const [key, user] of userByUsername) {
45
- if (currentUserId && user.id === currentUserId) continue;
64
+ const availability = directMessageAvailability(user, { currentUserId, channels });
65
+ if (availability.kind === "self") continue;
46
66
  const username = normalizeUsername(user.username ?? key);
47
67
  if (!username) continue;
48
68
  candidates.set(username, {
49
69
  username,
50
70
  displayName: user.displayName?.trim() || `@${username}`,
71
+ availability,
51
72
  });
52
73
  }
53
74
  return [...candidates.values()].sort((left, right) => left.username.localeCompare(right.username));
@@ -59,8 +80,30 @@ function setUsernameSelected(value: string, username: string, selected: boolean)
59
80
  return usernames.map((entry) => `@${entry}`).join(" ") + (usernames.length > 0 ? " " : "");
60
81
  }
61
82
 
62
- function usernamesLabel(usernames: string[], width: number): string {
63
- return truncateWithEllipsis(usernames.map((username) => `@${username}`).join(" "), width);
83
+ function clampLines(text: string, width: number, maxLines: number): string[] {
84
+ const lines = wrapTextLines(text, width);
85
+ if (lines.length <= maxLines) return lines.length > 0 ? lines : [""];
86
+ const kept = lines.slice(0, maxLines);
87
+ kept[maxLines - 1] = truncateWithEllipsis(`${kept[maxLines - 1]} ${lines[maxLines]}`, width);
88
+ return kept;
89
+ }
90
+
91
+ /**
92
+ * Terminal rows for the dialog in a pane `paneHeight` rows tall: the list
93
+ * shows up to six users; a short pane drops the key line first, then list
94
+ * rows, which scroll.
95
+ */
96
+ function terminalDialogLayout(paneHeight: number, itemCount: number, statusRows: number) {
97
+ const available = Math.max(TERMINAL_CHROME_ROWS + statusRows + 1, paneHeight - 2);
98
+ const wantedListRows = Math.max(1, Math.min(itemCount, MAX_RECENT_USERS));
99
+ const roomWithKeys = available - TERMINAL_CHROME_ROWS - statusRows - TERMINAL_KEYS_ROWS;
100
+ const showKeys = roomWithKeys >= Math.min(wantedListRows, 2);
101
+ const listHeight = Math.max(1, Math.min(wantedListRows, showKeys ? roomWithKeys : available - TERMINAL_CHROME_ROWS - statusRows));
102
+ return {
103
+ showKeys,
104
+ listHeight,
105
+ dialogHeight: TERMINAL_CHROME_ROWS + listHeight + statusRows + (showKeys ? TERMINAL_KEYS_ROWS : 0),
106
+ };
64
107
  }
65
108
 
66
109
  export function NewDmDialog({
@@ -68,14 +111,19 @@ export function NewDmDialog({
68
111
  height,
69
112
  userByUsername,
70
113
  currentUserId,
114
+ channels,
71
115
  onCancel,
116
+ onOpenChannel,
72
117
  onSubmit,
73
118
  }: {
74
119
  width: number;
75
120
  height: number;
76
121
  userByUsername: Map<string, ChatUserSummary>;
77
122
  currentUserId?: string | null;
123
+ /** The conversations you are in, so a DM you already share opens instead of being started. */
124
+ channels: readonly ChatChannel[];
78
125
  onCancel: () => void;
126
+ onOpenChannel: (channelId: string) => void;
79
127
  onSubmit: (usernames: string[]) => Promise<void>;
80
128
  }) {
81
129
  const { nativePaneChrome } = useUiCapabilities();
@@ -84,17 +132,17 @@ export function NewDmDialog({
84
132
  const valueRef = useRef("");
85
133
  const [selectedIndex, setSelectedIndex] = useState(0);
86
134
  const [submitting, setSubmitting] = useState(false);
135
+ // Holds off a second request while one is out, and a second open of a shared DM.
136
+ const submittingRef = useRef(false);
87
137
  const [error, setError] = useState<string | null>(null);
88
138
  const dialogWidth = Math.max(MIN_DIALOG_WIDTH, Math.min(MAX_DIALOG_WIDTH, width - 4));
89
- const dialogHeight = Math.min(DIALOG_HEIGHT, Math.max(8, height - 2));
90
- const left = Math.max(0, Math.floor((width - dialogWidth) / 2));
91
- const top = Math.max(0, Math.floor((height - dialogHeight) / 2));
92
139
  const contentWidth = Math.max(1, dialogWidth - 4);
93
- // A short terminal pane keeps the list and drops the key line.
94
- const showKeys = nativePaneChrome || dialogHeight - DIALOG_CHROME_ROWS - DIALOG_KEYS_ROWS >= 2;
95
140
  const selectedUsernames = useMemo(() => parseDmUsernames(value), [value]);
96
141
  const selectedUsernameSet = useMemo(() => new Set(selectedUsernames), [selectedUsernames]);
97
- const allCandidates = useMemo(() => candidateUsers(userByUsername, currentUserId), [currentUserId, userByUsername]);
142
+ const allCandidates = useMemo(
143
+ () => candidateUsers(userByUsername, currentUserId, channels),
144
+ [channels, currentUserId, userByUsername],
145
+ );
98
146
  const query = currentTokenQuery(value);
99
147
  const visibleCandidates = useMemo(() => {
100
148
  const filtered = query
@@ -102,21 +150,38 @@ export function NewDmDialog({
102
150
  : allCandidates;
103
151
  return filtered.slice(0, MAX_RECENT_USERS);
104
152
  }, [allCandidates, query]);
105
- const items = useMemo<ListViewItem[]>(() => visibleCandidates.map((candidate) => ({
106
- id: candidate.username,
107
- label: `@${candidate.username}`,
108
- detail: candidate.displayName,
109
- checked: selectedUsernameSet.has(candidate.username),
110
- })), [selectedUsernameSet, visibleCandidates]);
111
- const canSubmit = hasOnlyDmUsernameArgs(value) && selectedUsernames.length > 0 && !submitting;
153
+ const items = useMemo<ListViewItem[]>(() => visibleCandidates.map((candidate) => {
154
+ const refused = candidate.availability.kind === "refused";
155
+ return {
156
+ id: candidate.username,
157
+ label: `@${candidate.username}`,
158
+ detail: refused ? t("no DMs") : candidate.displayName,
159
+ checked: selectedUsernameSet.has(candidate.username),
160
+ disabled: refused,
161
+ };
162
+ }), [selectedUsernameSet, visibleCandidates]);
163
+ // A name the chat already knows cannot be messaged: say why as it is typed.
164
+ const knownRefusal = useMemo(
165
+ () => knownConversationRefusal(selectedUsernames, { userByUsername, currentUserId, channels }),
166
+ [channels, currentUserId, selectedUsernames, userByUsername],
167
+ );
168
+ const shownError = error ?? knownRefusal;
169
+ const canSubmit = hasOnlyDmUsernameArgs(value) && selectedUsernames.length > 0 && !submitting && !knownRefusal;
112
170
 
113
171
  useEffect(() => {
114
172
  inputRef.current?.focus?.();
115
173
  }, []);
116
174
 
175
+ // The cursor never rests on a user who cannot be picked.
117
176
  useEffect(() => {
118
- setSelectedIndex((current) => Math.max(0, Math.min(current, Math.max(items.length - 1, 0))));
119
- }, [items.length]);
177
+ setSelectedIndex((current) => {
178
+ const clamped = Math.max(0, Math.min(current, items.length - 1));
179
+ if (!items[clamped]?.disabled) return clamped;
180
+ const next = stepListCursor(items, clamped, 1);
181
+ return next !== clamped ? next : stepListCursor(items, clamped, -1);
182
+ });
183
+ }, [items]);
184
+ const highlightedItem = items[selectedIndex] && !items[selectedIndex]!.disabled ? items[selectedIndex] : undefined;
120
185
 
121
186
  const updateValue = (nextValue: string) => {
122
187
  valueRef.current = nextValue;
@@ -130,26 +195,42 @@ export function NewDmDialog({
130
195
  };
131
196
 
132
197
  const submit = async () => {
198
+ if (submittingRef.current) return;
133
199
  let submittedValue = valueRef.current;
134
200
  // Nothing typed yet: Enter starts with the highlighted user, as Tab would
135
201
  // have picked them.
136
- const highlighted = items[selectedIndex];
137
- if (highlighted && parseDmUsernames(submittedValue).length === 0 && currentTokenQuery(submittedValue) === "") {
138
- submittedValue = setUsernameSelected(submittedValue, highlighted.id, true);
202
+ if (highlightedItem && parseDmUsernames(submittedValue).length === 0 && currentTokenQuery(submittedValue) === "") {
203
+ submittedValue = setUsernameSelected(submittedValue, highlightedItem.id, true);
139
204
  updateValue(submittedValue);
140
205
  }
141
206
  const submittedUsernames = parseDmUsernames(submittedValue);
142
- if (!hasOnlyDmUsernameArgs(submittedValue) || submittedUsernames.length === 0 || submitting) {
207
+ if (!hasOnlyDmUsernameArgs(submittedValue) || submittedUsernames.length === 0) {
143
208
  setError(t("Enter at least one @username."));
144
209
  return;
145
210
  }
211
+ const refusal = knownConversationRefusal(submittedUsernames, { userByUsername, currentUserId, channels });
212
+ if (refusal) {
213
+ setError(refusal);
214
+ return;
215
+ }
216
+ const onlyUser = submittedUsernames.length === 1 ? userByUsername.get(submittedUsernames[0]!) : undefined;
217
+ const availability = onlyUser ? directMessageAvailability(onlyUser, { currentUserId, channels }) : null;
218
+ if (availability?.kind === "open") {
219
+ // The dialog closes with it; a second Enter in the same press opens nothing more.
220
+ submittingRef.current = true;
221
+ onOpenChannel(availability.channelId);
222
+ return;
223
+ }
224
+ submittingRef.current = true;
146
225
  setSubmitting(true);
147
226
  setError(null);
148
227
  try {
149
228
  await onSubmit(submittedUsernames);
150
- } catch {
151
- setError(t("Could not start conversation."));
229
+ } catch (submitError) {
230
+ setError(describeConversationStartError(submitError, submittedUsernames, userByUsername));
152
231
  setSubmitting(false);
232
+ } finally {
233
+ submittingRef.current = false;
153
234
  }
154
235
  };
155
236
 
@@ -163,18 +244,13 @@ export function NewDmDialog({
163
244
  if (isPlainKey(event, "up", "down")) {
164
245
  event.preventDefault?.();
165
246
  event.stopPropagation?.();
166
- setSelectedIndex((current) => {
167
- if (items.length === 0) return 0;
168
- return event.name === "up"
169
- ? Math.max(0, current - 1)
170
- : Math.min(items.length - 1, current + 1);
171
- });
247
+ setSelectedIndex((current) => (items.length === 0 ? 0 : stepListCursor(items, current, event.name === "up" ? -1 : 1)));
172
248
  return;
173
249
  }
174
- if (event.name === "tab" && items[selectedIndex]) {
250
+ if (event.name === "tab" && highlightedItem) {
175
251
  event.preventDefault?.();
176
252
  event.stopPropagation?.();
177
- toggleCandidate(items[selectedIndex]!.id);
253
+ toggleCandidate(highlightedItem.id);
178
254
  return;
179
255
  }
180
256
  if (event.name === "enter" || event.name === "return") {
@@ -184,90 +260,162 @@ export function NewDmDialog({
184
260
  }
185
261
  }, { allowEditable: true, phase: "before" });
186
262
 
263
+ const header = selectedUsernames.length > 0
264
+ ? selectedUsernames.map((username) => `@${username}`).join(" ")
265
+ : t("Recent users");
266
+ const status = shownError ?? (selectedUsernames.length > 1 ? t("Group chat") : t("Direct message"));
267
+ const startButton = (
268
+ <Button
269
+ label={submitting ? t("Starting") : t("Start")}
270
+ width={submitting ? 10 : START_BUTTON_WIDTH}
271
+ variant="primary"
272
+ disabled={!canSubmit}
273
+ stopPropagation
274
+ onPress={() => { void submit(); }}
275
+ />
276
+ );
277
+ const field = (
278
+ <TextField
279
+ inputRef={inputRef}
280
+ value={value}
281
+ placeholder="@username, @second"
282
+ focused
283
+ width={nativePaneChrome ? undefined : contentWidth}
284
+ backgroundColor={colors.panel}
285
+ onChange={(nextValue) => {
286
+ updateValue(nextValue);
287
+ setError(null);
288
+ }}
289
+ />
290
+ );
291
+ const list = (listHeight: number | undefined) => {
292
+ const scrollable = nativePaneChrome || (listHeight ?? 0) < items.length;
293
+ // The terminal's scroll bar takes the last column.
294
+ const rowWidth = scrollable ? contentWidth - 1 : contentWidth;
295
+ return (
296
+ <ListView
297
+ items={items}
298
+ selectedIndex={highlightedItem ? selectedIndex : -1}
299
+ height={listHeight}
300
+ scrollable={scrollable}
301
+ surface="plain"
302
+ rowGap={0}
303
+ rowHeight={nativePaneChrome ? DESKTOP_ROW_HEIGHT : undefined}
304
+ bgColor={colors.bg}
305
+ selectedBgColor={colors.selected}
306
+ hoverBgColor={hoverBg()}
307
+ emptyMessage={t("No recent users")}
308
+ selectOnHover
309
+ onSelect={setSelectedIndex}
310
+ onActivate={(item) => toggleCandidate(item.id)}
311
+ renderRow={(item, state) => (
312
+ <Box flexDirection="row" alignItems={nativePaneChrome ? "center" : undefined} width={nativePaneChrome ? "100%" : rowWidth} minWidth={0}>
313
+ <Box width={2} flexShrink={0}>
314
+ {state.disabled ? null : (
315
+ <Icon name={item.checked ? "check" : "plus"} size={11} color={state.selected ? colors.selectedText : colors.textDim} />
316
+ )}
317
+ </Box>
318
+ <Text
319
+ fg={state.selected ? colors.text : state.disabled ? colors.textDim : colors.textMuted}
320
+ attributes={state.selected ? TextAttributes.BOLD : 0}
321
+ style={nativePaneChrome ? ELLIPSIS_STYLE : undefined}
322
+ >
323
+ {nativePaneChrome ? item.label : truncateWithEllipsis(item.label, Math.max(1, rowWidth - 14))}
324
+ </Text>
325
+ <Box flexGrow={1} minWidth={1} />
326
+ {item.detail ? (
327
+ <Text fg={colors.textDim} style={nativePaneChrome ? { ...ELLIPSIS_STYLE, maxWidth: "45%" } : undefined}>
328
+ {nativePaneChrome ? item.detail : truncateWithEllipsis(item.detail, 10)}
329
+ </Text>
330
+ ) : null}
331
+ </Box>
332
+ )}
333
+ />
334
+ );
335
+ };
336
+ const footer = items.length > 0 ? "Tab add · Enter start" : "Enter start";
337
+ const stopPointer = (event: any) => {
338
+ event?.preventDefault?.();
339
+ event?.stopPropagation?.();
340
+ };
341
+
342
+ if (nativePaneChrome) {
343
+ // Sized and centered by the browser in the pane: the frame's padding and
344
+ // the rows are pixels here, so cell arithmetic would misplace both. In a
345
+ // short pane the list gives up its rows first and scrolls.
346
+ return (
347
+ <Box
348
+ position="absolute"
349
+ left={0}
350
+ top={0}
351
+ width="100%"
352
+ height="100%"
353
+ alignItems="center"
354
+ justifyContent="center"
355
+ style={{ zIndex: 8, padding: 8, pointerEvents: "none" }}
356
+ >
357
+ <Box
358
+ flexDirection="column"
359
+ onMouseDown={stopPointer}
360
+ style={{
361
+ ...modalSurfaceStyle(colors, { padding: 0, width: `min(calc(${MAX_DIALOG_WIDTH} * var(--cell-w)), 100%)`, maxHeight: "100%" }),
362
+ pointerEvents: "auto",
363
+ }}
364
+ >
365
+ <DialogFrame title="New DM" onClose={onCancel} footer={footer} shrinkable>
366
+ <Box flexDirection="column" flexShrink={1} minHeight={0} style={{ gap: 6 }}>
367
+ {field}
368
+ <Text fg={selectedUsernames.length > 0 ? colors.textMuted : colors.textDim} style={ELLIPSIS_STYLE}>
369
+ {header}
370
+ </Text>
371
+ {list(undefined)}
372
+ <Box flexDirection="row" alignItems="center" flexShrink={0} style={{ gap: 12, marginTop: 4 }}>
373
+ <Text fg={shownError ? colors.negative : colors.textDim} wrapText style={{ flexGrow: 1, flexShrink: 1, minWidth: 0 }}>
374
+ {status}
375
+ </Text>
376
+ {startButton}
377
+ </Box>
378
+ </Box>
379
+ </DialogFrame>
380
+ </Box>
381
+ </Box>
382
+ );
383
+ }
384
+
385
+ const statusWidth = Math.max(1, contentWidth - START_BUTTON_WIDTH - 1);
386
+ const statusLines = clampLines(status, statusWidth, MAX_STATUS_ROWS);
387
+ const layout = terminalDialogLayout(height, items.length, statusLines.length);
187
388
  return (
188
389
  <Box
189
390
  position="absolute"
190
- left={left}
191
- top={top}
391
+ left={Math.max(0, Math.floor((width - dialogWidth) / 2))}
392
+ top={Math.max(0, Math.floor((height - layout.dialogHeight) / 2))}
192
393
  width={dialogWidth}
193
- height={nativePaneChrome ? undefined : dialogHeight}
394
+ height={layout.dialogHeight}
194
395
  flexDirection="column"
195
- {...(nativePaneChrome ? {} : { border: true, borderColor: colors.borderFocused, backgroundColor: colors.bg, paddingX: 1 })}
196
- onMouseDown={(event: any) => {
197
- event?.preventDefault?.();
198
- event?.stopPropagation?.();
199
- }}
200
- style={nativePaneChrome
201
- ? { ...modalSurfaceStyle(colors, { padding: 0, width: `calc(${dialogWidth} * var(--cell-w))` }), zIndex: 8 }
202
- : { zIndex: 8 }}
396
+ border
397
+ borderColor={colors.borderFocused}
398
+ backgroundColor={colors.bg}
399
+ paddingX={1}
400
+ onMouseDown={stopPointer}
401
+ style={{ zIndex: 8 }}
203
402
  >
204
- <DialogFrame
205
- title="New DM"
206
- onClose={onCancel}
207
- footer={showKeys ? items.length > 0 ? "Tab add · Enter start" : "Enter start" : undefined}
208
- >
209
- <TextField
210
- inputRef={inputRef}
211
- value={value}
212
- placeholder="@username, @second"
213
- focused
214
- width={contentWidth}
215
- backgroundColor={colors.panel}
216
- onChange={(nextValue) => {
217
- updateValue(nextValue);
218
- setError(null);
219
- }}
220
- onSubmit={() => { void submit(); }}
221
- />
403
+ <DialogFrame title="New DM" onClose={onCancel} footer={layout.showKeys ? footer : undefined}>
404
+ {field}
222
405
  <Box height={1}>
223
406
  <Text fg={selectedUsernames.length > 0 ? colors.textMuted : colors.textDim}>
224
- {selectedUsernames.length > 0 ? usernamesLabel(selectedUsernames, contentWidth) : t("Recent users")}
407
+ {truncateWithEllipsis(header, contentWidth)}
225
408
  </Text>
226
409
  </Box>
227
- <ListView
228
- items={items}
229
- selectedIndex={items.length > 0 ? selectedIndex : -1}
230
- height={Math.max(1, dialogHeight - DIALOG_CHROME_ROWS - (showKeys ? DIALOG_KEYS_ROWS : 0))}
231
- bgColor={colors.bg}
232
- selectedBgColor={colors.selected}
233
- hoverBgColor={hoverBg()}
234
- emptyMessage={t("No recent users")}
235
- selectOnHover
236
- onSelect={setSelectedIndex}
237
- onActivate={(item) => toggleCandidate(item.id)}
238
- renderRow={(item, state) => (
239
- <Box flexDirection="row" width={contentWidth}>
240
- <Text fg={state.selected ? colors.selectedText : colors.textDim}>
241
- {item.checked ? "x " : "+ "}
242
- </Text>
243
- <Text
244
- fg={state.selected ? colors.text : colors.textMuted}
245
- attributes={state.selected ? TextAttributes.BOLD : 0}
246
- >
247
- {truncateWithEllipsis(item.label, Math.max(1, contentWidth - 12))}
248
- </Text>
249
- <Box flexGrow={1} />
250
- {item.detail ? (
251
- <Text fg={colors.textDim}>{truncateWithEllipsis(item.detail, 10)}</Text>
252
- ) : null}
253
- </Box>
254
- )}
255
- />
256
- <Box height={1} flexDirection="row">
257
- {error ? (
258
- <Text fg={colors.negative}>{truncateWithEllipsis(error, contentWidth)}</Text>
259
- ) : (
260
- <Text fg={colors.textDim}>{selectedUsernames.length > 1 ? t("Group chat") : t("Direct message")}</Text>
261
- )}
410
+ {list(layout.listHeight)}
411
+ <Box height={statusLines.length} flexDirection="row">
412
+ <Box width={statusWidth} flexDirection="column">
413
+ {statusLines.map((line, index) => (
414
+ <Text key={index} fg={shownError ? colors.negative : colors.textDim}>{line}</Text>
415
+ ))}
416
+ </Box>
262
417
  <Box flexGrow={1} />
263
- <Button
264
- label={submitting ? t("Starting") : t("Start")}
265
- width={submitting ? 10 : 7}
266
- variant="primary"
267
- disabled={!canSubmit}
268
- stopPropagation
269
- onPress={() => { void submit(); }}
270
- />
418
+ {startButton}
271
419
  </Box>
272
420
  </DialogFrame>
273
421
  </Box>
@@ -4,6 +4,7 @@ import type { InlineTickerCatalogEntry } from "../../../../state/hooks/inline-ti
4
4
  import { colors } from "../../../../theme/colors";
5
5
  import { t } from "../../../../i18n";
6
6
  import type { ChatAttachment, ChatMessage, ChatUserSummary } from "../../../../api-client";
7
+ import type { ChatUserAnchor, ChatUserContextMenuEvent } from "../message/types";
7
8
  import { DesktopChatMessage } from "../message/desktop";
8
9
  import { UserProfilePopover } from "../message/profile-popover";
9
10
  import { TerminalChatMessage } from "../message/terminal";
@@ -36,17 +37,25 @@ interface ChatTranscriptProps {
36
37
  latestEditableMessageId: string | null;
37
38
  openTicker: (symbol: string) => void;
38
39
  profilePopoverUser: ChatUserSummary | null;
40
+ /** The name or @mention the open card belongs beside. */
41
+ profilePopoverAnchor: ChatUserAnchor;
39
42
  registerMessageElement: (messageId: string, node: unknown | null) => void;
40
43
  scheduleProfilePopoverClose: () => void;
41
44
  scrollRef: MutableRef<ScrollBoxRenderable | null>;
42
45
  selectedIdx: number;
43
46
  setHoveredIdx: Dispatch<SetStateAction<number | null>>;
44
- showProfilePopover: (user: ChatUserSummary) => void;
47
+ showProfilePopover: (user: ChatUserSummary, anchor?: ChatUserAnchor) => void;
45
48
  /** A click on a name: pins its card, or closes the one it pinned. */
46
- toggleProfilePopover: (user: ChatUserSummary) => void;
49
+ toggleProfilePopover: (user: ChatUserSummary, anchor?: ChatUserAnchor) => void;
47
50
  /** Closes the card at once, pinned or not (a click outside it on the desktop). */
48
51
  dismissProfilePopover: () => void;
49
52
  onSetUpProfile: () => void;
53
+ /** Right-click on a name or @mention. */
54
+ onUserContextMenu: (user: ChatUserSummary, event: ChatUserContextMenuEvent, anchor?: ChatUserAnchor) => void;
55
+ /** The card's "Message" action for this user, or null where none is offered. */
56
+ profileMessageAction: { label: string; onPress: () => void } | null;
57
+ /** Why this user takes no DM from you, for a card that has no profile to show instead. */
58
+ profileMessageRefusal: string | null;
50
59
  stickyTranscript: boolean;
51
60
  user: { id: string; username: string; emailVerified: boolean } | null;
52
61
  userByUsername: Map<string, ChatUserSummary>;
@@ -76,6 +85,7 @@ export function ChatTranscript({
76
85
  latestEditableMessageId,
77
86
  openTicker,
78
87
  profilePopoverUser,
88
+ profilePopoverAnchor,
79
89
  registerMessageElement,
80
90
  scheduleProfilePopoverClose,
81
91
  scrollRef,
@@ -88,6 +98,9 @@ export function ChatTranscript({
88
98
  user,
89
99
  userByUsername,
90
100
  onSetUpProfile,
101
+ onUserContextMenu,
102
+ profileMessageAction,
103
+ profileMessageRefusal,
91
104
  }: ChatTranscriptProps) {
92
105
  return (
93
106
  <>
@@ -137,6 +150,7 @@ export function ChatTranscript({
137
150
  onUserHover={showProfilePopover}
138
151
  onUserHoverEnd={scheduleProfilePopoverClose}
139
152
  onUserActivate={toggleProfilePopover}
153
+ onUserContextMenu={onUserContextMenu}
140
154
  beginReplyTo={beginReplyTo}
141
155
  beginEditMessage={beginEditMessage}
142
156
  jumpToMessage={jumpToMessage}
@@ -162,6 +176,7 @@ export function ChatTranscript({
162
176
  onUserHover={showProfilePopover}
163
177
  onUserHoverEnd={scheduleProfilePopoverClose}
164
178
  onUserActivate={toggleProfilePopover}
179
+ onUserContextMenu={onUserContextMenu}
165
180
  beginReplyTo={beginReplyTo}
166
181
  beginEditMessage={beginEditMessage}
167
182
  jumpToMessage={jumpToMessage}
@@ -176,12 +191,15 @@ export function ChatTranscript({
176
191
  {profilePopoverUser && (
177
192
  <UserProfilePopover
178
193
  user={profilePopoverUser}
194
+ anchor={profilePopoverAnchor}
179
195
  width={chatWidth}
180
196
  onClose={scheduleProfilePopoverClose}
181
197
  onDismiss={dismissProfilePopover}
182
198
  onKeepOpen={cancelProfilePopoverClose}
183
199
  isOwnProfile={profilePopoverUser.id === user?.id}
184
200
  onSetUpProfile={onSetUpProfile}
201
+ messageAction={profileMessageAction}
202
+ messageRefusal={profileMessageRefusal}
185
203
  />
186
204
  )}
187
205
  </>