Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 3 additions & 26 deletions web-app/src/containers/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import TextareaAutosize from 'react-textarea-autosize'
import { cn } from '@/lib/utils'
import { usePrompt } from '@/hooks/usePrompt'
import { useThreads } from '@/hooks/useThreads'
import { useThreadManagement } from '@/hooks/useThreadManagement'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Button } from '@/components/ui/button'
import {
Expand Down Expand Up @@ -53,8 +52,7 @@ type ChatInputProps = {
const ChatInput = ({
model,
className,
initialMessage,
projectId,
initialMessage
}: ChatInputProps) => {
const textareaRef = useRef<HTMLTextAreaElement>(null)
const [isFocused, setIsFocused] = useState(false)
Expand All @@ -68,8 +66,6 @@ const ChatInput = ({
const prompt = usePrompt((state) => state.prompt)
const setPrompt = usePrompt((state) => state.setPrompt)
const currentThreadId = useThreads((state) => state.currentThreadId)
const updateThread = useThreads((state) => state.updateThread)
const { getFolderById } = useThreadManagement()
const { t } = useTranslation()
const spellCheckChatInput = useGeneralSetting(
(state) => state.spellCheckChatInput
Expand Down Expand Up @@ -196,27 +192,8 @@ const ChatInput = ({
)
setUploadedFiles([])

// Handle project assignment for new threads
if (projectId && !currentThreadId) {
const project = getFolderById(projectId)
if (project) {
// Use setTimeout to ensure the thread is created first
setTimeout(() => {
const newCurrentThreadId = useThreads.getState().currentThreadId
if (newCurrentThreadId) {
updateThread(newCurrentThreadId, {
metadata: {
project: {
id: project.id,
name: project.name,
updated_at: project.updated_at,
},
},
})
}
}, 100)
}
}
// Note: Project assignment for new threads is now handled directly in useChat.ts
// when creating the thread, ensuring the project system prompt is applied from the first message
}

useEffect(() => {
Expand Down
6 changes: 3 additions & 3 deletions web-app/src/containers/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ const LeftPanel = () => {
}
}

const handleProjectSave = (name: string) => {
const handleProjectSave = (name: string, systemPrompt?: string) => {
if (editingProjectKey) {
updateFolder(editingProjectKey, name)
updateFolder(editingProjectKey, name, systemPrompt)
} else {
const newProject = addFolder(name)
const newProject = addFolder(name, systemPrompt)
// Navigate to the newly created project
navigate({
to: '/project/$projectId',
Expand Down
45 changes: 36 additions & 9 deletions web-app/src/containers/dialogs/AddProjectDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { useThreadManagement } from '@/hooks/useThreadManagement'
import { toast } from 'sonner'
import { useTranslation } from '@/i18n/react-i18next-compat'
Expand All @@ -20,8 +21,9 @@ interface AddProjectDialogProps {
id: string
name: string
updated_at: number
systemPrompt?: string
}
onSave: (name: string) => void
onSave: (name: string, systemPrompt?: string) => void
}

export default function AddProjectDialog({
Expand All @@ -33,11 +35,13 @@ export default function AddProjectDialog({
}: AddProjectDialogProps) {
const { t } = useTranslation()
const [name, setName] = useState(initialData?.name || '')
const [systemPrompt, setSystemPrompt] = useState(initialData?.systemPrompt || '')
const { folders } = useThreadManagement()

useEffect(() => {
if (open) {
setName(initialData?.name || '')
setSystemPrompt(initialData?.systemPrompt || '')
}
}, [open, initialData])

Expand All @@ -58,16 +62,23 @@ export default function AddProjectDialog({
return
}

onSave(trimmedName)
onSave(trimmedName, systemPrompt.trim() || undefined)

// Show detailed success message
if (editingKey && initialData) {
toast.success(
t('projects.addProjectDialog.renameSuccess', {
oldName: initialData.name,
newName: trimmedName
})
)
const nameChanged = trimmedName !== initialData.name

if (nameChanged) {
toast.success(
t('projects.addProjectDialog.renameSuccess', {
oldName: initialData.name,
newName: trimmedName
})
)
} else {
// Only system prompt changed
toast.success(t('projects.addProjectDialog.updateSuccess', { projectName: trimmedName }))
}
} else {
toast.success(t('projects.addProjectDialog.createSuccess', { projectName: trimmedName }))
}
Expand All @@ -78,11 +89,15 @@ export default function AddProjectDialog({
const handleCancel = () => {
onOpenChange(false)
setName('')
setSystemPrompt('')
}

// Check if the button should be disabled
const isButtonDisabled =
!name.trim() || (editingKey && name.trim() === initialData?.name)
!name.trim() ||
(editingKey &&
name.trim() === initialData?.name &&
systemPrompt.trim() === (initialData?.systemPrompt))

return (
<Dialog open={open} onOpenChange={onOpenChange}>
Expand Down Expand Up @@ -110,6 +125,18 @@ export default function AddProjectDialog({
}}
/>
</div>
<div>
<label className="text-sm font-medium text-main-view-fg/80">
System Prompt (Optional)
</label>
<Textarea
value={systemPrompt}
onChange={(e) => setSystemPrompt(e.target.value)}
placeholder="Enter a custom system prompt that will be applied to all conversations in this project..."
className="mt-1"
rows={4}
/>
</div>
</div>
<DialogFooter>
<Button variant="link" onClick={handleCancel}>
Expand Down
Loading