refactor: Decentralize data fetching and add axis initialization

Refactor data fetching architecture from centralized App state to
component-local data management for improved maintainability and
data freshness guarantees.

Changes:
- SettingsModal: Fetch config data on modal open
- RecipePanel: Fetch recipe list on panel open
- IOMonitorPage: Fetch IO list on page mount with real-time updates
- Remove unnecessary props drilling through component hierarchy
- Simplify App.tsx by removing centralized config/recipes state

New feature:
- Add InitializeModal for sequential axis initialization (X, Y, Z)
- Each axis initializes with 3-second staggered start
- Progress bar animation for each axis
- Auto-close on completion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-25 01:35:32 +09:00
parent 27cc2507cf
commit 362263ab05
10 changed files with 631 additions and 201 deletions

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Play, Square, RotateCw, AlertTriangle, Siren, Terminal } from 'lucide-react';
import { Machine3D } from '../components/Machine3D';
import { SettingsModal } from '../components/SettingsModal';
import { InitializeModal } from '../components/InitializeModal';
import { RecipePanel } from '../components/RecipePanel';
import { MotionPanel } from '../components/MotionPanel';
import { CameraPanel } from '../components/CameraPanel';
@@ -13,21 +14,17 @@ import { SystemState, Recipe, IOPoint, LogEntry, RobotTarget, ConfigItem } from
interface HomePageProps {
systemState: SystemState;
currentRecipe: Recipe;
recipes: Recipe[];
robotTarget: RobotTarget;
logs: LogEntry[];
ioPoints: IOPoint[];
config: ConfigItem[] | null;
isConfigRefreshing: boolean;
doorStates: { front: boolean; right: boolean; left: boolean; back: boolean };
isLowPressure: boolean;
isEmergencyStop: boolean;
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | null;
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null;
onSelectRecipe: (r: Recipe) => void;
onMove: (axis: 'X' | 'Y' | 'Z', val: number) => void;
onControl: (action: 'start' | 'stop' | 'reset') => void;
onSaveConfig: (config: ConfigItem[]) => void;
onFetchConfig: () => void;
onCloseTab: () => void;
videoRef: React.RefObject<HTMLVideoElement>;
}
@@ -35,12 +32,9 @@ interface HomePageProps {
export const HomePage: React.FC<HomePageProps> = ({
systemState,
currentRecipe,
recipes,
robotTarget,
logs,
ioPoints,
config,
isConfigRefreshing,
doorStates,
isLowPressure,
isEmergencyStop,
@@ -49,7 +43,6 @@ export const HomePage: React.FC<HomePageProps> = ({
onMove,
onControl,
onSaveConfig,
onFetchConfig,
onCloseTab,
videoRef
}) => {
@@ -59,12 +52,6 @@ export const HomePage: React.FC<HomePageProps> = ({
}
}, [activeTab, videoRef]);
useEffect(() => {
if (activeTab === 'setting') {
onFetchConfig();
}
}, [activeTab, onFetchConfig]);
return (
<main className="relative w-full h-full flex gap-6 px-6">
{/* 3D Canvas (Background Layer) */}
@@ -101,24 +88,26 @@ export const HomePage: React.FC<HomePageProps> = ({
)}
{/* Recipe Selection Modal */}
{activeTab === 'recipe' && (
<RecipePanel
recipes={recipes}
currentRecipe={currentRecipe}
onSelectRecipe={onSelectRecipe}
onClose={onCloseTab}
/>
)}
<RecipePanel
isOpen={activeTab === 'recipe'}
currentRecipe={currentRecipe}
onSelectRecipe={onSelectRecipe}
onClose={onCloseTab}
/>
{/* Settings Modal */}
<SettingsModal
isOpen={activeTab === 'setting'}
onClose={onCloseTab}
config={config}
isRefreshing={isConfigRefreshing}
onSave={onSaveConfig}
/>
{/* Initialize Modal */}
<InitializeModal
isOpen={activeTab === 'initialize'}
onClose={onCloseTab}
/>
{/* Right Sidebar (Dashboard) */}
<div className="w-80 ml-auto z-20 flex flex-col gap-4">
<ModelInfoPanel currentRecipe={currentRecipe} />