Merge branch 'master' into feature/expand-project-with-ai

This commit is contained in:
Leon van Zyl
2026-01-10 10:22:12 +02:00
committed by GitHub
23 changed files with 985 additions and 183 deletions

View File

@@ -4,7 +4,7 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate } from '../lib/types'
import type { FeatureCreate, ModelsResponse, Settings, SettingsUpdate } from '../lib/types'
// ============================================================================
// Projects
@@ -200,3 +200,74 @@ export function useValidatePath() {
mutationFn: (path: string) => api.validatePath(path),
})
}
// ============================================================================
// Settings
// ============================================================================
// Default models response for placeholder (until API responds)
const DEFAULT_MODELS: ModelsResponse = {
models: [
{ id: 'claude-opus-4-5-20251101', name: 'Claude Opus 4.5' },
{ id: 'claude-sonnet-4-5-20250929', name: 'Claude Sonnet 4.5' },
],
default: 'claude-opus-4-5-20251101',
}
const DEFAULT_SETTINGS: Settings = {
yolo_mode: false,
model: 'claude-opus-4-5-20251101',
}
export function useAvailableModels() {
return useQuery({
queryKey: ['available-models'],
queryFn: api.getAvailableModels,
staleTime: 300000, // Cache for 5 minutes - models don't change often
retry: 1,
placeholderData: DEFAULT_MODELS,
})
}
export function useSettings() {
return useQuery({
queryKey: ['settings'],
queryFn: api.getSettings,
staleTime: 60000, // Cache for 1 minute
retry: 1,
placeholderData: DEFAULT_SETTINGS,
})
}
export function useUpdateSettings() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (settings: SettingsUpdate) => api.updateSettings(settings),
onMutate: async (newSettings) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['settings'] })
// Snapshot previous value
const previous = queryClient.getQueryData<Settings>(['settings'])
// Optimistically update
queryClient.setQueryData<Settings>(['settings'], (old) => ({
...DEFAULT_SETTINGS,
...old,
...newSettings,
}))
return { previous }
},
onError: (_err, _newSettings, context) => {
// Rollback on error
if (context?.previous) {
queryClient.setQueryData(['settings'], context.previous)
}
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['settings'] })
},
})
}

View File

@@ -33,7 +33,7 @@ function generateId(): string {
export function useSpecChat({
projectName,
onComplete,
// onComplete intentionally not used - user clicks "Continue to Project" button instead
onError,
}: UseSpecChatOptions): UseSpecChatReturn {
const [messages, setMessages] = useState<ChatMessage[]>([])
@@ -346,7 +346,7 @@ export function useSpecChat({
console.error('Failed to parse WebSocket message:', e)
}
}
}, [projectName, onComplete, onError])
}, [projectName, onError])
const start = useCallback(() => {
connect()