gloomberb 0.12.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +1 -2
- package/src/api-client/auth.ts +2 -1
- package/src/api-client/index.test.ts +34 -0
- package/src/api-client/index.ts +10 -2
- package/src/api-client/request.ts +4 -1
- package/src/api-client/research-activity.ts +61 -0
- package/src/api-client/types.ts +2 -1
- package/src/cli/commands/plugins.ts +4 -3
- package/src/cli/desktop-pane-shot.ts +79 -10
- package/src/cli/pane-functions/capabilities.ts +76 -23
- package/src/cli/pane-functions/cloud-session.test.ts +54 -0
- package/src/cli/pane-functions/cloud-session.ts +38 -0
- package/src/cli/pane-functions/dom.test.ts +41 -0
- package/src/cli/pane-functions/dom.ts +199 -0
- package/src/cli/pane-functions/index.test.ts +13 -2
- package/src/cli/pane-functions/index.ts +9 -5
- package/src/cli/pane-functions/intraday-shot.test.ts +307 -0
- package/src/cli/pane-functions/intraday-shot.ts +334 -0
- package/src/cli/pane-functions/report.test.ts +29 -1
- package/src/cli/pane-functions/report.ts +68 -7
- package/src/cli/pane-functions/screenshot.ts +195 -42
- package/src/cli/restore-plugins.ts +10 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -1
- package/src/components/chart/composite/composite-chart.tsx +87 -21
- package/src/components/chart/composite/rasterizer.ts +33 -0
- package/src/components/chart/composite/renderers.test.ts +51 -4
- package/src/components/chart/composite/scene.test.ts +128 -2
- package/src/components/chart/composite/scene.ts +92 -16
- package/src/components/chart/composite/text-renderer.ts +13 -0
- package/src/components/chart/composite/time-scale.ts +30 -10
- package/src/components/chart/composite/types.ts +26 -0
- package/src/components/command-bar/assist/runtime.ts +38 -30
- package/src/components/command-bar/surface/assist.test.tsx +63 -9
- package/src/components/command-bar/surface/test-harness.tsx +23 -4
- package/src/components/onboarding/account-step/chooser-panel.tsx +2 -2
- package/src/components/onboarding/account-step/qr-panel.tsx +2 -10
- package/src/components/onboarding/onboarding-wizard.test.tsx +38 -12
- package/src/components/onboarding/onboarding-wizard.tsx +49 -14
- package/src/data/config/store/index.test.ts +23 -0
- package/src/data/config/store/node.ts +7 -1
- package/src/data/config/store/normalize.ts +4 -0
- package/src/news/types.ts +1 -0
- package/src/plugins/builtin/cds/client.test.ts +20 -0
- package/src/plugins/builtin/cds/client.ts +13 -3
- package/src/plugins/builtin/cds/headless.test.ts +30 -0
- package/src/plugins/builtin/cds/headless.ts +113 -0
- package/src/plugins/builtin/cds/index.tsx +4 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -1
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chat/controller/channels.ts +2 -1
- package/src/plugins/builtin/chat/controller/index.ts +13 -5
- package/src/plugins/builtin/chat/controller/realtime.ts +24 -0
- package/src/plugins/builtin/chat/controller/session-runtime.ts +76 -8
- package/src/plugins/builtin/chat/controller/state.ts +1 -0
- package/src/plugins/builtin/chat/controller.test.ts +260 -4
- package/src/plugins/builtin/cloud/askg/executor.test.ts +160 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +429 -0
- package/src/plugins/builtin/cloud/askg/manifest.test.ts +153 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +314 -0
- package/src/plugins/builtin/cloud/askg/protocol.test.ts +190 -0
- package/src/plugins/builtin/cloud/askg/protocol.ts +286 -0
- package/src/plugins/builtin/cloud/askg/undo.test.ts +44 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +277 -0
- package/src/plugins/builtin/cloud/askg/verify.ts +130 -0
- package/src/plugins/builtin/cloud/auth-dialog.tsx +7 -1
- package/src/plugins/builtin/cloud/device-signin-dialog.tsx +21 -8
- package/src/plugins/builtin/cloud/plugin.tsx +2 -0
- package/src/plugins/builtin/cloud/verification-panel.tsx +56 -0
- package/src/plugins/builtin/congress-trades/client.ts +11 -0
- package/src/plugins/builtin/congress-trades/detail.tsx +3 -3
- package/src/plugins/builtin/congress-trades/headless.test.ts +98 -0
- package/src/plugins/builtin/congress-trades/headless.ts +145 -0
- package/src/plugins/builtin/congress-trades/pane.tsx +3 -3
- package/src/plugins/builtin/credit-conditions/client.ts +1 -1
- package/src/plugins/builtin/credit-conditions/headless.test.ts +31 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +55 -0
- package/src/plugins/builtin/credit-conditions/index.tsx +4 -0
- package/src/plugins/builtin/dividend-yield/headless.test.ts +88 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +135 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +12 -8
- package/src/plugins/builtin/dividend-yield/model.ts +4 -22
- package/src/plugins/builtin/dividend-yield/view.ts +17 -0
- package/src/plugins/builtin/earnings/headless.test.ts +82 -0
- package/src/plugins/builtin/earnings/headless.ts +162 -0
- package/src/plugins/builtin/earnings/index.tsx +2 -0
- package/src/plugins/builtin/earnings-calls/data.ts +29 -8
- package/src/plugins/builtin/earnings-calls/headless.test.ts +192 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +300 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +19 -9
- package/src/plugins/builtin/earnings-calls/model.ts +238 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +4 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +13 -11
- package/src/plugins/builtin/fear-greed/headless.test.ts +53 -0
- package/src/plugins/builtin/fear-greed/headless.ts +84 -0
- package/src/plugins/builtin/fear-greed/index.tsx +4 -0
- package/src/plugins/builtin/holders/client.ts +29 -0
- package/src/plugins/builtin/holders/headless.test.ts +58 -0
- package/src/plugins/builtin/holders/headless.ts +162 -0
- package/src/plugins/builtin/holders/index.tsx +14 -8
- package/src/plugins/builtin/holders/pane.tsx +7 -1
- package/src/plugins/builtin/insider/client.ts +50 -0
- package/src/plugins/builtin/insider/headless.test.ts +122 -0
- package/src/plugins/builtin/insider/headless.ts +117 -0
- package/src/plugins/builtin/insider/index.tsx +21 -50
- package/src/plugins/builtin/insider/insider-data.ts +1 -1
- package/src/plugins/builtin/insider/model.ts +72 -0
- package/src/plugins/builtin/ipo-calendar/client.ts +15 -0
- package/src/plugins/builtin/ipo-calendar/headless.test.ts +89 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +127 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +2 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +3 -15
- package/src/plugins/builtin/market-movers/client.ts +76 -0
- package/src/plugins/builtin/market-movers/headless.test.ts +34 -0
- package/src/plugins/builtin/market-movers/headless.ts +73 -0
- package/src/plugins/builtin/market-movers/index.tsx +11 -51
- package/src/plugins/builtin/news/headless.test.ts +138 -0
- package/src/plugins/builtin/news/headless.ts +190 -0
- package/src/plugins/builtin/news/index.tsx +13 -9
- package/src/plugins/builtin/news/wire/index.tsx +2 -1
- package/src/plugins/builtin/research/analyst-headless.test.ts +60 -0
- package/src/plugins/builtin/research/analyst-headless.ts +172 -0
- package/src/plugins/builtin/research/analyst-model.ts +219 -0
- package/src/plugins/builtin/research/analyst-pane.tsx +31 -221
- package/src/plugins/builtin/research/client.ts +12 -0
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -237
- package/src/plugins/builtin/research/event-model.ts +245 -0
- package/src/plugins/builtin/research/events-headless.test.ts +32 -0
- package/src/plugins/builtin/research/events-headless.ts +87 -0
- package/src/plugins/builtin/research/headless.test.ts +93 -0
- package/src/plugins/builtin/research/headless.ts +161 -0
- package/src/plugins/builtin/research/index.tsx +32 -18
- package/src/plugins/builtin/research-search/pane.tsx +4 -0
- package/src/plugins/builtin/scanner/headless.test.ts +59 -0
- package/src/plugins/builtin/scanner/headless.ts +125 -0
- package/src/plugins/builtin/scanner/index.ts +4 -0
- package/src/plugins/builtin/sec/client.ts +16 -0
- package/src/plugins/builtin/sec/headless.test.ts +72 -0
- package/src/plugins/builtin/sec/headless.ts +69 -0
- package/src/plugins/builtin/sec/index.tsx +20 -75
- package/src/plugins/builtin/sec/model.ts +89 -0
- package/src/plugins/builtin/sectors/client.ts +54 -0
- package/src/plugins/builtin/sectors/headless.test.ts +28 -0
- package/src/plugins/builtin/sectors/headless.ts +80 -0
- package/src/plugins/builtin/sectors/index.tsx +6 -51
- package/src/plugins/builtin/shared/cloud-upgrade.ts +8 -4
- package/src/plugins/builtin/short-interest/client.ts +5 -2
- package/src/plugins/builtin/short-interest/headless.test.ts +96 -0
- package/src/plugins/builtin/short-interest/headless.ts +111 -0
- package/src/plugins/builtin/short-interest/index.tsx +15 -9
- package/src/plugins/builtin/thirteenf/data.ts +13 -11
- package/src/plugins/builtin/thirteenf/headless.test.ts +112 -0
- package/src/plugins/builtin/thirteenf/headless.ts +286 -0
- package/src/plugins/builtin/thirteenf/index.tsx +4 -0
- package/src/plugins/builtin/thirteenf/model.ts +13 -0
- package/src/plugins/builtin/thirteenf/table.ts +3 -15
- package/src/plugins/builtin/ticker-detail/pane.tsx +14 -0
- package/src/plugins/builtin/treasury-auctions/headless.test.ts +34 -0
- package/src/plugins/builtin/treasury-auctions/headless.ts +95 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +4 -0
- package/src/plugins/builtin/volatility/client.ts +16 -3
- package/src/plugins/builtin/volatility/headless.test.ts +35 -0
- package/src/plugins/builtin/volatility/headless.ts +75 -0
- package/src/plugins/builtin/volatility/index.tsx +4 -0
- package/src/plugins/builtin/world-indices/client.ts +43 -0
- package/src/plugins/builtin/world-indices/headless.test.ts +32 -0
- package/src/plugins/builtin/world-indices/headless.ts +109 -0
- package/src/plugins/builtin/world-indices/index.tsx +4 -0
- package/src/plugins/builtin/yield-curve/headless.test.ts +24 -0
- package/src/plugins/builtin/yield-curve/headless.ts +67 -0
- package/src/plugins/builtin/yield-curve/index.tsx +6 -8
- package/src/plugins/builtin/yield-curve/treasury-data.ts +16 -6
- package/src/plugins/bundle.test.ts +58 -1
- package/src/plugins/bundle.ts +4 -2
- package/src/plugins/catalog-backend.test.ts +26 -0
- package/src/plugins/catalog-backend.ts +9 -2
- package/src/plugins/catalog-browser.test.ts +0 -13
- package/src/plugins/catalog-browser.ts +4 -0
- package/src/plugins/catalog-manifest.test.ts +15 -0
- package/src/plugins/catalog-manifest.ts +12 -5
- package/src/plugins/catalog-ui.ts +0 -6
- package/src/plugins/host-contract.ts +9 -0
- package/src/plugins/host-modules.ts +12 -0
- package/src/plugins/loader.ts +63 -15
- package/src/plugins/prediction-markets/headless.test.ts +119 -0
- package/src/plugins/prediction-markets/headless.ts +255 -0
- package/src/plugins/prediction-markets/index.tsx +2 -0
- package/src/plugins/seed.ts +3 -0
- package/src/public/broker.ts +6 -0
- package/src/remote/schema.test.ts +65 -0
- package/src/remote/schema.ts +322 -39
- package/src/remote/types.ts +49 -2
- package/src/renderers/browser/app-services.ts +3 -0
- package/src/renderers/browser/config-host.ts +24 -8
- package/src/renderers/browser/deeplink-bridge.test.ts +11 -0
- package/src/renderers/browser/deeplink-bridge.ts +15 -3
- package/src/renderers/browser/main.tsx +3 -1
- package/src/renderers/browser/research-entry.test.ts +8 -0
- package/src/renderers/browser/research-entry.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +2 -2
- package/src/renderers/electrobun/bun/desktop/initialization.ts +10 -3
- package/src/renderers/electrobun/bun/external-plugins.ts +20 -4
- package/src/renderers/electrobun/view/build-assets.ts +0 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +63 -10
- package/src/sources/gloomberb-cloud/news.ts +1 -0
- package/src/sync/core-contributors.test.ts +111 -0
- package/src/sync/core-contributors.ts +155 -1
- package/src/time-series/resolve.test.ts +118 -1
- package/src/time-series/resolve.ts +14 -16
- package/src/types/config.ts +2 -0
- package/src/plugins/broker-sync/broker-sync.test.ts +0 -188
- package/src/plugins/broker-sync/native-loader.ts +0 -10
- package/src/plugins/broker-sync/normalize.ts +0 -308
- package/src/plugins/broker-sync/public.ts +0 -122
- package/src/plugins/broker-sync/robinhood-native.ts +0 -367
- package/src/plugins/broker-sync/robinhood.ts +0 -114
- package/src/plugins/broker-sync/simplefin-native.ts +0 -201
- package/src/plugins/broker-sync/simplefin.ts +0 -70
- package/src/renderers/electrobun/view/native-stubs/broker-sync-native-loader.ts +0 -7
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HeadlessPaneDefinition,
|
|
3
|
+
HeadlessPaneLoadArgs,
|
|
4
|
+
} from "../../../types/plugin";
|
|
5
|
+
import {
|
|
6
|
+
loadCreditConditions,
|
|
7
|
+
type CreditConditionsLoadResult,
|
|
8
|
+
type CreditSeriesLoader,
|
|
9
|
+
} from "./client";
|
|
10
|
+
|
|
11
|
+
const COLUMNS = [
|
|
12
|
+
{ key: "label", header: "Index" },
|
|
13
|
+
{ key: "seriesId", header: "FRED series" },
|
|
14
|
+
{ key: "oasBp", header: "OAS", align: "right" as const, format: (value: unknown) => `${Number(value).toFixed(1)}bp` },
|
|
15
|
+
{
|
|
16
|
+
key: "dailyChangeBp",
|
|
17
|
+
header: "1D",
|
|
18
|
+
align: "right" as const,
|
|
19
|
+
format: (value: unknown) => value == null ? "-" : `${Number(value) > 0 ? "+" : ""}${Number(value).toFixed(1)}bp`,
|
|
20
|
+
},
|
|
21
|
+
{ key: "date", header: "As of" },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export interface CreditConditionsHeadlessDependencies {
|
|
25
|
+
load(args: HeadlessPaneLoadArgs, loader: CreditSeriesLoader): Promise<CreditConditionsLoadResult>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const defaultDependencies: CreditConditionsHeadlessDependencies = {
|
|
29
|
+
load: (_args, loader) => loadCreditConditions(false, loader),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export function createCreditConditionsHeadless(
|
|
33
|
+
dependencies: CreditConditionsHeadlessDependencies = defaultDependencies,
|
|
34
|
+
): HeadlessPaneDefinition<"rows"> {
|
|
35
|
+
return {
|
|
36
|
+
shape: "rows",
|
|
37
|
+
argument: { kind: "none" },
|
|
38
|
+
options: [],
|
|
39
|
+
columns: COLUMNS,
|
|
40
|
+
describe: "Credit Spreads",
|
|
41
|
+
async load(args, ctx) {
|
|
42
|
+
const result = await dependencies.load(
|
|
43
|
+
args,
|
|
44
|
+
(seriesId, options) => ctx.apiClient.getCloudFredSeries(seriesId, options),
|
|
45
|
+
);
|
|
46
|
+
return {
|
|
47
|
+
rows: result.rows.map((row) => ({ ...row })),
|
|
48
|
+
errors: result.errors,
|
|
49
|
+
metadata: { stale: result.stale },
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const creditConditionsHeadless = createCreditConditionsHeadless();
|
|
@@ -16,12 +16,15 @@ import type { PaneProps } from "../../../types/plugin";
|
|
|
16
16
|
import { colors } from "../../../theme/colors";
|
|
17
17
|
import type { PluginModule } from "../plugin-module";
|
|
18
18
|
import { getCachedCreditConditions, loadCreditConditions } from "./client";
|
|
19
|
+
import { creditConditionsHeadless } from "./headless";
|
|
19
20
|
import {
|
|
20
21
|
CREDIT_SERIES,
|
|
21
22
|
type CreditConditionRow,
|
|
22
23
|
type CreditSeriesId,
|
|
23
24
|
} from "./model";
|
|
24
25
|
|
|
26
|
+
export { creditConditionsHeadless } from "./headless";
|
|
27
|
+
|
|
25
28
|
type SortId = "label" | "oas" | "change";
|
|
26
29
|
interface Column extends DataTableColumn { id: SortId }
|
|
27
30
|
|
|
@@ -204,5 +207,6 @@ export const creditConditionsModule: PluginModule = {
|
|
|
204
207
|
description: "ICE BofA US corporate option-adjusted spreads from FRED.",
|
|
205
208
|
keywords: ["credit", "spread", "oas", "corporate", "high yield", "investment grade", "macro"],
|
|
206
209
|
shortcut: { prefix: "CRD" },
|
|
210
|
+
headless: creditConditionsHeadless,
|
|
207
211
|
}],
|
|
208
212
|
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { HeadlessPaneContext, HeadlessPaneLoadArgs } from "../../../types/plugin";
|
|
3
|
+
import type { DividendData } from "./client";
|
|
4
|
+
import { createDividendYieldHeadless } from "./headless";
|
|
5
|
+
|
|
6
|
+
const fixture: DividendData = {
|
|
7
|
+
price: 200,
|
|
8
|
+
metrics: {
|
|
9
|
+
trailingYield: 0.005,
|
|
10
|
+
forwardYield: 0.0052,
|
|
11
|
+
trailingRate: 1,
|
|
12
|
+
forwardRate: 1.04,
|
|
13
|
+
payoutRatio: 0.14,
|
|
14
|
+
growth1Y: 0.04,
|
|
15
|
+
growth3Y: 0.03,
|
|
16
|
+
paymentFrequency: "quarterly",
|
|
17
|
+
exDividendDate: new Date("2026-08-10T00:00:00.000Z"),
|
|
18
|
+
nextPayDate: new Date("2026-08-17T00:00:00.000Z"),
|
|
19
|
+
},
|
|
20
|
+
payments: [
|
|
21
|
+
{
|
|
22
|
+
exDate: new Date("2026-08-10T00:00:00.000Z"),
|
|
23
|
+
recordDate: null,
|
|
24
|
+
paymentDate: null,
|
|
25
|
+
declarationDate: null,
|
|
26
|
+
amount: 0.26,
|
|
27
|
+
currency: "USD",
|
|
28
|
+
type: "cash",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
exDate: new Date("2026-05-11T00:00:00.000Z"),
|
|
32
|
+
recordDate: null,
|
|
33
|
+
paymentDate: null,
|
|
34
|
+
declarationDate: null,
|
|
35
|
+
amount: 0.24,
|
|
36
|
+
currency: "USD",
|
|
37
|
+
type: "special",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function args(options: Record<string, string | number | boolean>): HeadlessPaneLoadArgs {
|
|
43
|
+
return {
|
|
44
|
+
rawArgument: "AAPL",
|
|
45
|
+
argument: "AAPL",
|
|
46
|
+
symbols: ["AAPL"],
|
|
47
|
+
options,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const context = {} as HeadlessPaneContext;
|
|
52
|
+
|
|
53
|
+
describe("dividend yield headless", () => {
|
|
54
|
+
test("maps metrics and payment rows", async () => {
|
|
55
|
+
const definition = createDividendYieldHeadless({
|
|
56
|
+
loadData: async () => fixture,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const result = await definition.load(args({ type: "all", limit: 40 }), context);
|
|
60
|
+
|
|
61
|
+
expect(result.sections[0]).toMatchObject({
|
|
62
|
+
title: "Dividend metrics",
|
|
63
|
+
entries: expect.arrayContaining([
|
|
64
|
+
{ label: "Trailing yield", value: 0.005 },
|
|
65
|
+
{ label: "Frequency", value: "quarterly" },
|
|
66
|
+
]),
|
|
67
|
+
});
|
|
68
|
+
expect(result.sections[1]).toMatchObject({
|
|
69
|
+
title: "Dividend history",
|
|
70
|
+
rows: [
|
|
71
|
+
expect.objectContaining({ exDate: "2026-08-10", amount: 0.26, type: "cash" }),
|
|
72
|
+
expect.objectContaining({ exDate: "2026-05-11", amount: 0.24, type: "special" }),
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("applies type and limit options", async () => {
|
|
78
|
+
const definition = createDividendYieldHeadless({ loadData: async () => fixture });
|
|
79
|
+
|
|
80
|
+
const result = await definition.load(args({ type: "cash", limit: 1 }), context);
|
|
81
|
+
const history = result.sections[1];
|
|
82
|
+
|
|
83
|
+
expect(history).toMatchObject({
|
|
84
|
+
rows: [expect.objectContaining({ type: "cash" })],
|
|
85
|
+
});
|
|
86
|
+
expect(result.metadata).toMatchObject({ totalPayments: 1, returnedPayments: 1 });
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HeadlessBundleResult,
|
|
3
|
+
HeadlessPaneContext,
|
|
4
|
+
HeadlessPaneDefinition,
|
|
5
|
+
HeadlessPaneLoadArgs,
|
|
6
|
+
} from "../../../types/plugin";
|
|
7
|
+
import { fetchDividendData, type DividendData } from "./client";
|
|
8
|
+
import type { DividendPayment } from "./types";
|
|
9
|
+
import { toDividendRows } from "./view";
|
|
10
|
+
|
|
11
|
+
const PAYMENT_COLUMNS = [
|
|
12
|
+
{ key: "exDate", header: "Ex-date" },
|
|
13
|
+
{ key: "amount", header: "Amount", align: "right" as const },
|
|
14
|
+
{ key: "currency", header: "CCY" },
|
|
15
|
+
{ key: "type", header: "Type" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export interface DividendYieldHeadlessDependencies {
|
|
19
|
+
loadData(symbol: string, context: HeadlessPaneContext): Promise<DividendData>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const defaultDependencies: DividendYieldHeadlessDependencies = {
|
|
23
|
+
async loadData(symbol, context) {
|
|
24
|
+
let currentPrice: number | null = null;
|
|
25
|
+
try {
|
|
26
|
+
currentPrice = (await context.marketData.getQuote(symbol, "")).price ?? null;
|
|
27
|
+
} catch {
|
|
28
|
+
currentPrice = null;
|
|
29
|
+
}
|
|
30
|
+
return fetchDividendData(symbol, currentPrice);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function matchesType(payment: DividendPayment, type: string): boolean {
|
|
35
|
+
return type === "all" || payment.type === type;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function projectDividendYieldHeadless(
|
|
39
|
+
data: DividendData,
|
|
40
|
+
args: HeadlessPaneLoadArgs,
|
|
41
|
+
): HeadlessBundleResult {
|
|
42
|
+
const type = String(args.options.type ?? "all");
|
|
43
|
+
const limit = Number(args.options.limit ?? 40);
|
|
44
|
+
const matching = data.payments.filter((payment) => matchesType(payment, type));
|
|
45
|
+
const selectedPayments = matching.slice(0, limit);
|
|
46
|
+
const rows = toDividendRows(selectedPayments).map((row, index) => {
|
|
47
|
+
const payment = selectedPayments[index];
|
|
48
|
+
return {
|
|
49
|
+
...row,
|
|
50
|
+
recordDate: payment?.recordDate?.toISOString() ?? null,
|
|
51
|
+
paymentDate: payment?.paymentDate?.toISOString() ?? null,
|
|
52
|
+
declarationDate: payment?.declarationDate?.toISOString() ?? null,
|
|
53
|
+
type: payment?.type ?? null,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
const metrics = data.metrics;
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
sections: [
|
|
60
|
+
{
|
|
61
|
+
title: "Dividend metrics",
|
|
62
|
+
entries: [
|
|
63
|
+
{ label: "Price", value: data.price },
|
|
64
|
+
{ label: "Trailing yield", value: metrics.trailingYield },
|
|
65
|
+
{ label: "Forward yield", value: metrics.forwardYield },
|
|
66
|
+
{ label: "Trailing rate", value: metrics.trailingRate },
|
|
67
|
+
{ label: "Forward rate", value: metrics.forwardRate },
|
|
68
|
+
{ label: "Payout ratio", value: metrics.payoutRatio },
|
|
69
|
+
{ label: "1Y growth", value: metrics.growth1Y },
|
|
70
|
+
{ label: "3Y growth", value: metrics.growth3Y },
|
|
71
|
+
{ label: "Frequency", value: metrics.paymentFrequency },
|
|
72
|
+
{ label: "Ex-dividend", value: metrics.exDividendDate },
|
|
73
|
+
{ label: "Next pay", value: metrics.nextPayDate },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: "Dividend history",
|
|
78
|
+
columns: PAYMENT_COLUMNS,
|
|
79
|
+
rows,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
metadata: {
|
|
83
|
+
totalPayments: matching.length,
|
|
84
|
+
returnedPayments: rows.length,
|
|
85
|
+
truncated: rows.length < matching.length,
|
|
86
|
+
type,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function createDividendYieldHeadless(
|
|
92
|
+
dependencies: DividendYieldHeadlessDependencies = defaultDependencies,
|
|
93
|
+
): HeadlessPaneDefinition<"bundle"> {
|
|
94
|
+
return {
|
|
95
|
+
shape: "bundle",
|
|
96
|
+
argument: {
|
|
97
|
+
kind: "ticker",
|
|
98
|
+
placeholder: "ticker",
|
|
99
|
+
description: "Company symbol.",
|
|
100
|
+
},
|
|
101
|
+
options: [
|
|
102
|
+
{
|
|
103
|
+
key: "type",
|
|
104
|
+
description: "Dividend payment type to include.",
|
|
105
|
+
type: "enum",
|
|
106
|
+
values: [
|
|
107
|
+
{ value: "all" },
|
|
108
|
+
{ value: "cash" },
|
|
109
|
+
{ value: "special" },
|
|
110
|
+
{ value: "stock" },
|
|
111
|
+
{ value: "unknown" },
|
|
112
|
+
],
|
|
113
|
+
defaultValue: "all",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
key: "limit",
|
|
117
|
+
description: "Maximum historical payments to return.",
|
|
118
|
+
type: "integer",
|
|
119
|
+
defaultValue: 40,
|
|
120
|
+
minimum: 1,
|
|
121
|
+
maximum: 200,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
describe: (args) => `Dividend Yield | ${String(args.argument)}`,
|
|
125
|
+
async load(args, context) {
|
|
126
|
+
const symbol = String(args.argument);
|
|
127
|
+
return projectDividendYieldHeadless(
|
|
128
|
+
await dependencies.loadData(symbol, context),
|
|
129
|
+
args,
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const dividendYieldHeadless = createDividendYieldHeadless();
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
YAHOO_DIVIDENDS_CONNECTION_ID,
|
|
7
7
|
} from "./client";
|
|
8
8
|
import { DividendYieldPane } from "./pane";
|
|
9
|
+
import { dividendYieldHeadless } from "./headless";
|
|
9
10
|
|
|
10
11
|
let disposeConnection: (() => void) | null = null;
|
|
11
12
|
|
|
@@ -50,13 +51,16 @@ export const dividendYieldModule: PluginModule = {
|
|
|
50
51
|
],
|
|
51
52
|
|
|
52
53
|
paneTemplates: [
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
{
|
|
55
|
+
...createTickerSurfacePaneTemplate({
|
|
56
|
+
id: "dividend-yield-pane",
|
|
57
|
+
paneId: "dividend-yield",
|
|
58
|
+
label: "Dividend Yield",
|
|
59
|
+
description: "Dividend history, trailing/forward yield, growth rates, and payment schedule.",
|
|
60
|
+
keywords: ["dividend", "yield", "dvd", "income", "payout", "ex-date", "distribution"],
|
|
61
|
+
shortcut: "DVD",
|
|
62
|
+
}),
|
|
63
|
+
headless: dividendYieldHeadless,
|
|
64
|
+
},
|
|
61
65
|
],
|
|
62
66
|
};
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type { DataTableColumn } from "../../../components";
|
|
2
2
|
import { compareSortValues, type SortDirection } from "../../../utils/sort-values";
|
|
3
|
-
import type {
|
|
3
|
+
import type { DividendRow } from "./view";
|
|
4
|
+
|
|
5
|
+
export { toDividendRows } from "./view";
|
|
6
|
+
export type { DividendRow } from "./view";
|
|
4
7
|
|
|
5
8
|
export type DividendColumnId = "exDate" | "amount" | "currency";
|
|
6
9
|
export type DividendColumn = DataTableColumn & { id: DividendColumnId };
|
|
7
10
|
|
|
8
|
-
export interface DividendRow {
|
|
9
|
-
key: string;
|
|
10
|
-
exDate: string;
|
|
11
|
-
amount: number;
|
|
12
|
-
currency: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
export interface DividendSortPreference {
|
|
16
12
|
columnId: DividendColumnId | null;
|
|
17
13
|
direction: SortDirection;
|
|
@@ -67,17 +63,3 @@ export function nextSortPreference(
|
|
|
67
63
|
}
|
|
68
64
|
return DEFAULT_SORT_PREFERENCE;
|
|
69
65
|
}
|
|
70
|
-
|
|
71
|
-
export function toDividendRows(payments: DividendPayment[]): DividendRow[] {
|
|
72
|
-
return payments.map((p, i) => ({
|
|
73
|
-
key: `${p.exDate.toISOString()}:${i}`,
|
|
74
|
-
exDate: formatDate(p.exDate),
|
|
75
|
-
amount: p.amount,
|
|
76
|
-
currency: p.currency,
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function formatDate(date: Date): string {
|
|
81
|
-
const iso = date.toISOString();
|
|
82
|
-
return iso.slice(0, 10);
|
|
83
|
-
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DividendPayment } from "./types";
|
|
2
|
+
|
|
3
|
+
export interface DividendRow {
|
|
4
|
+
key: string;
|
|
5
|
+
exDate: string;
|
|
6
|
+
amount: number;
|
|
7
|
+
currency: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function toDividendRows(payments: DividendPayment[]): DividendRow[] {
|
|
11
|
+
return payments.map((payment, index) => ({
|
|
12
|
+
key: `${payment.exDate.toISOString()}:${index}`,
|
|
13
|
+
exDate: payment.exDate.toISOString().slice(0, 10),
|
|
14
|
+
amount: payment.amount,
|
|
15
|
+
currency: payment.currency,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { EarningsEvent } from "../../../types/data-provider";
|
|
3
|
+
import type { HeadlessPaneContext, HeadlessPaneLoadArgs } from "../../../types/plugin";
|
|
4
|
+
import { createEarningsCalendarHeadless } from "./headless";
|
|
5
|
+
|
|
6
|
+
const events: EarningsEvent[] = [
|
|
7
|
+
{
|
|
8
|
+
symbol: "MSFT",
|
|
9
|
+
name: "Microsoft",
|
|
10
|
+
earningsDate: new Date("2026-09-08T20:00:00.000Z"),
|
|
11
|
+
earningsCallDate: new Date("2026-09-08T21:00:00.000Z"),
|
|
12
|
+
isDateEstimate: false,
|
|
13
|
+
epsEstimate: 3.67,
|
|
14
|
+
epsLow: 3.5,
|
|
15
|
+
epsHigh: 3.8,
|
|
16
|
+
epsGrowth: 0.12,
|
|
17
|
+
epsTrend30dAgo: 3.55,
|
|
18
|
+
epsRevisionUp30d: 8,
|
|
19
|
+
epsRevisionDown30d: 2,
|
|
20
|
+
epsActual: null,
|
|
21
|
+
revenueEstimate: 74_000_000_000,
|
|
22
|
+
revenueLow: 72_000_000_000,
|
|
23
|
+
revenueHigh: 76_000_000_000,
|
|
24
|
+
revenueGrowth: 0.16,
|
|
25
|
+
revenueActual: null,
|
|
26
|
+
surprise: null,
|
|
27
|
+
timing: "AMC",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
symbol: "AAPL",
|
|
31
|
+
name: "Apple",
|
|
32
|
+
earningsDate: new Date("2026-09-07T12:00:00.000Z"),
|
|
33
|
+
epsEstimate: 1.5,
|
|
34
|
+
epsActual: null,
|
|
35
|
+
revenueEstimate: 95_000_000_000,
|
|
36
|
+
revenueActual: null,
|
|
37
|
+
surprise: null,
|
|
38
|
+
timing: "BMO",
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
function args(options: Record<string, string | number | boolean>): HeadlessPaneLoadArgs {
|
|
43
|
+
return {
|
|
44
|
+
rawArgument: "AAPL,MSFT",
|
|
45
|
+
argument: ["AAPL", "MSFT"],
|
|
46
|
+
symbols: ["AAPL", "MSFT"],
|
|
47
|
+
options,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const context = {} as HeadlessPaneContext;
|
|
52
|
+
|
|
53
|
+
describe("earnings calendar headless", () => {
|
|
54
|
+
test("maps provider events into date-ordered rows", async () => {
|
|
55
|
+
const definition = createEarningsCalendarHeadless({
|
|
56
|
+
loadCalendar: async () => ({ events, fetchedAt: 123, stale: false }),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const result = await definition.load(args({ timing: "all", limit: 50 }), context);
|
|
60
|
+
|
|
61
|
+
expect(result.rows.map((row) => row.symbol)).toEqual(["AAPL", "MSFT"]);
|
|
62
|
+
expect(result.rows[1]).toMatchObject({
|
|
63
|
+
date: "2026-09-08T20:00:00.000Z",
|
|
64
|
+
timing: "AMC",
|
|
65
|
+
dateStatus: "confirmed",
|
|
66
|
+
epsEstimate: 3.67,
|
|
67
|
+
revenueEstimate: 74_000_000_000,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("applies timing and limit options", async () => {
|
|
72
|
+
const definition = createEarningsCalendarHeadless({
|
|
73
|
+
loadCalendar: async () => ({ events, fetchedAt: 123, stale: false }),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const result = await definition.load(args({ timing: "AMC", limit: 1 }), context);
|
|
77
|
+
|
|
78
|
+
expect(result.rows).toHaveLength(1);
|
|
79
|
+
expect(result.rows[0]?.symbol).toBe("MSFT");
|
|
80
|
+
expect(result.metadata).toMatchObject({ timing: "AMC", returned: 1 });
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { EarningsEvent } from "../../../types/data-provider";
|
|
2
|
+
import type {
|
|
3
|
+
HeadlessPaneContext,
|
|
4
|
+
HeadlessPaneDefinition,
|
|
5
|
+
HeadlessPaneLoadArgs,
|
|
6
|
+
HeadlessRowsResult,
|
|
7
|
+
} from "../../../types/plugin";
|
|
8
|
+
import {
|
|
9
|
+
loadEarningsCalendar,
|
|
10
|
+
type EarningsCalendarResult,
|
|
11
|
+
} from "./data/cache";
|
|
12
|
+
|
|
13
|
+
const EARNINGS_COLUMNS = [
|
|
14
|
+
{ key: "date", header: "Date" },
|
|
15
|
+
{ key: "timing", header: "When" },
|
|
16
|
+
{ key: "dateStatus", header: "Status" },
|
|
17
|
+
{ key: "symbol", header: "Ticker" },
|
|
18
|
+
{ key: "name", header: "Name" },
|
|
19
|
+
{ key: "epsEstimate", header: "EPS est", align: "right" as const },
|
|
20
|
+
{ key: "epsLow", header: "EPS low", align: "right" as const },
|
|
21
|
+
{ key: "epsHigh", header: "EPS high", align: "right" as const },
|
|
22
|
+
{ key: "epsGrowth", header: "EPS growth", align: "right" as const },
|
|
23
|
+
{ key: "epsTrend30dAgo", header: "EPS 30D ago", align: "right" as const },
|
|
24
|
+
{ key: "epsRevisionUp30d", header: "Rev up", align: "right" as const },
|
|
25
|
+
{ key: "epsRevisionDown30d", header: "Rev down", align: "right" as const },
|
|
26
|
+
{ key: "revenueEstimate", header: "Sales est", align: "right" as const },
|
|
27
|
+
{ key: "revenueLow", header: "Sales low", align: "right" as const },
|
|
28
|
+
{ key: "revenueHigh", header: "Sales high", align: "right" as const },
|
|
29
|
+
{ key: "revenueGrowth", header: "Sales growth", align: "right" as const },
|
|
30
|
+
{ key: "epsAnalysts", header: "EPS analysts", align: "right" as const },
|
|
31
|
+
{ key: "revenueAnalysts", header: "Sales analysts", align: "right" as const },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export interface EarningsCalendarHeadlessDependencies {
|
|
35
|
+
loadCalendar(
|
|
36
|
+
symbols: string[],
|
|
37
|
+
context: HeadlessPaneContext,
|
|
38
|
+
): Promise<EarningsCalendarResult>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const defaultDependencies: EarningsCalendarHeadlessDependencies = {
|
|
42
|
+
loadCalendar: (symbols, context) => loadEarningsCalendar(context.marketData, symbols),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function timingMatches(event: EarningsEvent, timing: string): boolean {
|
|
46
|
+
if (timing === "all") return true;
|
|
47
|
+
if (timing === "unknown") return !event.timing;
|
|
48
|
+
return event.timing?.toUpperCase() === timing;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function eventRow(event: EarningsEvent) {
|
|
52
|
+
return {
|
|
53
|
+
date: event.earningsDate.toISOString(),
|
|
54
|
+
earningsCallDate: event.earningsCallDate?.toISOString() ?? null,
|
|
55
|
+
timing: event.timing || null,
|
|
56
|
+
dateStatus: event.isDateEstimate == null
|
|
57
|
+
? null
|
|
58
|
+
: event.isDateEstimate
|
|
59
|
+
? "estimated"
|
|
60
|
+
: "confirmed",
|
|
61
|
+
symbol: event.symbol,
|
|
62
|
+
name: event.name,
|
|
63
|
+
epsEstimate: event.epsEstimate ?? null,
|
|
64
|
+
epsLow: event.epsLow ?? null,
|
|
65
|
+
epsHigh: event.epsHigh ?? null,
|
|
66
|
+
epsYearAgo: event.epsYearAgo ?? null,
|
|
67
|
+
epsGrowth: event.epsGrowth ?? null,
|
|
68
|
+
epsAnalysts: event.epsAnalysts ?? null,
|
|
69
|
+
epsTrend7dAgo: event.epsTrend7dAgo ?? null,
|
|
70
|
+
epsTrend30dAgo: event.epsTrend30dAgo ?? null,
|
|
71
|
+
epsRevisionUp7d: event.epsRevisionUp7d ?? null,
|
|
72
|
+
epsRevisionUp30d: event.epsRevisionUp30d ?? null,
|
|
73
|
+
epsRevisionDown7d: event.epsRevisionDown7d ?? null,
|
|
74
|
+
epsRevisionDown30d: event.epsRevisionDown30d ?? null,
|
|
75
|
+
epsActual: event.epsActual ?? null,
|
|
76
|
+
revenueEstimate: event.revenueEstimate ?? null,
|
|
77
|
+
revenueLow: event.revenueLow ?? null,
|
|
78
|
+
revenueHigh: event.revenueHigh ?? null,
|
|
79
|
+
revenueYearAgo: event.revenueYearAgo ?? null,
|
|
80
|
+
revenueGrowth: event.revenueGrowth ?? null,
|
|
81
|
+
revenueAnalysts: event.revenueAnalysts ?? null,
|
|
82
|
+
revenueActual: event.revenueActual ?? null,
|
|
83
|
+
surprise: event.surprise ?? null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function projectEarningsCalendarHeadless(
|
|
88
|
+
result: EarningsCalendarResult,
|
|
89
|
+
args: HeadlessPaneLoadArgs,
|
|
90
|
+
): HeadlessRowsResult {
|
|
91
|
+
const timing = String(args.options.timing ?? "all").toUpperCase();
|
|
92
|
+
const normalizedTiming = timing === "ALL" || timing === "UNKNOWN"
|
|
93
|
+
? timing.toLowerCase()
|
|
94
|
+
: timing;
|
|
95
|
+
const limit = Number(args.options.limit ?? 50);
|
|
96
|
+
const matching = result.events
|
|
97
|
+
.filter((event) => timingMatches(event, normalizedTiming))
|
|
98
|
+
.sort((left, right) => left.earningsDate.getTime() - right.earningsDate.getTime());
|
|
99
|
+
const rows = matching.slice(0, limit).map(eventRow);
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
columns: EARNINGS_COLUMNS,
|
|
103
|
+
rows,
|
|
104
|
+
errors: result.refreshError ? [result.refreshError] : undefined,
|
|
105
|
+
metadata: {
|
|
106
|
+
fetchedAt: result.fetchedAt,
|
|
107
|
+
stale: result.stale,
|
|
108
|
+
timing: normalizedTiming,
|
|
109
|
+
total: matching.length,
|
|
110
|
+
returned: rows.length,
|
|
111
|
+
truncated: rows.length < matching.length,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function createEarningsCalendarHeadless(
|
|
117
|
+
dependencies: EarningsCalendarHeadlessDependencies = defaultDependencies,
|
|
118
|
+
): HeadlessPaneDefinition<"rows"> {
|
|
119
|
+
return {
|
|
120
|
+
shape: "rows",
|
|
121
|
+
argument: {
|
|
122
|
+
kind: "symbol-list",
|
|
123
|
+
placeholder: "tickers",
|
|
124
|
+
description: "Comma-separated company symbols.",
|
|
125
|
+
minimum: 1,
|
|
126
|
+
maximum: 100,
|
|
127
|
+
},
|
|
128
|
+
options: [
|
|
129
|
+
{
|
|
130
|
+
key: "timing",
|
|
131
|
+
description: "Release timing to include.",
|
|
132
|
+
type: "enum",
|
|
133
|
+
values: [
|
|
134
|
+
{ value: "all" },
|
|
135
|
+
{ value: "BMO" },
|
|
136
|
+
{ value: "AMC" },
|
|
137
|
+
{ value: "TNS" },
|
|
138
|
+
{ value: "unknown" },
|
|
139
|
+
],
|
|
140
|
+
defaultValue: "all",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: "limit",
|
|
144
|
+
description: "Maximum earnings rows to return.",
|
|
145
|
+
type: "integer",
|
|
146
|
+
defaultValue: 50,
|
|
147
|
+
minimum: 1,
|
|
148
|
+
maximum: 200,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
columns: EARNINGS_COLUMNS,
|
|
152
|
+
describe: (args) => `Earnings Calendar | ${args.symbols.join(", ")}`,
|
|
153
|
+
async load(args, context) {
|
|
154
|
+
return projectEarningsCalendarHeadless(
|
|
155
|
+
await dependencies.loadCalendar(args.symbols, context),
|
|
156
|
+
args,
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const earningsCalendarHeadless = createEarningsCalendarHeadless();
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type EarningsDisplayRow,
|
|
24
24
|
type EarningsEventDisplayRow,
|
|
25
25
|
} from "./model";
|
|
26
|
+
import { earningsCalendarHeadless } from "./headless";
|
|
26
27
|
import {
|
|
27
28
|
buildEarningsColumns,
|
|
28
29
|
renderEarningsCell,
|
|
@@ -266,6 +267,7 @@ export const earningsModule: PluginModule = {
|
|
|
266
267
|
description: "Upcoming earnings dates and estimates for your tickers.",
|
|
267
268
|
keywords: ["earn", "earnings", "calendar", "eps", "revenue", "quarterly"],
|
|
268
269
|
shortcut: { prefix: "ERN" },
|
|
270
|
+
headless: earningsCalendarHeadless,
|
|
269
271
|
createInstance: (context) => ({
|
|
270
272
|
settings: context.activeCollectionId
|
|
271
273
|
? { collectionId: context.activeCollectionId }
|