@gloom-sh/terminal 0.19.1 → 0.19.3
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.
- package/README.md +7 -1
- package/package.json +2 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +58 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app/runtime/startup.ts +3 -1
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/chart-series.ts +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +101 -27
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +14 -10
- package/src/cli/commands/search.ts +84 -25
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +6 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/glossary.ts +2 -1
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +189 -11
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +51 -5
- package/src/cli/listing-arg.ts +63 -10
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +49 -6
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +51 -6
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +10 -5
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +8 -2
- package/src/components/layout/pane/footer/model.ts +73 -6
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +4 -2
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +60 -26
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/display.tsx +16 -5
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +16 -3
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +165 -90
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +324 -0
- package/src/data/sqlite/checkpointer.ts +285 -0
- package/src/data/sqlite/database.ts +80 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/market-data/realized-volatility.ts +4 -2
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/auto-update-node.ts +10 -6
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +30 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/client.ts +4 -1
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +5 -4
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +6 -4
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ/detail-view.tsx +16 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +19 -3
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/client.ts +4 -1
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +16 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/scanner/lock-note.ts +26 -3
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +73 -8
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +127 -29
- package/src/plugins/builtin/thirteenf/data.ts +165 -35
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
- package/src/plugins/builtin/thirteenf/types.ts +14 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/client.ts +4 -6
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +64 -42
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +5 -2
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +6 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/electrobun/view/ui-host.tsx +9 -2
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/resolve.ts +2 -1
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +12 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +25 -9
- package/src/telemetry/stall-reports.ts +218 -13
- package/src/test-support/outage.ts +8 -0
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +84 -1
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +104 -8
- package/src/tickers/search/index.ts +5 -2
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/market.ts +5 -3
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +75 -8
- package/src/time-series/resolve.ts +32 -4
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/time-series/types.ts +7 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +40 -3
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +17 -1
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +122 -5
- package/src/utils/perf-marks.ts +58 -12
- package/src/utils/price-history-integrity.ts +47 -1
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/time-series/studies.ts +0 -1628
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
|
+
import { sourceDidNotAnswer } from "../../../api-client/errors";
|
|
2
3
|
import type { JodiBoardPayload } from "../../../api-client/commodity-balances";
|
|
3
4
|
import { unavailableOnServer } from "../shared/cloud-resource";
|
|
4
5
|
import type { BalanceCommodity, Board } from "./model";
|
|
@@ -32,7 +33,9 @@ function readBoard(payload: JodiBoardPayload): Balances {
|
|
|
32
33
|
|| (payload.gas != null && !validBoard(payload.gas, "gas"))) {
|
|
33
34
|
throw new Error("The server returned an invalid oil and gas balance board");
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
// The server's source did not answer this time, which may pass; a board with no oil has none yet.
|
|
37
|
+
if (payload.status === "unavailable") throw sourceDidNotAnswer(JODI_NOT_AVAILABLE);
|
|
38
|
+
if (payload.oil == null) throw new Error(JODI_NOT_AVAILABLE);
|
|
36
39
|
if (!validBoard(payload.oil, "oil")) throw new Error("The server returned an invalid oil and gas balance board");
|
|
37
40
|
return { oil: payload.oil, gas: payload.gas ?? null, stale: payload.stale === true, gaps: payload.gaps };
|
|
38
41
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { jodiHeadless } from "./headless";
|
|
3
3
|
import { JODI_PANE_ID } from "./model";
|
|
4
|
-
import { JodiPane } from "./pane";
|
|
5
4
|
|
|
6
5
|
export const jodiModule: PluginModule = {
|
|
7
6
|
panes: [
|
|
@@ -9,7 +8,7 @@ export const jodiModule: PluginModule = {
|
|
|
9
8
|
id: JODI_PANE_ID,
|
|
10
9
|
name: "Oil and Gas Balances",
|
|
11
10
|
icon: "O",
|
|
12
|
-
component: JodiPane,
|
|
11
|
+
get component(): typeof import("./pane").JodiPane { const { JodiPane } = require("./pane"); return JodiPane; },
|
|
13
12
|
defaultPosition: "right",
|
|
14
13
|
defaultMode: "floating",
|
|
15
14
|
defaultFloatingSize: { width: 110, height: 30 },
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PaneTemplateContext, PaneTemplateCreateOptions } from "../../../types/plugin";
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
3
|
import { DEFAULT_FLOATING_SIZE, KELLY_PANE_ID } from "./constants";
|
|
4
|
-
import { KellySizerPane } from "./pane";
|
|
5
4
|
import { kellyHeadless } from "./headless";
|
|
6
5
|
|
|
7
6
|
function resolveTemplateSymbol(context: PaneTemplateContext, options?: PaneTemplateCreateOptions): string | null {
|
|
@@ -21,7 +20,7 @@ export const positionSizerModule: PluginModule = {
|
|
|
21
20
|
icon: "K",
|
|
22
21
|
// The bankroll is the account's value.
|
|
23
22
|
personalData: "holdings",
|
|
24
|
-
component: KellySizerPane,
|
|
23
|
+
get component(): typeof import("./pane").KellySizerPane { const { KellySizerPane } = require("./pane"); return KellySizerPane; },
|
|
25
24
|
defaultPosition: "right",
|
|
26
25
|
defaultMode: "floating",
|
|
27
26
|
defaultFloatingSize: DEFAULT_FLOATING_SIZE,
|
|
@@ -2,7 +2,6 @@ import { findPaneInstance, type LayoutConfig } from "../../../types/config";
|
|
|
2
2
|
import type { AppNotificationRequest, CommandResultDef, GloomPluginContext } from "../../../types/plugin";
|
|
3
3
|
import type { PluginModule } from "../plugin-module";
|
|
4
4
|
import type { AppAction } from "../../../state/app/context";
|
|
5
|
-
import { LayoutMarketplacePane } from "../../../layout-marketplace/pane";
|
|
6
5
|
import { apiClient } from "../../../api-client";
|
|
7
6
|
import { resolvePlanAccess } from "../../../api-client/plan-access";
|
|
8
7
|
import { getSharedRegistry } from "../../registry";
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
deskFunctions,
|
|
12
11
|
DESKS,
|
|
13
12
|
isDeskStock,
|
|
13
|
+
MORE_DESKS,
|
|
14
14
|
pickDeskCompany,
|
|
15
15
|
type Desk,
|
|
16
16
|
} from "../../../layout/desks";
|
|
@@ -60,10 +60,11 @@ function getFocusedPane(layout: LayoutConfig, focusedPaneId: string | null) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/** Desks whose key, name or one of whose functions matches what follows DESK. */
|
|
63
|
-
function matchDesks(query: string): Desk[] {
|
|
63
|
+
function matchDesks(query: string): Desk<string>[] {
|
|
64
64
|
const needle = query.trim().toLowerCase();
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const desks: Desk<string>[] = [...DESKS, ...MORE_DESKS];
|
|
66
|
+
if (!needle) return desks;
|
|
67
|
+
return desks.filter((desk) => (
|
|
67
68
|
desk.key.startsWith(needle)
|
|
68
69
|
|| desk.label.toLowerCase().includes(needle)
|
|
69
70
|
|| desk.name.toLowerCase().includes(needle)
|
|
@@ -75,7 +76,7 @@ function matchDesks(query: string): Desk[] {
|
|
|
75
76
|
* Opens the desk as a new tab after the others. Its company is the focused
|
|
76
77
|
* pane's stock, else the most recent stock the user looked at.
|
|
77
78
|
*/
|
|
78
|
-
async function addDesk(ctx: GloomPluginContext, desk: Desk): Promise<void> {
|
|
79
|
+
async function addDesk(ctx: GloomPluginContext, desk: Desk<string>): Promise<void> {
|
|
79
80
|
const registry = getSharedRegistry();
|
|
80
81
|
if (!registry || !dispatchRef || !getStateRef) return;
|
|
81
82
|
const config = ctx.getConfig();
|
|
@@ -110,8 +111,8 @@ export const layoutManagerModule: PluginModule = {
|
|
|
110
111
|
id: "layout-marketplace",
|
|
111
112
|
name: "Layouts",
|
|
112
113
|
icon: "L",
|
|
113
|
-
component: LayoutMarketplacePane,
|
|
114
|
-
reportFreshness: { status: "not-a-feed", basis: "layout listings" },
|
|
114
|
+
get component(): typeof import("../../../layout-marketplace/pane").LayoutMarketplacePane { const { LayoutMarketplacePane } = require("../../../layout-marketplace/pane"); return LayoutMarketplacePane; },
|
|
115
|
+
reportFreshness: { status: "not-a-feed", basis: "layout listings", local: true },
|
|
115
116
|
defaultPosition: "right",
|
|
116
117
|
defaultMode: "floating",
|
|
117
118
|
defaultFloatingSize: { width: 118, height: 34 },
|
|
@@ -128,7 +129,7 @@ export const layoutManagerModule: PluginModule = {
|
|
|
128
129
|
label: "Add a Desk",
|
|
129
130
|
description: "Add a ready-made desk for one kind of trading as a new layout tab",
|
|
130
131
|
keywords: ["desk", "desks", "workspace", "starter", "equities", "stocks", "options", "volatility", "futures",
|
|
131
|
-
"commodities", "rates", "credit", "fx", "macro", "active trading", "day trading"],
|
|
132
|
+
"commodities", "rates", "credit", "fx", "macro", "active trading", "day trading", "buildout", "ai buildout", "data centers"],
|
|
132
133
|
category: "config",
|
|
133
134
|
shortcut: "DESK",
|
|
134
135
|
shortcutArg: { placeholder: "desk", kind: "text", parse: (arg) => ({ query: arg.trim() }) },
|
|
@@ -152,7 +152,9 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
|
|
|
152
152
|
return { text: times(event.multiple), value: event.multiple };
|
|
153
153
|
}, [colors, model?.basis, release]);
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
// A figure wraps only into rows the table's least leaves, so the pane never spills.
|
|
156
|
+
const statMaxLines = height - 1 - 4;
|
|
157
|
+
const contentHeight = Math.max(4, height - 1 - statGridRows(stats, width, undefined, { maxLines: statMaxLines }));
|
|
156
158
|
const key = (event: MacroDayEvent) => `${event.kind}:${event.date}`;
|
|
157
159
|
|
|
158
160
|
return <Box width={width} height={height} flexDirection="column" overflow="hidden">
|
|
@@ -164,7 +166,7 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
|
|
|
164
166
|
{!symbol ? <EmptyState title="Select a ticker." /> : <PaneStatusBody subject="macro-day moves" loading={history.loading && !model}
|
|
165
167
|
error={!model ? history.error ?? identityError ?? null : null} empty={!!model && !model.events.length}>
|
|
166
168
|
{model ? <>
|
|
167
|
-
<StatGrid items={stats} width={width} />
|
|
169
|
+
<StatGrid items={stats} width={width} maxLines={statMaxLines} />
|
|
168
170
|
<DataTableView<MacroDayEvent> focused={focused} columns={columns} items={rows} rootWidth={width} rootHeight={contentHeight}
|
|
169
171
|
getItemKey={key} emptyStateTitle={surprise === "all" ? "No release days." : `No ${MACRO_SURPRISE_LABELS[surprise].toLowerCase()} prints.`} sortColumnId={null} sortDirection="desc" selectedTextOverridesCellColor
|
|
170
172
|
selection={{ kind: "id", selectedId: selectedRow, getId: key, onChange: (id) => setSelectedRow(id) }}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { GloomPlugin } from "../../../types/plugin";
|
|
2
2
|
import { MARKET_HALTS_PANE_ID } from "./model";
|
|
3
|
-
import { MarketHaltsPane } from "./pane";
|
|
4
3
|
|
|
5
4
|
export const marketHaltsPlugin: GloomPlugin = {
|
|
6
5
|
id: "market-halts",
|
|
@@ -20,7 +19,7 @@ export const marketHaltsPlugin: GloomPlugin = {
|
|
|
20
19
|
reportFreshness: { source: "Nasdaq Trader" },
|
|
21
20
|
name: "Market Halts",
|
|
22
21
|
icon: "H",
|
|
23
|
-
component: MarketHaltsPane,
|
|
22
|
+
get component(): typeof import("./pane").MarketHaltsPane { const { MarketHaltsPane } = require("./pane"); return MarketHaltsPane; },
|
|
24
23
|
defaultPosition: "right",
|
|
25
24
|
defaultMode: "floating",
|
|
26
25
|
defaultFloatingSize: { width: 124, height: 26 },
|
|
@@ -70,6 +70,7 @@ import {
|
|
|
70
70
|
type HeatmapSizeBy,
|
|
71
71
|
} from "./portfolio";
|
|
72
72
|
import { useAutoRefresh, useUpdatedAgo } from "../../../react/auto-refresh";
|
|
73
|
+
import { useQuoteDelayFooter } from "../shared/cloud-upgrade";
|
|
73
74
|
import {
|
|
74
75
|
LIVE_STREAMING_QUICK_SETTING,
|
|
75
76
|
useLiveStreamingSetting,
|
|
@@ -635,6 +636,13 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
635
636
|
useAutoRefresh(board?.checkedAt ?? null, autoRefresh, { intervalMs: heatmapCheckIntervalMs(board) });
|
|
636
637
|
|
|
637
638
|
usePaneStatusFooter({ registrationId: "market-heatmap-retained", stale: hasBoard && stale && !portfolioTab });
|
|
639
|
+
// Signed out or free, a market board is the delayed one, and the holdings' quotes are delayed ones.
|
|
640
|
+
const quoteDelay = useQuoteDelayFooter(
|
|
641
|
+
portfolioTab
|
|
642
|
+
? Array.from(financials.values(), (entry) => entry?.quote)
|
|
643
|
+
: shownBoard ? [{ dataSource: shownBoard.access === "realtime" ? "live" as const : "delayed" as const }] : [],
|
|
644
|
+
"heatmap-delay",
|
|
645
|
+
);
|
|
638
646
|
usePaneNoticeFooter({
|
|
639
647
|
registrationId: "market-heatmap-omitted",
|
|
640
648
|
notices: portfolioTab && portfolioBoard.omitted > 0
|
|
@@ -677,7 +685,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
677
685
|
// The caption takes the room the rest leaves, with "loading" counted in
|
|
678
686
|
// always, so a refresh never squeezes the row; a narrow pane drops its
|
|
679
687
|
// least important parts rather than truncating every segment.
|
|
680
|
-
const others = [...selected, ...failed, ...feed];
|
|
688
|
+
const others = [...selected, ...failed, ...feed, ...(quoteDelay ? [quoteDelay] : [])];
|
|
681
689
|
const room = width - others.reduce((total, segment) => total + footerSegmentWidth(segment) + 1, 0) - LOADING_FOOTER_WIDTH - 1;
|
|
682
690
|
const caption = shownBoard ? heatmapBoardCaption(shownBoard, { now: Date.now(), checked, failed: failed.length > 0, maxWidth: room }) : null;
|
|
683
691
|
return {
|
|
@@ -687,9 +695,10 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
687
695
|
...(caption ? [{ id: "board", parts: [{ text: caption, tone: "muted" as const }] }] : []),
|
|
688
696
|
...feed,
|
|
689
697
|
...loadingSegment,
|
|
698
|
+
...(quoteDelay ? [quoteDelay] : []),
|
|
690
699
|
],
|
|
691
700
|
};
|
|
692
|
-
}, [checked, feedStatus, hasBoard, loadError, loading, portfolioTab, selectedAsset, shownBoard, width]);
|
|
701
|
+
}, [checked, feedStatus, hasBoard, loadError, loading, portfolioTab, quoteDelay, selectedAsset, shownBoard, width]);
|
|
693
702
|
|
|
694
703
|
return (
|
|
695
704
|
<Box flexDirection="column" width={width} height={height}>
|
|
@@ -119,6 +119,7 @@ export async function loadMarketMoverTab(
|
|
|
119
119
|
...hydrated,
|
|
120
120
|
source: "gloom",
|
|
121
121
|
stale: trending.stale || !!hydrated.unavailableSymbols?.length,
|
|
122
|
+
...(trending.savedAt != null ? { savedAt: trending.savedAt } : {}),
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
125
|
const category = CATEGORY_MAP[tab];
|
|
@@ -2,6 +2,8 @@ import { Box, useUiCapabilities } from "../../../ui";
|
|
|
2
2
|
import { nextHeaderSort } from "../../../utils/sort-values";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { DataTableView, EmptyState, QueryBar, usePaneFooter, usePaneTabs, type DataTableKeyEvent } from "../../../components";
|
|
5
|
+
import { savedCopyFooterInfo } from "../../../components/layout/pane/footer";
|
|
6
|
+
import { STALE_SEGMENT } from "../../../components/layout/pane/status-footer";
|
|
5
7
|
import { handleRefreshKey } from "../../../components/data-table/table-pane";
|
|
6
8
|
import type { PaneProps } from "../../../types/plugin";
|
|
7
9
|
import type { PluginModule } from "../plugin-module";
|
|
@@ -12,6 +14,7 @@ import { useAssetData, usePluginPaneState, usePluginTickerActions } from "../../
|
|
|
12
14
|
import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
|
|
13
15
|
import { useAutoRefresh } from "../../../react/auto-refresh";
|
|
14
16
|
import { useQuoteBoard } from "../shared/use-quote-board";
|
|
17
|
+
import { useQuoteDelayFooter } from "../shared/cloud-upgrade";
|
|
15
18
|
import {
|
|
16
19
|
attachMarketMoversPersistence,
|
|
17
20
|
MARKET_SUMMARY_SYMBOLS,
|
|
@@ -60,6 +63,8 @@ import {
|
|
|
60
63
|
const NO_SAVED_SELECTION: string[] = [];
|
|
61
64
|
const SESSION_CHECK_MS = 30_000;
|
|
62
65
|
const NO_QUOTES: MoverQuote[] = [];
|
|
66
|
+
/** A list without Pro is the one built a delay before: the delayed clock reads it as one late price. */
|
|
67
|
+
const DELAYED_LIST = [{ dataSource: "delayed" as const }];
|
|
63
68
|
const moverKey = (row: Pick<ScreenerQuote, "symbol" | "exchange">) => publicTickerKey(row.symbol, row.exchange);
|
|
64
69
|
|
|
65
70
|
/** What is trading in New York, re-read every half minute so the pane follows 04:00, 09:30 and 16:00. */
|
|
@@ -167,6 +172,8 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
|
|
|
167
172
|
const [selectedSymbol, setSelectedSymbol] = useState<string | null>(null);
|
|
168
173
|
const [sortPreference, setSortPreference] = useState<MarketMoverSortPreference>(DEFAULT_SORT_PREFERENCE);
|
|
169
174
|
const [moversStale, setMoversStale] = useState(false);
|
|
175
|
+
// The list's refresh failed and a copy saved at this time (ms) answered instead.
|
|
176
|
+
const [moversSavedAt, setMoversSavedAt] = useState<number | null>(null);
|
|
170
177
|
const [lastSuccess, setLastSuccess] = useState<{ key: string; at: number } | null>(null);
|
|
171
178
|
|
|
172
179
|
const fetchGenRef = useRef(0);
|
|
@@ -241,11 +248,13 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
|
|
|
241
248
|
if (!options?.background) setSelectedSymbol(null);
|
|
242
249
|
}
|
|
243
250
|
setMoversStale(result.stale);
|
|
251
|
+
setMoversSavedAt(result.savedAt ?? null);
|
|
244
252
|
setLoadError(quoteError);
|
|
245
253
|
if (!quoteError && !result.stale) setLastSuccess({ key: `${tab}:${minFloat ?? ""}`, at: Date.now() });
|
|
246
254
|
} catch {
|
|
247
255
|
if (fetchGenRef.current !== gen) return;
|
|
248
256
|
setMoversStale(true);
|
|
257
|
+
setMoversSavedAt(null);
|
|
249
258
|
setLoadError("Market movers temporarily unavailable");
|
|
250
259
|
}
|
|
251
260
|
finally {
|
|
@@ -279,6 +288,8 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
|
|
|
279
288
|
handleRefreshKey(event, () => loadTab(activeTab, { forceRefresh: true }), { stopPropagation: true })
|
|
280
289
|
), [activeTab, loadTab]);
|
|
281
290
|
|
|
291
|
+
// Without Pro the lists are the delayed ones (with Pro the real-time ones), and say so.
|
|
292
|
+
const quoteDelay = useQuoteDelayFooter(rows.length > 0 ? DELAYED_LIST : [], "movers-delay");
|
|
282
293
|
usePaneFooter("market-movers", () => ({
|
|
283
294
|
info: [
|
|
284
295
|
...(loadError ? [{ id: "load-error", parts: [{ text: loadError, tone: "warning" as const }] }] : []),
|
|
@@ -288,14 +299,14 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
|
|
|
288
299
|
id: "feed",
|
|
289
300
|
parts: [{ text: feedStatus, tone: feedStatus === "live" ? "value" as const : "muted" as const }],
|
|
290
301
|
}] : []),
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}] : []),
|
|
302
|
+
// A saved copy answering a failed refresh says when it was saved; other stale rows say only that.
|
|
303
|
+
...(loadedKey === listKey ? savedCopyFooterInfo([moversSavedAt]) : []),
|
|
304
|
+
...(moversStale && moversSavedAt == null && loadedKey === listKey ? [STALE_SEGMENT] : []),
|
|
295
305
|
// The FLOAT column shows while a minimum is set; a float the source does not date says so once.
|
|
296
306
|
...partialFloatFooter(columns.some((column) => column.id === "floatShares"), rows),
|
|
307
|
+
...(quoteDelay ? [quoteDelay] : []),
|
|
297
308
|
],
|
|
298
|
-
}), [columns, feedStatus, listKey, loadedKey, loadError, loading, moversStale, rows, summaryQuotes]);
|
|
309
|
+
}), [columns, feedStatus, listKey, loadedKey, loadError, loading, moversStale, moversSavedAt, quoteDelay, rows, summaryQuotes]);
|
|
299
310
|
|
|
300
311
|
return (
|
|
301
312
|
<DataTableView<MarketMoverRow, MarketMoverColumn>
|
|
@@ -5,6 +5,7 @@ import { logFailure } from "../../../utils/log-failure";
|
|
|
5
5
|
import { savedCopyMark, servedFromSavedCopy } from "../../../data/saved-copies";
|
|
6
6
|
import type { PluginPersistence } from "../../../types/plugin";
|
|
7
7
|
import { apiClient } from "../../../api-client";
|
|
8
|
+
import { isTransientFailure, sourceDidNotAnswer } from "../../../api-client/errors";
|
|
8
9
|
import type {
|
|
9
10
|
CloudMarketResponse,
|
|
10
11
|
CloudMarketScreenerCategory,
|
|
@@ -96,6 +97,8 @@ function writeCache<T>(key: string, data: T): void {
|
|
|
96
97
|
export interface CachedResult<T> {
|
|
97
98
|
data: T;
|
|
98
99
|
stale: boolean;
|
|
100
|
+
/** Its refresh failed and the copy saved at this time (ms) answered instead. */
|
|
101
|
+
savedAt?: number;
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
async function loadCached<T>(
|
|
@@ -119,11 +122,13 @@ async function loadCached<T>(
|
|
|
119
122
|
return result;
|
|
120
123
|
})
|
|
121
124
|
.catch((error) => {
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
// The next read asks again rather than read the saved copy as current.
|
|
126
|
+
if (fallback) failedFetches.add(key);
|
|
127
|
+
// Serving the expired copy is right for a failure asking again may get past; hiding that it is
|
|
128
|
+
// expired is not. A command that shows it ends with when the copy was saved. A refusal or a
|
|
129
|
+
// reply that fails validation is the error, saved copy or not.
|
|
130
|
+
if (fallback && isTransientFailure(error)) {
|
|
131
|
+
return servedFromSavedCopy({ data: fallback.data, stale: true, savedAt: fallback.fetchedAt }, fallback.fetchedAt);
|
|
127
132
|
}
|
|
128
133
|
throw error;
|
|
129
134
|
})
|
|
@@ -146,6 +151,8 @@ export interface MarketMoversResult {
|
|
|
146
151
|
quotes: ScreenerQuote[];
|
|
147
152
|
source: MarketMoversDataSource;
|
|
148
153
|
stale: boolean;
|
|
154
|
+
/** Its refresh failed and the list saved at this time (ms) answered instead. */
|
|
155
|
+
savedAt?: number;
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
export interface PreferredMarketMoverSources {
|
|
@@ -268,6 +275,8 @@ export async function fetchScreenerResult(
|
|
|
268
275
|
const session = category === "most_actives" ? undefined : options?.session;
|
|
269
276
|
const load = async () => {
|
|
270
277
|
const response = await api.getMarketMovers(category, count, options?.forceRefresh, session);
|
|
278
|
+
// The service's own source did not answer this time: a saved list answers, as it does a 5xx.
|
|
279
|
+
if (!response.data && response.status === "retryable_error") throw sourceDidNotAnswer("Market movers temporarily unavailable");
|
|
271
280
|
if (!response.data) throw new Error("Invalid market movers response");
|
|
272
281
|
return { data: parseScreenerResponse(response.data), stale: response.stale === true || response.data.stale === true };
|
|
273
282
|
};
|
|
@@ -392,7 +401,13 @@ export async function fetchPreferredMarketMovers(
|
|
|
392
401
|
const eligibility = sources.isCloudEligible();
|
|
393
402
|
if (!(typeof eligibility === "boolean" ? eligibility : await eligibility)) {
|
|
394
403
|
const result = await sources.fetchMarket(category, count, options);
|
|
395
|
-
return {
|
|
404
|
+
return {
|
|
405
|
+
...savedCopyMark(result),
|
|
406
|
+
quotes: rankScreenerQuotes(category, result.data),
|
|
407
|
+
source: "gloom",
|
|
408
|
+
stale: result.stale,
|
|
409
|
+
...(result.savedAt != null ? { savedAt: result.savedAt } : {}),
|
|
410
|
+
};
|
|
396
411
|
}
|
|
397
412
|
|
|
398
413
|
const marketMetadata = sources.fetchMarket(
|
|
@@ -432,6 +447,7 @@ export async function fetchPreferredMarketMovers(
|
|
|
432
447
|
quotes: rankScreenerQuotes(category, fallback.data),
|
|
433
448
|
source: "gloom",
|
|
434
449
|
stale: fallback.stale,
|
|
450
|
+
...(fallback.savedAt != null ? { savedAt: fallback.savedAt } : {}),
|
|
435
451
|
};
|
|
436
452
|
}
|
|
437
453
|
|
|
@@ -448,6 +464,7 @@ export async function fetchTrendingResult(
|
|
|
448
464
|
const load = async () => {
|
|
449
465
|
const response = await (api.getMarketTrending ?? apiClient.getMarketTrending)(count);
|
|
450
466
|
if (response.status === "empty") return { data: [], stale: response.stale === true };
|
|
467
|
+
if (!response.data && response.status === "retryable_error") throw sourceDidNotAnswer("Market trends temporarily unavailable");
|
|
451
468
|
if (!response.data) throw new Error("Market trends unavailable");
|
|
452
469
|
return { data: parseTrendingResponse(response.data), stale: response.stale === true };
|
|
453
470
|
};
|
|
@@ -5,7 +5,9 @@ import type {
|
|
|
5
5
|
CloudSessionMoversSide,
|
|
6
6
|
} from "../../../api-client/market-movers";
|
|
7
7
|
import { usePlanAccess } from "../../../api-client/plan-access";
|
|
8
|
+
import { useQuoteDelayFooter } from "../shared/cloud-upgrade";
|
|
8
9
|
import { DataTableView, EmptyState, QueryBar, usePaneFooter, type DataTableKeyEvent } from "../../../components";
|
|
10
|
+
import { STALE_SEGMENT } from "../../../components/layout/pane/status-footer";
|
|
9
11
|
import { handleRefreshKey } from "../../../components/data-table/table-pane";
|
|
10
12
|
import {
|
|
11
13
|
buildScreenerQuoteTargets,
|
|
@@ -190,6 +192,7 @@ function SessionMoversTable({ view, session, focused, width, summaryQuotes, live
|
|
|
190
192
|
const sessionLabel = payload ? earlierSessionLabel(payload.session, session) : null;
|
|
191
193
|
// While its session trades, a free list says when it was built; a finished one is final and its date says enough.
|
|
192
194
|
const asOfLabel = payload && delayed && sessionTrading ? listAsOfLabel(payload.asOf, payload.session, session) : null;
|
|
195
|
+
const quoteDelay = useQuoteDelayFooter(payload ? [{ dataSource: delayed ? "delayed" : "live" }] : [], "movers-delay");
|
|
193
196
|
usePaneFooter("market-movers", () => ({
|
|
194
197
|
info: [
|
|
195
198
|
...(loadError ? [{ id: "load-error", parts: [{ text: loadError, tone: "warning" as const }] }] : []),
|
|
@@ -201,11 +204,12 @@ function SessionMoversTable({ view, session, focused, width, summaryQuotes, live
|
|
|
201
204
|
id: "feed",
|
|
202
205
|
parts: [{ text: feedStatus, tone: feedStatus === "live" ? "value" as const : "muted" as const }],
|
|
203
206
|
}] : []),
|
|
204
|
-
...(payload?.stale ? [
|
|
207
|
+
...(payload?.stale ? [STALE_SEGMENT] : []),
|
|
205
208
|
// A float the source does not date says so once, while the FLOAT column shows.
|
|
206
209
|
...partialFloatFooter(columns.some((column) => column.id === "floatShares"), rows),
|
|
210
|
+
...(quoteDelay ? [quoteDelay] : []),
|
|
207
211
|
],
|
|
208
|
-
}), [asOfLabel, columns, feedStatus, loadError, loading, payload?.stale, rows, sessionLabel, summaryQuotes]);
|
|
212
|
+
}), [asOfLabel, columns, feedStatus, loadError, loading, payload?.stale, quoteDelay, rows, sessionLabel, summaryQuotes]);
|
|
209
213
|
|
|
210
214
|
const openRow = useCallback((row: SessionMoverRow) => {
|
|
211
215
|
pinTicker(rowKey(row), { floating: true, paneType: TICKER_RESEARCH_PANE_ID, instrument: null });
|
|
@@ -3,7 +3,6 @@ import { valuationCache } from "./cache";
|
|
|
3
3
|
import { valuationSeriesDefinitions } from "./chart-series";
|
|
4
4
|
import { INDICATORS, resolveIndicatorArg } from "./indicators";
|
|
5
5
|
import { marketValuationHeadless } from "./headless";
|
|
6
|
-
import { MarketValuationPane } from "./pane";
|
|
7
6
|
import { buildValuationSettingsDef, VALUATION_DEFAULTS } from "./settings";
|
|
8
7
|
|
|
9
8
|
|
|
@@ -41,7 +40,7 @@ export const marketValuationModule: PluginModule = {
|
|
|
41
40
|
id: MARKET_VALUATION_PANE_ID,
|
|
42
41
|
name: "Market Valuation",
|
|
43
42
|
icon: "V",
|
|
44
|
-
component: MarketValuationPane,
|
|
43
|
+
get component(): typeof import("./pane").MarketValuationPane { const { MarketValuationPane } = require("./pane"); return MarketValuationPane; },
|
|
45
44
|
defaultPosition: "right",
|
|
46
45
|
defaultMode: "floating",
|
|
47
46
|
defaultFloatingSize: { width: 88, height: 34 },
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import type { GloomPlugin } from "../../../types/plugin";
|
|
2
2
|
import { fundBreadthCache, fundChangesCache, fundListCache, fundMembersCache } from "./client";
|
|
3
3
|
import { membersHeadless } from "./headless";
|
|
4
|
-
import { MembersPane } from "./pane";
|
|
5
4
|
import { membersTitle, TABS } from "./model";
|
|
6
5
|
export const membersPlugin: GloomPlugin = {
|
|
7
6
|
id: "members", name: "Index and ETF members", version: "1.0.0", description: "ETF holdings, member returns, contributions, breadth and index changes", toggleable: true,
|
|
8
7
|
setup(ctx) { fundBreadthCache.attach(ctx.persistence); fundListCache.attach(ctx.persistence); fundMembersCache.attach(ctx.persistence); fundChangesCache.attach(ctx.persistence); },
|
|
9
8
|
dispose() { fundBreadthCache.reset(); fundListCache.reset(); fundMembersCache.reset(); fundChangesCache.reset(); },
|
|
10
|
-
panes: [{ id: "members", name: "Index and ETF members", icon: "M", component: MembersPane, tickerFollower: true,
|
|
9
|
+
panes: [{ id: "members", name: "Index and ETF members", icon: "M", get component(): typeof import("./pane").MembersPane { const { MembersPane } = require("./pane"); return MembersPane; }, tickerFollower: true,
|
|
11
10
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 132, height: 32 }, tableExport: true,
|
|
12
11
|
settings: { fields: [{ key: "tab", label: "View", type: "select", options: TABS }] } }],
|
|
13
12
|
paneTemplates: [{ id: "members-pane", paneId: "members", label: "Index and ETF members", description: "ETF holdings, member returns, daily contributions, breadth and index changes.",
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { moneyMarketsCache } from "./client";
|
|
3
3
|
import { moneyMarketsHeadless } from "./headless";
|
|
4
|
-
import { MoneyMarketsPane } from "./pane";
|
|
5
4
|
import { MONEY_MARKET_SERIES } from "./series";
|
|
6
5
|
|
|
7
6
|
export const moneyMarketsModule: PluginModule = {
|
|
8
7
|
series: MONEY_MARKET_SERIES,
|
|
9
|
-
panes: [{ id: "money-markets", name: "Money Markets", icon: "$", component: MoneyMarketsPane,
|
|
8
|
+
panes: [{ id: "money-markets", name: "Money Markets", icon: "$", get component(): typeof import("./pane").MoneyMarketsPane { const { MoneyMarketsPane } = require("./pane"); return MoneyMarketsPane; },
|
|
10
9
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 88, height: 28 },
|
|
11
10
|
tableExport: true, headless: moneyMarketsHeadless,
|
|
12
11
|
settings: { title: "Money Markets", fields: [{ key: "tab", label: "View", type: "select",
|
|
@@ -2,6 +2,7 @@ import { useCallback, useMemo } from "react";
|
|
|
2
2
|
import { Box } from "../../../ui";
|
|
3
3
|
import { useAsyncResource, useAutoRefresh, usePaneSettingValue, usePluginPaneState, useUpdatedAgo } from "../../../public/react";
|
|
4
4
|
import { ChartTableHeader, CompositeChart, CurveSurface, curveGhostColors, EmptyState, formatPercentAxis, MarketBoardStack, PaneStatusBody, useChartTableSelection, usePaneNoticeFooter, usePaneStatusLinkFooter, usePaneTabs, type ChartTableChart, type MarketBoardRow, type StatItem } from "../../../components";
|
|
5
|
+
import { ageFooterSegment } from "../../../components/layout/pane/footer";
|
|
5
6
|
import { curveStrip, curveSurfaceMinRows } from "../../../components/chart/curve";
|
|
6
7
|
import { colors } from "../../../theme/colors";
|
|
7
8
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
@@ -125,7 +126,7 @@ export function MoneyMarketsPane({ width, height, focused }: PaneProps) {
|
|
|
125
126
|
notices: [...(data ? moneyMarketNotices(data) : []), ...(resource.data?.refreshError ? [resource.data.refreshError] : [])] });
|
|
126
127
|
usePaneStatusLinkFooter({ registrationId: "money-markets", focused, loading: resource.loading, error: resource.error,
|
|
127
128
|
url: selected?.observation.sourceUrl ?? null, showOpenHint: true,
|
|
128
|
-
info: data && updatedAgo ? [
|
|
129
|
+
info: data && updatedAgo ? [ageFooterSegment(updatedAgo)] : [],
|
|
129
130
|
stale: !!data && resource.data?.stale,
|
|
130
131
|
});
|
|
131
132
|
return <Box width={width} height={height} flexDirection="column">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MoneyMarketObservation } from "../../../api-client/money-markets";
|
|
2
2
|
import type { SeriesDefinition } from "../../../series/types";
|
|
3
|
-
import {
|
|
3
|
+
import { cachedSeriesNote } from "../shared/series-warning";
|
|
4
4
|
import { loadMoneyMarkets } from "./client";
|
|
5
5
|
|
|
6
6
|
function observations(history: readonly MoneyMarketObservation[]) {
|
|
@@ -21,8 +21,7 @@ export const MONEY_MARKET_SERIES: readonly SeriesDefinition[] = [
|
|
|
21
21
|
tags: ["liquidity", "Fed balance sheet", "TGA", "RRP", "money markets"],
|
|
22
22
|
load: async () => {
|
|
23
23
|
const resource = await loadMoneyMarkets();
|
|
24
|
-
|
|
25
|
-
return { points: observations(resource.payload.netLiquidity.history), ...(warning ? { warning } : {}) };
|
|
24
|
+
return { points: observations(resource.payload.netLiquidity.history), ...cachedSeriesNote(resource) };
|
|
26
25
|
},
|
|
27
26
|
},
|
|
28
27
|
{
|
|
@@ -34,8 +33,7 @@ export const MONEY_MARKET_SERIES: readonly SeriesDefinition[] = [
|
|
|
34
33
|
tags: ["bills", "curve", "money markets"],
|
|
35
34
|
load: async () => {
|
|
36
35
|
const resource = await loadMoneyMarkets();
|
|
37
|
-
|
|
38
|
-
return { points: observations(resource.payload.billsCurve.slope.history), ...(warning ? { warning } : {}) };
|
|
36
|
+
return { points: observations(resource.payload.billsCurve.slope.history), ...cachedSeriesNote(resource) };
|
|
39
37
|
},
|
|
40
38
|
},
|
|
41
39
|
];
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
import { parsePublicTickerKey } from "../../../utils/exchanges";
|
|
15
15
|
import { companyDataNotes, readCompanyFrom } from "../../../types/company-from";
|
|
16
16
|
import { formatUtcSeconds } from "../../../utils/utc-time";
|
|
17
|
+
import { newsSummaryLine } from "../../../news/news-model";
|
|
18
|
+
import { shortStoryId } from "../../../news/story-id";
|
|
17
19
|
import { cloudNewsFreshness, cloudRealtimeAccess } from "../shared/report-freshness";
|
|
18
20
|
import { REPORT_FILTER, REPORT_ROWS } from "../shared/headless-options";
|
|
19
21
|
|
|
@@ -25,6 +27,11 @@ const NEWS_COLUMNS = [
|
|
|
25
27
|
{ key: "tickers", header: "Tickers", textFormat: (value: unknown) => Array.isArray(value) ? value.join(", ") : String(value ?? "") },
|
|
26
28
|
{ key: "sentiment", header: "Sentiment" },
|
|
27
29
|
{ key: "importance", header: "Score", align: "right" as const },
|
|
30
|
+
// The short id `fn news-story-pane` opens the story by, and its summary on one line under the row; exports keep both whole.
|
|
31
|
+
{ key: "id", header: "ID", textFormat: (value: unknown) => typeof value === "string" ? shortStoryId(value) : "" },
|
|
32
|
+
{ key: "summary", header: "Summary", underRow: "line" as const,
|
|
33
|
+
textFormat: (value: unknown, row: Record<string, unknown>) =>
|
|
34
|
+
newsSummaryLine({ title: String(row.headline ?? ""), summary: typeof value === "string" ? value : undefined }) ?? "" },
|
|
28
35
|
];
|
|
29
36
|
|
|
30
37
|
export interface NewsHeadlessDependencies {
|
|
@@ -92,7 +92,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
92
92
|
{
|
|
93
93
|
id: NEWS_STORY_PANE_ID,
|
|
94
94
|
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
95
|
-
reportArgument: { kind: "free-text", placeholder: "story id", description: "The id of the story to open." },
|
|
95
|
+
reportArgument: { kind: "free-text", placeholder: "story id", description: "The id of the story to open.", identifier: true },
|
|
96
96
|
name: "Story",
|
|
97
97
|
icon: "A",
|
|
98
98
|
component: NewsStoryPane,
|
|
@@ -7,6 +7,7 @@ import { usePaneInstance } from "../../../../../state/app/context";
|
|
|
7
7
|
import type { PaneProps, PaneTemplateCreateOptions, PaneTemplateDef } from "../../../../../types/plugin";
|
|
8
8
|
import { usePluginAppActions } from "../../../../runtime";
|
|
9
9
|
import { usePersistedNewsArticles } from "../persisted-articles";
|
|
10
|
+
import { storyIdMatches } from "../../../../../news/story-id";
|
|
10
11
|
import { NewsDetailView } from "./detail-view";
|
|
11
12
|
import { useNewsArticleFooter } from "./footer";
|
|
12
13
|
|
|
@@ -33,7 +34,11 @@ function handOffNewsStory(article: NewsArticle): void {
|
|
|
33
34
|
|
|
34
35
|
function handedOffStory(articleId: string): NewsArticle | null {
|
|
35
36
|
if (!articleId) return null;
|
|
36
|
-
|
|
37
|
+
const exact = handedOffStories.get(articleId);
|
|
38
|
+
if (exact) return exact;
|
|
39
|
+
// A pane opened by a short id (`fn news-story-pane 6067684e`) takes the story whose id starts with it.
|
|
40
|
+
for (const [id, article] of handedOffStories) if (storyIdMatches(id, articleId)) return article;
|
|
41
|
+
return null;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export const openNewsStoryPane = (
|
|
@@ -82,9 +87,10 @@ export function NewsStoryPane({ focused, width }: PaneProps) {
|
|
|
82
87
|
const [loaded, setLoaded] = useState<NewsArticle | null>(() => handedOffStory(articleId));
|
|
83
88
|
// The pane keeps a copy of its story, so a relaunch or a shared layout shows
|
|
84
89
|
// it at once, including a story from an RSS feed that cannot be fetched by id.
|
|
85
|
-
|
|
90
|
+
// A story opened by its short id (`fn news-story-pane 6067684e`) is the one whose id starts with it.
|
|
91
|
+
const story = useMemo(() => (loaded && storyIdMatches(loaded.id, articleId) ? [loaded] : NO_STORY), [articleId, loaded]);
|
|
86
92
|
const kept = usePersistedNewsArticles("story", story);
|
|
87
|
-
const article = kept.find((entry) => entry.id
|
|
93
|
+
const article = kept.find((entry) => storyIdMatches(entry.id, articleId)) ?? null;
|
|
88
94
|
const [loading, setLoading] = useState(false);
|
|
89
95
|
const [error, setError] = useState<string | null>(null);
|
|
90
96
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { notesPluginMeta } from "../builtin-plugin-meta";
|
|
1
2
|
import { apiClient } from "../../../api-client";
|
|
2
3
|
import type { GloomPlugin } from "../../../types/plugin";
|
|
3
4
|
import { teamStore } from "../../../team/store";
|
|
@@ -12,11 +13,7 @@ import { createNotesTab } from "./ticker-notes-tab";
|
|
|
12
13
|
let disposeNotes: (() => void) | null = null;
|
|
13
14
|
|
|
14
15
|
export const notesPlugin: GloomPlugin = {
|
|
15
|
-
|
|
16
|
-
name: "Notes",
|
|
17
|
-
version: "2.0.0",
|
|
18
|
-
description: "Markdown notes on tickers and on their own, personal or shared with a team.",
|
|
19
|
-
toggleable: true,
|
|
16
|
+
...notesPluginMeta,
|
|
20
17
|
cliCommands: [notesCliCommand],
|
|
21
18
|
|
|
22
19
|
setup(ctx) {
|
|
@@ -79,7 +76,7 @@ export const notesPlugin: GloomPlugin = {
|
|
|
79
76
|
|
|
80
77
|
ctx.registerPane({
|
|
81
78
|
id: "quick-notes",
|
|
82
|
-
reportFreshness: { source: "Your notes", status: "not-a-feed", basis: "your notes" },
|
|
79
|
+
reportFreshness: { source: "Your notes", status: "not-a-feed", basis: "your notes", local: true },
|
|
83
80
|
name: "Notes",
|
|
84
81
|
personalData: "messages",
|
|
85
82
|
icon: "N",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { GloomPlugin, PaneTemplateCreateOptions } from "../../../types/plugin";
|
|
2
|
-
import { OpenFdaPane } from "./pane";
|
|
3
2
|
import { OPENFDA_PANE_ID, OPENFDA_PLUGIN_ID } from "./types";
|
|
4
3
|
|
|
5
4
|
const createOpenFdaPaneInstance = (options?: PaneTemplateCreateOptions) => {
|
|
@@ -35,7 +34,7 @@ export const openFdaPlugin: GloomPlugin = {
|
|
|
35
34
|
reportFreshness: { source: "US FDA", status: "not-a-feed", basis: "published reports" },
|
|
36
35
|
name: "FDA Reports",
|
|
37
36
|
icon: "F",
|
|
38
|
-
component: OpenFdaPane,
|
|
37
|
+
get component(): typeof import("./pane").OpenFdaPane { const { OpenFdaPane } = require("./pane"); return OpenFdaPane; },
|
|
39
38
|
defaultPosition: "right",
|
|
40
39
|
defaultMode: "floating",
|
|
41
40
|
defaultFloatingSize: { width: 100, height: 30 },
|