gloomberb 0.7.2 → 0.7.4
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 +158 -47
- package/src/components/chart/chart-types.ts +20 -2
- package/src/components/chart/chart.test.ts +179 -13
- package/src/components/chart/comparison-chart-renderer.test.ts +14 -30
- package/src/components/chart/comparison-chart-renderer.ts +50 -11
- package/src/components/chart/comparison-stock-chart.tsx +129 -129
- package/src/components/chart/market-session.ts +187 -0
- package/src/components/chart/native/chart-rasterizer.ts +108 -19
- package/src/components/chart/price-axis-labels.tsx +25 -9
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +97 -1
- package/src/components/chart/stock-chart.tsx +95 -49
- package/src/components/chart/time-axis-label.tsx +56 -2
- package/src/components/command-bar/command-bar.test.tsx +446 -120
- package/src/components/command-bar/command-bar.tsx +535 -384
- package/src/components/command-bar/command-registry.ts +16 -6
- package/src/components/command-bar/list-model.ts +8 -4
- package/src/components/command-bar/root-shortcuts.ts +4 -5
- package/src/components/command-bar/view-model.test.ts +21 -0
- package/src/components/command-bar/view-model.ts +17 -4
- 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 +15 -66
- 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/core/state/session-persistence.ts +25 -0
- 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-subscriptions.test.ts +102 -18
- package/src/market-data/coordinator.test.ts +122 -2
- package/src/market-data/coordinator.ts +200 -56
- package/src/market-data/hooks.test.tsx +31 -0
- package/src/market-data/hooks.tsx +1 -0
- 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/screener-pane.tsx +3 -0
- 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 +263 -48
- package/src/plugins/builtin/chat.test.tsx +312 -6
- package/src/plugins/builtin/chat.tsx +245 -66
- 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/market-movers/index.tsx +72 -40
- package/src/plugins/builtin/news-wire/breaking-pane.test.tsx +156 -0
- package/src/plugins/builtin/news-wire/breaking-pane.tsx +0 -90
- package/src/plugins/builtin/news-wire/index.tsx +1 -3
- 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 +13 -2
- package/src/plugins/builtin/portfolio-list/mutations.ts +17 -0
- package/src/plugins/builtin/portfolio-list/pane.tsx +139 -23
- 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 +311 -9
- package/src/plugins/builtin/quote-monitor.test.tsx +158 -25
- package/src/plugins/builtin/sectors/index.tsx +275 -43
- 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 +18 -7
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +445 -63
- package/src/plugins/builtin/ticker-detail/settings.ts +84 -3
- package/src/plugins/builtin/ticker-detail.test.tsx +2 -2
- package/src/plugins/builtin/world-indices/index.tsx +58 -19
- 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/sources/gloomberb-cloud.test.ts +55 -2
- package/src/sources/gloomberb-cloud.ts +180 -29
- package/src/sources/provider-router.test.ts +567 -10
- package/src/sources/provider-router.ts +323 -93
- package/src/sources/yahoo-finance.test.ts +37 -0
- package/src/sources/yahoo-finance.ts +48 -2
- package/src/state/app-bootstrap.test.ts +50 -23
- package/src/state/app-bootstrap.ts +29 -13
- package/src/state/app-context.test.ts +113 -0
- package/src/state/app-context.tsx +8 -4
- package/src/state/session-persistence.test.ts +5 -3
- package/src/state/use-inline-tickers.ts +3 -0
- package/src/state/use-quote-streaming.ts +11 -0
- package/src/theme/colors.ts +13 -14
- package/src/types/config.ts +9 -4
- package/src/types/data-provider.ts +5 -1
- package/src/types/financials.ts +1 -0
- package/src/types/plugin.ts +8 -1
- package/src/ui/context-menu.tsx +4 -4
- package/src/utils/api-client.test.ts +248 -0
- package/src/utils/api-client.ts +178 -26
- package/src/utils/exchanges.test.ts +16 -0
- package/src/utils/exchanges.ts +33 -0
- package/src/utils/fuzzy-search.ts +12 -1
- package/src/utils/keyboard.ts +31 -0
- package/src/utils/options.ts +1 -1
- package/src/utils/price-history.test.ts +28 -1
- package/src/utils/price-history.ts +16 -0
- package/src/utils/quote-freshness.test.ts +150 -0
- package/src/utils/quote-freshness.ts +42 -1
- package/src/utils/quote-resolution.ts +2 -0
- package/src/utils/quote-time.test.ts +34 -0
- package/src/utils/quote-time.ts +18 -5
- package/src/utils/ticker-search.test.ts +2 -2
- package/src/utils/ticker-search.ts +48 -1
- package/src/version.ts +1 -1
- package/src/plugins/builtin/news-wire/digest-store.ts +0 -44
|
@@ -2,8 +2,7 @@ import { Box, Input, ScrollBox, Text, Textarea, useUiCapabilities } from "../../
|
|
|
2
2
|
import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import type { RefObject } from "react";
|
|
4
4
|
import { TextAttributes, type InputRenderable, type ScrollBoxRenderable, type TextareaRenderable } from "../../ui";
|
|
5
|
-
import {
|
|
6
|
-
import { useViewport } from "../../react/input";
|
|
5
|
+
import { useShortcut, useViewport } from "../../react/input";
|
|
7
6
|
import { Button, NumberField, Spinner, TextField } from "../ui";
|
|
8
7
|
import { NativeSelect, openNativeSelect, type NativeSelectElement } from "../ui/native-select";
|
|
9
8
|
import { ToggleList } from "../toggle-list";
|
|
@@ -19,21 +18,25 @@ import {
|
|
|
19
18
|
commandBarSelectedText,
|
|
20
19
|
commandBarSubtleText,
|
|
21
20
|
commandBarText,
|
|
21
|
+
blendHex,
|
|
22
|
+
colors,
|
|
22
23
|
getCurrentThemeId,
|
|
23
24
|
previewTheme,
|
|
24
25
|
} from "../../theme/colors";
|
|
25
26
|
import {
|
|
26
27
|
getFocusedCollectionId,
|
|
28
|
+
syncConfigActiveLayoutState,
|
|
27
29
|
useAppDispatch,
|
|
28
30
|
useAppSelector,
|
|
29
31
|
useFocusedTicker,
|
|
30
32
|
type AppState,
|
|
31
33
|
} from "../../state/app-context";
|
|
34
|
+
import { scheduleConfigSave } from "../../state/config-save-scheduler";
|
|
32
35
|
import { fuzzyFilter } from "../../utils/fuzzy-search";
|
|
33
36
|
import { commands, matchPrefix, type Command } from "./command-registry";
|
|
34
37
|
import { useThemeColors } from "../../theme/theme-context";
|
|
35
38
|
import { ThemePicker, type ThemePickerHandle } from "./theme-picker";
|
|
36
|
-
import { exportConfig, importConfig, resetAllData
|
|
39
|
+
import { exportConfig, importConfig, resetAllData } from "../../data/config-store";
|
|
37
40
|
import type { DataProvider } from "../../types/data-provider";
|
|
38
41
|
import type { TickerRepository } from "../../data/ticker-repository";
|
|
39
42
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
@@ -185,6 +188,37 @@ const NATIVE_COMMAND_BAR_PADDING_X_PX = 14;
|
|
|
185
188
|
const NATIVE_COMMAND_BAR_PADDING_Y_PX = 14;
|
|
186
189
|
const QUICK_LOOK_TICKER_SEARCH_OPTIONS = { includeOptionContracts: false } as const;
|
|
187
190
|
|
|
191
|
+
function normalizeCommandTickerSearchText(value: string): string {
|
|
192
|
+
return value.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function isLikelyPlainTickerSearch(query: string): boolean {
|
|
196
|
+
const trimmed = query.trim();
|
|
197
|
+
if (!trimmed || /\s/.test(trimmed)) return false;
|
|
198
|
+
if (!/^[A-Za-z0-9.^=\-/]+$/.test(trimmed)) return false;
|
|
199
|
+
|
|
200
|
+
const compact = normalizeCommandTickerSearchText(trimmed);
|
|
201
|
+
if (compact.length < 2) return false;
|
|
202
|
+
if (compact.length <= 6) return true;
|
|
203
|
+
return /[.^=\-/]/.test(trimmed) && compact.length <= 10;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function isExactTickerResultMatch(item: ResultItem, query: string): boolean {
|
|
207
|
+
if (item.kind !== "ticker" && item.kind !== "search") return false;
|
|
208
|
+
const normalizedQuery = normalizeCommandTickerSearchText(query);
|
|
209
|
+
if (!normalizedQuery) return false;
|
|
210
|
+
return normalizeCommandTickerSearchText(item.label) === normalizedQuery;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getPaneTemplateArgKind(template: PaneTemplateDef): string | undefined {
|
|
214
|
+
return template.shortcut?.argKind ?? template.shortcut?.argPlaceholder;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function canPromptForPaneTemplateArg(template: PaneTemplateDef): boolean {
|
|
218
|
+
const argKind = getPaneTemplateArgKind(template);
|
|
219
|
+
return argKind === "ticker" || argKind === "ticker-list" || argKind === "tickers";
|
|
220
|
+
}
|
|
221
|
+
|
|
188
222
|
function getDefaultConfigBackupPath(): string {
|
|
189
223
|
const home = typeof process !== "undefined" ? process.env.HOME : undefined;
|
|
190
224
|
return `${home || "~"}/gloomberb-config-backup.json`;
|
|
@@ -563,9 +597,10 @@ const CommandBarListBody = memo(function CommandBarListBody({
|
|
|
563
597
|
|
|
564
598
|
const isSelected = row.globalIdx === visibleListState.selectedIdx;
|
|
565
599
|
const isHovered = row.globalIdx === visibleListState.hoveredIdx && !isSelected;
|
|
600
|
+
const itemRowKey = `item:${row.globalIdx}:${row.item.id}:${row.item.category}:${row.item.label}:${row.item.right || ""}`;
|
|
566
601
|
return (
|
|
567
602
|
<CommandBarListItemRow
|
|
568
|
-
key={
|
|
603
|
+
key={itemRowKey}
|
|
569
604
|
item={row.item}
|
|
570
605
|
globalIdx={row.globalIdx}
|
|
571
606
|
isSelected={isSelected}
|
|
@@ -618,6 +653,7 @@ export function CommandBar({
|
|
|
618
653
|
const tickers = useAppSelector((state) => state.tickers);
|
|
619
654
|
const financials = useAppSelector((state) => state.financials);
|
|
620
655
|
const focusedPaneId = useAppSelector((state) => state.focusedPaneId);
|
|
656
|
+
const activePanel = useAppSelector((state) => state.activePanel);
|
|
621
657
|
const layoutHistory = useAppSelector((state) => state.layoutHistory);
|
|
622
658
|
const recentTickers = useAppSelector((state) => state.recentTickers);
|
|
623
659
|
const commandBarOpen = useAppSelector((state) => state.commandBarOpen);
|
|
@@ -633,6 +669,7 @@ export function CommandBar({
|
|
|
633
669
|
tickers,
|
|
634
670
|
financials,
|
|
635
671
|
focusedPaneId,
|
|
672
|
+
activePanel,
|
|
636
673
|
layoutHistory,
|
|
637
674
|
recentTickers,
|
|
638
675
|
commandBarOpen,
|
|
@@ -643,6 +680,7 @@ export function CommandBar({
|
|
|
643
680
|
updateCheckInProgress,
|
|
644
681
|
updateNotice,
|
|
645
682
|
}) as AppState, [
|
|
683
|
+
activePanel,
|
|
646
684
|
commandBarLaunchRequest,
|
|
647
685
|
commandBarOpen,
|
|
648
686
|
commandBarQuery,
|
|
@@ -660,8 +698,16 @@ export function CommandBar({
|
|
|
660
698
|
]);
|
|
661
699
|
const stateRef = useRef(state);
|
|
662
700
|
stateRef.current = state;
|
|
701
|
+
const persistConfig = useCallback((nextConfig: AppState["config"]) => {
|
|
702
|
+
const currentState = stateRef.current;
|
|
703
|
+
scheduleConfigSave(syncConfigActiveLayoutState(
|
|
704
|
+
nextConfig,
|
|
705
|
+
currentState.paneState,
|
|
706
|
+
currentState.focusedPaneId,
|
|
707
|
+
currentState.activePanel,
|
|
708
|
+
));
|
|
709
|
+
}, []);
|
|
663
710
|
const { symbol: activeTickerSymbol, ticker: activeTickerData, financials: activeFinancials } = useFocusedTicker();
|
|
664
|
-
const renderer = useNativeRenderer();
|
|
665
711
|
const { width: termWidth, height: termHeight } = useViewport();
|
|
666
712
|
const { nativePaneChrome, cellWidthPx = 8, cellHeightPx = 18 } = useUiCapabilities();
|
|
667
713
|
const availableCommands = useMemo(
|
|
@@ -833,20 +879,16 @@ export function CommandBar({
|
|
|
833
879
|
: instance
|
|
834
880
|
)),
|
|
835
881
|
};
|
|
836
|
-
const nextConfig = {
|
|
837
|
-
...currentState.config,
|
|
838
|
-
layout: nextLayout,
|
|
839
|
-
layouts: currentState.config.layouts.map((savedLayout, index) => (
|
|
840
|
-
index === currentState.config.activeLayoutIndex ? { ...savedLayout, layout: nextLayout } : savedLayout
|
|
841
|
-
)),
|
|
842
|
-
};
|
|
843
882
|
dispatch({ type: "UPDATE_LAYOUT", layout: nextLayout });
|
|
844
|
-
void saveConfig(nextConfig);
|
|
845
883
|
dispatch({ type: "FOCUS_PANE", paneId: targetPane.instanceId });
|
|
846
884
|
}, [dispatch]);
|
|
847
885
|
|
|
848
|
-
const openFixedTickerPane = useCallback((symbol: string) => {
|
|
849
|
-
pluginRegistry.pinTicker(symbol, {
|
|
886
|
+
const openFixedTickerPane = useCallback((symbol: string, options?: { forceNewPane?: boolean }) => {
|
|
887
|
+
pluginRegistry.pinTicker(symbol, {
|
|
888
|
+
floating: true,
|
|
889
|
+
paneType: "ticker-detail",
|
|
890
|
+
forceNewPane: options?.forceNewPane,
|
|
891
|
+
});
|
|
850
892
|
}, [pluginRegistry]);
|
|
851
893
|
|
|
852
894
|
const commitTheme = useCallback((themeId: string) => {
|
|
@@ -872,7 +914,7 @@ export function CommandBar({
|
|
|
872
914
|
? findPaneInstance(currentState.config.layout, currentState.focusedPaneId)
|
|
873
915
|
: null;
|
|
874
916
|
if (options?.forceNewPane) {
|
|
875
|
-
openFixedTickerPane(symbol);
|
|
917
|
+
openFixedTickerPane(symbol, { forceNewPane: true });
|
|
876
918
|
return;
|
|
877
919
|
}
|
|
878
920
|
|
|
@@ -1165,9 +1207,9 @@ export function CommandBar({
|
|
|
1165
1207
|
);
|
|
1166
1208
|
dispatch({ type: "SET_CONFIG", config: nextConfig });
|
|
1167
1209
|
setActiveCollection(portfolio.id);
|
|
1168
|
-
|
|
1210
|
+
persistConfig(nextConfig);
|
|
1169
1211
|
notify(`Created portfolio "${portfolio.name}".`, { type: "success" });
|
|
1170
|
-
}, [dispatch, notify, setActiveCollection]);
|
|
1212
|
+
}, [dispatch, notify, persistConfig, setActiveCollection]);
|
|
1171
1213
|
|
|
1172
1214
|
const createWatchlist = useCallback(async (name: string) => {
|
|
1173
1215
|
const currentState = stateRef.current;
|
|
@@ -1184,9 +1226,9 @@ export function CommandBar({
|
|
|
1184
1226
|
};
|
|
1185
1227
|
dispatch({ type: "SET_CONFIG", config: nextConfig });
|
|
1186
1228
|
setActiveCollection(id);
|
|
1187
|
-
|
|
1229
|
+
persistConfig(nextConfig);
|
|
1188
1230
|
notify(`Created watchlist "${trimmedName}".`, { type: "success" });
|
|
1189
|
-
}, [dispatch, notify, setActiveCollection]);
|
|
1231
|
+
}, [dispatch, notify, persistConfig, setActiveCollection]);
|
|
1190
1232
|
|
|
1191
1233
|
const deleteWatchlist = useCallback(async (watchlistId: string) => {
|
|
1192
1234
|
const currentState = stateRef.current;
|
|
@@ -1204,9 +1246,9 @@ export function CommandBar({
|
|
|
1204
1246
|
const fallback = nextConfig.portfolios[0]?.id || nextConfig.watchlists[0]?.id || "";
|
|
1205
1247
|
if (fallback) setActiveCollection(fallback);
|
|
1206
1248
|
}
|
|
1207
|
-
|
|
1249
|
+
persistConfig(nextConfig);
|
|
1208
1250
|
notify(`Deleted "${watchlist.name}".`, { type: "success" });
|
|
1209
|
-
}, [activeCollectionId, dispatch, notify, setActiveCollection]);
|
|
1251
|
+
}, [activeCollectionId, dispatch, notify, persistConfig, setActiveCollection]);
|
|
1210
1252
|
|
|
1211
1253
|
const deletePortfolio = useCallback(async (portfolioId: string) => {
|
|
1212
1254
|
const currentState = stateRef.current;
|
|
@@ -1234,9 +1276,9 @@ export function CommandBar({
|
|
|
1234
1276
|
const fallback = nextConfig.portfolios[0]?.id || nextConfig.watchlists[0]?.id || "";
|
|
1235
1277
|
if (fallback) setActiveCollection(fallback);
|
|
1236
1278
|
}
|
|
1237
|
-
|
|
1279
|
+
persistConfig(nextConfig);
|
|
1238
1280
|
notify(`Deleted "${portfolio.name}".`, { type: "success" });
|
|
1239
|
-
}, [activeCollectionId, dispatch, notify, setActiveCollection, tickerRepository]);
|
|
1281
|
+
}, [activeCollectionId, dispatch, notify, persistConfig, setActiveCollection, tickerRepository]);
|
|
1240
1282
|
|
|
1241
1283
|
const setPortfolioPositionFromWorkflow = useCallback(async (values: Record<string, CommandBarFieldValue>) => {
|
|
1242
1284
|
const currentState = stateRef.current;
|
|
@@ -1499,6 +1541,7 @@ export function CommandBar({
|
|
|
1499
1541
|
const enabled = !disabledPlugins.includes(plugin.id);
|
|
1500
1542
|
const toggleAction = () => {
|
|
1501
1543
|
dispatch({ type: "TOGGLE_PLUGIN", pluginId: plugin.id });
|
|
1544
|
+
const currentState = stateRef.current;
|
|
1502
1545
|
const nextDisabled = enabled
|
|
1503
1546
|
? [...disabledPlugins, plugin.id]
|
|
1504
1547
|
: disabledPlugins.filter((entry) => entry !== plugin.id);
|
|
@@ -1507,7 +1550,7 @@ export function CommandBar({
|
|
|
1507
1550
|
pluginRegistry.hidePane(paneId);
|
|
1508
1551
|
}
|
|
1509
1552
|
}
|
|
1510
|
-
|
|
1553
|
+
persistConfig({ ...currentState.config, disabledPlugins: nextDisabled });
|
|
1511
1554
|
};
|
|
1512
1555
|
return {
|
|
1513
1556
|
id: `plugin:${plugin.id}`,
|
|
@@ -1520,7 +1563,7 @@ export function CommandBar({
|
|
|
1520
1563
|
action: toggleAction,
|
|
1521
1564
|
};
|
|
1522
1565
|
});
|
|
1523
|
-
}, [dispatch, pluginRegistry, state.config]);
|
|
1566
|
+
}, [dispatch, persistConfig, pluginRegistry, state.config]);
|
|
1524
1567
|
|
|
1525
1568
|
const buildLayoutItems = useCallback((
|
|
1526
1569
|
query: string,
|
|
@@ -2164,6 +2207,94 @@ export function CommandBar({
|
|
|
2164
2207
|
}
|
|
2165
2208
|
}, []);
|
|
2166
2209
|
|
|
2210
|
+
const activatePaneSettingField = useCallback((
|
|
2211
|
+
paneId: string,
|
|
2212
|
+
field: PaneSettingField,
|
|
2213
|
+
currentValue: unknown,
|
|
2214
|
+
options?: { keepRouteOpen?: boolean },
|
|
2215
|
+
) => {
|
|
2216
|
+
const normalized = normalizePaneSettingField(paneId, field, currentValue);
|
|
2217
|
+
if (normalized.mode === "toggle") {
|
|
2218
|
+
if (options?.keepRouteOpen) {
|
|
2219
|
+
updateTopRoute((route) => route.kind === "pane-settings"
|
|
2220
|
+
? { ...route, pendingFieldKey: field.key, error: null }
|
|
2221
|
+
: route);
|
|
2222
|
+
}
|
|
2223
|
+
void pluginRegistry.applyPaneSettingValueFn(paneId, field, !normalized.value)
|
|
2224
|
+
.then(() => {
|
|
2225
|
+
if (options?.keepRouteOpen) {
|
|
2226
|
+
updateTopRoute((route) => route.kind === "pane-settings"
|
|
2227
|
+
? { ...route, pendingFieldKey: null, error: null }
|
|
2228
|
+
: route);
|
|
2229
|
+
} else {
|
|
2230
|
+
closeAll({ revertThemePreview: false });
|
|
2231
|
+
}
|
|
2232
|
+
})
|
|
2233
|
+
.catch((error) => {
|
|
2234
|
+
if (options?.keepRouteOpen) {
|
|
2235
|
+
updateTopRoute((route) => route.kind === "pane-settings"
|
|
2236
|
+
? {
|
|
2237
|
+
...route,
|
|
2238
|
+
pendingFieldKey: null,
|
|
2239
|
+
error: error instanceof Error ? error.message : "Could not apply that setting.",
|
|
2240
|
+
}
|
|
2241
|
+
: route);
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
notify(error instanceof Error ? error.message : "Could not apply that setting.", { type: "error" });
|
|
2245
|
+
});
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (normalized.mode === "workflow" && normalized.route) {
|
|
2249
|
+
openWorkflowRoute(normalized.route);
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
if (normalized.mode === "picker") {
|
|
2253
|
+
openPickerRoute(normalized.route);
|
|
2254
|
+
}
|
|
2255
|
+
}, [
|
|
2256
|
+
closeAll,
|
|
2257
|
+
normalizePaneSettingField,
|
|
2258
|
+
notify,
|
|
2259
|
+
openPickerRoute,
|
|
2260
|
+
openWorkflowRoute,
|
|
2261
|
+
pluginRegistry,
|
|
2262
|
+
updateTopRoute,
|
|
2263
|
+
]);
|
|
2264
|
+
|
|
2265
|
+
const buildPaneSettingItems = useCallback((
|
|
2266
|
+
paneId: string | null,
|
|
2267
|
+
query: string,
|
|
2268
|
+
options?: { keepRouteOpen?: boolean },
|
|
2269
|
+
): ResultItem[] => {
|
|
2270
|
+
if (!paneId) return [];
|
|
2271
|
+
const descriptor = pluginRegistry.resolvePaneSettings(paneId);
|
|
2272
|
+
if (!descriptor) return [];
|
|
2273
|
+
|
|
2274
|
+
const category = descriptor.settingsDef.title || "Pane Settings";
|
|
2275
|
+
const paneLabel = descriptor.pane.title || descriptor.paneDef.name || descriptor.pane.paneId;
|
|
2276
|
+
const items = descriptor.settingsDef.fields.map((field): ResultItem => {
|
|
2277
|
+
const currentValue = descriptor.context.settings[field.key];
|
|
2278
|
+
return {
|
|
2279
|
+
id: `pane-setting:${field.key}`,
|
|
2280
|
+
label: field.label,
|
|
2281
|
+
detail: summarizePaneSettingValue(field, currentValue),
|
|
2282
|
+
category,
|
|
2283
|
+
kind: "action",
|
|
2284
|
+
right: field.type,
|
|
2285
|
+
searchText: `${category} ${paneLabel} ${field.label} ${field.description || ""} ${field.type}`,
|
|
2286
|
+
action: () => activatePaneSettingField(descriptor.paneId, field, currentValue, options),
|
|
2287
|
+
};
|
|
2288
|
+
});
|
|
2289
|
+
|
|
2290
|
+
return query
|
|
2291
|
+
? fuzzyFilter(items, query, (item) => `${item.label} ${item.detail} ${item.right || ""} ${item.searchText || ""}`)
|
|
2292
|
+
: items;
|
|
2293
|
+
}, [
|
|
2294
|
+
activatePaneSettingField,
|
|
2295
|
+
pluginRegistry,
|
|
2296
|
+
]);
|
|
2297
|
+
|
|
2167
2298
|
function readWorkflowTextareaValue(fieldId: string, fallback = ""): string {
|
|
2168
2299
|
const ref = getInputRef(workflowInputRefs.current, fieldId).current;
|
|
2169
2300
|
const nextValue = (ref as TextareaRenderable | null)?.editBuffer?.getText?.();
|
|
@@ -2446,7 +2577,7 @@ export function CommandBar({
|
|
|
2446
2577
|
const argPlaceholder = template.shortcut?.argPlaceholder;
|
|
2447
2578
|
return template.wizard.some((step) => step.type === "textarea" || step.key !== argPlaceholder);
|
|
2448
2579
|
}
|
|
2449
|
-
if (template
|
|
2580
|
+
if (canPromptForPaneTemplateArg(template)) {
|
|
2450
2581
|
return !arg?.trim();
|
|
2451
2582
|
}
|
|
2452
2583
|
return false;
|
|
@@ -2632,6 +2763,57 @@ export function CommandBar({
|
|
|
2632
2763
|
}]
|
|
2633
2764
|
), [mapTickerSearchCandidateToResultItem]);
|
|
2634
2765
|
|
|
2766
|
+
const mergeTickerSearchResultItems = useCallback((
|
|
2767
|
+
query: string,
|
|
2768
|
+
preferredItems: ResultItem[],
|
|
2769
|
+
fallbackItems: ResultItem[],
|
|
2770
|
+
): ResultItem[] => {
|
|
2771
|
+
const merged: ResultItem[] = [];
|
|
2772
|
+
const seen = new Set<string>();
|
|
2773
|
+
const addItem = (item: ResultItem) => {
|
|
2774
|
+
if (item.kind === "info") return;
|
|
2775
|
+
const key = `${item.label.trim().toUpperCase()}:${(item.right || "").trim().toUpperCase()}`;
|
|
2776
|
+
if (seen.has(key)) return;
|
|
2777
|
+
seen.add(key);
|
|
2778
|
+
merged.push(item);
|
|
2779
|
+
};
|
|
2780
|
+
preferredItems.forEach(addItem);
|
|
2781
|
+
fallbackItems.forEach(addItem);
|
|
2782
|
+
if (merged.length === 0) return fallbackItems;
|
|
2783
|
+
|
|
2784
|
+
return rankTickerSearchItems(merged, query)
|
|
2785
|
+
.map((item) => isExactTickerResultMatch(item, query) && item.category !== "Saved"
|
|
2786
|
+
? { ...item, category: "Exact Match" }
|
|
2787
|
+
: item);
|
|
2788
|
+
}, []);
|
|
2789
|
+
|
|
2790
|
+
const mergePlainRootTickerResults = useCallback((
|
|
2791
|
+
query: string,
|
|
2792
|
+
providerItems: ResultItem[],
|
|
2793
|
+
rootItems: ResultItem[],
|
|
2794
|
+
): ResultItem[] => {
|
|
2795
|
+
const merged: ResultItem[] = [];
|
|
2796
|
+
const seen = new Set<string>();
|
|
2797
|
+
const addItem = (item: ResultItem, options?: { skipInfo?: boolean }) => {
|
|
2798
|
+
if (options?.skipInfo && item.kind === "info") return;
|
|
2799
|
+
const key = (item.kind === "ticker" || item.kind === "search")
|
|
2800
|
+
? `${item.kind}:${item.label.trim().toUpperCase()}:${(item.right || "").trim().toUpperCase()}`
|
|
2801
|
+
: `${item.kind}:${item.id}`;
|
|
2802
|
+
if (seen.has(key)) return;
|
|
2803
|
+
seen.add(key);
|
|
2804
|
+
merged.push(item);
|
|
2805
|
+
};
|
|
2806
|
+
|
|
2807
|
+
providerItems
|
|
2808
|
+
.filter((item) => item.category === "Exact Match" || isExactTickerResultMatch(item, query))
|
|
2809
|
+
.forEach((item) => addItem(item, { skipInfo: true }));
|
|
2810
|
+
rootItems.forEach((item) => addItem(item));
|
|
2811
|
+
providerItems
|
|
2812
|
+
.filter((item) => item.category !== "Exact Match" && !isExactTickerResultMatch(item, query))
|
|
2813
|
+
.forEach((item) => addItem(item, { skipInfo: true }));
|
|
2814
|
+
return merged.length > 0 ? merged : rootItems;
|
|
2815
|
+
}, []);
|
|
2816
|
+
|
|
2635
2817
|
const buildTickerSearchCacheKey = useCallback((
|
|
2636
2818
|
query: string,
|
|
2637
2819
|
brokerId?: string | null,
|
|
@@ -2718,7 +2900,10 @@ export function CommandBar({
|
|
|
2718
2900
|
activeCollectionId,
|
|
2719
2901
|
}), [activeCollectionId, activeTickerSymbol, state.config, state.focusedPaneId]);
|
|
2720
2902
|
|
|
2721
|
-
const getAvailablePaneTemplates = useCallback((
|
|
2903
|
+
const getAvailablePaneTemplates = useCallback((
|
|
2904
|
+
options?: PaneTemplateCreateOptions,
|
|
2905
|
+
availability?: { includePromptableTickerTemplates?: boolean },
|
|
2906
|
+
): PaneTemplateDef[] => {
|
|
2722
2907
|
const disabledPlugins = new Set(state.config.disabledPlugins || []);
|
|
2723
2908
|
const context = getPaneTemplateContext();
|
|
2724
2909
|
return [...pluginRegistry.paneTemplates.values()]
|
|
@@ -2727,7 +2912,12 @@ export function CommandBar({
|
|
|
2727
2912
|
if (pluginId && disabledPlugins.has(pluginId)) return false;
|
|
2728
2913
|
if (!template.canCreate) return true;
|
|
2729
2914
|
try {
|
|
2730
|
-
|
|
2915
|
+
const canCreate = template.canCreate(context, options);
|
|
2916
|
+
if (canCreate) return true;
|
|
2917
|
+
return !!availability?.includePromptableTickerTemplates
|
|
2918
|
+
&& !options?.arg
|
|
2919
|
+
&& !context.activeTicker
|
|
2920
|
+
&& canPromptForPaneTemplateArg(template);
|
|
2731
2921
|
} catch (error) {
|
|
2732
2922
|
commandBarLog.error("Pane template canCreate failed", {
|
|
2733
2923
|
templateId: template.id,
|
|
@@ -2751,13 +2941,13 @@ export function CommandBar({
|
|
|
2751
2941
|
const prefix = template.shortcut?.prefix?.toUpperCase();
|
|
2752
2942
|
if (!prefix) return false;
|
|
2753
2943
|
const arg = trimmed.slice(prefix.length).trim();
|
|
2754
|
-
const argKind = template
|
|
2944
|
+
const argKind = getPaneTemplateArgKind(template);
|
|
2755
2945
|
if (upper !== prefix && (!argKind || !upper.startsWith(`${prefix} `))) return false;
|
|
2756
2946
|
if (!template.canCreate) return true;
|
|
2757
2947
|
try {
|
|
2758
2948
|
const canCreate = template.canCreate(context, arg ? { arg } : undefined);
|
|
2759
2949
|
if (canCreate) return true;
|
|
2760
|
-
if (!arg && !context.activeTicker && (
|
|
2950
|
+
if (!arg && !context.activeTicker && canPromptForPaneTemplateArg(template)) {
|
|
2761
2951
|
return true;
|
|
2762
2952
|
}
|
|
2763
2953
|
return false;
|
|
@@ -2837,8 +3027,11 @@ export function CommandBar({
|
|
|
2837
3027
|
const paneShortcutItems = useCallback((options?: {
|
|
2838
3028
|
filterQuery?: string;
|
|
2839
3029
|
createOptions?: PaneTemplateCreateOptions;
|
|
3030
|
+
includePromptableTickerTemplates?: boolean;
|
|
2840
3031
|
}): ResultItem[] => {
|
|
2841
|
-
const items = getAvailablePaneTemplates(options?.createOptions
|
|
3032
|
+
const items = getAvailablePaneTemplates(options?.createOptions, {
|
|
3033
|
+
includePromptableTickerTemplates: options?.includePromptableTickerTemplates,
|
|
3034
|
+
})
|
|
2842
3035
|
.filter((template) => template.shortcut)
|
|
2843
3036
|
.map((template) => createPaneTemplateItem(template, {
|
|
2844
3037
|
category: "Panes",
|
|
@@ -3128,7 +3321,7 @@ export function CommandBar({
|
|
|
3128
3321
|
},
|
|
3129
3322
|
};
|
|
3130
3323
|
dispatch({ type: "SET_CONFIG", config: nextConfig });
|
|
3131
|
-
|
|
3324
|
+
persistConfig(nextConfig);
|
|
3132
3325
|
closeAll({ revertThemePreview: false });
|
|
3133
3326
|
return;
|
|
3134
3327
|
}
|
|
@@ -3217,6 +3410,7 @@ export function CommandBar({
|
|
|
3217
3410
|
|
|
3218
3411
|
useEffect(() => {
|
|
3219
3412
|
if (tickerSearchRouteQuery == null) {
|
|
3413
|
+
searchRequestIdRef.current += 1;
|
|
3220
3414
|
setTickerSearchPending(false);
|
|
3221
3415
|
setTickerSearchResults([]);
|
|
3222
3416
|
if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
|
|
@@ -3225,6 +3419,7 @@ export function CommandBar({
|
|
|
3225
3419
|
|
|
3226
3420
|
const searchQuery = tickerSearchRouteQuery.trim();
|
|
3227
3421
|
if (!searchQuery) {
|
|
3422
|
+
searchRequestIdRef.current += 1;
|
|
3228
3423
|
setTickerSearchPending(false);
|
|
3229
3424
|
setTickerSearchResults([]);
|
|
3230
3425
|
if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
|
|
@@ -3239,7 +3434,7 @@ export function CommandBar({
|
|
|
3239
3434
|
activePortfolio?.brokerInstanceId,
|
|
3240
3435
|
);
|
|
3241
3436
|
setTickerSearchResults(cachedCandidates
|
|
3242
|
-
? buildTickerSearchResultItems(cachedCandidates, searchQuery)
|
|
3437
|
+
? mergeTickerSearchResultItems(searchQuery, localItems, buildTickerSearchResultItems(cachedCandidates, searchQuery))
|
|
3243
3438
|
: localItems);
|
|
3244
3439
|
const requestId = ++searchRequestIdRef.current;
|
|
3245
3440
|
const searchDelay = skipTickerSearchDebounceRef.current ? 0 : 200;
|
|
@@ -3266,7 +3461,11 @@ export function CommandBar({
|
|
|
3266
3461
|
activePortfolio?.brokerId,
|
|
3267
3462
|
activePortfolio?.brokerInstanceId,
|
|
3268
3463
|
);
|
|
3269
|
-
setTickerSearchResults(
|
|
3464
|
+
setTickerSearchResults(mergeTickerSearchResultItems(
|
|
3465
|
+
searchQuery,
|
|
3466
|
+
localTickerSearchResultItems(searchQuery, { limit: 6 }),
|
|
3467
|
+
buildTickerSearchResultItems(combined, searchQuery),
|
|
3468
|
+
));
|
|
3270
3469
|
} catch {
|
|
3271
3470
|
if (requestId !== searchRequestIdRef.current) return;
|
|
3272
3471
|
const nextItems: ResultItem[] = [{
|
|
@@ -3295,6 +3494,7 @@ export function CommandBar({
|
|
|
3295
3494
|
buildTickerSearchResultItems,
|
|
3296
3495
|
localTickerSearchResultItems,
|
|
3297
3496
|
mapTickerSearchCandidateToResultItem,
|
|
3497
|
+
mergeTickerSearchResultItems,
|
|
3298
3498
|
readTickerSearchCache,
|
|
3299
3499
|
tickerSearchRouteQuery,
|
|
3300
3500
|
writeTickerSearchCache,
|
|
@@ -3559,8 +3759,8 @@ export function CommandBar({
|
|
|
3559
3759
|
label: "Type a ticker symbol",
|
|
3560
3760
|
detail: "Open security details after resolving a ticker",
|
|
3561
3761
|
category: "Search",
|
|
3562
|
-
kind: "
|
|
3563
|
-
action: () =>
|
|
3762
|
+
kind: "command",
|
|
3763
|
+
action: () => openModeRoute("ticker-search", ""),
|
|
3564
3764
|
});
|
|
3565
3765
|
} else if (match.arg) {
|
|
3566
3766
|
items.push(...localTickerSearchResultItems(match.arg, { limit: 6 }));
|
|
@@ -3610,7 +3810,9 @@ export function CommandBar({
|
|
|
3610
3810
|
const allItems = [
|
|
3611
3811
|
...tickerItems,
|
|
3612
3812
|
...commandItems,
|
|
3613
|
-
...
|
|
3813
|
+
...buildLayoutItems("", { confirmDangerousActions: true }),
|
|
3814
|
+
...buildPaneSettingItems(state.focusedPaneId, rootQuery),
|
|
3815
|
+
...paneShortcutItems({ includePromptableTickerTemplates: true }),
|
|
3614
3816
|
...nonShortcutPaneTemplateItems(),
|
|
3615
3817
|
...tickerActionItems(),
|
|
3616
3818
|
...pluginCommandItems(),
|
|
@@ -3625,6 +3827,7 @@ export function CommandBar({
|
|
|
3625
3827
|
activeTickerSymbol,
|
|
3626
3828
|
availableCommands,
|
|
3627
3829
|
buildLayoutItems,
|
|
3830
|
+
buildPaneSettingItems,
|
|
3628
3831
|
buildPluginItems,
|
|
3629
3832
|
createQuickLookLocalTickerCandidates,
|
|
3630
3833
|
createPluginCommandItem,
|
|
@@ -3644,6 +3847,18 @@ export function CommandBar({
|
|
|
3644
3847
|
tickerActionItems,
|
|
3645
3848
|
]);
|
|
3646
3849
|
|
|
3850
|
+
const rootPlainTickerSearchArg = useMemo(() => {
|
|
3851
|
+
if (activeMatch || rootShortcutIntent.kind !== "none" || !isLikelyPlainTickerSearch(rootQuery)) return null;
|
|
3852
|
+
const normalizedQuery = normalizeCommandTickerSearchText(rootQuery);
|
|
3853
|
+
const hasExactNonTickerResult = rootResultModel.items.some((item) => (
|
|
3854
|
+
item.kind !== "ticker"
|
|
3855
|
+
&& item.kind !== "search"
|
|
3856
|
+
&& normalizeCommandTickerSearchText(item.label) === normalizedQuery
|
|
3857
|
+
));
|
|
3858
|
+
return hasExactNonTickerResult ? null : rootQuery.trim();
|
|
3859
|
+
}, [activeMatch, rootQuery, rootResultModel.items, rootShortcutIntent.kind]);
|
|
3860
|
+
const rootTickerSearchArg = rootSecurityDescriptionArg ?? rootPlainTickerSearchArg;
|
|
3861
|
+
|
|
3647
3862
|
useEffect(() => {
|
|
3648
3863
|
if (currentRoute) return;
|
|
3649
3864
|
|
|
@@ -3668,6 +3883,7 @@ export function CommandBar({
|
|
|
3668
3883
|
|
|
3669
3884
|
useEffect(() => {
|
|
3670
3885
|
if (currentRoute) {
|
|
3886
|
+
rootSearchRequestIdRef.current += 1;
|
|
3671
3887
|
setRootSearching(false);
|
|
3672
3888
|
setRootProviderResults(null);
|
|
3673
3889
|
setRootProviderResultsQuery(null);
|
|
@@ -3676,7 +3892,8 @@ export function CommandBar({
|
|
|
3676
3892
|
return;
|
|
3677
3893
|
}
|
|
3678
3894
|
|
|
3679
|
-
if (!
|
|
3895
|
+
if (!rootTickerSearchArg) {
|
|
3896
|
+
rootSearchRequestIdRef.current += 1;
|
|
3680
3897
|
setRootSearching(false);
|
|
3681
3898
|
setRootProviderResults(null);
|
|
3682
3899
|
setRootProviderResultsQuery(null);
|
|
@@ -3685,7 +3902,7 @@ export function CommandBar({
|
|
|
3685
3902
|
return;
|
|
3686
3903
|
}
|
|
3687
3904
|
|
|
3688
|
-
const searchQuery =
|
|
3905
|
+
const searchQuery = rootTickerSearchArg;
|
|
3689
3906
|
if (rootSearchTimerRef.current) clearTimeout(rootSearchTimerRef.current);
|
|
3690
3907
|
if (rootLastSearchedQueryRef.current === searchQuery) {
|
|
3691
3908
|
return;
|
|
@@ -3699,7 +3916,10 @@ export function CommandBar({
|
|
|
3699
3916
|
activeSearchPortfolio?.brokerId,
|
|
3700
3917
|
activeSearchPortfolio?.brokerInstanceId,
|
|
3701
3918
|
);
|
|
3702
|
-
|
|
3919
|
+
const localItems = localTickerSearchResultItems(searchQuery, { limit: 6 });
|
|
3920
|
+
setRootProviderResults(cachedCandidates
|
|
3921
|
+
? mergeTickerSearchResultItems(searchQuery, localItems, buildTickerSearchResultItems(cachedCandidates, searchQuery))
|
|
3922
|
+
: null);
|
|
3703
3923
|
setRootProviderResultsQuery(cachedCandidates ? searchQuery : null);
|
|
3704
3924
|
|
|
3705
3925
|
const requestId = ++rootSearchRequestIdRef.current;
|
|
@@ -3723,7 +3943,11 @@ export function CommandBar({
|
|
|
3723
3943
|
activeSearchPortfolio?.brokerId,
|
|
3724
3944
|
activeSearchPortfolio?.brokerInstanceId,
|
|
3725
3945
|
);
|
|
3726
|
-
setRootProviderResults(
|
|
3946
|
+
setRootProviderResults(mergeTickerSearchResultItems(
|
|
3947
|
+
searchQuery,
|
|
3948
|
+
localTickerSearchResultItems(searchQuery, { limit: 6 }),
|
|
3949
|
+
buildTickerSearchResultItems(combined, searchQuery),
|
|
3950
|
+
));
|
|
3727
3951
|
setRootProviderResultsQuery(searchQuery);
|
|
3728
3952
|
} catch {
|
|
3729
3953
|
if (requestId !== rootSearchRequestIdRef.current) return;
|
|
@@ -3751,20 +3975,50 @@ export function CommandBar({
|
|
|
3751
3975
|
buildTickerSearchResultItems,
|
|
3752
3976
|
currentRoute,
|
|
3753
3977
|
dataProvider,
|
|
3978
|
+
localTickerSearchResultItems,
|
|
3979
|
+
mergeTickerSearchResultItems,
|
|
3754
3980
|
readTickerSearchCache,
|
|
3755
|
-
|
|
3981
|
+
rootTickerSearchArg,
|
|
3756
3982
|
state.config.portfolios,
|
|
3757
3983
|
state.tickers,
|
|
3758
3984
|
writeTickerSearchCache,
|
|
3759
3985
|
]);
|
|
3760
3986
|
|
|
3761
3987
|
const rootResults = useMemo(() => {
|
|
3762
|
-
if (
|
|
3988
|
+
if (rootTickerSearchArg && rootProviderResultsQuery === rootTickerSearchArg && rootProviderResults) {
|
|
3989
|
+
if (rootPlainTickerSearchArg) {
|
|
3990
|
+
return mergePlainRootTickerResults(rootPlainTickerSearchArg, rootProviderResults, rootResultModel.items);
|
|
3991
|
+
}
|
|
3763
3992
|
return rootProviderResults;
|
|
3764
3993
|
}
|
|
3765
3994
|
return rootResultModel.items;
|
|
3766
|
-
}, [
|
|
3767
|
-
|
|
3995
|
+
}, [
|
|
3996
|
+
mergePlainRootTickerResults,
|
|
3997
|
+
rootPlainTickerSearchArg,
|
|
3998
|
+
rootProviderResults,
|
|
3999
|
+
rootProviderResultsQuery,
|
|
4000
|
+
rootResultModel.items,
|
|
4001
|
+
rootTickerSearchArg,
|
|
4002
|
+
]);
|
|
4003
|
+
const rootSectionOrder = rootPlainTickerSearchArg ? "app-first" : "default";
|
|
4004
|
+
const orderedRootResults = useMemo(
|
|
4005
|
+
() => orderListResults(rootResults, { sectionOrder: rootSectionOrder }),
|
|
4006
|
+
[rootResults, rootSectionOrder],
|
|
4007
|
+
);
|
|
4008
|
+
const activeRootProviderResultsKey = useMemo(() => {
|
|
4009
|
+
if (!rootTickerSearchArg || rootProviderResultsQuery !== rootTickerSearchArg || !rootProviderResults) return null;
|
|
4010
|
+
return [
|
|
4011
|
+
rootTickerSearchArg,
|
|
4012
|
+
...rootProviderResults.map((item) => `${item.id}:${item.category}:${item.label}:${item.right || ""}`),
|
|
4013
|
+
].join("\n");
|
|
4014
|
+
}, [rootProviderResults, rootProviderResultsQuery, rootTickerSearchArg]);
|
|
4015
|
+
|
|
4016
|
+
useEffect(() => {
|
|
4017
|
+
if (!activeRootProviderResultsKey) return;
|
|
4018
|
+
setRootSelectedIdx(0);
|
|
4019
|
+
setRootHoveredIdx(null);
|
|
4020
|
+
nativeListScrollRef.current?.scrollTo(0);
|
|
4021
|
+
}, [activeRootProviderResultsKey]);
|
|
3768
4022
|
|
|
3769
4023
|
const rootGhostCompletion = !currentRoute && rootShortcutIntent.kind === "inferred-complete"
|
|
3770
4024
|
? rootShortcutIntent.completionQuery
|
|
@@ -3776,7 +4030,7 @@ export function CommandBar({
|
|
|
3776
4030
|
if (currentRoute || rootShortcutIntent.kind === "none") return null;
|
|
3777
4031
|
|
|
3778
4032
|
if (rootShortcutIntent.source === "pane-template") {
|
|
3779
|
-
const argKind = rootShortcutIntent.template
|
|
4033
|
+
const argKind = getPaneTemplateArgKind(rootShortcutIntent.template);
|
|
3780
4034
|
if (argKind === "ticker") {
|
|
3781
4035
|
const symbol = normalizeTickerInput(activeTickerSymbol, rootShortcutIntent.argText);
|
|
3782
4036
|
if (symbol) {
|
|
@@ -3792,9 +4046,9 @@ export function CommandBar({
|
|
|
3792
4046
|
}
|
|
3793
4047
|
const inferred = normalizeTickerInput(activeTickerSymbol, undefined);
|
|
3794
4048
|
if (inferred) {
|
|
3795
|
-
return `Shortcut: ${rootShortcutIntent.label}
|
|
4049
|
+
return `Shortcut: ${rootShortcutIntent.label} for ${inferred} · Tab to accept`;
|
|
3796
4050
|
}
|
|
3797
|
-
return `Shortcut: ${rootShortcutIntent.label} · Enter tickers
|
|
4051
|
+
return `Shortcut: ${rootShortcutIntent.label} · Enter tickers`;
|
|
3798
4052
|
}
|
|
3799
4053
|
return `Shortcut: ${rootShortcutIntent.label}`;
|
|
3800
4054
|
}
|
|
@@ -3809,8 +4063,8 @@ export function CommandBar({
|
|
|
3809
4063
|
const symbol = normalizeTickerInput(activeTickerSymbol, rootShortcutIntent.argText);
|
|
3810
4064
|
if (symbol) {
|
|
3811
4065
|
return rootShortcutIntent.kind === "inferred-complete"
|
|
3812
|
-
? `Shortcut:
|
|
3813
|
-
: `Shortcut:
|
|
4066
|
+
? `Shortcut: ${rootShortcutIntent.prefix} ${symbol} · Tab to accept`
|
|
4067
|
+
: `Shortcut: ${rootShortcutIntent.prefix} ${symbol}`;
|
|
3814
4068
|
}
|
|
3815
4069
|
return "Shortcut: Description";
|
|
3816
4070
|
}
|
|
@@ -3865,7 +4119,7 @@ export function CommandBar({
|
|
|
3865
4119
|
return true;
|
|
3866
4120
|
}
|
|
3867
4121
|
if (intent.source === "pane-template") {
|
|
3868
|
-
const argKind = intent.template
|
|
4122
|
+
const argKind = getPaneTemplateArgKind(intent.template);
|
|
3869
4123
|
if (argKind === "ticker") {
|
|
3870
4124
|
openModeRoute("ticker-search", intent.argText, {
|
|
3871
4125
|
action: "pane-template",
|
|
@@ -3959,7 +4213,7 @@ export function CommandBar({
|
|
|
3959
4213
|
}
|
|
3960
4214
|
return {
|
|
3961
4215
|
id: `security-description:${match.arg}`,
|
|
3962
|
-
label:
|
|
4216
|
+
label: `${match.prefix} ${match.arg.toUpperCase()}`,
|
|
3963
4217
|
detail: "Open security details or resolve the ticker",
|
|
3964
4218
|
category: "Search",
|
|
3965
4219
|
kind: "command",
|
|
@@ -4066,6 +4320,7 @@ export function CommandBar({
|
|
|
4066
4320
|
emptyDetail: emptyState.detail,
|
|
4067
4321
|
footerLeft: getScreenFooterLeft(null),
|
|
4068
4322
|
footerRight: getScreenFooterRight(null),
|
|
4323
|
+
sectionOrder: rootSectionOrder,
|
|
4069
4324
|
};
|
|
4070
4325
|
}
|
|
4071
4326
|
|
|
@@ -4162,21 +4417,7 @@ export function CommandBar({
|
|
|
4162
4417
|
if (currentRoute.kind === "pane-settings") {
|
|
4163
4418
|
const descriptor = pluginRegistry.resolvePaneSettings(currentRoute.paneId);
|
|
4164
4419
|
if (!descriptor) return null;
|
|
4165
|
-
const
|
|
4166
|
-
const currentValue = descriptor.context.settings[field.key];
|
|
4167
|
-
return {
|
|
4168
|
-
id: `pane-setting:${field.key}`,
|
|
4169
|
-
label: field.label,
|
|
4170
|
-
detail: summarizePaneSettingValue(field, currentValue),
|
|
4171
|
-
category: descriptor.settingsDef.title || "Pane Settings",
|
|
4172
|
-
kind: "action" as const,
|
|
4173
|
-
right: field.type,
|
|
4174
|
-
action: () => {},
|
|
4175
|
-
};
|
|
4176
|
-
});
|
|
4177
|
-
const filtered = currentRoute.query
|
|
4178
|
-
? fuzzyFilter(items, currentRoute.query, (item) => `${item.label} ${item.detail} ${item.right || ""}`)
|
|
4179
|
-
: items;
|
|
4420
|
+
const filtered = buildPaneSettingItems(currentRoute.paneId, currentRoute.query, { keepRouteOpen: true });
|
|
4180
4421
|
return {
|
|
4181
4422
|
kind: "pane-settings",
|
|
4182
4423
|
title: descriptor.settingsDef.title || "Pane Settings",
|
|
@@ -4201,6 +4442,7 @@ export function CommandBar({
|
|
|
4201
4442
|
activeTickerData,
|
|
4202
4443
|
activeTickerSymbol,
|
|
4203
4444
|
buildLayoutItems,
|
|
4445
|
+
buildPaneSettingItems,
|
|
4204
4446
|
buildPluginItems,
|
|
4205
4447
|
closeAll,
|
|
4206
4448
|
createPaneTemplateItem,
|
|
@@ -4226,6 +4468,7 @@ export function CommandBar({
|
|
|
4226
4468
|
rootModeInfo.kind,
|
|
4227
4469
|
rootQuery,
|
|
4228
4470
|
orderedRootResults,
|
|
4471
|
+
rootSectionOrder,
|
|
4229
4472
|
rootSearching,
|
|
4230
4473
|
rootSelectedIdx,
|
|
4231
4474
|
rootShortcutIntent,
|
|
@@ -4648,40 +4891,7 @@ export function CommandBar({
|
|
|
4648
4891
|
}
|
|
4649
4892
|
|
|
4650
4893
|
if (currentRoute?.kind === "pane-settings") {
|
|
4651
|
-
|
|
4652
|
-
if (!descriptor) return;
|
|
4653
|
-
const selectedField = descriptor.settingsDef.fields.find((field) => `pane-setting:${field.key}` === selected.id);
|
|
4654
|
-
if (!selectedField) return;
|
|
4655
|
-
const currentValue = descriptor.context.settings[selectedField.key];
|
|
4656
|
-
const normalized = normalizePaneSettingField(currentRoute.paneId, selectedField, currentValue);
|
|
4657
|
-
if (normalized.mode === "toggle") {
|
|
4658
|
-
updateTopRoute((route) => route.kind === "pane-settings"
|
|
4659
|
-
? { ...route, pendingFieldKey: selectedField.key, error: null }
|
|
4660
|
-
: route);
|
|
4661
|
-
void pluginRegistry.applyPaneSettingValueFn(currentRoute.paneId, selectedField, !normalized.value)
|
|
4662
|
-
.then(() => {
|
|
4663
|
-
updateTopRoute((route) => route.kind === "pane-settings"
|
|
4664
|
-
? { ...route, pendingFieldKey: null, error: null }
|
|
4665
|
-
: route);
|
|
4666
|
-
})
|
|
4667
|
-
.catch((error) => {
|
|
4668
|
-
updateTopRoute((route) => route.kind === "pane-settings"
|
|
4669
|
-
? {
|
|
4670
|
-
...route,
|
|
4671
|
-
pendingFieldKey: null,
|
|
4672
|
-
error: error instanceof Error ? error.message : "Could not apply that setting.",
|
|
4673
|
-
}
|
|
4674
|
-
: route);
|
|
4675
|
-
});
|
|
4676
|
-
return;
|
|
4677
|
-
}
|
|
4678
|
-
if (normalized.mode === "workflow" && normalized.route) {
|
|
4679
|
-
openWorkflowRoute(normalized.route);
|
|
4680
|
-
return;
|
|
4681
|
-
}
|
|
4682
|
-
if (normalized.mode === "picker") {
|
|
4683
|
-
openPickerRoute(normalized.route);
|
|
4684
|
-
}
|
|
4894
|
+
void selected.action();
|
|
4685
4895
|
return;
|
|
4686
4896
|
}
|
|
4687
4897
|
|
|
@@ -4689,10 +4899,7 @@ export function CommandBar({
|
|
|
4689
4899
|
}, [
|
|
4690
4900
|
closeAll,
|
|
4691
4901
|
currentRoute,
|
|
4692
|
-
normalizePaneSettingField,
|
|
4693
4902
|
openInlineConfirm,
|
|
4694
|
-
openPickerRoute,
|
|
4695
|
-
openWorkflowRoute,
|
|
4696
4903
|
persistLayoutChange,
|
|
4697
4904
|
pluginRegistry,
|
|
4698
4905
|
resolveImmediateRootSelection,
|
|
@@ -4842,343 +5049,277 @@ export function CommandBar({
|
|
|
4842
5049
|
}
|
|
4843
5050
|
}, [currentRoute, pluginRegistry, updateTopRoute, updateWorkflowValue]);
|
|
4844
5051
|
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
preventDefault: () => void;
|
|
4856
|
-
}) => void) => void;
|
|
4857
|
-
offInternal?: (event: "keypress", handler: (event: {
|
|
4858
|
-
name: string;
|
|
4859
|
-
sequence?: string;
|
|
4860
|
-
ctrl?: boolean;
|
|
4861
|
-
option?: boolean;
|
|
4862
|
-
meta?: boolean;
|
|
4863
|
-
shift?: boolean;
|
|
4864
|
-
stopPropagation: () => void;
|
|
4865
|
-
preventDefault: () => void;
|
|
4866
|
-
}) => void) => void;
|
|
4867
|
-
};
|
|
4868
|
-
if (!keyInput) return undefined;
|
|
4869
|
-
const handleKeyPress = (event: {
|
|
4870
|
-
name: string;
|
|
4871
|
-
sequence?: string;
|
|
4872
|
-
ctrl?: boolean;
|
|
4873
|
-
option?: boolean;
|
|
4874
|
-
meta?: boolean;
|
|
4875
|
-
shift?: boolean;
|
|
4876
|
-
stopPropagation: () => void;
|
|
4877
|
-
preventDefault: () => void;
|
|
4878
|
-
}) => {
|
|
4879
|
-
if (event.name === "escape" || event.name === "`") {
|
|
5052
|
+
useShortcut((event) => {
|
|
5053
|
+
if (event.name === "escape" || event.name === "`") {
|
|
5054
|
+
event.stopPropagation();
|
|
5055
|
+
event.preventDefault();
|
|
5056
|
+
dismissCommandBar();
|
|
5057
|
+
return;
|
|
5058
|
+
}
|
|
5059
|
+
|
|
5060
|
+
if (currentRoute?.kind === "confirm") {
|
|
5061
|
+
if (isPlainBackspace(event)) {
|
|
4880
5062
|
event.stopPropagation();
|
|
4881
5063
|
event.preventDefault();
|
|
4882
|
-
|
|
5064
|
+
popRoute();
|
|
4883
5065
|
return;
|
|
4884
5066
|
}
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
event.preventDefault();
|
|
4890
|
-
popRoute();
|
|
4891
|
-
return;
|
|
4892
|
-
}
|
|
4893
|
-
if (event.name === "return" || event.name === "enter" || event.name === "y") {
|
|
4894
|
-
event.stopPropagation();
|
|
4895
|
-
event.preventDefault();
|
|
4896
|
-
void confirmCurrentRoute();
|
|
4897
|
-
return;
|
|
4898
|
-
}
|
|
4899
|
-
if (event.name === "n") {
|
|
4900
|
-
event.stopPropagation();
|
|
4901
|
-
event.preventDefault();
|
|
4902
|
-
popRoute();
|
|
4903
|
-
}
|
|
5067
|
+
if (event.name === "return" || event.name === "enter" || event.name === "y") {
|
|
5068
|
+
event.stopPropagation();
|
|
5069
|
+
event.preventDefault();
|
|
5070
|
+
void confirmCurrentRoute();
|
|
4904
5071
|
return;
|
|
4905
5072
|
}
|
|
4906
|
-
|
|
4907
|
-
if (
|
|
4908
|
-
currentRoute
|
|
4909
|
-
&& (currentRoute.kind === "mode"
|
|
4910
|
-
|| currentRoute.kind === "picker"
|
|
4911
|
-
|| currentRoute.kind === "pane-settings")
|
|
4912
|
-
&& isPlainBackspace(event)
|
|
4913
|
-
&& currentRoute.query.length === 0
|
|
4914
|
-
) {
|
|
5073
|
+
if (event.name === "n") {
|
|
4915
5074
|
event.stopPropagation();
|
|
4916
5075
|
event.preventDefault();
|
|
4917
5076
|
popRoute();
|
|
4918
|
-
return;
|
|
4919
5077
|
}
|
|
5078
|
+
return;
|
|
5079
|
+
}
|
|
4920
5080
|
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
return;
|
|
4935
|
-
}
|
|
4936
|
-
}
|
|
4937
|
-
|
|
4938
|
-
if (event.name === "tab") {
|
|
4939
|
-
event.stopPropagation();
|
|
4940
|
-
event.preventDefault();
|
|
4941
|
-
moveWorkflowFocus(event.shift ? -1 : 1);
|
|
4942
|
-
return;
|
|
4943
|
-
}
|
|
4944
|
-
|
|
4945
|
-
if (activeTextarea && event.ctrl && event.name === "s") {
|
|
4946
|
-
event.stopPropagation();
|
|
4947
|
-
event.preventDefault();
|
|
4948
|
-
void submitWorkflowRoute(currentRoute);
|
|
4949
|
-
return;
|
|
4950
|
-
}
|
|
5081
|
+
if (
|
|
5082
|
+
currentRoute
|
|
5083
|
+
&& (currentRoute.kind === "mode"
|
|
5084
|
+
|| currentRoute.kind === "picker"
|
|
5085
|
+
|| currentRoute.kind === "pane-settings")
|
|
5086
|
+
&& isPlainBackspace(event)
|
|
5087
|
+
&& currentRoute.query.length === 0
|
|
5088
|
+
) {
|
|
5089
|
+
event.stopPropagation();
|
|
5090
|
+
event.preventDefault();
|
|
5091
|
+
popRoute();
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
4951
5094
|
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
5095
|
+
if (currentRoute?.kind === "workflow") {
|
|
5096
|
+
const visibleFields = getVisibleWorkflowFields(currentRoute.fields, currentRoute.values);
|
|
5097
|
+
const activeField = visibleFields.find((field) => field.id === currentRoute.activeFieldId) ?? visibleFields[0];
|
|
5098
|
+
const activeTextarea = activeField?.type === "textarea";
|
|
4955
5099
|
|
|
4956
|
-
|
|
5100
|
+
if (isPlainBackspace(event)) {
|
|
5101
|
+
const activeValue = activeField
|
|
5102
|
+
? getWorkflowFieldStringValue(activeField, currentRoute.values[activeField.id])
|
|
5103
|
+
: "";
|
|
5104
|
+
if (!activeField || !isWorkflowTextField(activeField) || activeValue.length === 0) {
|
|
4957
5105
|
event.stopPropagation();
|
|
4958
5106
|
event.preventDefault();
|
|
4959
|
-
|
|
5107
|
+
popRoute();
|
|
4960
5108
|
return;
|
|
4961
5109
|
}
|
|
5110
|
+
}
|
|
4962
5111
|
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
5112
|
+
if (event.name === "tab") {
|
|
5113
|
+
event.stopPropagation();
|
|
5114
|
+
event.preventDefault();
|
|
5115
|
+
moveWorkflowFocus(event.shift ? -1 : 1);
|
|
5116
|
+
return;
|
|
5117
|
+
}
|
|
4969
5118
|
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
5119
|
+
if (activeTextarea && event.ctrl && event.name === "s") {
|
|
5120
|
+
event.stopPropagation();
|
|
5121
|
+
event.preventDefault();
|
|
5122
|
+
void submitWorkflowRoute(currentRoute);
|
|
5123
|
+
return;
|
|
5124
|
+
}
|
|
4976
5125
|
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|| (nativePaneChrome && event.name === "space" && activeField?.type === "select")
|
|
4981
|
-
) {
|
|
4982
|
-
if (!activeField) return;
|
|
4983
|
-
if (activeField.type === "select" || activeField.type === "multi-select" || activeField.type === "ordered-multi-select" || activeField.type === "toggle") {
|
|
4984
|
-
event.stopPropagation();
|
|
4985
|
-
event.preventDefault();
|
|
4986
|
-
if (nativePaneChrome && activeField.type === "select") {
|
|
4987
|
-
openNativeSelect(workflowNativeSelectRefs.current.get(activeField.id));
|
|
4988
|
-
return;
|
|
4989
|
-
}
|
|
4990
|
-
openWorkflowFieldPicker(currentRoute, activeField);
|
|
4991
|
-
return;
|
|
4992
|
-
}
|
|
4993
|
-
}
|
|
5126
|
+
if (activeTextarea && (event.name === "up" || event.name === "down" || (event.ctrl && (event.name === "p" || event.name === "n")))) {
|
|
5127
|
+
return;
|
|
5128
|
+
}
|
|
4994
5129
|
|
|
5130
|
+
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5131
|
+
event.stopPropagation();
|
|
5132
|
+
event.preventDefault();
|
|
5133
|
+
moveWorkflowFocus(-1);
|
|
4995
5134
|
return;
|
|
4996
5135
|
}
|
|
4997
5136
|
|
|
4998
|
-
if (
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
moveListSelection(-1);
|
|
5003
|
-
return;
|
|
5004
|
-
}
|
|
5005
|
-
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5006
|
-
event.stopPropagation();
|
|
5007
|
-
event.preventDefault();
|
|
5008
|
-
moveListSelection(1);
|
|
5009
|
-
return;
|
|
5010
|
-
}
|
|
5011
|
-
if (currentRoute.pickerId === "field-multi-select" && (event.name === "space" || event.sequence === " ")) {
|
|
5012
|
-
event.stopPropagation();
|
|
5013
|
-
event.preventDefault();
|
|
5014
|
-
const listState = visibleListStateRef.current;
|
|
5015
|
-
const selected = listState?.results[listState.selectedIdx];
|
|
5016
|
-
if (!selected) return;
|
|
5017
|
-
handleMultiSelectToggle(selected.id);
|
|
5018
|
-
return;
|
|
5019
|
-
}
|
|
5020
|
-
if (currentRoute.pickerId === "field-multi-select" && event.name === "[") {
|
|
5021
|
-
event.stopPropagation();
|
|
5022
|
-
event.preventDefault();
|
|
5023
|
-
handleMultiSelectMove("up");
|
|
5024
|
-
return;
|
|
5025
|
-
}
|
|
5026
|
-
if (currentRoute.pickerId === "field-multi-select" && event.name === "]") {
|
|
5027
|
-
event.stopPropagation();
|
|
5028
|
-
event.preventDefault();
|
|
5029
|
-
handleMultiSelectMove("down");
|
|
5030
|
-
return;
|
|
5031
|
-
}
|
|
5032
|
-
if (event.name === "return" || event.name === "enter") {
|
|
5033
|
-
event.stopPropagation();
|
|
5034
|
-
event.preventDefault();
|
|
5035
|
-
if (currentRoute.pickerId === "field-multi-select") {
|
|
5036
|
-
commitMultiSelectPicker();
|
|
5037
|
-
return;
|
|
5038
|
-
}
|
|
5039
|
-
activateListSelection();
|
|
5040
|
-
}
|
|
5137
|
+
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5138
|
+
event.stopPropagation();
|
|
5139
|
+
event.preventDefault();
|
|
5140
|
+
moveWorkflowFocus(1);
|
|
5041
5141
|
return;
|
|
5042
5142
|
}
|
|
5043
5143
|
|
|
5044
|
-
if (
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
moveListSelection(-1);
|
|
5049
|
-
return;
|
|
5050
|
-
}
|
|
5051
|
-
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5052
|
-
event.stopPropagation();
|
|
5053
|
-
event.preventDefault();
|
|
5054
|
-
moveListSelection(1);
|
|
5055
|
-
return;
|
|
5056
|
-
}
|
|
5057
|
-
if (event.name === "return" || event.name === "enter" || event.name === "space") {
|
|
5058
|
-
event.stopPropagation();
|
|
5059
|
-
event.preventDefault();
|
|
5060
|
-
activateListSelection();
|
|
5061
|
-
}
|
|
5144
|
+
if (event.name === "space" && activeField?.type === "toggle") {
|
|
5145
|
+
event.stopPropagation();
|
|
5146
|
+
event.preventDefault();
|
|
5147
|
+
updateWorkflowValue(activeField.id, !coerceFieldBoolean(currentRoute.values[activeField.id]));
|
|
5062
5148
|
return;
|
|
5063
5149
|
}
|
|
5064
5150
|
|
|
5065
|
-
if (
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5073
|
-
event.stopPropagation();
|
|
5074
|
-
event.preventDefault();
|
|
5075
|
-
themePickerRef.current?.move(1);
|
|
5076
|
-
return;
|
|
5077
|
-
}
|
|
5078
|
-
if (event.name === "return" || event.name === "enter") {
|
|
5151
|
+
if (
|
|
5152
|
+
event.name === "return"
|
|
5153
|
+
|| event.name === "enter"
|
|
5154
|
+
|| (nativePaneChrome && event.name === "space" && activeField?.type === "select")
|
|
5155
|
+
) {
|
|
5156
|
+
if (!activeField) return;
|
|
5157
|
+
if (activeField.type === "select" || activeField.type === "multi-select" || activeField.type === "ordered-multi-select" || activeField.type === "toggle") {
|
|
5079
5158
|
event.stopPropagation();
|
|
5080
5159
|
event.preventDefault();
|
|
5081
|
-
|
|
5160
|
+
if (nativePaneChrome && activeField.type === "select") {
|
|
5161
|
+
openNativeSelect(workflowNativeSelectRefs.current.get(activeField.id));
|
|
5162
|
+
return;
|
|
5163
|
+
}
|
|
5164
|
+
openWorkflowFieldPicker(currentRoute, activeField);
|
|
5082
5165
|
return;
|
|
5083
5166
|
}
|
|
5084
5167
|
}
|
|
5085
5168
|
|
|
5086
|
-
|
|
5087
|
-
|
|
5169
|
+
return;
|
|
5170
|
+
}
|
|
5088
5171
|
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5172
|
+
if (currentRoute?.kind === "picker") {
|
|
5173
|
+
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5174
|
+
event.stopPropagation();
|
|
5175
|
+
event.preventDefault();
|
|
5176
|
+
moveListSelection(-1);
|
|
5177
|
+
return;
|
|
5095
5178
|
}
|
|
5096
|
-
|
|
5097
5179
|
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5098
5180
|
event.stopPropagation();
|
|
5099
5181
|
event.preventDefault();
|
|
5100
5182
|
moveListSelection(1);
|
|
5101
5183
|
return;
|
|
5102
5184
|
}
|
|
5185
|
+
if (currentRoute.pickerId === "field-multi-select" && (event.name === "space" || event.sequence === " ")) {
|
|
5186
|
+
event.stopPropagation();
|
|
5187
|
+
event.preventDefault();
|
|
5188
|
+
const listState = visibleListStateRef.current;
|
|
5189
|
+
const selected = listState?.results[listState.selectedIdx];
|
|
5190
|
+
if (!selected) return;
|
|
5191
|
+
handleMultiSelectToggle(selected.id);
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
if (currentRoute.pickerId === "field-multi-select" && event.name === "[") {
|
|
5195
|
+
event.stopPropagation();
|
|
5196
|
+
event.preventDefault();
|
|
5197
|
+
handleMultiSelectMove("up");
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
5200
|
+
if (currentRoute.pickerId === "field-multi-select" && event.name === "]") {
|
|
5201
|
+
event.stopPropagation();
|
|
5202
|
+
event.preventDefault();
|
|
5203
|
+
handleMultiSelectMove("down");
|
|
5204
|
+
return;
|
|
5205
|
+
}
|
|
5206
|
+
if (event.name === "return" || event.name === "enter") {
|
|
5207
|
+
event.stopPropagation();
|
|
5208
|
+
event.preventDefault();
|
|
5209
|
+
if (currentRoute.pickerId === "field-multi-select") {
|
|
5210
|
+
commitMultiSelectPicker();
|
|
5211
|
+
return;
|
|
5212
|
+
}
|
|
5213
|
+
activateListSelection();
|
|
5214
|
+
}
|
|
5215
|
+
return;
|
|
5216
|
+
}
|
|
5103
5217
|
|
|
5218
|
+
if (currentRoute?.kind === "pane-settings") {
|
|
5104
5219
|
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5105
5220
|
event.stopPropagation();
|
|
5106
5221
|
event.preventDefault();
|
|
5107
5222
|
moveListSelection(-1);
|
|
5108
5223
|
return;
|
|
5109
5224
|
}
|
|
5110
|
-
|
|
5111
|
-
if ((event.meta && (event.name === "backspace" || event.name === "delete")) || (event.ctrl && event.name === "u")) {
|
|
5225
|
+
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5112
5226
|
event.stopPropagation();
|
|
5113
5227
|
event.preventDefault();
|
|
5114
|
-
|
|
5228
|
+
moveListSelection(1);
|
|
5115
5229
|
return;
|
|
5116
5230
|
}
|
|
5231
|
+
if (event.name === "return" || event.name === "enter" || event.name === "space") {
|
|
5232
|
+
event.stopPropagation();
|
|
5233
|
+
event.preventDefault();
|
|
5234
|
+
activateListSelection();
|
|
5235
|
+
}
|
|
5236
|
+
return;
|
|
5237
|
+
}
|
|
5117
5238
|
|
|
5118
|
-
|
|
5239
|
+
if (themePickerActive) {
|
|
5240
|
+
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5119
5241
|
event.stopPropagation();
|
|
5120
5242
|
event.preventDefault();
|
|
5121
|
-
|
|
5122
|
-
const nextQuery = trimmed.replace(/[^\s]+$/, "").replace(/\s+$/, "");
|
|
5123
|
-
setActiveListQuery(nextQuery);
|
|
5243
|
+
themePickerRef.current?.move(-1);
|
|
5124
5244
|
return;
|
|
5125
5245
|
}
|
|
5126
|
-
|
|
5127
|
-
const pluginToggleMode = (currentRoute?.kind === "mode" && currentRoute.screen === "plugins")
|
|
5128
|
-
|| (!currentRoute && rootModeInfo.kind === "plugins");
|
|
5129
|
-
if (pluginToggleMode && event.name === "space") {
|
|
5246
|
+
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5130
5247
|
event.stopPropagation();
|
|
5131
5248
|
event.preventDefault();
|
|
5132
|
-
|
|
5133
|
-
if (selected?.pluginToggle) {
|
|
5134
|
-
void selected.pluginToggle();
|
|
5135
|
-
}
|
|
5249
|
+
themePickerRef.current?.move(1);
|
|
5136
5250
|
return;
|
|
5137
5251
|
}
|
|
5138
|
-
|
|
5139
5252
|
if (event.name === "return" || event.name === "enter") {
|
|
5140
5253
|
event.stopPropagation();
|
|
5141
5254
|
event.preventDefault();
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
return;
|
|
5145
|
-
}
|
|
5146
|
-
activateListSelection();
|
|
5255
|
+
themePickerRef.current?.commit();
|
|
5256
|
+
return;
|
|
5147
5257
|
}
|
|
5148
|
-
}
|
|
5258
|
+
}
|
|
5149
5259
|
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5260
|
+
const activeListState = visibleListStateRef.current;
|
|
5261
|
+
if (!activeListState) return;
|
|
5262
|
+
|
|
5263
|
+
if (!currentRoute && event.name === "tab") {
|
|
5264
|
+
if (acceptRootShortcutTab()) {
|
|
5265
|
+
event.stopPropagation();
|
|
5266
|
+
event.preventDefault();
|
|
5267
|
+
return;
|
|
5268
|
+
}
|
|
5154
5269
|
}
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5270
|
+
|
|
5271
|
+
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5272
|
+
event.stopPropagation();
|
|
5273
|
+
event.preventDefault();
|
|
5274
|
+
moveListSelection(1);
|
|
5275
|
+
return;
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5279
|
+
event.stopPropagation();
|
|
5280
|
+
event.preventDefault();
|
|
5281
|
+
moveListSelection(-1);
|
|
5282
|
+
return;
|
|
5283
|
+
}
|
|
5284
|
+
|
|
5285
|
+
if ((event.meta && (event.name === "backspace" || event.name === "delete")) || (event.ctrl && event.name === "u")) {
|
|
5286
|
+
event.stopPropagation();
|
|
5287
|
+
event.preventDefault();
|
|
5288
|
+
setActiveListQuery("");
|
|
5289
|
+
return;
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
if ((event.ctrl && event.name === "w") || (event.meta && (event.name === "h" || event.name === "u"))) {
|
|
5293
|
+
event.stopPropagation();
|
|
5294
|
+
event.preventDefault();
|
|
5295
|
+
const trimmed = activeListState.query.replace(/\s+$/, "");
|
|
5296
|
+
const nextQuery = trimmed.replace(/[^\s]+$/, "").replace(/\s+$/, "");
|
|
5297
|
+
setActiveListQuery(nextQuery);
|
|
5298
|
+
return;
|
|
5299
|
+
}
|
|
5300
|
+
|
|
5301
|
+
const pluginToggleMode = (currentRoute?.kind === "mode" && currentRoute.screen === "plugins")
|
|
5302
|
+
|| (!currentRoute && rootModeInfo.kind === "plugins");
|
|
5303
|
+
if (pluginToggleMode && event.name === "space") {
|
|
5304
|
+
event.stopPropagation();
|
|
5305
|
+
event.preventDefault();
|
|
5306
|
+
const selected = activeListState.results[activeListState.selectedIdx];
|
|
5307
|
+
if (selected?.pluginToggle) {
|
|
5308
|
+
void selected.pluginToggle();
|
|
5160
5309
|
}
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
openWorkflowFieldPicker,
|
|
5175
|
-
popRoute,
|
|
5176
|
-
renderer,
|
|
5177
|
-
rootModeInfo.kind,
|
|
5178
|
-
setActiveListQuery,
|
|
5179
|
-
themePickerActive,
|
|
5180
|
-
updateWorkflowValue,
|
|
5181
|
-
]);
|
|
5310
|
+
return;
|
|
5311
|
+
}
|
|
5312
|
+
|
|
5313
|
+
if (event.name === "return" || event.name === "enter") {
|
|
5314
|
+
event.stopPropagation();
|
|
5315
|
+
event.preventDefault();
|
|
5316
|
+
if (event.shift) {
|
|
5317
|
+
activateListSelection({ secondary: true });
|
|
5318
|
+
return;
|
|
5319
|
+
}
|
|
5320
|
+
activateListSelection();
|
|
5321
|
+
}
|
|
5322
|
+
}, { phase: "before" });
|
|
5182
5323
|
|
|
5183
5324
|
const barWidth = nativePaneChrome
|
|
5184
5325
|
? Math.max(46, Math.min(78, termWidth - 10, Math.floor(termWidth * 0.64)))
|
|
@@ -5221,8 +5362,18 @@ export function CommandBar({
|
|
|
5221
5362
|
Math.max(7, estimateWorkflowBodyRows(currentRoute)),
|
|
5222
5363
|
)
|
|
5223
5364
|
: baseBodyHeight;
|
|
5224
|
-
const
|
|
5225
|
-
|
|
5365
|
+
const shouldUseCompactListHeight = nativePaneChrome
|
|
5366
|
+
&& visibleListState != null
|
|
5367
|
+
&& !themePickerActive
|
|
5368
|
+
&& !showCustomMultiSelectPicker;
|
|
5369
|
+
const listBodyHeight = shouldUseCompactListHeight
|
|
5370
|
+
? Math.min(baseBodyHeight, Math.max(1, nativeListRows.length))
|
|
5371
|
+
: baseBodyHeight;
|
|
5372
|
+
const bodyHeight = currentRoute?.kind === "workflow"
|
|
5373
|
+
? workflowBodyHeight
|
|
5374
|
+
: shouldUseCompactListHeight
|
|
5375
|
+
? listBodyHeight
|
|
5376
|
+
: baseBodyHeight;
|
|
5226
5377
|
const nativePanelPaddingColumns = nativePaneChrome
|
|
5227
5378
|
? Math.ceil((NATIVE_COMMAND_BAR_PADDING_X_PX * 2) / Math.max(1, cellWidthPx))
|
|
5228
5379
|
: 0;
|
|
@@ -5233,7 +5384,7 @@ export function CommandBar({
|
|
|
5233
5384
|
|| currentRoute?.kind === "confirm"
|
|
5234
5385
|
|| showCustomMultiSelectPicker)
|
|
5235
5386
|
? 1
|
|
5236
|
-
: 3;
|
|
5387
|
+
: currentRoute ? 3 : 2;
|
|
5237
5388
|
const barHeight = nativePaneChrome
|
|
5238
5389
|
? bodyHeight + nativeBodyChromeRows + nativePanelPaddingRows
|
|
5239
5390
|
: bodyHeight + 7;
|
|
@@ -5578,7 +5729,7 @@ export function CommandBar({
|
|
|
5578
5729
|
data-gloom-role="command-bar-panel"
|
|
5579
5730
|
style={nativePaneChrome ? {
|
|
5580
5731
|
borderRadius: 8,
|
|
5581
|
-
boxShadow:
|
|
5732
|
+
boxShadow: `0 14px 32px ${blendHex(commandBarBg(), colors.bg, 0.18)}`,
|
|
5582
5733
|
overflow: "hidden",
|
|
5583
5734
|
padding: `${NATIVE_COMMAND_BAR_PADDING_Y_PX}px ${NATIVE_COMMAND_BAR_PADDING_X_PX}px`,
|
|
5584
5735
|
} : undefined}
|
|
@@ -5669,15 +5820,15 @@ export function CommandBar({
|
|
|
5669
5820
|
paletteText={paletteText}
|
|
5670
5821
|
panelBg={panelBg}
|
|
5671
5822
|
onPreview={applyThemePreview}
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5823
|
+
onCommit={(themeId) => {
|
|
5824
|
+
const nextConfig = {
|
|
5825
|
+
...stateRef.current.config,
|
|
5826
|
+
theme: themeId,
|
|
5827
|
+
};
|
|
5828
|
+
commitTheme(themeId);
|
|
5829
|
+
persistConfig(nextConfig);
|
|
5830
|
+
closeAll({ revertThemePreview: false });
|
|
5831
|
+
}}
|
|
5681
5832
|
/>
|
|
5682
5833
|
)}
|
|
5683
5834
|
|