gloomberb 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -54
- package/package.json +14 -13
- package/patches/{@opentui%2Fcore@0.1.90.patch → @opentui%2Fcore@0.3.2.patch} +175 -90
- package/src/api-client/chat.ts +8 -0
- package/src/api-client/index.test.ts +30 -0
- package/src/api-client/index.ts +4 -0
- package/src/api-client/normalizers.ts +1 -0
- package/src/api-client/types.ts +1 -0
- package/src/app/global-shortcuts.test.tsx +54 -4
- package/src/app/global-shortcuts.ts +11 -5
- package/src/capabilities/factories.ts +4 -0
- package/src/components/chart/comparison/data.test.ts +54 -0
- package/src/components/chart/comparison/data.ts +47 -24
- package/src/components/chart/core/projection.ts +51 -27
- package/src/components/command-bar/action-runtime.ts +1 -0
- package/src/components/command-bar/layout-items/current-layout.test.ts +115 -0
- package/src/components/command-bar/layout-items/current-layout.ts +33 -0
- package/src/components/command-bar/list/view.tsx +3 -1
- package/src/components/command-bar/pane-templates/items.ts +4 -1
- package/src/components/command-bar/panel/body.tsx +1 -0
- package/src/components/command-bar/routes/root/results.ts +0 -30
- package/src/components/command-bar/routes/root/runtime.ts +2 -20
- package/src/components/command-bar/routes/ticker-search/actions.ts +42 -4
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -1
- package/src/components/command-bar/routing/launch-request.ts +14 -7
- package/src/components/command-bar/routing/list-state.ts +1 -3
- package/src/components/command-bar/surface/index.test.tsx +76 -4
- package/src/components/command-bar/surface/index.tsx +0 -2
- package/src/components/command-bar/surface/pane.test.tsx +1 -0
- package/src/components/command-bar/surface/test-harness.tsx +1 -0
- package/src/components/command-bar/view-model.ts +3 -3
- package/src/components/data-table/stack-view.test.tsx +14 -11
- package/src/components/data-table/stack-view.tsx +1 -2
- package/src/components/data-table/view.test.tsx +24 -18
- package/src/components/data-table/view.tsx +313 -83
- package/src/components/feed-data-table/stack-view.tsx +6 -8
- package/src/components/layout/pane/footer/index.test.tsx +6 -0
- package/src/components/layout/pane/footer/index.tsx +14 -2
- package/src/components/layout/pane/title.ts +5 -1
- package/src/components/layout/shell/index.test.tsx +120 -2
- package/src/components/layout/shell/index.tsx +2 -0
- package/src/components/layout/shell/menu.ts +1 -7
- package/src/components/layout/shell/pane/actions.ts +8 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +12 -2
- package/src/components/layout/shell/shortcuts.ts +14 -6
- package/src/components/layout/shell/window-mode/index.ts +8 -3
- package/src/components/layout/window-edit/presentation.ts +4 -4
- package/src/components/onboarding/onboarding-steps.tsx +3 -2
- package/src/components/pane-settings-dialog/field-dialogs.tsx +0 -2
- package/src/components/pane-settings-dialog/tui.tsx +1 -1
- package/src/components/ticker/list-table-view.tsx +17 -25
- package/src/components/ui/choice-dialog.tsx +12 -2
- package/src/components/ui/multi-select/dialog.tsx +17 -5
- package/src/components/ui/remote-image.tsx +1 -14
- package/src/components/ui/shortcut-hint.tsx +14 -2
- package/src/components/ui/table-layout.test.ts +2 -2
- package/src/components/ui/table-layout.ts +8 -2
- package/src/components/ui/tabs.tsx +115 -86
- package/src/components/ui/ui.test.tsx +83 -4
- package/src/core/state/app/types.ts +12 -4
- package/src/market-data/coordinator/auxiliary.ts +29 -1
- package/src/market-data/coordinator/index.ts +17 -1
- package/src/market-data/hooks.tsx +17 -1
- package/src/market-data/selectors.ts +4 -0
- package/src/plugins/builtin/account-management/form-components.tsx +0 -4
- package/src/plugins/builtin/account-management/model.test.ts +54 -0
- package/src/plugins/builtin/account-management/model.ts +13 -3
- package/src/plugins/builtin/account-management/pane.tsx +5 -11
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/pane.tsx +5 -3
- package/src/plugins/builtin/analytics/index.tsx +0 -3
- package/src/plugins/builtin/analytics/view.tsx +6 -5
- package/src/plugins/builtin/broker-manager/index.tsx +6 -6
- package/src/plugins/builtin/buildout/pane/index.tsx +6 -6
- package/src/plugins/builtin/changelog/index.tsx +40 -27
- package/src/plugins/builtin/changelog/model.test.ts +77 -0
- package/src/plugins/builtin/changelog/model.ts +98 -0
- package/src/plugins/builtin/chat/channel-labels.ts +53 -0
- package/src/plugins/builtin/chat/channels.test.ts +28 -0
- package/src/plugins/builtin/chat/channels.ts +36 -19
- package/src/plugins/builtin/chat/chat.test.tsx +264 -5
- package/src/plugins/builtin/chat/content/channel-navigation.ts +50 -11
- package/src/plugins/builtin/chat/content/composer-runtime.test.tsx +144 -0
- package/src/plugins/builtin/chat/content/composer-runtime.ts +151 -20
- package/src/plugins/builtin/chat/content/composer.tsx +23 -2
- package/src/plugins/builtin/chat/content/index.tsx +66 -4
- package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +27 -1
- package/src/plugins/builtin/chat/content/transcript.tsx +8 -0
- package/src/plugins/builtin/chat/content/types.ts +1 -0
- package/src/plugins/builtin/chat/controller/index.ts +41 -0
- package/src/plugins/builtin/chat/controller/messages.ts +18 -0
- package/src/plugins/builtin/chat/controller/notifications.ts +10 -4
- package/src/plugins/builtin/chat/controller/utils.ts +6 -3
- package/src/plugins/builtin/chat/controller/view.ts +1 -1
- package/src/plugins/builtin/chat/controller.test.ts +189 -0
- package/src/plugins/builtin/chat/edit-window.ts +24 -0
- package/src/plugins/builtin/chat/layout.ts +94 -31
- package/src/plugins/builtin/chat/message/action-chip.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +53 -20
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +16 -10
- package/src/plugins/builtin/chat/message/render-state.ts +5 -1
- package/src/plugins/builtin/chat/message/terminal.tsx +49 -20
- package/src/plugins/builtin/chat/message/types.ts +2 -0
- package/src/plugins/builtin/chat/pane.tsx +35 -7
- package/src/plugins/builtin/chat/sidebar.test.tsx +72 -0
- package/src/plugins/builtin/chat/status-widget.tsx +29 -11
- package/src/plugins/builtin/chat/test-harness.tsx +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +3 -0
- package/src/plugins/builtin/cloud-tweets/table.tsx +7 -11
- package/src/plugins/builtin/congress-trades/pane.tsx +14 -22
- package/src/plugins/builtin/earnings/index.tsx +8 -7
- package/src/plugins/builtin/econ/index.tsx +6 -8
- package/src/plugins/builtin/help/components.tsx +1 -1
- package/src/plugins/builtin/help/index.test.tsx +105 -30
- package/src/plugins/builtin/help/index.tsx +326 -164
- package/src/plugins/builtin/help/shortcut-model.ts +5 -6
- package/src/plugins/builtin/holders/pane.tsx +7 -6
- package/src/plugins/builtin/market-movers/index.tsx +6 -3
- package/src/plugins/builtin/news/wire/news/table.tsx +7 -6
- package/src/plugins/builtin/options/view.tsx +16 -8
- package/src/plugins/builtin/portfolio-list/column-values.ts +304 -1
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +93 -0
- package/src/plugins/builtin/portfolio-list/pane/data.ts +7 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +25 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +281 -0
- package/src/plugins/builtin/portfolio-list/settings.ts +27 -0
- package/src/plugins/builtin/portfolio-list/table.tsx +4 -2
- package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +10 -68
- package/src/plugins/builtin/research/analyst-pane.tsx +1 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +358 -7
- package/src/plugins/builtin/research/index.test.ts +30 -1
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +6 -8
- package/src/plugins/builtin/sec/filing-documents.ts +66 -0
- package/src/plugins/builtin/sec/index.tsx +132 -20
- package/src/plugins/builtin/sectors/index.tsx +13 -23
- package/src/plugins/builtin/shared/ticker-request.ts +1 -0
- package/src/plugins/builtin/substack/api/auth.ts +185 -0
- package/src/plugins/builtin/substack/api/cache.ts +78 -0
- package/src/plugins/builtin/substack/api/loaders.ts +146 -0
- package/src/plugins/builtin/substack/api/store.ts +186 -0
- package/src/plugins/builtin/substack/api/types.ts +40 -0
- package/src/plugins/builtin/substack/api.test.ts +298 -0
- package/src/plugins/builtin/substack/article-detail.tsx +359 -0
- package/src/plugins/builtin/substack/article-stack.tsx +129 -0
- package/src/plugins/builtin/substack/content.ts +478 -0
- package/src/plugins/builtin/substack/feed-tabs.tsx +41 -0
- package/src/plugins/builtin/substack/index.tsx +49 -0
- package/src/plugins/builtin/substack/login-view.tsx +126 -0
- package/src/plugins/builtin/substack/model.test.ts +155 -0
- package/src/plugins/builtin/substack/normalize.ts +343 -0
- package/src/plugins/builtin/substack/pane-footer.ts +71 -0
- package/src/plugins/builtin/substack/pane-state.ts +170 -0
- package/src/plugins/builtin/substack/pane.tsx +500 -0
- package/src/plugins/builtin/substack/table.ts +111 -0
- package/src/plugins/builtin/substack/types.ts +71 -0
- package/src/plugins/builtin/substack/utils.ts +131 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +26 -25
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +5 -4
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -4
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +6 -5
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +10 -8
- package/src/plugins/builtin/ticker-detail/index.test.tsx +16 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/pane.tsx +13 -1
- package/src/plugins/builtin/world-indices/index.tsx +9 -6
- package/src/plugins/catalog-ui.ts +2 -0
- package/src/plugins/pane-manager/layout-state.ts +11 -0
- package/src/plugins/pane-manager.ts +1 -1
- package/src/plugins/prediction-markets/pane.tsx +10 -9
- package/src/plugins/registry/index.ts +3 -0
- package/src/plugins/runtime/context.tsx +1 -0
- package/src/plugins/runtime/index.tsx +4 -0
- package/src/react/use-throttled-commit-value.ts +116 -0
- package/src/renderers/electrobun/bun/desktop/http-fetch.test.ts +42 -0
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/data-table/index.tsx +3 -2
- package/src/renderers/electrobun/view/data-table/row.tsx +2 -2
- package/src/renderers/electrobun/view/host/input.tsx +23 -2
- package/src/renderers/electrobun/view/http-fetch.ts +10 -3
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/sources/gloomberb-cloud/index.ts +4 -0
- package/src/sources/provider-router/cache.ts +1 -0
- package/src/sources/provider-router/document-routes.ts +45 -0
- package/src/sources/provider-router/index.ts +4 -0
- package/src/sources/sec-edgar/content.ts +9 -3
- package/src/sources/sec-edgar.test.ts +108 -1
- package/src/sources/sec-edgar.ts +105 -1
- package/src/sources/yahoo-finance.ts +4 -0
- package/src/state/app/context/index.test.tsx +16 -0
- package/src/test-support/plugin-runtime.ts +1 -0
- package/src/tickers/search/index.ts +1 -0
- package/src/types/data-provider.ts +11 -0
- package/src/ui/host.tsx +1 -0
- package/src/version.ts +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Box, ImageSurface, Text } from "../../ui";
|
|
2
2
|
import { colors } from "../../theme/colors";
|
|
3
|
-
import { ExternalLinkText } from "./external-link";
|
|
4
3
|
import { normalizedHttpUrl } from "../../utils/url";
|
|
5
4
|
|
|
6
5
|
export interface RemoteImageProps {
|
|
@@ -11,13 +10,6 @@ export interface RemoteImageProps {
|
|
|
11
10
|
label?: string;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
function truncate(value: string, width: number): string {
|
|
15
|
-
if (width <= 0) return "";
|
|
16
|
-
if (value.length <= width) return value;
|
|
17
|
-
if (width <= 3) return value.slice(0, width);
|
|
18
|
-
return `${value.slice(0, width - 3)}...`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
13
|
export function RemoteImage({
|
|
22
14
|
src,
|
|
23
15
|
alt = "Image",
|
|
@@ -37,13 +29,8 @@ export function RemoteImage({
|
|
|
37
29
|
height={Math.max(4, height)}
|
|
38
30
|
objectFit="contain"
|
|
39
31
|
>
|
|
40
|
-
<Box flexDirection="column"
|
|
32
|
+
<Box flexDirection="column">
|
|
41
33
|
<Text fg={colors.textDim}>{label}</Text>
|
|
42
|
-
<ExternalLinkText
|
|
43
|
-
url={imageUrl}
|
|
44
|
-
label={truncate(imageUrl, resolvedWidth)}
|
|
45
|
-
color={colors.textBright}
|
|
46
|
-
/>
|
|
47
34
|
</Box>
|
|
48
35
|
</ImageSurface>
|
|
49
36
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StyledText, Text, TextAttributes } from "../../ui";
|
|
2
2
|
import { colors } from "../../theme/colors";
|
|
3
|
+
import { useRef } from "react";
|
|
3
4
|
|
|
4
5
|
type ShortcutHintMouseEvent = {
|
|
5
6
|
stopPropagation?: () => void;
|
|
@@ -36,6 +37,17 @@ export function ShortcutHint({
|
|
|
36
37
|
const keyColor = disabled ? colors.textMuted : colors.textBright;
|
|
37
38
|
const labelColor = disabled ? colors.textMuted : colors.textDim;
|
|
38
39
|
const keyText = `[${hotkey}]`;
|
|
40
|
+
const triggerMouseDownRef = useRef(false);
|
|
41
|
+
const startPress = (event?: ShortcutHintMouseEvent) => {
|
|
42
|
+
triggerMouseDownRef.current = true;
|
|
43
|
+
stopMouseEvent(event);
|
|
44
|
+
};
|
|
45
|
+
const finishPress = (event?: ShortcutHintMouseEvent) => {
|
|
46
|
+
const startedOnTrigger = triggerMouseDownRef.current;
|
|
47
|
+
triggerMouseDownRef.current = false;
|
|
48
|
+
if (startedOnTrigger) onPress?.(event);
|
|
49
|
+
else stopMouseEvent(event);
|
|
50
|
+
};
|
|
39
51
|
|
|
40
52
|
return (
|
|
41
53
|
<Text
|
|
@@ -47,8 +59,8 @@ export function ShortcutHint({
|
|
|
47
59
|
])}
|
|
48
60
|
fg={disabled ? colors.textMuted : colors.textDim}
|
|
49
61
|
attributes={interactive ? TextAttributes.BOLD : 0}
|
|
50
|
-
onMouseDown={interactive ?
|
|
51
|
-
onMouseUp={interactive ?
|
|
62
|
+
onMouseDown={interactive ? startPress : undefined}
|
|
63
|
+
onMouseUp={interactive ? finishPress : undefined}
|
|
52
64
|
{...(dataGloomRole ? { "data-gloom-role": dataGloomRole } : {})}
|
|
53
65
|
/>
|
|
54
66
|
);
|
|
@@ -27,7 +27,7 @@ describe("table layout", () => {
|
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
29
|
expect(template).toBe(
|
|
30
|
-
"minmax(
|
|
30
|
+
"minmax(calc(4 * var(--cell-w)), calc(4 * var(--cell-w))) minmax(calc(14 * var(--cell-w)), 40fr) minmax(calc(8 * var(--cell-w)), calc(24 * var(--cell-w))) minmax(calc(5 * var(--cell-w)), calc(5 * var(--cell-w)))",
|
|
31
31
|
);
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -37,6 +37,6 @@ describe("table layout", () => {
|
|
|
37
37
|
{ width: 8, align: "right" },
|
|
38
38
|
]);
|
|
39
39
|
|
|
40
|
-
expect(template).toBe("minmax(
|
|
40
|
+
expect(template).toBe("minmax(calc(8 * var(--cell-w)), 12fr) minmax(calc(8 * var(--cell-w)), 8fr)");
|
|
41
41
|
});
|
|
42
42
|
});
|
|
@@ -8,6 +8,7 @@ export interface TableWidthColumn {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const TRAILING_COLUMN_GUTTER_WIDTH = 1;
|
|
11
|
+
const WEB_CELL_UNIT = "var(--cell-w)";
|
|
11
12
|
|
|
12
13
|
export function getTableWidth(columns: readonly TableWidthColumn[]): number {
|
|
13
14
|
return columns.reduce((sum, column) => sum + column.width + 1, 2);
|
|
@@ -57,15 +58,20 @@ function columnFlexWeight(column: TableWidthColumn): number {
|
|
|
57
58
|
return flexGrow > 0 ? baseWeight * Math.max(1, flexGrow) : baseWeight;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
function cellWidthCss(width: number): string {
|
|
62
|
+
return `calc(${width} * ${WEB_CELL_UNIT})`;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
export function buildTableGridTemplateColumns(columns: readonly TableWidthColumn[]): string {
|
|
61
66
|
const hasFlexColumn = columns.some((column) => (column.flexGrow ?? 0) > 0);
|
|
62
67
|
return columns
|
|
63
68
|
.map((column) => {
|
|
64
69
|
const width = normalizedColumnWidth(column);
|
|
70
|
+
const minWidth = cellWidthCss(columnMinCh(column));
|
|
65
71
|
if (!hasFlexColumn || (column.flexGrow ?? 0) > 0) {
|
|
66
|
-
return `minmax(${
|
|
72
|
+
return `minmax(${minWidth}, ${columnFlexWeight(column)}fr)`;
|
|
67
73
|
}
|
|
68
|
-
return `minmax(${
|
|
74
|
+
return `minmax(${minWidth}, ${cellWidthCss(width)})`;
|
|
69
75
|
})
|
|
70
76
|
.join(" ");
|
|
71
77
|
}
|
|
@@ -30,6 +30,7 @@ export interface TabsProps {
|
|
|
30
30
|
onAdd?: () => void;
|
|
31
31
|
focused?: boolean;
|
|
32
32
|
keyboardNavigation?: boolean;
|
|
33
|
+
scrollable?: boolean;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
const WHEEL_DELTA_PER_CELL = 8;
|
|
@@ -45,9 +46,16 @@ export function Tabs({
|
|
|
45
46
|
onAdd,
|
|
46
47
|
focused = false,
|
|
47
48
|
keyboardNavigation = true,
|
|
49
|
+
scrollable = true,
|
|
48
50
|
}: TabsProps) {
|
|
49
51
|
const ui = useUiHost();
|
|
50
52
|
const NativeTabs = ui.Tabs;
|
|
53
|
+
const navigationValueRef = useRef<string | null>(activeValue);
|
|
54
|
+
const renderedActiveValueRef = useRef<string | null>(activeValue);
|
|
55
|
+
if (renderedActiveValueRef.current !== activeValue) {
|
|
56
|
+
renderedActiveValueRef.current = activeValue;
|
|
57
|
+
navigationValueRef.current = activeValue;
|
|
58
|
+
}
|
|
51
59
|
const palette = {
|
|
52
60
|
activeFg: variant === "bare" ? colors.textBright : colors.text,
|
|
53
61
|
inactiveFg: colors.textDim,
|
|
@@ -62,18 +70,26 @@ export function Tabs({
|
|
|
62
70
|
closeFg: colors.textMuted,
|
|
63
71
|
addFg: colors.textMuted,
|
|
64
72
|
};
|
|
73
|
+
const handleSelect = useCallback((value: string) => {
|
|
74
|
+
navigationValueRef.current = value;
|
|
75
|
+
onSelect(value);
|
|
76
|
+
}, [onSelect]);
|
|
77
|
+
|
|
65
78
|
const selectAdjacentTab = useCallback((direction: -1 | 1) => {
|
|
66
79
|
const enabledTabs = tabs.filter((tab) => !tab.disabled);
|
|
67
80
|
if (enabledTabs.length === 0) return;
|
|
68
81
|
|
|
69
|
-
const
|
|
82
|
+
const navigationValue = enabledTabs.some((tab) => tab.value === navigationValueRef.current)
|
|
83
|
+
? navigationValueRef.current
|
|
84
|
+
: activeValue;
|
|
85
|
+
const activeIndex = enabledTabs.findIndex((tab) => tab.value === navigationValue);
|
|
70
86
|
const nextIndex = activeIndex >= 0
|
|
71
87
|
? Math.max(0, Math.min(activeIndex + direction, enabledTabs.length - 1))
|
|
72
88
|
: direction > 0 ? 0 : enabledTabs.length - 1;
|
|
73
89
|
const nextTab = enabledTabs[nextIndex];
|
|
74
|
-
if (!nextTab || nextTab.value ===
|
|
75
|
-
|
|
76
|
-
}, [activeValue,
|
|
90
|
+
if (!nextTab || nextTab.value === navigationValue) return;
|
|
91
|
+
handleSelect(nextTab.value);
|
|
92
|
+
}, [activeValue, handleSelect, tabs]);
|
|
77
93
|
|
|
78
94
|
useShortcut((event) => {
|
|
79
95
|
if (event.ctrl || event.meta || event.alt || event.targetEditable) return;
|
|
@@ -96,7 +112,7 @@ export function Tabs({
|
|
|
96
112
|
<NativeTabs
|
|
97
113
|
tabs={tabs}
|
|
98
114
|
activeValue={activeValue}
|
|
99
|
-
onSelect={
|
|
115
|
+
onSelect={handleSelect}
|
|
100
116
|
compact={compact}
|
|
101
117
|
variant={variant}
|
|
102
118
|
closeMode={closeMode}
|
|
@@ -111,12 +127,13 @@ export function Tabs({
|
|
|
111
127
|
<OpenTuiTabs
|
|
112
128
|
tabs={tabs}
|
|
113
129
|
activeValue={activeValue}
|
|
114
|
-
onSelect={
|
|
130
|
+
onSelect={handleSelect}
|
|
115
131
|
compact={compact}
|
|
116
132
|
variant={variant}
|
|
117
133
|
closeMode={closeMode}
|
|
118
134
|
addLabel={addLabel}
|
|
119
135
|
onAdd={onAdd}
|
|
136
|
+
scrollable={scrollable}
|
|
120
137
|
palette={palette}
|
|
121
138
|
/>
|
|
122
139
|
);
|
|
@@ -140,6 +157,7 @@ function OpenTuiTabs({
|
|
|
140
157
|
closeMode = "always",
|
|
141
158
|
addLabel = "+",
|
|
142
159
|
onAdd,
|
|
160
|
+
scrollable = true,
|
|
143
161
|
palette,
|
|
144
162
|
}: TabsProps & {
|
|
145
163
|
palette: {
|
|
@@ -213,6 +231,96 @@ function OpenTuiTabs({
|
|
|
213
231
|
scrollBox.scrollTo({ x: nextLeft, y: scrollBox.scrollTop });
|
|
214
232
|
};
|
|
215
233
|
|
|
234
|
+
const tabRow = (
|
|
235
|
+
<Box flexDirection="row" width={totalWidth} height={1}>
|
|
236
|
+
{tabs.map((tab, index) => {
|
|
237
|
+
const active = tab.value === activeValue;
|
|
238
|
+
const hovered = hoveredValue === tab.value && !tab.disabled;
|
|
239
|
+
const tabWidth = tabWidths[index] ?? tab.label.length + 2;
|
|
240
|
+
const showClose = !!tab.onClose && (closeMode === "always" || active);
|
|
241
|
+
const attributes = (active ? TextAttributes.BOLD : 0)
|
|
242
|
+
| (variant === "underline" && !compact && (active || hovered) ? TextAttributes.UNDERLINE : 0);
|
|
243
|
+
const startHover = tab.disabled
|
|
244
|
+
? undefined
|
|
245
|
+
: () => {
|
|
246
|
+
setHoveredValue((current) => (current === tab.value ? current : tab.value));
|
|
247
|
+
};
|
|
248
|
+
const endHover = tab.disabled
|
|
249
|
+
? undefined
|
|
250
|
+
: () => {
|
|
251
|
+
setHoveredValue((current) => (current === tab.value ? null : current));
|
|
252
|
+
};
|
|
253
|
+
const selectTab = tab.disabled
|
|
254
|
+
? undefined
|
|
255
|
+
: (event: TabPointerEvent) => {
|
|
256
|
+
if (event.button === 2 && tab.onContextMenu) {
|
|
257
|
+
event.preventDefault?.();
|
|
258
|
+
event.stopPropagation?.();
|
|
259
|
+
tab.onContextMenu(tab.value, event);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
event.stopPropagation?.();
|
|
264
|
+
onSelect(tab.value);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<Box
|
|
269
|
+
key={tab.value}
|
|
270
|
+
width={tabWidth}
|
|
271
|
+
height={1}
|
|
272
|
+
flexDirection="row"
|
|
273
|
+
backgroundColor={active && variant === "pill" ? palette.activeBg : hovered ? palette.hoverBg : undefined}
|
|
274
|
+
onMouseOver={startHover}
|
|
275
|
+
onMouseMove={startHover}
|
|
276
|
+
onMouseOut={endHover}
|
|
277
|
+
onMouseDown={selectTab}
|
|
278
|
+
onDoubleClick={tab.disabled || !tab.onDoubleClick ? undefined : () => tab.onDoubleClick?.(tab.value)}
|
|
279
|
+
>
|
|
280
|
+
<Text
|
|
281
|
+
fg={tab.disabled ? palette.disabledFg : active && variant === "pill" ? palette.activePillFg : active ? palette.activeFg : hovered ? palette.hoverFg : palette.inactiveFg}
|
|
282
|
+
attributes={attributes}
|
|
283
|
+
onMouseDown={selectTab}
|
|
284
|
+
>
|
|
285
|
+
{` ${tab.label} `}
|
|
286
|
+
</Text>
|
|
287
|
+
{showClose && (
|
|
288
|
+
<Text
|
|
289
|
+
fg={active && variant === "pill" ? palette.activePillFg : palette.closeFg}
|
|
290
|
+
onMouseDown={(event: any) => {
|
|
291
|
+
event.preventDefault?.();
|
|
292
|
+
event.stopPropagation?.();
|
|
293
|
+
tab.onClose?.(tab.value);
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
{"x "}
|
|
297
|
+
</Text>
|
|
298
|
+
)}
|
|
299
|
+
</Box>
|
|
300
|
+
);
|
|
301
|
+
})}
|
|
302
|
+
{onAdd && (
|
|
303
|
+
<Box
|
|
304
|
+
width={addWidth}
|
|
305
|
+
height={1}
|
|
306
|
+
backgroundColor={hoveredValue === "__add__" ? palette.hoverBg : undefined}
|
|
307
|
+
onMouseMove={() => setHoveredValue((current) => (current === "__add__" ? current : "__add__"))}
|
|
308
|
+
onMouseOut={() => setHoveredValue((current) => (current === "__add__" ? null : current))}
|
|
309
|
+
onMouseDown={(event: TabPointerEvent) => {
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
onAdd();
|
|
312
|
+
}}
|
|
313
|
+
>
|
|
314
|
+
<Text fg={hoveredValue === "__add__" ? palette.hoverFg : palette.addFg}>
|
|
315
|
+
{` ${addLabel} `}
|
|
316
|
+
</Text>
|
|
317
|
+
</Box>
|
|
318
|
+
)}
|
|
319
|
+
</Box>
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
if (!scrollable) return tabRow;
|
|
323
|
+
|
|
216
324
|
return (
|
|
217
325
|
<ScrollBox
|
|
218
326
|
ref={scrollRef}
|
|
@@ -223,86 +331,7 @@ function OpenTuiTabs({
|
|
|
223
331
|
horizontalScrollbarOptions={{ visible: false }}
|
|
224
332
|
onMouseScroll={handleMouseScroll}
|
|
225
333
|
>
|
|
226
|
-
|
|
227
|
-
{tabs.map((tab, index) => {
|
|
228
|
-
const active = tab.value === activeValue;
|
|
229
|
-
const hovered = hoveredValue === tab.value && !tab.disabled;
|
|
230
|
-
const tabWidth = tabWidths[index] ?? tab.label.length + 2;
|
|
231
|
-
const showClose = !!tab.onClose && (closeMode === "always" || active);
|
|
232
|
-
const attributes = (active ? TextAttributes.BOLD : 0)
|
|
233
|
-
| (variant === "underline" && !compact && (active || hovered) ? TextAttributes.UNDERLINE : 0);
|
|
234
|
-
const startHover = tab.disabled
|
|
235
|
-
? undefined
|
|
236
|
-
: () => {
|
|
237
|
-
setHoveredValue((current) => (current === tab.value ? current : tab.value));
|
|
238
|
-
};
|
|
239
|
-
const endHover = tab.disabled
|
|
240
|
-
? undefined
|
|
241
|
-
: () => {
|
|
242
|
-
setHoveredValue((current) => (current === tab.value ? null : current));
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
return (
|
|
246
|
-
<Box
|
|
247
|
-
key={tab.value}
|
|
248
|
-
width={tabWidth}
|
|
249
|
-
height={1}
|
|
250
|
-
flexDirection="row"
|
|
251
|
-
backgroundColor={active && variant === "pill" ? palette.activeBg : hovered ? palette.hoverBg : undefined}
|
|
252
|
-
onMouseOver={startHover}
|
|
253
|
-
onMouseMove={startHover}
|
|
254
|
-
onMouseOut={endHover}
|
|
255
|
-
onMouseDown={tab.disabled ? undefined : (event: TabPointerEvent) => {
|
|
256
|
-
if (event.button === 2 && tab.onContextMenu) {
|
|
257
|
-
event.preventDefault?.();
|
|
258
|
-
event.stopPropagation?.();
|
|
259
|
-
tab.onContextMenu(tab.value, event);
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
event.preventDefault();
|
|
263
|
-
onSelect(tab.value);
|
|
264
|
-
}}
|
|
265
|
-
onDoubleClick={tab.disabled || !tab.onDoubleClick ? undefined : () => tab.onDoubleClick?.(tab.value)}
|
|
266
|
-
>
|
|
267
|
-
<Text
|
|
268
|
-
fg={tab.disabled ? palette.disabledFg : active && variant === "pill" ? palette.activePillFg : active ? palette.activeFg : hovered ? palette.hoverFg : palette.inactiveFg}
|
|
269
|
-
attributes={attributes}
|
|
270
|
-
>
|
|
271
|
-
{` ${tab.label} `}
|
|
272
|
-
</Text>
|
|
273
|
-
{showClose && (
|
|
274
|
-
<Text
|
|
275
|
-
fg={active && variant === "pill" ? palette.activePillFg : palette.closeFg}
|
|
276
|
-
onMouseDown={(event: any) => {
|
|
277
|
-
event.preventDefault?.();
|
|
278
|
-
event.stopPropagation?.();
|
|
279
|
-
tab.onClose?.(tab.value);
|
|
280
|
-
}}
|
|
281
|
-
>
|
|
282
|
-
{"x "}
|
|
283
|
-
</Text>
|
|
284
|
-
)}
|
|
285
|
-
</Box>
|
|
286
|
-
);
|
|
287
|
-
})}
|
|
288
|
-
{onAdd && (
|
|
289
|
-
<Box
|
|
290
|
-
width={addWidth}
|
|
291
|
-
height={1}
|
|
292
|
-
backgroundColor={hoveredValue === "__add__" ? palette.hoverBg : undefined}
|
|
293
|
-
onMouseMove={() => setHoveredValue((current) => (current === "__add__" ? current : "__add__"))}
|
|
294
|
-
onMouseOut={() => setHoveredValue((current) => (current === "__add__" ? null : current))}
|
|
295
|
-
onMouseDown={(event: TabPointerEvent) => {
|
|
296
|
-
event.preventDefault();
|
|
297
|
-
onAdd();
|
|
298
|
-
}}
|
|
299
|
-
>
|
|
300
|
-
<Text fg={hoveredValue === "__add__" ? palette.hoverFg : palette.addFg}>
|
|
301
|
-
{` ${addLabel} `}
|
|
302
|
-
</Text>
|
|
303
|
-
</Box>
|
|
304
|
-
)}
|
|
305
|
-
</Box>
|
|
334
|
+
{tabRow}
|
|
306
335
|
</ScrollBox>
|
|
307
336
|
);
|
|
308
337
|
}
|
|
@@ -151,6 +151,7 @@ function DataTableHorizontalScrollHarness({
|
|
|
151
151
|
<DataTableView
|
|
152
152
|
rootWidth={containerWidth}
|
|
153
153
|
rootHeight={containerHeight}
|
|
154
|
+
selection={{ kind: "none" }}
|
|
154
155
|
columns={columns}
|
|
155
156
|
items={items}
|
|
156
157
|
sortColumnId={null}
|
|
@@ -159,8 +160,6 @@ function DataTableHorizontalScrollHarness({
|
|
|
159
160
|
headerScrollRef={headerScrollRef}
|
|
160
161
|
scrollRef={scrollRef}
|
|
161
162
|
getItemKey={(row) => row.id}
|
|
162
|
-
isSelected={() => false}
|
|
163
|
-
onSelect={() => {}}
|
|
164
163
|
renderCell={(row) => ({ text: row.name })}
|
|
165
164
|
emptyStateTitle="No rows."
|
|
166
165
|
showHorizontalScrollbar={showHorizontalScrollbar}
|
|
@@ -228,7 +227,7 @@ function MultiSelectDialogButtonHarness() {
|
|
|
228
227
|
);
|
|
229
228
|
}
|
|
230
229
|
|
|
231
|
-
function ChoiceDialogHarness() {
|
|
230
|
+
function ChoiceDialogHarness({ selectedChoiceId }: { selectedChoiceId?: string } = {}) {
|
|
232
231
|
return (
|
|
233
232
|
<ChoiceDialog
|
|
234
233
|
title="Choose Account"
|
|
@@ -241,6 +240,7 @@ function ChoiceDialogHarness() {
|
|
|
241
240
|
{ id: "beta", label: "Beta", description: "Beta account" },
|
|
242
241
|
{ id: "gamma", label: "Gamma", description: "Gamma account" },
|
|
243
242
|
]}
|
|
243
|
+
selectedChoiceId={selectedChoiceId}
|
|
244
244
|
/>
|
|
245
245
|
);
|
|
246
246
|
}
|
|
@@ -318,6 +318,7 @@ describe("shared UI kit", () => {
|
|
|
318
318
|
|
|
319
319
|
test("moves focused tabs with arrow keys and leaves Tab for pane focus", async () => {
|
|
320
320
|
let lastSelected = "overview";
|
|
321
|
+
const selectedValues: string[] = [];
|
|
321
322
|
|
|
322
323
|
function KeyboardTabsHarness() {
|
|
323
324
|
const [activeValue, setActiveValue] = useState("overview");
|
|
@@ -331,6 +332,7 @@ describe("shared UI kit", () => {
|
|
|
331
332
|
activeValue={activeValue}
|
|
332
333
|
onSelect={(value) => {
|
|
333
334
|
lastSelected = value;
|
|
335
|
+
selectedValues.push(value);
|
|
334
336
|
setActiveValue(value);
|
|
335
337
|
}}
|
|
336
338
|
focused
|
|
@@ -343,17 +345,73 @@ describe("shared UI kit", () => {
|
|
|
343
345
|
await act(async () => {
|
|
344
346
|
await testSetup!.renderOnce();
|
|
345
347
|
testSetup!.mockInput.pressArrow("right");
|
|
348
|
+
testSetup!.mockInput.pressArrow("right");
|
|
346
349
|
await testSetup!.renderOnce();
|
|
347
350
|
});
|
|
348
351
|
|
|
349
|
-
expect(
|
|
352
|
+
expect(selectedValues).toEqual(["news", "chart"]);
|
|
353
|
+
expect(lastSelected).toBe("chart");
|
|
350
354
|
|
|
351
355
|
await act(async () => {
|
|
352
356
|
testSetup!.mockInput.pressTab();
|
|
353
357
|
await testSetup!.renderOnce();
|
|
354
358
|
});
|
|
355
359
|
|
|
360
|
+
expect(lastSelected).toBe("chart");
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
test("selects tabs by clicking their text labels", async () => {
|
|
364
|
+
let lastSelected = "overview";
|
|
365
|
+
const selectedValues: string[] = [];
|
|
366
|
+
|
|
367
|
+
function PointerTabsHarness() {
|
|
368
|
+
const [activeValue, setActiveValue] = useState("overview");
|
|
369
|
+
return (
|
|
370
|
+
<Tabs
|
|
371
|
+
tabs={[
|
|
372
|
+
{ label: "Overview", value: "overview" },
|
|
373
|
+
{ label: "News", value: "news" },
|
|
374
|
+
{ label: "Chart", value: "chart" },
|
|
375
|
+
]}
|
|
376
|
+
activeValue={activeValue}
|
|
377
|
+
onSelect={(value) => {
|
|
378
|
+
lastSelected = value;
|
|
379
|
+
selectedValues.push(value);
|
|
380
|
+
setActiveValue(value);
|
|
381
|
+
}}
|
|
382
|
+
scrollable={false}
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
testSetup = await testRender(<PointerTabsHarness />, { width: 40, height: 4 });
|
|
388
|
+
|
|
389
|
+
await act(async () => {
|
|
390
|
+
await testSetup!.renderOnce();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
let frame = testSetup.captureCharFrame();
|
|
394
|
+
const newsCol = frame.split("\n")[0]!.indexOf("News");
|
|
395
|
+
expect(newsCol).toBeGreaterThanOrEqual(0);
|
|
396
|
+
|
|
397
|
+
await act(async () => {
|
|
398
|
+
await testSetup!.mockMouse.click(newsCol + 1, 0);
|
|
399
|
+
await testSetup!.renderOnce();
|
|
400
|
+
});
|
|
401
|
+
|
|
356
402
|
expect(lastSelected).toBe("news");
|
|
403
|
+
|
|
404
|
+
frame = testSetup.captureCharFrame();
|
|
405
|
+
const chartCol = frame.split("\n")[0]!.indexOf("Chart");
|
|
406
|
+
expect(chartCol).toBeGreaterThanOrEqual(0);
|
|
407
|
+
|
|
408
|
+
await act(async () => {
|
|
409
|
+
await testSetup!.mockMouse.click(chartCol + 1, 0);
|
|
410
|
+
await testSetup!.renderOnce();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(selectedValues).toEqual(["news", "chart"]);
|
|
414
|
+
expect(lastSelected).toBe("chart");
|
|
357
415
|
});
|
|
358
416
|
|
|
359
417
|
test("renders tab actions for editable tab sets", async () => {
|
|
@@ -407,6 +465,15 @@ describe("shared UI kit", () => {
|
|
|
407
465
|
expect(button).toBeDefined();
|
|
408
466
|
expect(button!.width).toBe(" IND: SMA ".length);
|
|
409
467
|
|
|
468
|
+
await act(async () => {
|
|
469
|
+
await testSetup!.mockMouse.release(button!.x + 1, button!.y);
|
|
470
|
+
await Promise.resolve();
|
|
471
|
+
await testSetup!.renderOnce();
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
frame = testSetup.captureCharFrame();
|
|
475
|
+
expect(frame).not.toContain("Chart Indicators");
|
|
476
|
+
|
|
410
477
|
await act(async () => {
|
|
411
478
|
await testSetup!.mockMouse.click(button!.x + 1, button!.y);
|
|
412
479
|
await Promise.resolve();
|
|
@@ -470,6 +537,18 @@ describe("shared UI kit", () => {
|
|
|
470
537
|
expect(resolvedChoice).toBe("gamma");
|
|
471
538
|
});
|
|
472
539
|
|
|
540
|
+
test("preselects the current choice in choice dialogs", async () => {
|
|
541
|
+
testSetup = await testRender(<ChoiceDialogHarness selectedChoiceId="beta" />, { width: 44, height: 10 });
|
|
542
|
+
|
|
543
|
+
await act(async () => {
|
|
544
|
+
await testSetup!.renderOnce();
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const frame = testSetup.captureCharFrame();
|
|
548
|
+
expect(frame).toContain("Beta account");
|
|
549
|
+
expect(frame).not.toContain("Alpha account");
|
|
550
|
+
});
|
|
551
|
+
|
|
473
552
|
test("cancels choice dialogs with escape", async () => {
|
|
474
553
|
testSetup = await testRender(<ChoiceDialogHarness />, { width: 44, height: 10 });
|
|
475
554
|
|
|
@@ -26,10 +26,18 @@ export interface CollectionSortPreference {
|
|
|
26
26
|
direction: SortDirection;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
interface
|
|
29
|
+
interface CommandBarLaunchRequestBase {
|
|
30
|
+
sequence: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface CommandBarPluginLaunchRequest extends CommandBarLaunchRequestBase {
|
|
30
34
|
kind: "plugin-command";
|
|
31
35
|
commandId: string;
|
|
32
|
-
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface CommandBarTickerSearchLaunchRequest extends CommandBarLaunchRequestBase {
|
|
39
|
+
kind: "ticker-search";
|
|
40
|
+
query?: string;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
export interface AppState {
|
|
@@ -44,7 +52,7 @@ export interface AppState {
|
|
|
44
52
|
recentTickers: string[];
|
|
45
53
|
commandBarOpen: boolean;
|
|
46
54
|
commandBarQuery: string;
|
|
47
|
-
commandBarLaunchRequest:
|
|
55
|
+
commandBarLaunchRequest: CommandBarPluginLaunchRequest | CommandBarTickerSearchLaunchRequest | null;
|
|
48
56
|
themePreview: string | null;
|
|
49
57
|
refreshing: Set<string>;
|
|
50
58
|
initialized: boolean;
|
|
@@ -74,7 +82,7 @@ export type AppAction =
|
|
|
74
82
|
type: "SET_COMMAND_BAR";
|
|
75
83
|
open: boolean;
|
|
76
84
|
query?: string;
|
|
77
|
-
launch?: { kind: "plugin-command"; commandId: string } | null;
|
|
85
|
+
launch?: { kind: "plugin-command"; commandId: string } | { kind: "ticker-search"; query?: string } | null;
|
|
78
86
|
}
|
|
79
87
|
| { type: "SET_COMMAND_BAR_QUERY"; query: string }
|
|
80
88
|
| { type: "SET_REFRESHING"; symbol: string; refreshing: boolean }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataProvider, SecFilingItem } from "../../types/data-provider";
|
|
1
|
+
import type { DataProvider, SecFilingDocument, SecFilingItem } from "../../types/data-provider";
|
|
2
2
|
import type { NewsArticle } from "../../news/types";
|
|
3
3
|
import type { OptionsChain } from "../../types/financials";
|
|
4
4
|
import type { NewsRequest, OptionsRequest, SecFilingsRequest } from "../request-types";
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
buildNewsKey,
|
|
27
27
|
buildOptionsKey,
|
|
28
28
|
buildSecContentKey,
|
|
29
|
+
buildSecDocumentsKey,
|
|
29
30
|
buildSecFilingsKey,
|
|
30
31
|
toMarketDataContext,
|
|
31
32
|
} from "../selectors";
|
|
@@ -170,6 +171,33 @@ export function loadSecFilingContentEntry(options: {
|
|
|
170
171
|
});
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
export function loadSecFilingDocumentsEntry(options: {
|
|
175
|
+
dataProvider: DataProvider;
|
|
176
|
+
filing: SecFilingItem;
|
|
177
|
+
store: QueryStore<SecFilingDocument[]>;
|
|
178
|
+
runSingleFlight: RunSingleFlight;
|
|
179
|
+
}): Promise<QueryEntry<SecFilingDocument[]>> {
|
|
180
|
+
const { dataProvider, filing, store, runSingleFlight } = options;
|
|
181
|
+
const key = buildSecDocumentsKey(filing.accessionNumber);
|
|
182
|
+
return loadAuxiliaryEntry({
|
|
183
|
+
dataProvider,
|
|
184
|
+
key,
|
|
185
|
+
store,
|
|
186
|
+
ttlMs: SEC_CONTENT_CACHE_TTL_MS,
|
|
187
|
+
runSingleFlight,
|
|
188
|
+
load: async (startedAt) => {
|
|
189
|
+
if (!dataProvider.getSecFilingDocuments) {
|
|
190
|
+
const attempt = createAttempt(dataProvider.id, startedAt, "unsupported", "UNSUPPORTED_RANGE", "SEC filing documents are not available");
|
|
191
|
+
return store.update(key, (current) => errorEntry(current, attempt));
|
|
192
|
+
}
|
|
193
|
+
const data = await dataProvider.getSecFilingDocuments(filing);
|
|
194
|
+
const status = data.length > 0 ? "success" : "empty";
|
|
195
|
+
const attempts = [createAttempt(dataProvider.id, startedAt, status, data.length > 0 ? undefined : "NO_DATA")];
|
|
196
|
+
return store.update(key, (current) => readyEntry(current, data.length > 0 ? data : null, dataProvider.id, attempts, { keepLastGoodOnEmpty: true }));
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
173
201
|
export function loadArticleSummaryEntry(options: {
|
|
174
202
|
dataProvider: DataProvider;
|
|
175
203
|
url: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataProvider, SecFilingItem } from "../../types/data-provider";
|
|
1
|
+
import type { DataProvider, SecFilingDocument, SecFilingItem } from "../../types/data-provider";
|
|
2
2
|
import type { NewsArticle } from "../../news/types";
|
|
3
3
|
import type { OptionsChain, PricePoint, Quote, TickerFinancials } from "../../types/financials";
|
|
4
4
|
import type { ChartRequest, InstrumentRef, NewsRequest, OptionsRequest, SecFilingsRequest } from "../request-types";
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
buildOptionsKey,
|
|
14
14
|
buildQuoteKey,
|
|
15
15
|
buildSecContentKey,
|
|
16
|
+
buildSecDocumentsKey,
|
|
16
17
|
buildSecFilingsKey,
|
|
17
18
|
buildSnapshotKey,
|
|
18
19
|
resolveEntryData,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
loadNewsEntry,
|
|
42
43
|
loadOptionsEntry,
|
|
43
44
|
loadSecFilingContentEntry,
|
|
45
|
+
loadSecFilingDocumentsEntry,
|
|
44
46
|
loadSecFilingsEntry,
|
|
45
47
|
} from "./auxiliary";
|
|
46
48
|
import {
|
|
@@ -72,6 +74,7 @@ export class MarketDataCoordinator {
|
|
|
72
74
|
private readonly newsStore = new QueryStore<NewsArticle[]>((key) => this.events.bump(key));
|
|
73
75
|
private readonly optionsStore = new QueryStore<OptionsChain>((key) => this.events.bump(key));
|
|
74
76
|
private readonly secFilingsStore = new QueryStore<SecFilingItem[]>((key) => this.events.bump(key));
|
|
77
|
+
private readonly secDocumentsStore = new QueryStore<SecFilingDocument[]>((key) => this.events.bump(key));
|
|
75
78
|
private readonly secContentStore = new QueryStore<string | null>((key) => this.events.bump(key));
|
|
76
79
|
private readonly articleSummaryStore = new QueryStore<string | null>((key) => this.events.bump(key));
|
|
77
80
|
private readonly fxStore = new QueryStore<number>((key) => this.events.bump(key));
|
|
@@ -135,6 +138,10 @@ export class MarketDataCoordinator {
|
|
|
135
138
|
return this.secContentStore.get(buildSecContentKey(accessionNumber));
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
getSecDocumentsEntry(accessionNumber: string): QueryEntry<SecFilingDocument[]> {
|
|
142
|
+
return this.secDocumentsStore.get(buildSecDocumentsKey(accessionNumber));
|
|
143
|
+
}
|
|
144
|
+
|
|
138
145
|
getArticleSummaryEntry(url: string): QueryEntry<string | null> {
|
|
139
146
|
return this.articleSummaryStore.get(buildArticleSummaryKey(url));
|
|
140
147
|
}
|
|
@@ -336,6 +343,15 @@ export class MarketDataCoordinator {
|
|
|
336
343
|
});
|
|
337
344
|
}
|
|
338
345
|
|
|
346
|
+
async loadSecFilingDocuments(filing: SecFilingItem): Promise<QueryEntry<SecFilingDocument[]>> {
|
|
347
|
+
return loadSecFilingDocumentsEntry({
|
|
348
|
+
dataProvider: this.dataProvider,
|
|
349
|
+
filing,
|
|
350
|
+
store: this.secDocumentsStore,
|
|
351
|
+
runSingleFlight: (key, task) => this.runSingleFlight(key, task),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
339
355
|
async loadArticleSummary(url: string): Promise<QueryEntry<string | null>> {
|
|
340
356
|
return loadArticleSummaryEntry({
|
|
341
357
|
dataProvider: this.dataProvider,
|