gloomberb 0.9.7 → 0.9.9

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 (276) hide show
  1. package/package.json +1 -1
  2. package/src/api-client/auth.ts +20 -0
  3. package/src/api-client/index.test.ts +3 -3
  4. package/src/api-client/index.ts +48 -6
  5. package/src/api-client/request.test.ts +63 -0
  6. package/src/api-client/request.ts +53 -5
  7. package/src/api-client/types.ts +45 -2
  8. package/src/app/pane-runtime/layout-placement.ts +0 -1
  9. package/src/app/runtime/desktop-deeplink.test.ts +87 -0
  10. package/src/app/runtime/desktop-deeplink.ts +496 -0
  11. package/src/app.tsx +34 -0
  12. package/src/brokers/account-cache.ts +2 -10
  13. package/src/brokers/broker-portfolio-sync.ts +0 -1
  14. package/src/brokers/broker-ticker-sync.ts +20 -16
  15. package/src/brokers/remote-broker-adapter.ts +3 -0
  16. package/src/capabilities/registry.test.ts +25 -0
  17. package/src/capabilities/registry.ts +22 -5
  18. package/src/cli/commands/automation.ts +1 -3
  19. package/src/cli/commands/command-utils.ts +0 -7
  20. package/src/cli/commands/overview.ts +2 -2
  21. package/src/cli/commands/plugins.ts +34 -17
  22. package/src/cli/index.ts +2 -2
  23. package/src/cli.test.ts +0 -157
  24. package/src/components/chart/bar-chart-renderer.test.ts +87 -12
  25. package/src/components/chart/bar-chart-renderer.ts +111 -55
  26. package/src/components/chart/comparison/renderer.ts +0 -1
  27. package/src/components/chart/comparison-stock-chart/render-output.ts +3 -8
  28. package/src/components/chart/comparison-stock-chart/view.tsx +0 -2
  29. package/src/components/chart/core/index.test.ts +0 -24
  30. package/src/components/chart/core/renderer.ts +0 -4
  31. package/src/components/chart/core/resolution.test.ts +0 -17
  32. package/src/components/chart/core/resolution.ts +0 -26
  33. package/src/components/chart/core/scroll.test.ts +0 -6
  34. package/src/components/chart/core/scroll.ts +0 -22
  35. package/src/components/chart/core/viewport.test.ts +2 -23
  36. package/src/components/chart/core/viewport.ts +0 -27
  37. package/src/components/chart/market-session.ts +1 -1
  38. package/src/components/chart/native/surface/hooks.ts +10 -3
  39. package/src/components/chart/static/bar-chart-surface.tsx +104 -20
  40. package/src/components/chart/stock-chart/data-runtime.ts +0 -1
  41. package/src/components/chart/stock-chart/footer.test.ts +65 -0
  42. package/src/components/chart/stock-chart/footer.ts +68 -13
  43. package/src/components/chart/stock-chart/resolved.tsx +18 -4
  44. package/src/components/chart/stock-chart/viewport/effects.ts +0 -3
  45. package/src/components/command-bar/helpers.test.ts +1 -80
  46. package/src/components/command-bar/helpers.ts +1 -36
  47. package/src/components/command-bar/pane-settings.ts +1 -1
  48. package/src/components/command-bar/pane-templates/items.ts +11 -3
  49. package/src/components/command-bar/panel/runtime.ts +0 -2
  50. package/src/components/command-bar/routes/root/results.ts +1 -1
  51. package/src/components/command-bar/routes/ticker-search/results.ts +0 -11
  52. package/src/components/command-bar/surface/index.test.tsx +52 -16
  53. package/src/components/command-bar/surface/index.tsx +0 -1
  54. package/src/components/command-bar/workflow/ops.ts +81 -20
  55. package/src/components/feed-data-table/stack-view.test.tsx +36 -130
  56. package/src/components/feed-data-table/stack-view.tsx +0 -1
  57. package/src/components/index.ts +1 -0
  58. package/src/components/layout/shell/index.test.tsx +2 -113
  59. package/src/components/layout/shell/index.tsx +0 -1
  60. package/src/components/layout/shell/menu.ts +0 -1
  61. package/src/components/layout/shell/terminal-pointer-runtime.ts +0 -1
  62. package/src/components/onboarding/onboarding-wizard.tsx +3 -3
  63. package/src/components/onboarding/wizard-keyboard.ts +2 -23
  64. package/src/components/price-selector-dialog.tsx +3 -3
  65. package/src/components/ticker/badge/text.tsx +0 -1
  66. package/src/components/toggle-list.tsx +29 -73
  67. package/src/components/ui/button.tsx +4 -1
  68. package/src/components/ui/checkbox.tsx +76 -0
  69. package/src/components/ui/choice-dialog.tsx +15 -3
  70. package/src/components/ui/frame.tsx +1 -1
  71. package/src/components/ui/index.ts +2 -0
  72. package/src/components/ui/message-composer.tsx +4 -0
  73. package/src/components/ui/native-select.tsx +4 -2
  74. package/src/components/ui/page-stack-view.tsx +1 -1
  75. package/src/components/ui/ui.test.tsx +0 -78
  76. package/src/core/state/app/layout-reducer.ts +0 -1
  77. package/src/data/config/layout.ts +3 -3
  78. package/src/data/resource-store.ts +6 -0
  79. package/src/data/sqlite/cache.test.ts +5 -0
  80. package/src/data/ticker-store.ts +0 -7
  81. package/src/market-data/coordinator/auxiliary.ts +1 -44
  82. package/src/market-data/coordinator/entries.ts +0 -1
  83. package/src/market-data/coordinator/events.test.ts +49 -0
  84. package/src/market-data/coordinator/events.ts +25 -4
  85. package/src/market-data/coordinator/index.test.ts +223 -10
  86. package/src/market-data/coordinator/index.ts +41 -21
  87. package/src/market-data/coordinator/quotes.ts +13 -11
  88. package/src/market-data/coordinator/subscriptions.test.ts +1 -0
  89. package/src/market-data/hooks.tsx +17 -13
  90. package/src/market-data/market/freshness.ts +58 -1
  91. package/src/market-data/market/status.ts +19 -1
  92. package/src/market-data/query-store.ts +0 -4
  93. package/src/market-data/quotes/freshness.test.ts +49 -1
  94. package/src/market-data/quotes/freshness.ts +8 -0
  95. package/src/market-data/quotes/resolution.test.ts +185 -0
  96. package/src/market-data/quotes/resolution.ts +96 -10
  97. package/src/market-data/request-types.test.ts +61 -1
  98. package/src/market-data/request-types.ts +42 -8
  99. package/src/market-data/result-types.ts +0 -11
  100. package/src/market-data/selectors.ts +1 -5
  101. package/src/news/aggregator.ts +5 -1
  102. package/src/pane-settings.test.ts +0 -18
  103. package/src/plugins/builtin/account-management/footer.ts +2 -5
  104. package/src/plugins/builtin/account-management/form-components.tsx +175 -59
  105. package/src/plugins/builtin/account-management/keyboard.ts +32 -2
  106. package/src/plugins/builtin/account-management/model.test.ts +99 -4
  107. package/src/plugins/builtin/account-management/model.ts +259 -23
  108. package/src/plugins/builtin/account-management/pane.tsx +784 -155
  109. package/src/plugins/builtin/broker-manager/index.test.tsx +0 -32
  110. package/src/plugins/builtin/buildout/cells.tsx +1 -1
  111. package/src/plugins/builtin/buildout/detail/satellite-images.tsx +1 -1
  112. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -1
  113. package/src/plugins/builtin/buildout/format.ts +2 -11
  114. package/src/plugins/builtin/chat/chat.test.tsx +127 -1
  115. package/src/plugins/builtin/chat/content/channel-navigation.ts +1 -21
  116. package/src/plugins/builtin/chat/content/composer-cursor.ts +29 -0
  117. package/src/plugins/builtin/chat/content/composer-runtime.ts +22 -24
  118. package/src/plugins/builtin/chat/content/composer.tsx +84 -1
  119. package/src/plugins/builtin/chat/content/index.tsx +153 -16
  120. package/src/plugins/builtin/chat/content/layout-metrics.ts +10 -1
  121. package/src/plugins/builtin/chat/content/mentions.test.ts +74 -0
  122. package/src/plugins/builtin/chat/content/mentions.ts +88 -0
  123. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +264 -0
  124. package/src/plugins/builtin/chat/content/shortcuts.ts +47 -1
  125. package/src/plugins/builtin/chat/content/snapshot.ts +7 -0
  126. package/src/plugins/builtin/chat/content/transcript.tsx +0 -5
  127. package/src/plugins/builtin/chat/controller/index.ts +0 -10
  128. package/src/plugins/builtin/chat/controller.test.ts +5 -5
  129. package/src/plugins/builtin/chat/message/profile-popover.test.tsx +36 -0
  130. package/src/plugins/builtin/chat/message/profile-popover.tsx +124 -20
  131. package/src/plugins/builtin/chat/sidebar.test.tsx +83 -6
  132. package/src/plugins/builtin/chat/sidebar.tsx +26 -2
  133. package/src/plugins/builtin/chat/test-harness.tsx +22 -12
  134. package/src/plugins/builtin/cloud/plugin.tsx +8 -1
  135. package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -1
  136. package/src/plugins/builtin/congress-trades/model.ts +2 -7
  137. package/src/plugins/builtin/congress-trades/pane.tsx +0 -1
  138. package/src/plugins/builtin/correlation/index.tsx +4 -1
  139. package/src/plugins/builtin/correlation/relationship/controls.tsx +8 -2
  140. package/src/plugins/builtin/correlation/relationship/model.ts +22 -2
  141. package/src/plugins/builtin/correlation/relationship/pane.tsx +9 -3
  142. package/src/plugins/builtin/earnings/index.tsx +0 -9
  143. package/src/plugins/builtin/econ/index.tsx +1 -5
  144. package/src/plugins/builtin/help/index.tsx +2 -2
  145. package/src/plugins/builtin/holders/pane.tsx +0 -5
  146. package/src/plugins/builtin/insider/index.tsx +1 -8
  147. package/src/plugins/builtin/kelly-sizer/index.test.tsx +0 -26
  148. package/src/plugins/builtin/kelly-sizer/index.tsx +0 -2
  149. package/src/plugins/builtin/market-movers/index.tsx +0 -2
  150. package/src/plugins/builtin/news/index.tsx +0 -1
  151. package/src/plugins/builtin/news/wire/news/table.tsx +0 -11
  152. package/src/plugins/builtin/options/view.test.tsx +1 -38
  153. package/src/plugins/builtin/plugin-groups.ts +17 -3
  154. package/src/plugins/builtin/portfolio-list/column-values.ts +15 -8
  155. package/src/plugins/builtin/portfolio-list/index.test.ts +52 -25
  156. package/src/plugins/builtin/portfolio-list/metrics.test.ts +44 -7
  157. package/src/plugins/builtin/portfolio-list/pane/data.test.ts +54 -0
  158. package/src/plugins/builtin/portfolio-list/pane/data.ts +50 -3
  159. package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +314 -16
  160. package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -4
  161. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +83 -24
  162. package/src/plugins/builtin/sec/filing-documents.ts +0 -11
  163. package/src/plugins/builtin/sec/index.tsx +0 -2
  164. package/src/plugins/builtin/substack/article-detail.tsx +1 -1
  165. package/src/plugins/builtin/thirteenf/api.ts +0 -15
  166. package/src/plugins/builtin/thirteenf/pane.tsx +1 -3
  167. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +42 -6
  168. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/model.ts +415 -64
  169. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings.ts +23 -2
  170. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/types.ts +8 -1
  171. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph.tsx +3 -1
  172. package/src/plugins/builtin/ticker-detail/data-panes.test.ts +95 -1
  173. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +0 -7
  174. package/src/plugins/builtin/ticker-detail/index.tsx +2 -0
  175. package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +5 -34
  176. package/src/plugins/builtin/world-indices/index.tsx +0 -4
  177. package/src/plugins/builtin/world-indices/model.ts +0 -7
  178. package/src/plugins/ibkr/account-cache.ts +1 -1
  179. package/src/plugins/ibkr/gateway/market-data.ts +12 -5
  180. package/src/plugins/ibkr/gateway/service/index.test.ts +31 -0
  181. package/src/plugins/ibkr/portfolio-performance.ts +1 -1
  182. package/src/plugins/ibkr/trade/utils.ts +1 -7
  183. package/src/plugins/loader.ts +2 -1
  184. package/src/plugins/prediction-markets/detail.test.tsx +0 -34
  185. package/src/plugins/registry/context.ts +15 -0
  186. package/src/plugins/registry/contributions.ts +22 -11
  187. package/src/plugins/registry/index.test.ts +44 -0
  188. package/src/plugins/registry/index.ts +75 -26
  189. package/src/remote/controller.ts +1 -7
  190. package/src/remote/json-patch.ts +15 -1
  191. package/src/remote/server.ts +16 -6
  192. package/src/renderers/electrobun/bun/application-menu/index.ts +1 -1
  193. package/src/renderers/electrobun/bun/core-capabilities.ts +2 -0
  194. package/src/renderers/electrobun/bun/desktop/http-fetch.test.ts +14 -0
  195. package/src/renderers/electrobun/bun/desktop/http-fetch.ts +8 -0
  196. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
  197. package/src/renderers/electrobun/bun/index.ts +42 -0
  198. package/src/renderers/electrobun/shared/protocol.ts +5 -0
  199. package/src/renderers/electrobun/view/backend-rpc.ts +29 -0
  200. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
  201. package/src/renderers/electrobun/view/data-table/dom.ts +0 -1
  202. package/src/renderers/electrobun/view/desktop/controls.tsx +135 -4
  203. package/src/renderers/electrobun/view/desktop/list-view.tsx +38 -25
  204. package/src/renderers/electrobun/view/desktop-deeplink-bridge.ts +10 -0
  205. package/src/renderers/electrobun/view/host/box.tsx +0 -2
  206. package/src/renderers/electrobun/view/host/mouse.ts +0 -11
  207. package/src/renderers/electrobun/view/host/scroll-box.tsx +1 -2
  208. package/src/renderers/electrobun/view/host/text.tsx +1 -2
  209. package/src/renderers/electrobun/view/http-fetch.ts +15 -2
  210. package/src/renderers/electrobun/view/main.tsx +3 -0
  211. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -18
  212. package/src/renderers/electrobun/view/remote/capability-invoker.test.ts +50 -0
  213. package/src/renderers/electrobun/view/remote/capability-invoker.ts +36 -0
  214. package/src/renderers/electrobun/view/ui-host.tsx +2 -0
  215. package/src/renderers/opentui/host.tsx +11 -3
  216. package/src/renderers/opentui/input-host.tsx +5 -1
  217. package/src/sources/gloomberb-cloud/index.test.ts +0 -72
  218. package/src/sources/gloomberb-cloud/index.ts +1 -30
  219. package/src/sources/gloomberb-cloud/news.ts +0 -12
  220. package/src/sources/provider-router/batches.ts +11 -3
  221. package/src/sources/provider-router/cached-financials.test.ts +123 -0
  222. package/src/sources/provider-router/financial-routes.ts +77 -5
  223. package/src/sources/provider-router/financials.test.ts +49 -0
  224. package/src/sources/provider-router/financials.ts +40 -3
  225. package/src/sources/provider-router/index.test.ts +314 -0
  226. package/src/sources/provider-router/primary.ts +17 -3
  227. package/src/sources/provider-router/search.ts +5 -0
  228. package/src/sources/provider-router/streaming.ts +6 -1
  229. package/src/sources/provider-router/supplemental.ts +4 -3
  230. package/src/sources/sec-edgar.test.ts +42 -0
  231. package/src/sources/sec-edgar.ts +1 -2
  232. package/src/sources/yahoo-finance/history.ts +5 -1
  233. package/src/sources/yahoo-finance/mappers.test.ts +29 -0
  234. package/src/sources/yahoo-finance/mappers.ts +2 -1
  235. package/src/sources/yahoo-finance/options.ts +59 -14
  236. package/src/sources/yahoo-finance/quote-summary.ts +4 -1
  237. package/src/sources/yahoo-finance/requests.ts +2 -1
  238. package/src/sources/yahoo-finance/snapshots.ts +13 -2
  239. package/src/sources/yahoo-finance.test.ts +40 -21
  240. package/src/sources/yahoo-finance.ts +19 -10
  241. package/src/state/app/context/index.test.tsx +0 -81
  242. package/src/state/app/context/selector.test.tsx +6 -2
  243. package/src/state/hooks/quote-streaming.test.ts +14 -1
  244. package/src/state/hooks/quote-streaming.ts +5 -4
  245. package/src/sync/controller.test.ts +31 -0
  246. package/src/sync/controller.ts +300 -0
  247. package/src/sync/core-contributors.test.ts +251 -0
  248. package/src/sync/core-contributors.ts +400 -0
  249. package/src/sync/profile-analytics.ts +39 -0
  250. package/src/sync/react.ts +53 -0
  251. package/src/sync/types.ts +77 -0
  252. package/src/test-support/data-provider.ts +0 -1
  253. package/src/types/desktop-deeplink.ts +7 -0
  254. package/src/types/plugin.ts +3 -0
  255. package/src/ui/host.tsx +15 -1
  256. package/src/ui/index.tsx +2 -0
  257. package/src/updater.test.ts +0 -21
  258. package/src/updater.ts +20 -16
  259. package/src/utils/async-deadline.ts +26 -0
  260. package/src/utils/exchanges.test.ts +11 -1
  261. package/src/utils/exchanges.ts +5 -1
  262. package/src/utils/selection-clipboard.ts +2 -2
  263. package/src/version.ts +1 -1
  264. package/src/components/layout/pane/header.test.tsx +0 -39
  265. package/src/plugins/builtin/chat/channels.test.ts +0 -28
  266. package/src/plugins/builtin/chat/index.tsx +0 -4
  267. package/src/plugins/builtin/cloud-tweets/index.ts +0 -1
  268. package/src/plugins/builtin/earnings/index.test.ts +0 -12
  269. package/src/plugins/builtin/help/index.test.tsx +0 -242
  270. package/src/plugins/builtin/substack/article-detail.test.tsx +0 -10
  271. package/src/renderers/electrobun/bun/application-menu/index.test.ts +0 -21
  272. package/src/renderers/electrobun/bun/window/focus.test.ts +0 -35
  273. package/src/renderers/electrobun/view/host/mouse.test.ts +0 -37
  274. package/src/renderers/electrobun/view/host/text.test.ts +0 -22
  275. package/src/renderers/opentui/dialog-host.test.tsx +0 -44
  276. /package/src/{plugins/ibkr → utils}/hash.ts +0 -0
