authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-03 14:49:50-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-03 18:22:29-08:00
log326595b148e410174e79c9a6e7f63006478ffaf6
treee9aee918fc8ebdc54fcd4808965254df8561afd8
parent41a8468b08e9a33ea2418fefc16f7c68e3778d7e

Add Vitest to web app and remove unused composer/env props

- add `vitest` to `apps/web` devDependencies and lockfile - remove unused `envMode` prop from `BranchToolbar` usage and signature - drop unused composer command input ref in `ChatView`

4 files changed, 34 insertions(+), 29 deletions(-)

apps/web/package.json+2-1
...@@ -44,6 +44,7 @@...@@ -44,6 +44,7 @@
44 "babel-plugin-react-compiler": "^19.0.0-beta-e552027-20250112",44 "babel-plugin-react-compiler": "^19.0.0-beta-e552027-20250112",
45 "tailwindcss": "^4.0.0",45 "tailwindcss": "^4.0.0",
46 "typescript": "catalog:",46 "typescript": "catalog:",
47 "vite": "^8.0.0-beta.12"47 "vite": "^8.0.0-beta.12",
48 "vitest": "catalog:"
48 }49 }
49}50}
apps/web/src/components/BranchToolbar.tsx-2
...@@ -15,7 +15,6 @@ import { Button } from "./ui/button";...@@ -15,7 +15,6 @@ import { Button } from "./ui/button";
1515
16interface BranchToolbarProps {16interface BranchToolbarProps {
17 threadId: ThreadId;17 threadId: ThreadId;
18 envMode: EnvMode;
19 onEnvModeChange: (mode: EnvMode) => void;18 onEnvModeChange: (mode: EnvMode) => void;
20 envLocked: boolean;19 envLocked: boolean;
21 onComposerFocusRequest?: () => void;20 onComposerFocusRequest?: () => void;
...@@ -23,7 +22,6 @@ interface BranchToolbarProps {...@@ -23,7 +22,6 @@ interface BranchToolbarProps {
2322
24export default function BranchToolbar({23export default function BranchToolbar({
25 threadId,24 threadId,
26 envMode,
27 onEnvModeChange,25 onEnvModeChange,
28 envLocked,26 envLocked,
29 onComposerFocusRequest,27 onComposerFocusRequest,
apps/web/src/components/ChatView.tsx+31-26
...@@ -524,7 +524,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -524,7 +524,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
524 const pendingUserScrollUpIntentRef = useRef(false);524 const pendingUserScrollUpIntentRef = useRef(false);
525 const pendingAutoScrollFrameRef = useRef<number | null>(null);525 const pendingAutoScrollFrameRef = useRef<number | null>(null);
526 const composerEditorRef = useRef<ComposerPromptEditorHandle>(null);526 const composerEditorRef = useRef<ComposerPromptEditorHandle>(null);
527 const composerCommandInputRef = useRef<HTMLInputElement>(null);
528 const composerFormRef = useRef<HTMLFormElement>(null);527 const composerFormRef = useRef<HTMLFormElement>(null);
529 const composerFormHeightRef = useRef(0);528 const composerFormHeightRef = useRef(0);
530 const composerImagesRef = useRef<ComposerImageAttachment[]>([]);529 const composerImagesRef = useRef<ComposerImageAttachment[]>([]);
...@@ -633,7 +632,8 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -633,7 +632,8 @@ export default function ChatView({ threadId }: ChatViewProps) {
633 [selectedModel, settings.customCodexModels],632 [selectedModel, settings.customCodexModels],
634 );633 );
635 const slashModelOptions = useMemo(634 const slashModelOptions = useMemo(
636 () => getSlashModelOptions(settings.customCodexModels, composerTrigger?.query ?? "", selectedModel),635 () =>
636 getSlashModelOptions(settings.customCodexModels, composerTrigger?.query ?? "", selectedModel),
637 [composerTrigger?.query, selectedModel, settings.customCodexModels],637 [composerTrigger?.query, selectedModel, settings.customCodexModels],
638 );638 );
639 const phase = derivePhase(activeThread?.session ?? null);639 const phase = derivePhase(activeThread?.session ?? null);
...@@ -912,12 +912,12 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -912,12 +912,12 @@ export default function ChatView({ threadId }: ChatViewProps) {
912 }912 }
913913
914 return slashModelOptions.map(({ slug, name }) => ({914 return slashModelOptions.map(({ slug, name }) => ({
915 id: `model:${slug}`,915 id: `model:${slug}`,
916 type: "model" as const,916 type: "model" as const,
917 model: slug,917 model: slug,
918 label: name,918 label: name,
919 description: slug,919 description: slug,
920 }));920 }));
921 }, [composerTrigger, slashModelOptions, workspaceEntries]);921 }, [composerTrigger, slashModelOptions, workspaceEntries]);
922 const composerMenuOpen = Boolean(composerTrigger);922 const composerMenuOpen = Boolean(composerTrigger);
923 const activeComposerMenuItem = useMemo(923 const activeComposerMenuItem = useMemo(
...@@ -2312,12 +2312,9 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2312,12 +2312,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
2312 return;2312 return;
2313 }2313 }
2314 if (item.type === "slash-command") {2314 if (item.type === "slash-command") {
2315 const applied = applyPromptReplacement(2315 const applied = applyPromptReplacement(trigger.rangeStart, trigger.rangeEnd, "/model ", {
2316 trigger.rangeStart,2316 expectedText: expectedToken,
2317 trigger.rangeEnd,2317 });
2318 "/model ",
2319 { expectedText: expectedToken },
2320 );
2321 if (applied) {2318 if (applied) {
2322 setComposerHighlightedItemId(null);2319 setComposerHighlightedItemId(null);
2323 }2320 }
...@@ -2360,18 +2357,27 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2360,18 +2357,27 @@ export default function ChatView({ threadId }: ChatViewProps) {
2360 workspaceEntriesQuery.isLoading ||2357 workspaceEntriesQuery.isLoading ||
2361 workspaceEntriesQuery.isFetching);2358 workspaceEntriesQuery.isFetching);
23622359
2363 const onPromptChange = useCallback((nextPrompt: string, nextCursor: number, cursorAdjacentToMention: boolean) => {2360 const onPromptChange = useCallback(
2364 promptRef.current = nextPrompt;2361 (nextPrompt: string, nextCursor: number, cursorAdjacentToMention: boolean) => {
2365 setPrompt(nextPrompt);2362 promptRef.current = nextPrompt;
2366 setComposerCursor(nextCursor);2363 setPrompt(nextPrompt);
2367 setComposerTrigger(2364 setComposerCursor(nextCursor);
2368 cursorAdjacentToMention2365 setComposerTrigger(
2369 ? null2366 cursorAdjacentToMention
2370 : detectComposerTrigger(nextPrompt, expandCollapsedComposerCursor(nextPrompt, nextCursor)),2367 ? null
2371 );2368 : detectComposerTrigger(
2372 }, [setPrompt]);2369 nextPrompt,
2370 expandCollapsedComposerCursor(nextPrompt, nextCursor),
2371 ),
2372 );
2373 },
2374 [setPrompt],
2375 );
23732376
2374 const onComposerCommandKey = (key: "ArrowDown" | "ArrowUp" | "Enter" | "Tab", event: KeyboardEvent) => {2377 const onComposerCommandKey = (
2378 key: "ArrowDown" | "ArrowUp" | "Enter" | "Tab",
2379 event: KeyboardEvent,
2380 ) => {
2375 const { trigger } = resolveActiveComposerTrigger();2381 const { trigger } = resolveActiveComposerTrigger();
2376 const menuIsActive = composerMenuOpenRef.current || trigger !== null;2382 const menuIsActive = composerMenuOpenRef.current || trigger !== null;
23772383
...@@ -2778,7 +2784,6 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -2778,7 +2784,6 @@ export default function ChatView({ threadId }: ChatViewProps) {
2778 {isGitRepo && (2784 {isGitRepo && (
2779 <BranchToolbar2785 <BranchToolbar
2780 threadId={activeThread.id}2786 threadId={activeThread.id}
2781 envMode={envMode}
2782 onEnvModeChange={onEnvModeChange}2787 onEnvModeChange={onEnvModeChange}
2783 envLocked={envLocked}2788 envLocked={envLocked}
2784 onComposerFocusRequest={scheduleComposerFocus}2789 onComposerFocusRequest={scheduleComposerFocus}
bun.lock+1
...@@ -95,6 +95,7 @@...@@ -95,6 +95,7 @@
95 "tailwindcss": "^4.0.0",95 "tailwindcss": "^4.0.0",
96 "typescript": "catalog:",96 "typescript": "catalog:",
97 "vite": "^8.0.0-beta.12",97 "vite": "^8.0.0-beta.12",
98 "vitest": "catalog:",
98 },99 },
99 },100 },
100 "packages/contracts": {101 "packages/contracts": {