fix: Save draft message in Chat Form when adding System Prompt from new chat view

This commit is contained in:
Aleksander Grygier 2026-01-24 13:32:49 +01:00
parent 0fe25847ff
commit 16aa6fae0a
4 changed files with 49 additions and 7 deletions

View File

@ -12,7 +12,7 @@
onFileUpload?: (files: File[]) => void; onFileUpload?: (files: File[]) => void;
onSend?: (message: string, files?: ChatUploadedFile[]) => Promise<boolean>; onSend?: (message: string, files?: ChatUploadedFile[]) => Promise<boolean>;
onStop?: () => void; onStop?: () => void;
onSystemPromptAdd?: () => void; onSystemPromptAdd?: (draft: { message: string; files: ChatUploadedFile[] }) => void;
showHelperText?: boolean; showHelperText?: boolean;
uploadedFiles?: ChatUploadedFile[]; uploadedFiles?: ChatUploadedFile[];
} }
@ -32,8 +32,21 @@
}: Props = $props(); }: Props = $props();
let inputAreaRef: ChatFormInputArea | undefined = $state(undefined); let inputAreaRef: ChatFormInputArea | undefined = $state(undefined);
let message = $state(''); let message = $state(initialMessage);
let previousIsLoading = $state(isLoading); let previousIsLoading = $state(isLoading);
let previousInitialMessage = $state(initialMessage);
// Sync message when initialMessage prop changes (e.g., after draft restoration)
$effect(() => {
if (initialMessage !== previousInitialMessage) {
message = initialMessage;
previousInitialMessage = initialMessage;
}
});
function handleSystemPromptClick() {
onSystemPromptAdd?.({ message, files: uploadedFiles });
}
let hasLoadingAttachments = $derived(uploadedFiles.some((f) => f.isLoading)); let hasLoadingAttachments = $derived(uploadedFiles.some((f) => f.isLoading));
@ -101,7 +114,7 @@
onFilesAdd={handleFilesAdd} onFilesAdd={handleFilesAdd}
{onStop} {onStop}
onSubmit={handleSubmit} onSubmit={handleSubmit}
onSystemPromptClick={onSystemPromptAdd} onSystemPromptClick={handleSystemPromptClick}
onUploadedFileRemove={handleUploadedFileRemove} onUploadedFileRemove={handleUploadedFileRemove}
/> />
</div> </div>

View File

@ -39,7 +39,7 @@
onMcpPromptArgumentsChange?: (fileId: string, args: Record<string, string>) => void; onMcpPromptArgumentsChange?: (fileId: string, args: Record<string, string>) => void;
onStop?: () => void; onStop?: () => void;
onSubmit?: () => void; onSubmit?: () => void;
onSystemPromptClick?: () => void; onSystemPromptClick?: (draft: { message: string; files: ChatUploadedFile[] }) => void;
onUploadedFileRemove?: (fileId: string) => void; onUploadedFileRemove?: (fileId: string) => void;
onUploadedFilesChange?: (files: ChatUploadedFile[]) => void; onUploadedFilesChange?: (files: ChatUploadedFile[]) => void;
onValueChange?: (value: string) => void; onValueChange?: (value: string) => void;
@ -422,7 +422,7 @@
onFileUpload={handleFileUpload} onFileUpload={handleFileUpload}
onMicClick={handleMicClick} onMicClick={handleMicClick}
{onStop} {onStop}
{onSystemPromptClick} onSystemPromptClick={() => onSystemPromptClick?.({ message: value, files: uploadedFiles })}
onMcpPromptClick={showMcpPromptButton ? () => (isPromptPickerOpen = true) : undefined} onMcpPromptClick={showMcpPromptButton ? () => (isPromptPickerOpen = true) : undefined}
/> />
</div> </div>

View File

@ -400,7 +400,7 @@
onFileUpload={handleFileUpload} onFileUpload={handleFileUpload}
onSend={handleSendMessage} onSend={handleSendMessage}
onStop={() => chatStore.stopGeneration()} onStop={() => chatStore.stopGeneration()}
onSystemPromptAdd={() => chatStore.addSystemPrompt()} onSystemPromptAdd={handleSystemPromptAdd}
showHelperText={false} showHelperText={false}
bind:uploadedFiles bind:uploadedFiles
/> />
@ -460,7 +460,7 @@
onFileUpload={handleFileUpload} onFileUpload={handleFileUpload}
onSend={handleSendMessage} onSend={handleSendMessage}
onStop={() => chatStore.stopGeneration()} onStop={() => chatStore.stopGeneration()}
onSystemPromptAdd={() => chatStore.addSystemPrompt()} onSystemPromptAdd={handleSystemPromptAdd}
showHelperText={true} showHelperText={true}
bind:uploadedFiles bind:uploadedFiles
/> />

View File

@ -41,6 +41,10 @@ class ChatStore {
private addFilesHandler: ((files: File[]) => void) | null = $state(null); private addFilesHandler: ((files: File[]) => void) | null = $state(null);
pendingEditMessageId = $state<string | null>(null); pendingEditMessageId = $state<string | null>(null);
// Draft preservation for navigation (e.g., when adding system prompt from welcome page)
private _pendingDraftMessage = $state<string>('');
private _pendingDraftFiles = $state<ChatUploadedFile[]>([]);
constructor() { constructor() {
if (browser) { if (browser) {
chatClient.setStoreCallbacks({ chatClient.setStoreCallbacks({
@ -219,6 +223,31 @@ class ChatStore {
this.pendingEditMessageId = null; this.pendingEditMessageId = null;
} }
savePendingDraft(message: string, files: ChatUploadedFile[]): void {
this._pendingDraftMessage = message;
this._pendingDraftFiles = [...files];
}
consumePendingDraft(): { message: string; files: ChatUploadedFile[] } | null {
if (!this._pendingDraftMessage && this._pendingDraftFiles.length === 0) {
return null;
}
const draft = {
message: this._pendingDraftMessage,
files: [...this._pendingDraftFiles]
};
this._pendingDraftMessage = '';
this._pendingDraftFiles = [];
return draft;
}
hasPendingDraft(): boolean {
return Boolean(this._pendingDraftMessage) || this._pendingDraftFiles.length > 0;
}
getAllLoadingChats(): string[] { getAllLoadingChats(): string[] {
return Array.from(this.chatLoadingStates.keys()); return Array.from(this.chatLoadingStates.keys());
} }