authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-07-21 14:29:23-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-21 14:29:23-07:00
log23c18fda7a969634a30888e36b2da45f6d66a83b
tree49a65cdd7b888d6a7f4577521ab3744c2f22a8a4
parentc0bb2373450231e3931937d2f703e35ce906ed85
signature Signed by PGP key B5690EEEBB952194

fix(web): keep composer editable while disconnected (#4241)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

1 files changed, 8 insertions(+), 12 deletions(-)

apps/web/src/components/chat/ChatComposer.tsx+8-12
......@@ -1159,6 +1159,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
11591159 isSendBusy ||
11601160 isConnecting ||
11611161 projectSelectionRequired ||
1162 environmentUnavailable !== null ||
11621163 !composerSendState.hasSendableContent;
11631164 const collapsedComposerPrimaryActionLabel = "Send message";
11641165 const showMobilePendingAnswerActions =
......@@ -1697,7 +1698,9 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
16971698
16981699 const shouldBlurMobileComposerOnSubmit = useCallback(() => {
16991700 if (!isMobileViewport) return false;
1700 if (isSendBusy || isConnecting || phase === "running") return false;
1701 if (isSendBusy || isConnecting || environmentUnavailable !== null || phase === "running") {
1702 return false;
1703 }
17011704 if (activePendingProgress) {
17021705 return activePendingProgress.isLastQuestion && Boolean(activePendingResolvedAnswers);
17031706 }
......@@ -1706,6 +1709,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
17061709 activePendingProgress,
17071710 activePendingResolvedAnswers,
17081711 composerSendState.hasSendableContent,
1712 environmentUnavailable,
17091713 isConnecting,
17101714 isMobileViewport,
17111715 isSendBusy,
......@@ -1892,8 +1896,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
18921896 isConnecting ||
18931897 isComposerApprovalState ||
18941898 pendingUserInputs.length > 0 ||
1895 projectSelectionRequired ||
1896 (environmentUnavailable !== null && activePendingProgress === null)
1899 projectSelectionRequired
18971900 ) {
18981901 return false;
18991902 }
......@@ -2101,8 +2104,6 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
21012104 isComposerApprovalState,
21022105 pendingUserInputs.length,
21032106 projectSelectionRequired,
2104 environmentUnavailable,
2105 activePendingProgress,
21062107 applyPromptReplacement,
21072108 isComposerModelPickerOpen,
21082109 readComposerSnapshot,
......@@ -2144,7 +2145,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
21442145 className={cn(
21452146 "chat-composer-glass rounded-[20px] border transition-[background-color] duration-200 has-focus-visible:border-ring/45",
21462147 isDragOverComposer ? "border-primary/70 bg-accent/45" : "border-border",
2147 environmentUnavailable || projectSelectionRequired ? "opacity-75" : null,
2148 projectSelectionRequired ? "opacity-75" : null,
21482149 composerProviderState.composerSurfaceClassName,
21492150 )}
21502151 onFocusCapture={(event) => {
......@@ -2502,12 +2503,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
25022503 ? "Ask for follow-up changes or attach images"
25032504 : "Ask anything, @tag files/folders, $use skills, or / for commands"
25042505 }
2505 disabled={
2506 isConnecting ||
2507 isComposerApprovalState ||
2508 projectSelectionRequired ||
2509 (environmentUnavailable !== null && activePendingProgress === null)
2510 }
2506 disabled={isConnecting || isComposerApprovalState || projectSelectionRequired}
25112507 />
25122508 {showMobilePendingAnswerActions ? (
25132509 <div