mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-03 20:41:07 +02:00
Fix compose box issues
This commit is contained in:
parent
8e16ac6204
commit
ef378ba802
4 changed files with 48 additions and 4 deletions
|
|
@ -53,6 +53,7 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({
|
||||||
const [lastResponse, setLastResponse] = useState<unknown | null>(null);
|
const [lastResponse, setLastResponse] = useState<unknown | null>(null);
|
||||||
const [currentStatus, setCurrentStatus] = useState<'thinking' | 'planning' | 'generating'>('thinking');
|
const [currentStatus, setCurrentStatus] = useState<'thinking' | 'planning' | 'generating'>('thinking');
|
||||||
const statusIntervalRef = useRef<NodeJS.Timeout>();
|
const statusIntervalRef = useRef<NodeJS.Timeout>();
|
||||||
|
const [isLastInteracted, setIsLastInteracted] = useState(isInitialState);
|
||||||
|
|
||||||
// Notify parent of message changes
|
// Notify parent of message changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -85,6 +86,7 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({
|
||||||
content: prompt
|
content: prompt
|
||||||
}]);
|
}]);
|
||||||
setResponseError(null);
|
setResponseError(null);
|
||||||
|
setIsLastInteracted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleApplyChange = useCallback((
|
const handleApplyChange = useCallback((
|
||||||
|
|
@ -313,6 +315,8 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({
|
||||||
loading={loadingResponse}
|
loading={loadingResponse}
|
||||||
disabled={loadingResponse}
|
disabled={loadingResponse}
|
||||||
initialFocus={isInitialState}
|
initialFocus={isInitialState}
|
||||||
|
shouldAutoFocus={isLastInteracted}
|
||||||
|
onFocus={() => setIsLastInteracted(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export function Chat({
|
||||||
const [lastAgenticRequest, setLastAgenticRequest] = useState<unknown | null>(null);
|
const [lastAgenticRequest, setLastAgenticRequest] = useState<unknown | null>(null);
|
||||||
const [lastAgenticResponse, setLastAgenticResponse] = useState<unknown | null>(null);
|
const [lastAgenticResponse, setLastAgenticResponse] = useState<unknown | null>(null);
|
||||||
const [optimisticMessages, setOptimisticMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages);
|
const [optimisticMessages, setOptimisticMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages);
|
||||||
|
const [isLastInteracted, setIsLastInteracted] = useState(false);
|
||||||
|
|
||||||
const getCopyContent = useCallback(() => {
|
const getCopyContent = useCallback(() => {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
|
|
@ -90,6 +91,7 @@ export function Chat({
|
||||||
}];
|
}];
|
||||||
setMessages(updatedMessages);
|
setMessages(updatedMessages);
|
||||||
setFetchResponseError(null);
|
setFetchResponseError(null);
|
||||||
|
setIsLastInteracted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset state when workflow changes
|
// reset state when workflow changes
|
||||||
|
|
@ -293,6 +295,8 @@ export function Chat({
|
||||||
handleUserMessage={handleUserMessage}
|
handleUserMessage={handleUserMessage}
|
||||||
messages={messages.filter(msg => msg.content !== undefined) as any}
|
messages={messages.filter(msg => msg.content !== undefined) as any}
|
||||||
loading={loadingAssistantResponse}
|
loading={loadingAssistantResponse}
|
||||||
|
shouldAutoFocus={isLastInteracted}
|
||||||
|
onFocus={() => setIsLastInteracted(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ interface ComposeBoxCopilotProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
initialFocus?: boolean;
|
initialFocus?: boolean;
|
||||||
|
shouldAutoFocus?: boolean;
|
||||||
|
onFocus?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ComposeBoxCopilot({
|
export function ComposeBoxCopilot({
|
||||||
|
|
@ -28,18 +30,29 @@ export function ComposeBoxCopilot({
|
||||||
loading,
|
loading,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
initialFocus = false,
|
initialFocus = false,
|
||||||
|
shouldAutoFocus = false,
|
||||||
|
onFocus,
|
||||||
}: ComposeBoxCopilotProps) {
|
}: ComposeBoxCopilotProps) {
|
||||||
const [input, setInput] = useState('');
|
const [input, setInput] = useState('');
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const previousMessagesLength = useRef(messages.length);
|
||||||
|
|
||||||
// Add effect to handle initial focus
|
// Handle initial focus
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialFocus && textareaRef.current) {
|
if (initialFocus && textareaRef.current) {
|
||||||
textareaRef.current.focus();
|
textareaRef.current.focus();
|
||||||
}
|
}
|
||||||
}, [initialFocus]);
|
}, [initialFocus]);
|
||||||
|
|
||||||
|
// Handle auto-focus when new messages arrive
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldAutoFocus && messages.length > previousMessagesLength.current && textareaRef.current) {
|
||||||
|
textareaRef.current.focus();
|
||||||
|
}
|
||||||
|
previousMessagesLength.current = messages.length;
|
||||||
|
}, [messages.length, shouldAutoFocus]);
|
||||||
|
|
||||||
function handleInput() {
|
function handleInput() {
|
||||||
const prompt = input.trim();
|
const prompt = input.trim();
|
||||||
if (!prompt) {
|
if (!prompt) {
|
||||||
|
|
@ -56,6 +69,11 @@ export function ComposeBoxCopilot({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFocus = () => {
|
||||||
|
setIsFocused(true);
|
||||||
|
onFocus?.();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
{/* Keyboard shortcut hint */}
|
{/* Keyboard shortcut hint */}
|
||||||
|
|
@ -74,7 +92,7 @@ export function ComposeBoxCopilot({
|
||||||
value={input}
|
value={input}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
onKeyDown={handleInputKeyDown}
|
onKeyDown={handleInputKeyDown}
|
||||||
onFocus={() => setIsFocused(true)}
|
onFocus={handleFocus}
|
||||||
onBlur={() => setIsFocused(false)}
|
onBlur={() => setIsFocused(false)}
|
||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
placeholder="Type a message..."
|
placeholder="Type a message..."
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useRef } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { Button, Spinner } from "@heroui/react";
|
import { Button, Spinner } from "@heroui/react";
|
||||||
|
|
||||||
|
|
@ -7,6 +7,8 @@ interface ComposeBoxPlaygroundProps {
|
||||||
messages: any[];
|
messages: any[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
shouldAutoFocus?: boolean;
|
||||||
|
onFocus?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ComposeBoxPlayground({
|
export function ComposeBoxPlayground({
|
||||||
|
|
@ -14,10 +16,21 @@ export function ComposeBoxPlayground({
|
||||||
messages,
|
messages,
|
||||||
loading,
|
loading,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
shouldAutoFocus = false,
|
||||||
|
onFocus,
|
||||||
}: ComposeBoxPlaygroundProps) {
|
}: ComposeBoxPlaygroundProps) {
|
||||||
const [input, setInput] = useState('');
|
const [input, setInput] = useState('');
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const previousMessagesLength = useRef(messages.length);
|
||||||
|
|
||||||
|
// Handle auto-focus when new messages arrive
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldAutoFocus && messages.length > previousMessagesLength.current && textareaRef.current) {
|
||||||
|
textareaRef.current.focus();
|
||||||
|
}
|
||||||
|
previousMessagesLength.current = messages.length;
|
||||||
|
}, [messages.length, shouldAutoFocus]);
|
||||||
|
|
||||||
function handleInput() {
|
function handleInput() {
|
||||||
const prompt = input.trim();
|
const prompt = input.trim();
|
||||||
|
|
@ -35,6 +48,11 @@ export function ComposeBoxPlayground({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFocus = () => {
|
||||||
|
setIsFocused(true);
|
||||||
|
onFocus?.();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
{/* Keyboard shortcut hint */}
|
{/* Keyboard shortcut hint */}
|
||||||
|
|
@ -53,7 +71,7 @@ export function ComposeBoxPlayground({
|
||||||
value={input}
|
value={input}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
onKeyDown={handleInputKeyDown}
|
onKeyDown={handleInputKeyDown}
|
||||||
onFocus={() => setIsFocused(true)}
|
onFocus={handleFocus}
|
||||||
onBlur={() => setIsFocused(false)}
|
onBlur={() => setIsFocused(false)}
|
||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
placeholder="Type a message..."
|
placeholder="Type a message..."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue