From e118b87a3e8f16de708e5d5ed7d78cc1c5232be2 Mon Sep 17 00:00:00 2001 From: Gros Frumos Date: Tue, 17 Mar 2026 18:24:02 +0200 Subject: [PATCH] =?UTF-8?q?kin:=20KIN-INFRA-003=20=D0=98=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20command=20injection=20=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B7=20deploy=5Fpath=20=D0=B2=20SSH-=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/frontend/src/__tests__/deploy-standardized.test.ts | 8 ++++---- web/frontend/src/components/LiveConsole.vue | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/web/frontend/src/__tests__/deploy-standardized.test.ts b/web/frontend/src/__tests__/deploy-standardized.test.ts index 567d7f2..c3ebcc1 100644 --- a/web/frontend/src/__tests__/deploy-standardized.test.ts +++ b/web/frontend/src/__tests__/deploy-standardized.test.ts @@ -106,7 +106,7 @@ beforeEach(() => { success: true, exit_code: 0, stdout: '', stderr: '', duration_seconds: 2, } as any) vi.mocked(api.createProjectLink).mockResolvedValue({ - id: 1, from_project: 'KIN', to_project: 'BRS', link_type: 'depends_on', description: null, created_at: '2026-01-01', + id: 1, from_project: 'KIN', to_project: 'BRS', type: 'depends_on', description: null, created_at: '2026-01-01', } as any) vi.mocked(api.deleteProjectLink).mockResolvedValue(undefined as any) }) @@ -496,7 +496,7 @@ describe('ProjectView — Links таб', () => { it('связи отображаются при links.length > 0', async () => { const links = [ - { id: 1, from_project: 'KIN', to_project: 'BRS', link_type: 'depends_on', description: 'test', created_at: '2026-01-01' }, + { id: 1, from_project: 'KIN', to_project: 'BRS', type: 'depends_on', description: 'test', created_at: '2026-01-01' }, ] vi.mocked(api.projectLinks).mockResolvedValue(links as any) const wrapper = await mountProjectView() @@ -505,9 +505,9 @@ describe('ProjectView — Links таб', () => { expect(wrapper.text()).toContain('depends_on') }) - it('link_type и description отображаются для каждой связи', async () => { + it('type и description отображаются для каждой связи', async () => { const links = [ - { id: 2, from_project: 'KIN', to_project: 'API', link_type: 'triggers', description: 'API call', created_at: '2026-01-01' }, + { id: 2, from_project: 'KIN', to_project: 'API', type: 'triggers', description: 'API call', created_at: '2026-01-01' }, ] vi.mocked(api.projectLinks).mockResolvedValue(links as any) const wrapper = await mountProjectView() diff --git a/web/frontend/src/components/LiveConsole.vue b/web/frontend/src/components/LiveConsole.vue index 9e67404..dac380f 100644 --- a/web/frontend/src/components/LiveConsole.vue +++ b/web/frontend/src/components/LiveConsole.vue @@ -14,6 +14,7 @@ const consoleEl = ref(null) let sinceId = 0 let userScrolled = false let timer: ReturnType | null = null +let scrollTimer: ReturnType | null = null const MAX_LOGS = 500 @@ -44,9 +45,9 @@ async function fetchLogs() { sinceId = Math.max(...newLogs.map(l => l.id)) logs.value = [...logs.value, ...newLogs].slice(-MAX_LOGS) // Scroll after DOM update - setTimeout(scrollToBottom, 0) - } catch (e: any) { - error.value = e.message + scrollTimer = setTimeout(scrollToBottom, 0) + } catch (e: unknown) { + error.value = e instanceof Error ? e.message : String(e) } } @@ -62,6 +63,7 @@ function startPolling() { function stopPolling() { if (timer) { clearInterval(timer); timer = null } + if (scrollTimer) { clearTimeout(scrollTimer); scrollTimer = null } } async function toggle() {