gloomberb 0.7.2 → 0.7.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 +79 -132
- package/package.json +1 -1
- package/src/app.tsx +73 -67
- package/src/components/chart/chart-data.ts +7 -2
- package/src/components/chart/chart-pane-settings.ts +7 -4
- package/src/components/chart/chart-renderer.ts +49 -15
- package/src/components/chart/chart-types.ts +2 -2
- package/src/components/chart/chart.test.ts +27 -8
- package/src/components/chart/comparison-stock-chart.tsx +84 -121
- package/src/components/chart/native/chart-rasterizer.ts +43 -17
- package/src/components/chart/price-axis-labels.tsx +25 -9
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +1 -1
- package/src/components/chart/stock-chart.tsx +59 -41
- package/src/components/command-bar/command-bar.test.tsx +446 -120
- package/src/components/command-bar/command-bar.tsx +528 -383
- package/src/components/command-bar/command-registry.ts +16 -6
- package/src/components/command-bar/root-shortcuts.ts +4 -5
- package/src/components/command-bar/view-model.test.ts +1 -0
- package/src/components/command-bar/view-model.ts +2 -1
- package/src/components/command-bar/workflow-ops.ts +11 -32
- package/src/components/data-table-view.test.tsx +24 -1
- package/src/components/data-table-view.tsx +3 -2
- package/src/components/feed-data-table-stack-view.tsx +3 -2
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/floating-pane.tsx +9 -2
- package/src/components/layout/pane-footer.tsx +1 -1
- package/src/components/layout/pane-header.tsx +4 -2
- package/src/components/layout/pane-sizing.ts +12 -0
- package/src/components/layout/pane.tsx +24 -2
- package/src/components/layout/shell.tsx +24 -10
- package/src/components/layout/status-bar.test.tsx +4 -1
- package/src/components/layout/status-bar.tsx +4 -24
- package/src/components/markdown-text.tsx +53 -8
- package/src/components/onboarding/onboarding-wizard.tsx +7 -6
- package/src/components/pane-settings-dialog.tsx +9 -6
- package/src/components/pane-template-wizard.tsx +3 -2
- package/src/components/price-selector-dialog.tsx +3 -2
- package/src/components/price-sparkline-view.tsx +463 -0
- package/src/components/price-sparkline.ts +46 -0
- package/src/components/table-view-shared.tsx +21 -3
- package/src/components/ticker-list-table-view.tsx +3 -2
- package/src/components/ticker-list-table.tsx +11 -51
- package/src/components/toggle-list.tsx +3 -3
- package/src/components/ui/choice-dialog.tsx +3 -2
- package/src/components/ui/multi-select-dialog.tsx +3 -2
- package/src/components/ui/native-select.tsx +3 -3
- package/src/core/state/app-state.ts +210 -80
- package/src/data/config-store-node.ts +113 -25
- package/src/data/config-store.test.ts +65 -3
- package/src/data/plugin-state-store.ts +39 -13
- package/src/data/sqlite-cache.test.ts +13 -0
- package/src/market-data/coordinator.ts +8 -1
- package/src/news/aggregator.test.ts +41 -0
- package/src/news/aggregator.ts +61 -9
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +25 -6
- package/src/plugins/builtin/ai/settings.ts +3 -0
- package/src/plugins/builtin/broker-manager/index.tsx +4 -3
- package/src/plugins/builtin/chat-controller.test.ts +398 -17
- package/src/plugins/builtin/chat-controller.ts +258 -44
- package/src/plugins/builtin/chat.test.tsx +257 -6
- package/src/plugins/builtin/chat.tsx +225 -60
- package/src/plugins/builtin/comparison-chart.test.tsx +117 -3
- package/src/plugins/builtin/correlation/colors.test.ts +39 -0
- package/src/plugins/builtin/correlation/colors.ts +87 -0
- package/src/plugins/builtin/correlation/index.test.tsx +151 -0
- package/src/plugins/builtin/correlation/index.tsx +92 -21
- package/src/plugins/builtin/debug.tsx +4 -3
- package/src/plugins/builtin/econ/index.tsx +3 -2
- package/src/plugins/builtin/help.test.tsx +2 -2
- package/src/plugins/builtin/holders/index.tsx +25 -13
- package/src/plugins/builtin/layout-manager.tsx +1 -7
- package/src/plugins/builtin/news-wire/index.tsx +1 -1
- package/src/plugins/builtin/news-wire/news-detail-view.tsx +3 -2
- package/src/plugins/builtin/news-wire/news-preset-pane.tsx +4 -1
- package/src/plugins/builtin/news-wire/persisted-articles.ts +7 -1
- package/src/plugins/builtin/options.tsx +9 -17
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +6 -10
- package/src/plugins/builtin/portfolio-list/metrics.ts +11 -0
- package/src/plugins/builtin/portfolio-list/mutations.ts +17 -0
- package/src/plugins/builtin/portfolio-list/pane.tsx +117 -18
- package/src/plugins/builtin/portfolio-list/quick-add.tsx +422 -0
- package/src/plugins/builtin/portfolio-list/settings.ts +20 -12
- package/src/plugins/builtin/portfolio-list/table.tsx +3 -3
- package/src/plugins/builtin/portfolio-list.test.tsx +282 -2
- package/src/plugins/builtin/quote-monitor.test.tsx +158 -25
- package/src/plugins/builtin/sectors/index.tsx +252 -41
- package/src/plugins/builtin/sectors/sector-data.ts +41 -1
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +30 -9
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +25 -15
- package/src/plugins/builtin/ticker-detail/pane.tsx +0 -6
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +442 -63
- package/src/plugins/builtin/ticker-detail/settings.ts +84 -3
- package/src/plugins/builtin/ticker-detail.test.tsx +2 -2
- package/src/plugins/ibkr/trading-pane.tsx +3 -2
- package/src/plugins/plugin-runtime.tsx +2 -2
- package/src/plugins/prediction-markets/settings.ts +4 -0
- package/src/plugins/registry.test.ts +55 -0
- package/src/plugins/registry.ts +11 -4
- package/src/plugins/ticker-navigation.test.ts +35 -5
- package/src/plugins/ticker-navigation.ts +16 -22
- package/src/renderers/electrobun/bun/application-menu-click.test.ts +9 -0
- package/src/renderers/electrobun/bun/application-menu-click.ts +7 -4
- package/src/renderers/electrobun/bun/application-menu.ts +6 -1
- package/src/renderers/electrobun/bun/desktop-workspace.ts +47 -29
- package/src/renderers/electrobun/bun/index.ts +52 -13
- package/src/renderers/electrobun/view/app-services.ts +51 -9
- package/src/renderers/electrobun/view/backend-rpc.ts +5 -8
- package/src/renderers/electrobun/view/desktop-controls.tsx +4 -4
- package/src/renderers/electrobun/view/main.tsx +0 -16
- package/src/renderers/electrobun/view/styles.css +23 -21
- package/src/renderers/electrobun/view/ui-host.tsx +6 -4
- package/src/renderers/opentui/host.tsx +2 -1
- package/src/renderers/opentui/start.tsx +1 -1
- package/src/renderers/opentui/test-utils.tsx +6 -5
- package/src/state/app-bootstrap.ts +3 -3
- package/src/state/app-context.test.ts +113 -0
- package/src/state/app-context.tsx +8 -4
- package/src/theme/colors.ts +13 -14
- package/src/types/config.ts +9 -4
- package/src/types/plugin.ts +8 -1
- package/src/ui/context-menu.tsx +4 -4
- package/src/utils/api-client.test.ts +128 -0
- package/src/utils/api-client.ts +112 -7
- package/src/utils/fuzzy-search.ts +12 -1
- package/src/utils/keyboard.ts +31 -0
- package/src/utils/ticker-search.test.ts +2 -2
- package/src/utils/ticker-search.ts +48 -1
- package/src/version.ts +1 -1
|
@@ -18,8 +18,7 @@ import type { ColumnConfig } from "../types/config";
|
|
|
18
18
|
import type { TickerFinancials, PricePoint } from "../types/financials";
|
|
19
19
|
import type { TickerRecord } from "../types/ticker";
|
|
20
20
|
import { padTo } from "../utils/format";
|
|
21
|
-
import {
|
|
22
|
-
import type { ProjectedChartPoint } from "./chart/chart-data";
|
|
21
|
+
import { PRICE_SPARKLINE_COLUMN_ID, PriceSparkline } from "./price-sparkline-view";
|
|
23
22
|
import { tableContentWidthProps, useMeasuredTableContentWidth } from "./ui/table-layout";
|
|
24
23
|
import { useViewport } from "../react/input";
|
|
25
24
|
import { measurePerf } from "../utils/perf-marks";
|
|
@@ -88,7 +87,6 @@ export interface TickerListTableProps {
|
|
|
88
87
|
onRowActivate?: (ticker: TickerRecord) => void;
|
|
89
88
|
emptyTitle?: string;
|
|
90
89
|
emptyHint?: string;
|
|
91
|
-
showSparklines?: boolean;
|
|
92
90
|
virtualize?: boolean;
|
|
93
91
|
overscan?: number;
|
|
94
92
|
}
|
|
@@ -155,38 +153,6 @@ const TickerListHeader = memo(function TickerListHeader({
|
|
|
155
153
|
);
|
|
156
154
|
});
|
|
157
155
|
|
|
158
|
-
function renderSparkline(priceHistory: PricePoint[]): StyledContent | null {
|
|
159
|
-
if (priceHistory.length < 5) return null;
|
|
160
|
-
|
|
161
|
-
const last20 = priceHistory.slice(-20);
|
|
162
|
-
const points: ProjectedChartPoint[] = last20.map((pt) => ({
|
|
163
|
-
date: pt.date,
|
|
164
|
-
open: pt.open ?? pt.close,
|
|
165
|
-
high: pt.high ?? pt.close,
|
|
166
|
-
low: pt.low ?? pt.close,
|
|
167
|
-
close: pt.close,
|
|
168
|
-
volume: pt.volume ?? 0,
|
|
169
|
-
}));
|
|
170
|
-
|
|
171
|
-
const first = last20[0]?.close ?? 0;
|
|
172
|
-
const last = last20[last20.length - 1]?.close ?? 0;
|
|
173
|
-
const trend = last >= first ? "positive" : "negative";
|
|
174
|
-
const palette = resolveChartPalette(colors, trend);
|
|
175
|
-
|
|
176
|
-
const result = renderChart(points, {
|
|
177
|
-
width: 10,
|
|
178
|
-
height: 1,
|
|
179
|
-
showVolume: false,
|
|
180
|
-
volumeHeight: 0,
|
|
181
|
-
cursorX: null,
|
|
182
|
-
cursorY: null,
|
|
183
|
-
mode: "line",
|
|
184
|
-
colors: palette,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
return result.lines[0] ?? null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
156
|
const TickerListRow = memo(function TickerListRow({
|
|
191
157
|
columns,
|
|
192
158
|
ticker,
|
|
@@ -201,7 +167,6 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
201
167
|
onRowActivate,
|
|
202
168
|
onRowContextMenu,
|
|
203
169
|
openContextMenuOnMouseDown,
|
|
204
|
-
showSparklines,
|
|
205
170
|
priceHistory,
|
|
206
171
|
contentWidth,
|
|
207
172
|
}: {
|
|
@@ -218,7 +183,6 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
218
183
|
onRowActivate?: (ticker: TickerRecord) => void;
|
|
219
184
|
onRowContextMenu: (ticker: TickerRecord, financials: TickerFinancials | undefined, event: unknown) => void;
|
|
220
185
|
openContextMenuOnMouseDown: boolean;
|
|
221
|
-
showSparklines?: boolean;
|
|
222
186
|
priceHistory?: PricePoint[];
|
|
223
187
|
contentWidth: number;
|
|
224
188
|
}) {
|
|
@@ -226,10 +190,6 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
226
190
|
const lastActivatedAtRef = useRef<number | null>(null);
|
|
227
191
|
const rowBg = isSelected ? colors.selected : isHovered ? hoverBg() : colors.bg;
|
|
228
192
|
|
|
229
|
-
const sparkline = showSparklines && priceHistory && priceHistory.length >= 5
|
|
230
|
-
? renderSparkline(priceHistory)
|
|
231
|
-
: null;
|
|
232
|
-
|
|
233
193
|
return (
|
|
234
194
|
<Box
|
|
235
195
|
flexDirection="row"
|
|
@@ -268,6 +228,14 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
268
228
|
}}
|
|
269
229
|
>
|
|
270
230
|
{columns.map((column) => {
|
|
231
|
+
if (column.id === PRICE_SPARKLINE_COLUMN_ID) {
|
|
232
|
+
return (
|
|
233
|
+
<Box key={column.id} width={column.width + 1} overflow="hidden">
|
|
234
|
+
<PriceSparkline priceHistory={priceHistory} width={column.width} />
|
|
235
|
+
</Box>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
271
239
|
const { text, color } = resolveCell(column, ticker, financials);
|
|
272
240
|
const baseFg = color || (isSelected ? colors.selectedText : colors.text);
|
|
273
241
|
const shouldFlash = flashDirection != null && FLASHABLE_QUOTE_COLUMN_IDS.has(column.id);
|
|
@@ -283,11 +251,6 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
283
251
|
</Box>
|
|
284
252
|
);
|
|
285
253
|
})}
|
|
286
|
-
{sparkline && (
|
|
287
|
-
<Box width={12}>
|
|
288
|
-
<Text content={sparkline} />
|
|
289
|
-
</Box>
|
|
290
|
-
)}
|
|
291
254
|
</Box>
|
|
292
255
|
);
|
|
293
256
|
}, (previous, next) => (
|
|
@@ -304,7 +267,6 @@ const TickerListRow = memo(function TickerListRow({
|
|
|
304
267
|
&& previous.onRowActivate === next.onRowActivate
|
|
305
268
|
&& previous.onRowContextMenu === next.onRowContextMenu
|
|
306
269
|
&& previous.openContextMenuOnMouseDown === next.openContextMenuOnMouseDown
|
|
307
|
-
&& previous.showSparklines === next.showSparklines
|
|
308
270
|
&& previous.priceHistory === next.priceHistory
|
|
309
271
|
&& previous.contentWidth === next.contentWidth
|
|
310
272
|
));
|
|
@@ -329,7 +291,6 @@ export function TickerListTable({
|
|
|
329
291
|
onRowActivate,
|
|
330
292
|
emptyTitle = "No tickers.",
|
|
331
293
|
emptyHint = "Press Ctrl+P to add one.",
|
|
332
|
-
showSparklines,
|
|
333
294
|
virtualize = true,
|
|
334
295
|
overscan = 4,
|
|
335
296
|
}: TickerListTableProps) {
|
|
@@ -347,8 +308,8 @@ export function TickerListTable({
|
|
|
347
308
|
hoveredIdxRef.current = hoveredIdx;
|
|
348
309
|
const safeFlashSymbols = flashSymbols ?? EMPTY_FLASH_SYMBOLS;
|
|
349
310
|
const tableWidth = useMemo(
|
|
350
|
-
() => columns.reduce((sum, column) => sum + column.width + 1, 2)
|
|
351
|
-
[columns
|
|
311
|
+
() => columns.reduce((sum, column) => sum + column.width + 1, 2),
|
|
312
|
+
[columns],
|
|
352
313
|
);
|
|
353
314
|
const { contentWidth, measureContentWidth } = useMeasuredTableContentWidth(
|
|
354
315
|
tableWidth,
|
|
@@ -492,7 +453,6 @@ export function TickerListTable({
|
|
|
492
453
|
onRowActivate={onRowActivate}
|
|
493
454
|
onRowContextMenu={handleRowContextMenu}
|
|
494
455
|
openContextMenuOnMouseDown={nativeContextMenu !== true}
|
|
495
|
-
showSparklines={showSparklines}
|
|
496
456
|
priceHistory={financialsMap.get(ticker.metadata.ticker)?.priceHistory}
|
|
497
457
|
contentWidth={contentWidth}
|
|
498
458
|
/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Box, Text, useUiHost } from "../ui";
|
|
2
2
|
import { TextAttributes } from "../ui";
|
|
3
|
-
import { colors } from "../theme/colors";
|
|
3
|
+
import { blendHex, colors } from "../theme/colors";
|
|
4
4
|
import { ListView, type ListRowState, type ListViewItem } from "./ui/list-view";
|
|
5
5
|
|
|
6
6
|
export interface ToggleListItem {
|
|
@@ -76,8 +76,8 @@ function DesktopToggleRow({
|
|
|
76
76
|
border: `1px solid ${checkboxBorder}`,
|
|
77
77
|
borderRadius: 4,
|
|
78
78
|
boxShadow: enabled
|
|
79
|
-
?
|
|
80
|
-
:
|
|
79
|
+
? `inset 0 1px 0 ${blendHex(colors.borderFocused, colors.textBright, 0.28)}`
|
|
80
|
+
: `inset 0 1px 0 ${blendHex(colors.bg, colors.textBright, 0.05)}`,
|
|
81
81
|
}}
|
|
82
82
|
>
|
|
83
83
|
{enabled && (
|
|
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from "react";
|
|
|
2
2
|
import { Box, Text } from "../../ui";
|
|
3
3
|
import { type PromptContext, useDialogKeyboard } from "../../ui/dialog";
|
|
4
4
|
import { colors } from "../../theme/colors";
|
|
5
|
+
import { isPlainKey } from "../../utils/keyboard";
|
|
5
6
|
import { DialogFrame } from "./frame";
|
|
6
7
|
import { ListView, type ListViewItem } from "./list-view";
|
|
7
8
|
|
|
@@ -58,9 +59,9 @@ export function ChoiceDialog({
|
|
|
58
59
|
|
|
59
60
|
useDialogKeyboard((event) => {
|
|
60
61
|
event.stopPropagation();
|
|
61
|
-
if (event
|
|
62
|
+
if (isPlainKey(event, "up", "k")) {
|
|
62
63
|
setIndex((current) => clampChoiceIndex(current - 1, choices.length));
|
|
63
|
-
} else if (event
|
|
64
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
64
65
|
setIndex((current) => clampChoiceIndex(current + 1, choices.length));
|
|
65
66
|
} else if (event.name === "enter" || event.name === "return") {
|
|
66
67
|
activateChoice(selectedChoice);
|
|
@@ -5,6 +5,7 @@ import { type AlertContext, useDialog, useDialogKeyboard } from "../../ui/dialog
|
|
|
5
5
|
import { type ReactNode, useEffect, useMemo, useState } from "react";
|
|
6
6
|
import { colors } from "../../theme/colors";
|
|
7
7
|
import { isDetailBackNavigationKey } from "../../utils/back-navigation";
|
|
8
|
+
import { isPlainKey } from "../../utils/keyboard";
|
|
8
9
|
import { ToggleList } from "../toggle-list";
|
|
9
10
|
import { Button } from "./button";
|
|
10
11
|
import { DialogFrame } from "./frame";
|
|
@@ -176,10 +177,10 @@ export function MultiSelectDialogContent({
|
|
|
176
177
|
|
|
177
178
|
useDialogKeyboard((event) => {
|
|
178
179
|
event.stopPropagation();
|
|
179
|
-
if (event
|
|
180
|
+
if (isPlainKey(event, "up", "k")) {
|
|
180
181
|
const nextIndex = Math.max(0, selectedIndex - 1);
|
|
181
182
|
setSelectedOptionId(displayOptions[nextIndex]?.value ?? selectedOptionId);
|
|
182
|
-
} else if (event
|
|
183
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
183
184
|
const nextIndex = Math.min(displayOptions.length - 1, selectedIndex + 1);
|
|
184
185
|
setSelectedOptionId(displayOptions[nextIndex]?.value ?? selectedOptionId);
|
|
185
186
|
} else if (isSpaceKey(event)) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { type CSSProperties } from "react";
|
|
4
4
|
import { Box } from "../../ui";
|
|
5
|
-
import { colors } from "../../theme/colors";
|
|
5
|
+
import { blendHex, colors } from "../../theme/colors";
|
|
6
6
|
|
|
7
7
|
export type NativeSelectElement = HTMLSelectElement & { showPicker?: () => void };
|
|
8
8
|
|
|
@@ -51,11 +51,11 @@ export function NativeSelect({
|
|
|
51
51
|
width,
|
|
52
52
|
height: 28,
|
|
53
53
|
color: colors.text,
|
|
54
|
-
backgroundColor:
|
|
54
|
+
backgroundColor: blendHex(colors.panel, colors.textBright, 0.06),
|
|
55
55
|
border: `1px solid ${colors.border}`,
|
|
56
56
|
borderRadius: 6,
|
|
57
57
|
padding: "0 8px",
|
|
58
|
-
boxShadow:
|
|
58
|
+
boxShadow: `inset 0 1px 0 ${blendHex(colors.bg, colors.textBright, 0.05)}`,
|
|
59
59
|
cursor: "pointer",
|
|
60
60
|
font: "inherit",
|
|
61
61
|
letterSpacing: 0,
|