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.