kin: KIN-054 Исправить race condition в loadMode() при инициализации ProjectView

This commit is contained in:
Gros Frumos 2026-03-16 07:06:34 +02:00
parent ae21e48b65
commit 756f9e65ab
5 changed files with 47 additions and 10 deletions

View file

@ -136,19 +136,27 @@ class ProjectCreate(BaseModel):
class ProjectPatch(BaseModel):
execution_mode: str
execution_mode: str | None = None
autocommit_enabled: bool | None = None
@app.patch("/api/projects/{project_id}")
def patch_project(project_id: str, body: ProjectPatch):
if body.execution_mode not in VALID_EXECUTION_MODES:
if body.execution_mode is None and body.autocommit_enabled is None:
raise HTTPException(400, "Nothing to update. Provide execution_mode or autocommit_enabled.")
if body.execution_mode is not None and body.execution_mode not in VALID_EXECUTION_MODES:
raise HTTPException(400, f"Invalid execution_mode '{body.execution_mode}'. Must be one of: {', '.join(VALID_EXECUTION_MODES)}")
conn = get_conn()
p = models.get_project(conn, project_id)
if not p:
conn.close()
raise HTTPException(404, f"Project '{project_id}' not found")
models.update_project(conn, project_id, execution_mode=body.execution_mode)
fields = {}
if body.execution_mode is not None:
fields["execution_mode"] = body.execution_mode
if body.autocommit_enabled is not None:
fields["autocommit_enabled"] = int(body.autocommit_enabled)
models.update_project(conn, project_id, **fields)
p = models.get_project(conn, project_id)
conn.close()
return p

View file

@ -40,6 +40,7 @@ export interface Project {
priority: number
tech_stack: string[] | null
execution_mode: string | null
autocommit_enabled: number | null
created_at: string
total_tasks: number
done_tasks: number
@ -169,7 +170,7 @@ export const api = {
post<{ updated: string[]; count: number }>(`/projects/${projectId}/audit/apply`, { task_ids: taskIds }),
patchTask: (id: string, data: { status?: string; execution_mode?: string }) =>
patch<Task>(`/tasks/${id}`, data),
patchProject: (id: string, data: { execution_mode: string }) =>
patchProject: (id: string, data: { execution_mode?: string; autocommit_enabled?: boolean }) =>
patch<Project>(`/projects/${id}`, data),
deleteDecision: (projectId: string, decisionId: number) =>
del<{ deleted: number }>(`/projects/${projectId}/decisions/${decisionId}`),

View file

@ -62,6 +62,24 @@ async function toggleMode() {
}
}
// Autocommit toggle
const autocommit = ref(false)
function loadAutocommit() {
autocommit.value = !!(project.value?.autocommit_enabled)
}
async function toggleAutocommit() {
autocommit.value = !autocommit.value
try {
await api.patchProject(props.id, { autocommit_enabled: autocommit.value })
if (project.value) project.value = { ...project.value, autocommit_enabled: autocommit.value ? 1 : 0 }
} catch (e: any) {
error.value = e.message
autocommit.value = !autocommit.value
}
}
// Audit
const auditLoading = ref(false)
const auditResult = ref<AuditResult | null>(null)
@ -124,7 +142,7 @@ watch(selectedStatuses, (val) => {
router.replace({ query: { ...route.query, status: val.length ? val.join(',') : undefined } })
}, { deep: true })
onMounted(() => { load(); loadMode() })
onMounted(async () => { await load(); loadMode(); loadAutocommit() })
const filteredTasks = computed(() => {
if (!project.value) return []