@@ -21,17 +21,6 @@ export function documentContentTarget(filing: SecFilingItem, document: SecFiling
21
21
  };
22
22
  }
23
23
 
24
- export function formatDocumentLabel(document: SecFilingDocument): string {
25
- const label = document.isPrimary ? "PRIMARY" : document.type || "DOCUMENT";
26
- const description = document.description
27
- && document.description !== document.document
28
- && document.description !== document.type
29
- ? ` | ${document.description}`
30
- : "";
31
- const size = document.size ? ` | ${document.size}` : "";
32
- return `${label.padEnd(8)} ${document.document}${description}${size}`;
33
- }
34
-
35
24
  export function formatCompactDocumentLabel(document: SecFilingDocument): string {
36
25
  const label = document.isPrimary ? "PRIMARY" : document.type || "DOCUMENT";
37
26
  const description = document.description
@@ -229,8 +229,6 @@ function toFeedItems(
229
229
  eyebrow: filing.form,
230
230
  title: form4Preview ? `${displayTitle} | ${form4Preview}` : enrichedTitle,
231
231
  timestamp: filing.filingDate,
232
- preview: form4Preview
233
- ?? (filing.items ? `Items ${filing.items}` : (formDesc || filing.primaryDocument)),
234
232
  detailTitle: enrichedTitle,
235
233
  detailMeta: [
236
234
  `Filed ${formatFiledAt(filing)}`,
@@ -43,7 +43,7 @@ const ARTICLE_IMAGE_MAX_HEIGHT = 26;
43
43
  const ARTICLE_IMAGE_MIN_HEIGHT = 6;
44
44
  const ARTICLE_IMAGE_LEGACY_HEIGHT_CAP = 14;
45
45
 
46
- export function resolveArticleImageSize(lineWidth: number) {
46
+ function resolveArticleImageSize(lineWidth: number) {
47
47
  const safeLineWidth = Math.max(1, Math.floor(lineWidth));
48
48
  const width = Math.min(safeLineWidth, ARTICLE_IMAGE_MAX_WIDTH);
49
49
  const legacyHeight = Math.min(ARTICLE_IMAGE_LEGACY_HEIGHT_CAP, Math.floor(width * 0.32));
@@ -226,21 +226,6 @@ export async function searchThirteenFFunds(
226
226
  return arrayResponse(raw).map(mapFund).filter((fund): fund is ThirteenFFund => !!fund);
227
227
  }
228
228
 
229
- export async function listThirteenFFilers(
230
- limit = 50,
231
- signal?: AbortSignal,
232
- options: { forceRefresh?: boolean; offset?: number } = {},
233
- ): Promise<ThirteenFFund[]> {
234
- const raw = await fetchForms13F<unknown>("/filers", {
235
- offset: options.offset ?? 0,
236
- limit,
237
- }, { signal, forceRefresh: options.forceRefresh });
238
- return arrayResponse(raw).map((entry) => mapFund({
239
- cik: entry.cik,
240
- name: Array.isArray(entry.company_names) ? entry.company_names[0] : entry.company_name,
241
- })).filter((fund): fund is ThirteenFFund => !!fund);
242
- }
243
-
244
229
  export async function listTopThirteenFFunds(
245
230
  quarter: string,
246
231
  limit = 50,
@@ -235,7 +235,6 @@ export function ThirteenFPane({ focused, width, height }: PaneProps) {
235
235
  }, { allowEditable: true });
236
236
 
237
237
  const sortedRows = useMemo(() => sortBrowserRows(rows, sortPreference), [rows, sortPreference]);
238
- const selectedIndex = selectedIndexById(sortedRows, selectedId);
239
238
  const columns = useMemo(() => buildBrowserColumns(width), [width]);
240
239
 
241
240
  useEffect(() => {
@@ -643,7 +642,7 @@ function FundDetailView({
643
642
  getId: (row) => row.id,
644
643
  onChange: (id) => setFilingSelectedId(id),
645
644
  }}
646
- onActivate={openFilingInPane}
645
+ onActivate={(row) => openFilingInPane(row)}
647
646
  onDetailKeyDown={(event) => {
648
647
  if (event.name !== "o" || !openFiling?.url) return false;
649
648
  event.preventDefault?.();
@@ -755,7 +754,6 @@ function FilingDetailView({
755
754
  sortPreference,
756
755
  )
757
756
  ), [filing.tableValueTotal, holdings, sortPreference]);
758
- const selectedPositionIndex = selectedIndexById(positionRows, selectedPositionId);
759
757
  const columns = useMemo(() => buildFilingPositionColumns(width), [width]);
760
758
 
761
759
  useEffect(() => {
@@ -9,7 +9,9 @@ import {
9
9
  } from "../../../../../components";
10
10
  import { useShortcut } from "../../../../../react/input";
11
11
  import type { BarChartHover } from "../../../../../components/chart/bar-chart-renderer";
12
+ import type { MouseInteractionEvent } from "../../../../../components/chart/core/pointer";
12
13
  import { StaticBarChartSurface } from "../../../../../components/chart/static/bar-chart-surface";
14
+ import { useAppDispatch, usePaneInstanceId } from "../../../../../state/app/context";
13
15
  import { colors, priceColor } from "../../../../../theme/colors";
14
16
  import { usePluginPaneState } from "../../../../runtime";
15
17
  import { loadingErrorFooterInfo, refreshFooterHint, useClampSelectedIndex } from "../../../shared/table-pane";
@@ -60,7 +62,10 @@ export function FundamentalGraphContent({
60
62
  setChartKind: (updater: (current: GraphKind) => GraphKind) => void;
61
63
  onCapture?: (capturing: boolean) => void;
62
64
  }) {
65
+ const dispatch = useAppDispatch();
66
+ const paneId = usePaneInstanceId();
63
67
  const [selectedIdx, setSelectedIdx] = usePluginPaneState<number>("selectedIdx", 0);
68
+ const [hiddenSeriesIds, setHiddenSeriesIds] = usePluginPaneState<string[]>("hiddenSeriesIds", []);
64
69
  const [hoveredBar, setHoveredBar] = useState<BarChartHover | null>(null);
65
70
  const [metricTabsFocused, setMetricTabsFocused] = useState(false);
66
71
  const definition = metricDef(chartKind, metric);
@@ -69,17 +74,23 @@ export function FundamentalGraphContent({
69
74
  label: definition.label,
70
75
  value: definition.key,
71
76
  })), [metricOptions]);
72
- const multiSymbol = new Set(rows.map((row) => row.symbol)).size > 1;
77
+ const chartSeries = useMemo(() => buildGraphBarSeries(rows), [rows]);
78
+ const chartSeriesIds = useMemo(() => new Set(chartSeries.map((series) => series.id)), [chartSeries]);
79
+ const hiddenSeriesIdSet = useMemo(() => new Set(hiddenSeriesIds), [hiddenSeriesIds]);
80
+ const visibleRows = useMemo(() => rows.filter((row) => {
81
+ const seriesId = row.symbol || "value";
82
+ return !hiddenSeriesIdSet.has(seriesId);
83
+ }), [hiddenSeriesIdSet, rows]);
84
+ const multiSymbol = new Set(visibleRows.map((row) => row.symbol)).size > 1;
73
85
  const columns = useMemo(() => buildFundamentalColumns(width, multiSymbol), [multiSymbol, width]);
74
- const tableRows = useMemo(() => [...rows].sort((left, right) => (
86
+ const tableRows = useMemo(() => [...visibleRows].sort((left, right) => (
75
87
  right.date.localeCompare(left.date) || left.symbol.localeCompare(right.symbol)
76
- )), [rows]);
88
+ )), [visibleRows]);
77
89
  const boundedSelectedIdx = tableRows.length > 0 ? Math.min(selectedIdx, tableRows.length - 1) : -1;
78
90
  const minTableHeight = tableRows.length > 0 ? 4 : 3;
79
91
  const desiredChartHeight = height >= 14 ? Math.min(16, Math.max(9, Math.floor(height * 0.58))) : Math.max(4, Math.floor(height / 2));
80
92
  const chartHeight = Math.max(1, Math.min(desiredChartHeight, Math.max(1, height - minTableHeight)));
81
93
  const tableHeight = Math.max(0, height - chartHeight);
82
- const chartSeries = useMemo(() => buildGraphBarSeries(rows), [rows]);
83
94
  const selectMetric = useCallback((value: string) => {
84
95
  const nextMetric = value as GraphMetricKey;
85
96
  const nextKind = metricKind(nextMetric);
@@ -88,11 +99,19 @@ export function FundamentalGraphContent({
88
99
  setChartKind(() => nextKind);
89
100
  setMetric(() => nextMetric);
90
101
  }, [setChartKind, setMetric]);
91
- const focusMetricTabs = useCallback(() => {
102
+ const focusPaneForMouseInteraction = useCallback((event: MouseInteractionEvent | null | undefined) => {
103
+ event?.stopPropagation?.();
104
+ event?.preventDefault?.();
105
+ if (!focused) {
106
+ dispatch({ type: "FOCUS_PANE", paneId });
107
+ }
108
+ }, [dispatch, focused, paneId]);
109
+ const focusMetricTabs = useCallback((event?: MouseInteractionEvent | null) => {
110
+ focusPaneForMouseInteraction(event);
92
111
  if (metricTabsFocused) return;
93
112
  setMetricTabsFocused(true);
94
113
  onCapture?.(true);
95
- }, [metricTabsFocused, onCapture]);
114
+ }, [focusPaneForMouseInteraction, metricTabsFocused, onCapture]);
96
115
  const releaseMetricTabs = useCallback(() => {
97
116
  if (!metricTabsFocused) return;
98
117
  setMetricTabsFocused(false);
@@ -103,6 +122,14 @@ export function FundamentalGraphContent({
103
122
  selectMetric(value);
104
123
  }, [focusMetricTabs, selectMetric]);
105
124
  const togglePeriod = useCallback(() => setPeriod((current) => current === "annual" ? "quarterly" : "annual"), [setPeriod]);
125
+ const toggleSeries = useCallback((seriesId: string) => {
126
+ setHiddenSeriesIds((current) => {
127
+ const hidden = new Set(current);
128
+ if (hidden.has(seriesId)) hidden.delete(seriesId);
129
+ else hidden.add(seriesId);
130
+ return [...hidden].filter((id) => chartSeriesIds.has(id));
131
+ });
132
+ }, [chartSeriesIds, setHiddenSeriesIds]);
106
133
  const hoveredValue = useMemo(() => {
107
134
  if (!hoveredBar) return null;
108
135
  const label = chartSeries.length > 1 ? `${hoveredBar.category} ${hoveredBar.seriesLabel}` : hoveredBar.category;
@@ -111,6 +138,13 @@ export function FundamentalGraphContent({
111
138
 
112
139
  useClampSelectedIndex(tableRows.length, selectedIdx, setSelectedIdx);
113
140
 
141
+ useEffect(() => {
142
+ setHiddenSeriesIds((current) => {
143
+ const next = current.filter((id) => chartSeriesIds.has(id));
144
+ return next.length === current.length ? current : next;
145
+ });
146
+ }, [chartSeriesIds, setHiddenSeriesIds]);
147
+
114
148
  useEffect(() => {
115
149
  if (!focused && metricTabsFocused) {
116
150
  setMetricTabsFocused(false);
@@ -228,6 +262,8 @@ export function FundamentalGraphContent({
228
262
  width={width}
229
263
  height={chartHeight}
230
264
  series={chartSeries}
265
+ hiddenSeriesIds={hiddenSeriesIds}
266
+ onToggleSeries={toggleSeries}
231
267
  header={metricHeader}
232
268
  formatValue={definition.format}
233
269
  onHoverChange={setHoveredBar}