From 37ac150a9408c3b67d2a0d7256d9da07692150b7 Mon Sep 17 00:00:00 2001 From: Mariusz Banach Date: Wed, 18 Feb 2026 00:46:15 +0100 Subject: [PATCH] MAESTRO: wire analyse shortcut action feedback --- ...b-header-analyzer-Phase-03-Header-Input.md | 2 +- frontend/src/app/page.tsx | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md index 53bf089..6d8e96d 100644 --- a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md +++ b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md @@ -41,7 +41,7 @@ Note: `npx vitest run src/__tests__/AnalyseButton.test.tsx` passes; Vitest emits - [x] User can paste text into the header input area - [x] User can drop an EML/TXT file and see it auto-populate the input - [x] Analyse button is disabled when input is empty -- [ ] Ctrl+Enter keyboard shortcut triggers the analyse action +- [x] Ctrl+Enter keyboard shortcut triggers the analyse action - [ ] Dark hacker theme is visible with correct colour palette - [ ] Validation shows user-friendly errors for empty and oversized input - [ ] `npx eslint src/` and `npx prettier --check src/` pass with zero errors diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index fb5d789..865c885 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import AnalyseButton from "../components/AnalyseButton"; import FileDropZone from "../components/FileDropZone"; @@ -8,7 +8,31 @@ import HeaderInput from "../components/HeaderInput"; export default function Home() { const [headerInput, setHeaderInput] = useState(""); + const [isAnalyzing, setIsAnalyzing] = useState(false); const hasHeaderInput = headerInput.trim().length > 0; + const analyseTimeoutRef = useRef(null); + + useEffect(() => { + return () => { + if (analyseTimeoutRef.current !== null) { + window.clearTimeout(analyseTimeoutRef.current); + } + }; + }, []); + + const handleAnalyse = () => { + if (!hasHeaderInput) { + return; + } + + setIsAnalyzing(true); + if (analyseTimeoutRef.current !== null) { + window.clearTimeout(analyseTimeoutRef.current); + } + analyseTimeoutRef.current = window.setTimeout(() => { + setIsAnalyzing(false); + }, 800); + }; return (
@@ -44,7 +68,11 @@ export default function Home() { heuristics, and delivery path insights.

- undefined} /> +
Ctrl