Disable chat input while extensions load (#4417)

This commit is contained in:
Amed Rodriguez
2025-09-02 14:03:20 -07:00
committed by GitHub
parent d6dbbab8bc
commit 4e9c5e3e2d
8 changed files with 105 additions and 52 deletions
+37 -27
View File
@@ -86,6 +86,7 @@ interface ChatInputProps {
autoSubmit: boolean;
setAncestorMessages?: (messages: Message[]) => void;
append?: (message: Message) => void;
isExtensionsLoading?: boolean;
}
export default function ChatInput({
@@ -111,6 +112,7 @@ export default function ChatInput({
autoSubmit = false,
append,
setAncestorMessages,
isExtensionsLoading = false,
}: ChatInputProps) {
const [_value, setValue] = useState(initialValue);
const [displayValue, setDisplayValue] = useState(initialValue); // For immediate visual feedback
@@ -1125,6 +1127,25 @@ export default function ChatInput({
const isAnyImageLoading = pastedImages.some((img) => img.isLoading);
const isAnyDroppedFileLoading = allDroppedFiles.some((file) => file.isLoading);
const isSubmitButtonDisabled =
!hasSubmittableContent ||
isAnyImageLoading ||
isAnyDroppedFileLoading ||
isRecording ||
isTranscribing ||
isCompacting ||
!agentIsReady ||
isExtensionsLoading;
const isUserInputDisabled =
isAnyImageLoading ||
isAnyDroppedFileLoading ||
isRecording ||
isTranscribing ||
isCompacting ||
!agentIsReady ||
isExtensionsLoading;
// Queue management functions - no storage persistence, only in-memory
const handleRemoveQueuedMessage = (messageId: string) => {
setQueuedMessages((prev) => prev.filter((msg) => msg.id !== messageId));
@@ -1239,6 +1260,7 @@ export default function ChatInput({
onBlur={() => setIsFocused(false)}
ref={textAreaRef}
rows={1}
disabled={isUserInputDisabled}
style={{
maxHeight: `${maxHeight}px`,
overflowY: 'auto',
@@ -1349,23 +1371,9 @@ export default function ChatInput({
size="sm"
shape="round"
variant="outline"
disabled={
!hasSubmittableContent ||
isAnyImageLoading ||
isAnyDroppedFileLoading ||
isRecording ||
isTranscribing ||
isCompacting ||
!agentIsReady
}
disabled={isSubmitButtonDisabled}
className={`rounded-full px-10 py-2 flex items-center gap-2 ${
!hasSubmittableContent ||
isAnyImageLoading ||
isAnyDroppedFileLoading ||
isRecording ||
isTranscribing ||
isCompacting ||
!agentIsReady
isSubmitButtonDisabled
? 'bg-slate-600 text-white cursor-not-allowed opacity-50 border-slate-600'
: 'bg-slate-600 text-white hover:bg-slate-700 border-slate-600 hover:cursor-pointer'
}`}
@@ -1377,17 +1385,19 @@ export default function ChatInput({
</TooltipTrigger>
<TooltipContent>
<p>
{isCompacting
? 'Compacting conversation...'
: isAnyImageLoading
? 'Waiting for images to save...'
: isAnyDroppedFileLoading
? 'Processing dropped files...'
: isRecording
? 'Recording...'
: isTranscribing
? 'Transcribing...'
: (chatContext?.agentWaitingMessage ?? 'Send')}
{isExtensionsLoading
? 'Loading extensions...'
: isCompacting
? 'Compacting conversation...'
: isAnyImageLoading
? 'Waiting for images to save...'
: isAnyDroppedFileLoading
? 'Processing dropped files...'
: isRecording
? 'Recording...'
: isTranscribing
? 'Transcribing...'
: (chatContext?.agentWaitingMessage ?? 'Send')}
</p>
</TooltipContent>
</Tooltip>
+11 -9
View File
@@ -16,9 +16,10 @@ import { Ollama } from './icons';
interface OllamaSetupProps {
onSuccess: () => void;
onCancel: () => void;
setIsExtensionsLoading?: (loading: boolean) => void;
}
export function OllamaSetup({ onSuccess, onCancel }: OllamaSetupProps) {
export function OllamaSetup({ onSuccess, onCancel, setIsExtensionsLoading }: OllamaSetupProps) {
const { addExtension, getExtensions, upsert } = useConfig();
const [isChecking, setIsChecking] = useState(true);
const [ollamaDetected, setOllamaDetected] = useState(false);
@@ -113,6 +114,7 @@ export function OllamaSetup({ onSuccess, onCancel }: OllamaSetupProps) {
await initializeSystem('ollama', getPreferredModel(), {
getExtensions,
addExtension,
setIsExtensionsLoading,
});
toastService.success({
@@ -157,7 +159,9 @@ export function OllamaSetup({ onSuccess, onCancel }: OllamaSetupProps) {
{ollamaDetected ? (
<div className="space-y-4">
<div className="flex items-start mb-16">
<span className="inline-block px-2 py-1 text-xs font-medium bg-green-600 text-white rounded-full">Ollama is detected and running</span>
<span className="inline-block px-2 py-1 text-xs font-medium bg-green-600 text-white rounded-full">
Ollama is detected and running
</span>
</div>
{modelStatus === 'checking' ? (
@@ -185,14 +189,10 @@ export function OllamaSetup({ onSuccess, onCancel }: OllamaSetupProps) {
) : modelStatus === 'downloading' ? (
<div className="space-y-4">
<div className="bg-background-info/10 border border-border-info rounded-lg p-4">
<p className="text-text-info text-sm">
Downloading {getPreferredModel()}...
</p>
<p className="text-text-info text-sm">Downloading {getPreferredModel()}...</p>
{downloadProgress && (
<>
<p className="text-text-muted text-xs mt-2">
{downloadProgress.status}
</p>
<p className="text-text-muted text-xs mt-2">{downloadProgress.status}</p>
{downloadProgress.total && downloadProgress.completed && (
<div className="mt-3">
<div className="bg-background-muted rounded-full h-2 overflow-hidden">
@@ -225,7 +225,9 @@ export function OllamaSetup({ onSuccess, onCancel }: OllamaSetupProps) {
) : (
<div className="space-y-4">
<div className="flex items-start mb-16">
<span className="inline-block px-2 py-1 text-xs font-medium bg-orange-600 text-white rounded-full">Ollama is not detected on your system</span>
<span className="inline-block px-2 py-1 text-xs font-medium bg-orange-600 text-white rounded-full">
Ollama is not detected on your system
</span>
</div>
{isPolling ? (
+5 -1
View File
@@ -14,9 +14,10 @@ import { OpenRouter } from './icons';
interface ProviderGuardProps {
children: React.ReactNode;
setIsExtensionsLoading?: (loading: boolean) => void;
}
export default function ProviderGuard({ children }: ProviderGuardProps) {
export default function ProviderGuard({ children, setIsExtensionsLoading }: ProviderGuardProps) {
const { read, getExtensions, addExtension } = useConfig();
const navigate = useNavigate();
const [isChecking, setIsChecking] = useState(true);
@@ -72,6 +73,7 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
await initializeSystem(provider as string, model as string, {
getExtensions,
addExtension,
setIsExtensionsLoading,
});
toastService.configure({ silent: false });
@@ -138,6 +140,7 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
await initializeSystem(provider as string, model as string, {
getExtensions,
addExtension,
setIsExtensionsLoading,
});
toastService.configure({ silent: false });
@@ -267,6 +270,7 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
setShowOllamaSetup(false);
setShowFirstTimeSetup(true);
}}
setIsExtensionsLoading={setIsExtensionsLoading}
/>
</div>
</div>
+3
View File
@@ -36,6 +36,7 @@ export default function Hub({
setPairChat,
setView,
setIsGoosehintsModalOpen,
isExtensionsLoading,
}: {
readyForAutoUserPrompt: boolean;
chat: ChatType;
@@ -43,6 +44,7 @@ export default function Hub({
setPairChat: (chat: ChatType) => void;
setView: (view: View, viewOptions?: ViewOptions) => void;
setIsGoosehintsModalOpen: (isOpen: boolean) => void;
isExtensionsLoading: boolean;
}) {
// Handle chat input submission - create new chat and navigate to pair
const handleSubmit = (e: React.FormEvent) => {
@@ -101,6 +103,7 @@ export default function Hub({
disableAnimation={false}
sessionCosts={undefined}
setIsGoosehintsModalOpen={setIsGoosehintsModalOpen}
isExtensionsLoading={isExtensionsLoading}
/>
</div>
</ContextManagerProvider>
@@ -10,9 +10,14 @@ import { toastService } from '../../../toasts';
interface ProviderSettingsProps {
onClose: () => void;
isOnboarding: boolean;
setIsExtensionsLoading?: (loading: boolean) => void;
}
export default function ProviderSettings({ onClose, isOnboarding }: ProviderSettingsProps) {
export default function ProviderSettings({
onClose,
isOnboarding,
setIsExtensionsLoading,
}: ProviderSettingsProps) {
const { getProviders, upsert, getExtensions, addExtension } = useConfig();
const [loading, setLoading] = useState(true);
const [providers, setProviders] = useState<ProviderDetails[]>([]);
@@ -71,6 +76,7 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett
await initializeSystem(provider.name, model, {
getExtensions,
addExtension,
setIsExtensionsLoading,
});
toastService.configure({ silent: false });
@@ -92,7 +98,7 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett
});
}
},
[onClose, upsert, getExtensions, addExtension]
[onClose, upsert, getExtensions, addExtension, setIsExtensionsLoading]
);
return (