gloomberb 0.3.3 → 0.4.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 +27 -16
- package/package.json +1 -1
- package/src/app.tsx +29 -65
- package/src/cli/base-converter.ts +31 -0
- package/src/cli/commands/search.ts +11 -3
- package/src/cli/commands/ticker.ts +22 -11
- package/src/cli/context.ts +27 -32
- package/src/cli/helpers.ts +1 -4
- package/src/cli/index.ts +140 -123
- package/src/cli/registry.test.ts +226 -0
- package/src/cli/registry.ts +201 -0
- package/src/cli.test.ts +219 -0
- package/src/components/chart/chart-controller.ts +309 -0
- package/src/components/chart/chart-data.ts +5 -6
- package/src/components/chart/chart-pane-settings.ts +27 -0
- package/src/components/chart/chart-renderer.ts +7 -2
- package/src/components/chart/chart-resolution.test.ts +56 -0
- package/src/components/chart/chart-resolution.ts +362 -0
- package/src/components/chart/chart-types.ts +12 -4
- package/src/components/chart/chart-viewport.test.ts +25 -0
- package/src/components/chart/chart-viewport.ts +28 -0
- package/src/components/chart/chart.test.ts +26 -0
- package/src/components/chart/comparison-chart-data.ts +20 -27
- package/src/components/chart/comparison-stock-chart.tsx +374 -99
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +124 -0
- package/src/components/chart/stock-chart.tsx +484 -112
- package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +4 -4
- package/src/components/command-bar/command-bar.test.tsx +650 -5
- package/src/components/command-bar/command-bar.tsx +359 -63
- package/src/components/command-bar/command-registry.ts +8 -0
- package/src/components/command-bar/helpers.test.ts +23 -1
- package/src/components/command-bar/helpers.ts +14 -5
- package/src/components/command-bar/pane-template-display.ts +12 -0
- package/src/components/command-bar/root-shortcuts.ts +2 -1
- package/src/components/command-bar/workflow-ops.ts +4 -2
- package/src/components/detail-feed-view.test.tsx +124 -49
- package/src/components/detail-feed-view.tsx +396 -160
- package/src/components/layout/floating-pane.tsx +1 -1
- package/src/components/layout/pane-header.tsx +26 -2
- package/src/components/layout/shell.tsx +62 -50
- package/src/components/layout/status-bar.test.tsx +66 -0
- package/src/components/layout/status-bar.tsx +26 -5
- package/src/components/onboarding/onboarding-wizard.test.tsx +65 -0
- package/src/components/onboarding/onboarding-wizard.tsx +5 -6
- package/src/components/ticker-list-table.test.tsx +83 -0
- package/src/components/ticker-list-table.tsx +174 -97
- package/src/components/ui/data-table.tsx +27 -2
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/page-stack-view.tsx +60 -0
- package/src/components/use-double-click-activation.ts +31 -0
- package/src/index.tsx +10 -10
- package/src/market-data/coordinator.test.ts +92 -4
- package/src/market-data/coordinator.ts +32 -5
- package/src/market-data/hooks.test.tsx +120 -0
- package/src/market-data/hooks.tsx +53 -16
- package/src/market-data/request-types.ts +4 -2
- package/src/market-data/selectors.ts +24 -58
- package/src/plugins/builtin/chat-controller.test.ts +370 -3
- package/src/plugins/builtin/chat-controller.ts +310 -35
- package/src/plugins/builtin/chat.test.tsx +118 -6
- package/src/plugins/builtin/chat.tsx +175 -116
- package/src/plugins/builtin/comparison-chart.test.tsx +66 -5
- package/src/plugins/builtin/comparison-chart.tsx +21 -1
- package/src/plugins/builtin/news.tsx +1 -11
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +656 -0
- package/src/plugins/builtin/portfolio-list/command-bar.ts +122 -0
- package/src/plugins/builtin/portfolio-list/header.tsx +16 -34
- package/src/plugins/builtin/portfolio-list/index.tsx +5 -0
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +61 -0
- package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
- package/src/plugins/builtin/portfolio-list/mutations.test.ts +187 -0
- package/src/plugins/builtin/portfolio-list/mutations.ts +226 -0
- package/src/plugins/builtin/portfolio-list/pane.tsx +39 -17
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -2
- package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.test.tsx +163 -0
- package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +81 -0
- package/src/plugins/builtin/sec.tsx +1 -11
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +13 -2
- package/src/plugins/builtin/ticker-detail/financials-tab.tsx +21 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +45 -10
- package/src/plugins/builtin/ticker-detail/pane.tsx +35 -17
- package/src/plugins/builtin/ticker-detail/settings.ts +19 -1
- package/src/plugins/builtin/ticker-detail.test.tsx +47 -0
- package/src/plugins/catalog.ts +65 -0
- package/src/plugins/ibkr/broker-adapter.ts +28 -0
- package/src/plugins/ibkr/gateway-service.test.ts +75 -1
- package/src/plugins/ibkr/gateway-service.ts +179 -9
- package/src/plugins/pane-manager.test.ts +1 -1
- package/src/plugins/plugin-runtime.tsx +27 -7
- package/src/plugins/prediction-markets/chart.test.tsx +139 -0
- package/src/plugins/prediction-markets/chart.tsx +65 -436
- package/src/plugins/prediction-markets/cli.ts +28 -0
- package/src/plugins/prediction-markets/controller-data.ts +17 -5
- package/src/plugins/prediction-markets/controller.ts +141 -121
- package/src/plugins/prediction-markets/detail/outcomes.tsx +2 -6
- package/src/plugins/prediction-markets/detail/pane.tsx +4 -25
- package/src/plugins/prediction-markets/detail/shared.tsx +0 -1
- package/src/plugins/prediction-markets/detail.test.tsx +4 -0
- package/src/plugins/prediction-markets/index.tsx +2 -0
- package/src/plugins/prediction-markets/launch.ts +51 -16
- package/src/plugins/prediction-markets/metrics.ts +9 -5
- package/src/plugins/prediction-markets/pane.test.tsx +160 -58
- package/src/plugins/prediction-markets/pane.tsx +74 -183
- package/src/plugins/prediction-markets/table.tsx +6 -3
- package/src/plugins/prediction-markets/types.ts +0 -1
- package/src/sources/gloomberb-cloud.test.ts +29 -0
- package/src/sources/gloomberb-cloud.ts +89 -1
- package/src/sources/provider-router.test.ts +308 -3
- package/src/sources/provider-router.ts +247 -17
- package/src/sources/yahoo-finance.test.ts +26 -0
- package/src/sources/yahoo-finance.ts +54 -3
- package/src/state/app-context-selector.test.tsx +99 -0
- package/src/state/app-context.test.ts +18 -0
- package/src/state/app-context.tsx +170 -65
- package/src/state/selectors.ts +25 -0
- package/src/theme/colors.ts +8 -8
- package/src/theme/themes.test.ts +2 -0
- package/src/theme/themes.ts +22 -10
- package/src/types/broker.ts +21 -0
- package/src/types/config.ts +17 -1
- package/src/types/data-provider.ts +18 -0
- package/src/types/financials.ts +31 -1
- package/src/types/plugin.ts +70 -0
- package/src/utils/api-client.test.ts +57 -0
- package/src/utils/api-client.ts +35 -12
- package/src/utils/back-navigation.ts +27 -0
- package/src/utils/format.test.ts +14 -0
- package/src/utils/format.ts +3 -3
- package/src/utils/market-status.ts +46 -1
- package/src/utils/price-history.test.ts +25 -0
- package/src/utils/price-history.ts +29 -5
- package/src/utils/quote-freshness.ts +127 -0
- package/src/utils/quote-resolution.test.ts +277 -0
- package/src/utils/quote-resolution.ts +641 -0
- package/src/utils/slugify.ts +3 -0
- package/src/utils/timestamp.ts +25 -0
- package/src/version.ts +1 -1
- package/src/cli/commands/portfolio.ts +0 -210
- package/src/cli/commands/watchlist.ts +0 -210
- package/src/plugins/builtin/data-providers.ts +0 -16
- package/src/sources/exchange-rates.ts +0 -18
- package/src/utils/ascii-chart.ts +0 -172
- package/src/utils/ticker-tokenizer.test.ts +0 -48
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type AppConfig,
|
|
8
8
|
type SavedLayout,
|
|
9
9
|
} from "../../types/config";
|
|
10
|
-
import type { PaneDef } from "../../types/plugin";
|
|
10
|
+
import type { CliLaunchRequest, PaneDef } from "../../types/plugin";
|
|
11
11
|
import type { AppSessionSnapshot } from "../../state/session-persistence";
|
|
12
12
|
import { PREDICTION_CATEGORY_OPTIONS, type PredictionCategoryId } from "./categories";
|
|
13
13
|
import { BROWSE_TABS } from "./navigation";
|
|
@@ -48,20 +48,7 @@ function normalizeArg(value: string): string {
|
|
|
48
48
|
return value.trim().toLowerCase();
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export function
|
|
52
|
-
args: string[],
|
|
53
|
-
): PredictionLaunchIntent | null {
|
|
54
|
-
const [command, ...rest] = args;
|
|
55
|
-
if (!command) return null;
|
|
56
|
-
const normalizedCommand = normalizeArg(command);
|
|
57
|
-
if (
|
|
58
|
-
normalizedCommand !== "predictions" &&
|
|
59
|
-
normalizedCommand !== "prediction-markets" &&
|
|
60
|
-
normalizedCommand !== "pm"
|
|
61
|
-
) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
51
|
+
export function parsePredictionCommandArgs(args: string[]): PredictionLaunchIntent {
|
|
65
52
|
let venueScope: PredictionVenueScope = "all";
|
|
66
53
|
let categoryId: PredictionCategoryId = "all";
|
|
67
54
|
let browseTab: PredictionBrowseTab = "top";
|
|
@@ -70,7 +57,7 @@ export function parsePredictionLaunchArgs(
|
|
|
70
57
|
let browseExplicit = false;
|
|
71
58
|
const searchTokens: string[] = [];
|
|
72
59
|
|
|
73
|
-
for (const arg of
|
|
60
|
+
for (const arg of args) {
|
|
74
61
|
const normalized = normalizeArg(arg);
|
|
75
62
|
if (!normalized) continue;
|
|
76
63
|
|
|
@@ -100,6 +87,23 @@ export function parsePredictionLaunchArgs(
|
|
|
100
87
|
};
|
|
101
88
|
}
|
|
102
89
|
|
|
90
|
+
export function parsePredictionLaunchArgs(
|
|
91
|
+
args: string[],
|
|
92
|
+
): PredictionLaunchIntent | null {
|
|
93
|
+
const [command, ...rest] = args;
|
|
94
|
+
if (!command) return null;
|
|
95
|
+
const normalizedCommand = normalizeArg(command);
|
|
96
|
+
if (
|
|
97
|
+
normalizedCommand !== "predictions" &&
|
|
98
|
+
normalizedCommand !== "prediction-markets" &&
|
|
99
|
+
normalizedCommand !== "pm"
|
|
100
|
+
) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return parsePredictionCommandArgs(rest);
|
|
105
|
+
}
|
|
106
|
+
|
|
103
107
|
function syncActiveLayout(
|
|
104
108
|
layouts: SavedLayout[],
|
|
105
109
|
activeLayoutIndex: number,
|
|
@@ -238,3 +242,34 @@ export function applyPredictionLaunchIntentToSessionSnapshot(
|
|
|
238
242
|
savedAt: Date.now(),
|
|
239
243
|
};
|
|
240
244
|
}
|
|
245
|
+
|
|
246
|
+
export function createPredictionLaunchRequest(
|
|
247
|
+
intent: PredictionLaunchIntent,
|
|
248
|
+
): CliLaunchRequest<{ paneInstanceId: string; intent: PredictionLaunchIntent }> {
|
|
249
|
+
return {
|
|
250
|
+
applyConfig(config, env) {
|
|
251
|
+
const result = applyPredictionLaunchIntentToConfig(config, intent, {
|
|
252
|
+
width: Math.max(env.terminalWidth, 120),
|
|
253
|
+
height: Math.max(env.terminalHeight, 40),
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
config: result.config,
|
|
257
|
+
launchState: {
|
|
258
|
+
paneInstanceId: result.paneInstanceId,
|
|
259
|
+
intent,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
},
|
|
263
|
+
applySessionSnapshot(config, snapshot, launchState) {
|
|
264
|
+
if (!launchState) {
|
|
265
|
+
return applyPredictionLaunchIntentToSessionSnapshot(config, snapshot, PREDICTION_MAIN_INSTANCE_ID, intent);
|
|
266
|
+
}
|
|
267
|
+
return applyPredictionLaunchIntentToSessionSnapshot(
|
|
268
|
+
config,
|
|
269
|
+
snapshot,
|
|
270
|
+
launchState.paneInstanceId,
|
|
271
|
+
launchState.intent,
|
|
272
|
+
);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
@@ -170,13 +170,17 @@ export function getNextPredictionSort(
|
|
|
170
170
|
current: PredictionSortPreference,
|
|
171
171
|
columnId: string,
|
|
172
172
|
): PredictionSortPreference {
|
|
173
|
+
const initialDirection =
|
|
174
|
+
columnId === "ends" || TEXT_SORT_COLUMNS.has(columnId) ? "asc" : "desc";
|
|
175
|
+
const alternateDirection = initialDirection === "asc" ? "desc" : "asc";
|
|
176
|
+
|
|
173
177
|
if (current.columnId !== columnId) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
return { columnId, direction: initialDirection };
|
|
179
|
+
}
|
|
180
|
+
if (current.direction === initialDirection) {
|
|
181
|
+
return { columnId, direction: alternateDirection };
|
|
177
182
|
}
|
|
178
|
-
|
|
179
|
-
return { columnId: null, direction: "desc" };
|
|
183
|
+
return { columnId: null, direction: initialDirection };
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
export function filterPredictionMarkets(
|
|
@@ -83,14 +83,15 @@ describe("prediction markets pane interactions", () => {
|
|
|
83
83
|
expect(frame).toContain("Will the Fed cut rates?");
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
test("
|
|
86
|
+
test("selects a market on single click and opens detail on double click", async () => {
|
|
87
87
|
installPredictionMarketMocks();
|
|
88
88
|
|
|
89
89
|
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
90
90
|
await flushFrames(testSetup);
|
|
91
91
|
|
|
92
92
|
let frame = testSetup.captureCharFrame();
|
|
93
|
-
expect(frame).toContain("
|
|
93
|
+
expect(frame).toContain("All venues");
|
|
94
|
+
expect(frame).not.toContain("VOL = native venue units");
|
|
94
95
|
expect(frame).toContain("Will inflation fall?");
|
|
95
96
|
expect(frame).toContain("Kalshi");
|
|
96
97
|
|
|
@@ -114,10 +115,60 @@ describe("prediction markets pane interactions", () => {
|
|
|
114
115
|
|
|
115
116
|
frame = testSetup.captureCharFrame();
|
|
116
117
|
expect(frame).toContain("Will the Fed cut rates?");
|
|
118
|
+
expect(frame).not.toContain("Kalshi primary rule");
|
|
119
|
+
|
|
120
|
+
await act(async () => {
|
|
121
|
+
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
122
|
+
await testSetup!.renderOnce();
|
|
123
|
+
});
|
|
124
|
+
await flushFrames(testSetup);
|
|
125
|
+
|
|
126
|
+
frame = testSetup.captureCharFrame();
|
|
117
127
|
expect(frame).toContain("Kalshi primary rule");
|
|
118
128
|
});
|
|
119
129
|
|
|
120
|
-
test("
|
|
130
|
+
test("loads selected detail once instead of refetching in a render loop", async () => {
|
|
131
|
+
const { fetchUrls } = installPredictionMarketMocks();
|
|
132
|
+
|
|
133
|
+
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
134
|
+
await flushFrames(testSetup);
|
|
135
|
+
|
|
136
|
+
const frame = testSetup.captureCharFrame();
|
|
137
|
+
const lines = frame.split("\n");
|
|
138
|
+
const kalshiRow = lines.findIndex((line) =>
|
|
139
|
+
line.includes("Will the Fed cut rates?"),
|
|
140
|
+
);
|
|
141
|
+
const kalshiCol = lines[kalshiRow]?.indexOf("Will the Fed cut rates?") ?? -1;
|
|
142
|
+
|
|
143
|
+
await act(async () => {
|
|
144
|
+
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
145
|
+
await testSetup!.renderOnce();
|
|
146
|
+
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
147
|
+
await testSetup!.renderOnce();
|
|
148
|
+
});
|
|
149
|
+
await flushFrames(testSetup, 8);
|
|
150
|
+
|
|
151
|
+
const eventFetches = fetchUrls.filter((url) =>
|
|
152
|
+
url.includes("/trade-api/v2/events/FED-1"),
|
|
153
|
+
);
|
|
154
|
+
const orderbookFetches = fetchUrls.filter((url) =>
|
|
155
|
+
url.includes("/trade-api/v2/markets/KAL-1/orderbook"),
|
|
156
|
+
);
|
|
157
|
+
const tradeFetches = fetchUrls.filter((url) =>
|
|
158
|
+
url.includes("/trade-api/v2/markets/trades?ticker=KAL-1"),
|
|
159
|
+
);
|
|
160
|
+
const historyFetches = fetchUrls.filter((url) =>
|
|
161
|
+
url.includes("/trade-api/v2/series/FED/markets/KAL-1/candlesticks"),
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(eventFetches).toHaveLength(2);
|
|
165
|
+
expect(orderbookFetches).toHaveLength(1);
|
|
166
|
+
expect(tradeFetches).toHaveLength(1);
|
|
167
|
+
expect(historyFetches).toHaveLength(1);
|
|
168
|
+
expect(testSetup.captureCharFrame()).not.toContain("Loading market detail...");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("moves selection through the list with keyboard navigation without opening detail", async () => {
|
|
121
172
|
installPredictionMarketMocks();
|
|
122
173
|
|
|
123
174
|
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
@@ -136,6 +187,102 @@ describe("prediction markets pane interactions", () => {
|
|
|
136
187
|
|
|
137
188
|
const frame = testSetup.captureCharFrame();
|
|
138
189
|
expect(frame).toContain("Will the Fed cut rates?");
|
|
190
|
+
expect(frame).not.toContain("Kalshi primary rule");
|
|
191
|
+
expect(frame).not.toContain("<- Back");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("keeps a clicked header sort instead of snapping back to the default sort", async () => {
|
|
195
|
+
installPredictionMarketMocks();
|
|
196
|
+
|
|
197
|
+
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
198
|
+
await flushFrames(testSetup);
|
|
199
|
+
|
|
200
|
+
const frame = testSetup.captureCharFrame();
|
|
201
|
+
const lines = frame.split("\n");
|
|
202
|
+
const headerRow = lines.findIndex((line) => line.includes("VENUE"));
|
|
203
|
+
const headerCol = lines[headerRow]?.indexOf("VENUE") ?? -1;
|
|
204
|
+
|
|
205
|
+
expect(headerRow).toBeGreaterThan(-1);
|
|
206
|
+
expect(headerCol).toBeGreaterThan(-1);
|
|
207
|
+
|
|
208
|
+
await act(async () => {
|
|
209
|
+
await testSetup!.mockMouse.click(headerCol + 1, headerRow);
|
|
210
|
+
await testSetup!.renderOnce();
|
|
211
|
+
});
|
|
212
|
+
await flushFrames(testSetup, 4);
|
|
213
|
+
|
|
214
|
+
const nextFrame = testSetup.captureCharFrame();
|
|
215
|
+
const nextLines = nextFrame.split("\n");
|
|
216
|
+
const kalshiRow = nextLines.findIndex((line) =>
|
|
217
|
+
line.includes("Will the Fed cut rates?"),
|
|
218
|
+
);
|
|
219
|
+
const polymarketRow = nextLines.findIndex((line) =>
|
|
220
|
+
line.includes("Will inflation fall?"),
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
expect(
|
|
224
|
+
harnessStateRef.current?.paneState[TEST_PANE_ID]?.pluginState?.[
|
|
225
|
+
"prediction-markets"
|
|
226
|
+
]?.sortPreference,
|
|
227
|
+
).toEqual({ columnId: "venue", direction: "asc" });
|
|
228
|
+
expect(nextLines[headerRow]).toContain("VENUE ▲");
|
|
229
|
+
expect(kalshiRow).toBeGreaterThan(-1);
|
|
230
|
+
expect(polymarketRow).toBeGreaterThan(-1);
|
|
231
|
+
expect(kalshiRow).toBeLessThan(polymarketRow);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("cycles the ends header through reverse date order before resetting", async () => {
|
|
235
|
+
installPredictionMarketMocks();
|
|
236
|
+
|
|
237
|
+
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
238
|
+
await flushFrames(testSetup);
|
|
239
|
+
|
|
240
|
+
const frame = testSetup.captureCharFrame();
|
|
241
|
+
const lines = frame.split("\n");
|
|
242
|
+
const headerRow = lines.findIndex((line) => line.includes("ENDS"));
|
|
243
|
+
const headerCol = lines[headerRow]?.indexOf("ENDS") ?? -1;
|
|
244
|
+
|
|
245
|
+
expect(headerRow).toBeGreaterThan(-1);
|
|
246
|
+
expect(headerCol).toBeGreaterThan(-1);
|
|
247
|
+
|
|
248
|
+
await act(async () => {
|
|
249
|
+
await testSetup!.mockMouse.click(headerCol + 1, headerRow);
|
|
250
|
+
await testSetup!.renderOnce();
|
|
251
|
+
});
|
|
252
|
+
await flushFrames(testSetup, 2);
|
|
253
|
+
|
|
254
|
+
const sortedFrame = testSetup.captureCharFrame();
|
|
255
|
+
const sortedLines = sortedFrame.split("\n");
|
|
256
|
+
const sortedHeaderRow = sortedLines.findIndex((line) => line.includes("ENDS"));
|
|
257
|
+
const sortedHeaderCol = sortedLines[sortedHeaderRow]?.indexOf("ENDS") ?? -1;
|
|
258
|
+
|
|
259
|
+
expect(sortedHeaderRow).toBeGreaterThan(-1);
|
|
260
|
+
expect(sortedHeaderCol).toBeGreaterThan(-1);
|
|
261
|
+
|
|
262
|
+
await act(async () => {
|
|
263
|
+
await testSetup!.mockMouse.click(sortedHeaderCol + 1, sortedHeaderRow);
|
|
264
|
+
await testSetup!.renderOnce();
|
|
265
|
+
});
|
|
266
|
+
await flushFrames(testSetup, 4);
|
|
267
|
+
|
|
268
|
+
const nextFrame = testSetup.captureCharFrame();
|
|
269
|
+
const nextLines = nextFrame.split("\n");
|
|
270
|
+
const kalshiRow = nextLines.findIndex((line) =>
|
|
271
|
+
line.includes("Will the Fed cut rates?"),
|
|
272
|
+
);
|
|
273
|
+
const polymarketRow = nextLines.findIndex((line) =>
|
|
274
|
+
line.includes("Will inflation fall?"),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
expect(
|
|
278
|
+
harnessStateRef.current?.paneState[TEST_PANE_ID]?.pluginState?.[
|
|
279
|
+
"prediction-markets"
|
|
280
|
+
]?.sortPreference,
|
|
281
|
+
).toEqual({ columnId: "ends", direction: "desc" });
|
|
282
|
+
expect(nextLines[headerRow]).toContain("ENDS ▼");
|
|
283
|
+
expect(kalshiRow).toBeGreaterThan(-1);
|
|
284
|
+
expect(polymarketRow).toBeGreaterThan(-1);
|
|
285
|
+
expect(kalshiRow).toBeLessThan(polymarketRow);
|
|
139
286
|
});
|
|
140
287
|
|
|
141
288
|
test("does not wrap to the last row when moving up without a selection", async () => {
|
|
@@ -157,7 +304,7 @@ describe("prediction markets pane interactions", () => {
|
|
|
157
304
|
).toBe("polymarket:pm-1");
|
|
158
305
|
});
|
|
159
306
|
|
|
160
|
-
test("supports detail outcome navigation and
|
|
307
|
+
test("supports detail outcome navigation and backspace return from the keyboard", async () => {
|
|
161
308
|
attachPredictionMarketsPersistence(new MemoryPersistence());
|
|
162
309
|
|
|
163
310
|
globalThis.fetch = (async (input: Request | string | URL) => {
|
|
@@ -286,17 +433,15 @@ describe("prediction markets pane interactions", () => {
|
|
|
286
433
|
]?.selectedDetailMarketKey,
|
|
287
434
|
).toBe("kalshi:KXFED-27APR-T4.50");
|
|
288
435
|
|
|
289
|
-
await emitKeypress(testSetup, { name: "
|
|
436
|
+
await emitKeypress(testSetup, { name: "backspace", sequence: "\u007f" });
|
|
290
437
|
await flushFrames(testSetup);
|
|
291
438
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
]?.focusRegion,
|
|
296
|
-
).toBe("list");
|
|
439
|
+
const frame = testSetup.captureCharFrame();
|
|
440
|
+
expect(frame).toContain("search markets");
|
|
441
|
+
expect(frame).not.toContain("Rule 2");
|
|
297
442
|
});
|
|
298
443
|
|
|
299
|
-
test("
|
|
444
|
+
test("opens full-page detail from a row double click and preserves the browse selection", async () => {
|
|
300
445
|
installPredictionMarketMocks();
|
|
301
446
|
|
|
302
447
|
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
@@ -312,62 +457,19 @@ describe("prediction markets pane interactions", () => {
|
|
|
312
457
|
await act(async () => {
|
|
313
458
|
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
314
459
|
await testSetup!.renderOnce();
|
|
315
|
-
});
|
|
316
|
-
await flushFrames(testSetup);
|
|
317
|
-
|
|
318
|
-
await act(async () => {
|
|
319
460
|
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
320
461
|
await testSetup!.renderOnce();
|
|
321
462
|
});
|
|
322
463
|
await flushFrames(testSetup);
|
|
323
464
|
|
|
465
|
+
const detailFrame = testSetup.captureCharFrame();
|
|
466
|
+
expect(detailFrame).toContain("<- Back");
|
|
467
|
+
expect(detailFrame).toContain("Kalshi primary rule");
|
|
324
468
|
expect(
|
|
325
469
|
harnessStateRef.current?.paneState[TEST_PANE_ID]?.pluginState?.[
|
|
326
470
|
"prediction-markets"
|
|
327
471
|
]?.selectedRowKey,
|
|
328
|
-
).
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
test("resizes the list/detail split by dragging the divider", async () => {
|
|
332
|
-
installPredictionMarketMocks();
|
|
333
|
-
|
|
334
|
-
testSetup = await testRender(<Harness />, { width: 120, height: 34 });
|
|
335
|
-
await flushFrames(testSetup);
|
|
336
|
-
|
|
337
|
-
let frame = testSetup.captureCharFrame();
|
|
338
|
-
const lines = frame.split("\n");
|
|
339
|
-
const kalshiRow = lines.findIndex((line) =>
|
|
340
|
-
line.includes("Will the Fed cut rates?"),
|
|
341
|
-
);
|
|
342
|
-
const kalshiCol = lines[kalshiRow]?.indexOf("Will the Fed cut rates?") ?? -1;
|
|
343
|
-
|
|
344
|
-
await act(async () => {
|
|
345
|
-
await testSetup!.mockMouse.click(kalshiCol + 1, kalshiRow);
|
|
346
|
-
await testSetup!.renderOnce();
|
|
347
|
-
});
|
|
348
|
-
await flushFrames(testSetup);
|
|
349
|
-
|
|
350
|
-
frame = testSetup.captureCharFrame();
|
|
351
|
-
const dividerLines = frame.split("\n");
|
|
352
|
-
const dividerRow = dividerLines.findIndex((line) => line.includes("│"));
|
|
353
|
-
const dividerCol = dividerLines[dividerRow]?.indexOf("│") ?? -1;
|
|
354
|
-
|
|
355
|
-
await act(async () => {
|
|
356
|
-
await testSetup!.mockMouse.drag(
|
|
357
|
-
dividerCol,
|
|
358
|
-
dividerRow,
|
|
359
|
-
dividerCol + 10,
|
|
360
|
-
dividerRow,
|
|
361
|
-
);
|
|
362
|
-
await testSetup!.renderOnce();
|
|
363
|
-
});
|
|
364
|
-
await flushFrames(testSetup);
|
|
365
|
-
|
|
366
|
-
expect(
|
|
367
|
-
harnessStateRef.current?.paneState[TEST_PANE_ID]?.pluginState?.[
|
|
368
|
-
"prediction-markets"
|
|
369
|
-
]?.detailSplitRatio,
|
|
370
|
-
).toBeGreaterThan(0.42);
|
|
472
|
+
).toBe("kalshi:KAL-1");
|
|
371
473
|
});
|
|
372
474
|
|
|
373
475
|
test("switches categories with arrows and venues with shift+arrows", async () => {
|