kin: KIN-054 Исправить race condition в loadMode() при инициализации ProjectView
This commit is contained in:
parent
ae21e48b65
commit
756f9e65ab
5 changed files with 47 additions and 10 deletions
|
|
@ -47,9 +47,13 @@ def _build_claude_env() -> dict:
|
|||
if bin_dir.is_dir():
|
||||
extra.append(str(bin_dir))
|
||||
|
||||
seen = set(existing)
|
||||
new_dirs = [d for d in extra if d and d not in seen]
|
||||
env["PATH"] = ":".join(new_dirs + existing)
|
||||
seen: set[str] = set()
|
||||
deduped: list[str] = []
|
||||
for d in extra + existing:
|
||||
if d and d not in seen:
|
||||
seen.add(d)
|
||||
deduped.append(d)
|
||||
env["PATH"] = ":".join(deduped)
|
||||
return env
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1173,7 +1173,13 @@ class TestClaudePath:
|
|||
)
|
||||
|
||||
def test_build_claude_env_no_duplicate_paths(self):
|
||||
"""_build_claude_env не должен дублировать уже существующие пути."""
|
||||
"""_build_claude_env не должен дублировать уже существующие пути.
|
||||
|
||||
Мокируем PATH на фиксированное значение, чтобы тест не зависел от
|
||||
реального окружения (решение #48).
|
||||
"""
|
||||
fixed_path = "/usr/bin:/bin"
|
||||
with patch.dict("os.environ", {"PATH": fixed_path}, clear=False):
|
||||
env = _build_claude_env()
|
||||
path_dirs = env["PATH"].split(":")
|
||||
seen = set()
|
||||
|
|
|
|||
14
web/api.py
14
web/api.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}`),
|
||||
|
|
|
|||
|
|
@ -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 []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue