From 243077c64768ca9bdaf01f61a425f332aba2e228 Mon Sep 17 00:00:00 2001 From: Ashwin V C Date: Fri, 20 Feb 2026 14:48:25 +0530 Subject: [PATCH 1/2] fix: Ran react-doctor to fix all common issue patterns in Frontend --- .agents/react-doctor/AGENTS.md | 15 ++++ .agents/react-doctor/SKILL.md | 19 ++++++ .../src/components/DenoisingStepsSlider.tsx | 2 +- frontend/src/components/ImageManager.tsx | 2 +- frontend/src/components/PromptInput.tsx | 5 +- frontend/src/components/PromptTimeline.tsx | 68 ++++++++++++------- frontend/src/components/StatusBar.tsx | 20 +++--- .../src/components/TimelinePromptEditor.tsx | 5 +- frontend/src/components/VideoOutput.tsx | 9 +++ .../src/components/ui/debounced-slider.tsx | 21 ++++-- frontend/src/components/ui/play-overlay.tsx | 18 +++++ 11 files changed, 141 insertions(+), 43 deletions(-) create mode 100644 .agents/react-doctor/AGENTS.md create mode 100644 .agents/react-doctor/SKILL.md diff --git a/.agents/react-doctor/AGENTS.md b/.agents/react-doctor/AGENTS.md new file mode 100644 index 000000000..3db6436b2 --- /dev/null +++ b/.agents/react-doctor/AGENTS.md @@ -0,0 +1,15 @@ +# React Doctor + +Run after making React changes to catch issues early. Use when reviewing code, finishing a feature, or fixing bugs in a React project. + +Scans your React codebase for security, performance, correctness, and architecture issues. Outputs a 0-100 score with actionable diagnostics. + +## Usage + +```bash +npx -y react-doctor@latest . --verbose --diff +``` + +## Workflow + +Run after making changes to catch issues early. Fix errors first, then re-run to verify the score improved. diff --git a/.agents/react-doctor/SKILL.md b/.agents/react-doctor/SKILL.md new file mode 100644 index 000000000..8cc27cf32 --- /dev/null +++ b/.agents/react-doctor/SKILL.md @@ -0,0 +1,19 @@ +--- +name: react-doctor +description: Run after making React changes to catch issues early. Use when reviewing code, finishing a feature, or fixing bugs in a React project. +version: 1.0.0 +--- + +# React Doctor + +Scans your React codebase for security, performance, correctness, and architecture issues. Outputs a 0-100 score with actionable diagnostics. + +## Usage + +```bash +npx -y react-doctor@latest . --verbose --diff +``` + +## Workflow + +Run after making changes to catch issues early. Fix errors first, then re-run to verify the score improved. diff --git a/frontend/src/components/DenoisingStepsSlider.tsx b/frontend/src/components/DenoisingStepsSlider.tsx index 8a675eb4a..49431a85a 100644 --- a/frontend/src/components/DenoisingStepsSlider.tsx +++ b/frontend/src/components/DenoisingStepsSlider.tsx @@ -169,7 +169,7 @@ export function DenoisingStepsSlider({
{localValue.map((stepValue, index) => ( (
{managedPrompts.map((prompt, index) => { return ( -
+
(null); const [timelineWidth, setTimelineWidth] = useState(800); const [visibleStartTime, setVisibleStartTime] = useState(0); - const [visibleEndTime, setVisibleEndTime] = useState( - DEFAULT_VISIBLE_END_TIME - ); const [zoomLevel, setZoomLevel] = useState(1); // Check if live mode is active const isLive = useMemo(() => prompts.some(p => p.isLive), [prompts]); + // Calculate timeline metrics - simple derivations, no memoization needed + const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomLevel; + const visibleTimeRange = timelineWidth / pixelsPerSecond; + + // Derive visible end time from start time and time range (no state needed) + const visibleEndTime = visibleStartTime + visibleTimeRange; + // Memoized filtered prompts for better performance const visiblePrompts = useMemo(() => { return prompts.filter( @@ -223,16 +227,6 @@ export function PromptTimeline({ ); }, [prompts, visibleStartTime, visibleEndTime]); - // Calculate timeline metrics - const pixelsPerSecond = useMemo( - () => BASE_PIXELS_PER_SECOND * zoomLevel, - [zoomLevel] - ); - const visibleTimeRange = useMemo( - () => timelineWidth / pixelsPerSecond, - [timelineWidth, pixelsPerSecond] - ); - // Scroll timeline to show a specific time const scrollToTime = useCallback( (time: number) => { @@ -254,15 +248,9 @@ export function PromptTimeline({ // Reset UI state setTimelineWidth(TIMELINE_RESET_STATE.timelineWidth); setVisibleStartTime(TIMELINE_RESET_STATE.visibleStartTime); - setVisibleEndTime(TIMELINE_RESET_STATE.visibleEndTime); setZoomLevel(TIMELINE_RESET_STATE.zoomLevel); }, []); - // Update visible end time when zoom level or timeline width changes - useEffect(() => { - setVisibleEndTime(visibleStartTime + visibleTimeRange); - }, [visibleStartTime, visibleTimeRange]); - // Auto-scroll timeline during playback to follow the red line useEffect(() => { // Don't auto-scroll if user is manually dragging or not playing @@ -509,13 +497,25 @@ export function PromptTimeline({ const maxEndTime = Math.max( ...importedPrompts.map((p: TimelinePrompt) => p.endTime || 0) ); - // Set visible end time to show all prompts, with minimum of default visible range - const newVisibleEndTime = Math.max( + // Calculate the target visible end time to show all prompts + const targetVisibleEndTime = Math.max( maxEndTime + 2, // Add 2 seconds buffer DEFAULT_VISIBLE_END_TIME ); + // Adjust zoom level to fit the range (visibleEndTime = visibleStartTime + timelineWidth / pixelsPerSecond) + // pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomLevel + // targetVisibleEndTime = 0 + timelineWidth / (BASE_PIXELS_PER_SECOND * newZoom) + // newZoom = timelineWidth / (BASE_PIXELS_PER_SECOND * targetVisibleEndTime) + const newZoom = Math.max( + MIN_ZOOM_LEVEL, + Math.min( + MAX_ZOOM_LEVEL, + timelineWidth / + (BASE_PIXELS_PER_SECOND * targetVisibleEndTime) + ) + ); setVisibleStartTime(0); - setVisibleEndTime(newVisibleEndTime); + setZoomLevel(newZoom); } // Import settings if available and callback is provided @@ -550,6 +550,7 @@ export function PromptTimeline({ resetTimelineUI, onTimeChange, _onPromptSubmit, + timelineWidth, ] ); @@ -820,6 +821,8 @@ export function PromptTimeline({ {/* Timeline track */}
handlePromptClick(e, prompt)} + onKeyDown={e => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handlePromptClick( + e as unknown as React.MouseEvent, + prompt + ); + } + }} > {/* Resize handles */} {!isPlaying && !isLivePrompt && ( <>
@@ -947,6 +966,9 @@ export function PromptTimeline({ } />
@@ -967,7 +989,7 @@ export function PromptTimeline({ // Display blend prompts vertically prompt.prompts.map((promptItem, idx) => (
{promptItem.text} ({promptItem.weight}%) diff --git a/frontend/src/components/StatusBar.tsx b/frontend/src/components/StatusBar.tsx index d43cd8c89..f7aaa5b10 100644 --- a/frontend/src/components/StatusBar.tsx +++ b/frontend/src/components/StatusBar.tsx @@ -4,16 +4,14 @@ interface StatusBarProps { bitrate?: number; } -export function StatusBar({ className = "", fps, bitrate }: StatusBarProps) { - const MetricItem = ({ - label, - value, - unit = "", - }: { - label: string; - value: number | string; - unit?: string; - }) => ( +interface MetricItemProps { + label: string; + value: number | string; + unit?: string; +} + +function MetricItem({ label, value, unit = "" }: MetricItemProps) { + return (
{label}: @@ -22,7 +20,9 @@ export function StatusBar({ className = "", fps, bitrate }: StatusBarProps) {
); +} +export function StatusBar({ className = "", fps, bitrate }: StatusBarProps) { const formatBitrate = (bps?: number): string => { if (bps === undefined || bps === 0) return "N/A"; diff --git a/frontend/src/components/TimelinePromptEditor.tsx b/frontend/src/components/TimelinePromptEditor.tsx index 90647fdcf..d35591dbf 100644 --- a/frontend/src/components/TimelinePromptEditor.tsx +++ b/frontend/src/components/TimelinePromptEditor.tsx @@ -248,7 +248,10 @@ export function TimelinePromptEditor({
{prompts.map((promptItem, index) => { return ( -
+
{ + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleVideoClick(); + } + }} >