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:
@@ -35,17 +35,13 @@ const INITIAL_IO: IOPoint[] = [
|
||||
// --- MAIN APP ---
|
||||
|
||||
export default function App() {
|
||||
const [activeTab, setActiveTab] = useState<'recipe' | 'motion' | 'camera' | 'setting' | null>(null);
|
||||
const [activeIOTab, setActiveIOTab] = useState<'in' | 'out'>('in');
|
||||
const [activeTab, setActiveTab] = useState<'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null>(null);
|
||||
const [systemState, setSystemState] = useState<SystemState>(SystemState.IDLE);
|
||||
const [recipes, setRecipes] = useState<Recipe[]>([]);
|
||||
const [currentRecipe, setCurrentRecipe] = useState<Recipe | null>(null);
|
||||
const [currentRecipe, setCurrentRecipe] = useState<Recipe>({ id: '0', name: 'No Recipe', lastModified: '-' });
|
||||
const [robotTarget, setRobotTarget] = useState<RobotTarget>({ x: 0, y: 0, z: 0 });
|
||||
const [logs, setLogs] = useState<LogEntry[]>([]);
|
||||
const [ioPoints, setIoPoints] = useState<IOPoint[]>([]);
|
||||
const [currentTime, setCurrentTime] = useState(new Date());
|
||||
const [config, setConfig] = useState<ConfigItem[] | null>(null);
|
||||
const [isConfigRefreshing, setIsConfigRefreshing] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isHostConnected, setIsHostConnected] = useState(false);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
@@ -94,39 +90,20 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
const initSystem = async () => {
|
||||
addLog("SYSTEM STARTED", "info");
|
||||
// Initial IO data will be loaded by HomePage when it mounts
|
||||
try {
|
||||
const ioStr = await comms.getIOList();
|
||||
const ioData = JSON.parse(ioStr);
|
||||
setIoPoints(ioData);
|
||||
addLog("IO LIST LOADED", "info");
|
||||
|
||||
const recipeStr = await comms.getRecipeList();
|
||||
const recipeData = JSON.parse(recipeStr);
|
||||
setRecipes(recipeData);
|
||||
if (recipeData.length > 0) setCurrentRecipe(recipeData[0]);
|
||||
addLog("RECIPE LIST LOADED", "info");
|
||||
} catch (e) {
|
||||
addLog("FAILED TO LOAD SYSTEM DATA", "error");
|
||||
// Fallback to empty or keep initial if needed
|
||||
addLog("FAILED TO LOAD IO DATA", "error");
|
||||
}
|
||||
setIsLoading(false);
|
||||
};
|
||||
initSystem();
|
||||
}, []);
|
||||
|
||||
// -- CONFIG FETCHING (for settings modal) --
|
||||
const fetchConfig = React.useCallback(async () => {
|
||||
setIsConfigRefreshing(true);
|
||||
try {
|
||||
const configStr = await comms.getConfig();
|
||||
setConfig(JSON.parse(configStr));
|
||||
addLog("CONFIG REFRESHED", "info");
|
||||
} catch (e) {
|
||||
addLog("CONFIG REFRESH FAILED", "error");
|
||||
}
|
||||
setIsConfigRefreshing(false);
|
||||
}, []);
|
||||
|
||||
const addLog = (msg: string, type: 'info' | 'warning' | 'error' = 'info') => {
|
||||
setLogs(prev => [{ id: Date.now() + Math.random(), timestamp: new Date().toLocaleTimeString(), message: msg, type }, ...prev].slice(0, 50));
|
||||
};
|
||||
@@ -171,7 +148,6 @@ export default function App() {
|
||||
const handleSaveConfig = async (newConfig: ConfigItem[]) => {
|
||||
try {
|
||||
await comms.saveConfig(JSON.stringify(newConfig));
|
||||
setConfig(newConfig);
|
||||
addLog("CONFIGURATION SAVED", "info");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -202,10 +178,7 @@ export default function App() {
|
||||
currentTime={currentTime}
|
||||
isHostConnected={isHostConnected}
|
||||
robotTarget={robotTarget}
|
||||
onTabChange={(tab) => {
|
||||
setActiveTab(tab);
|
||||
if (tab === null) setActiveIOTab('in'); // Reset IO tab when closing
|
||||
}}
|
||||
onTabChange={setActiveTab}
|
||||
activeTab={activeTab}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
@@ -215,13 +188,10 @@ export default function App() {
|
||||
element={
|
||||
<HomePage
|
||||
systemState={systemState}
|
||||
currentRecipe={currentRecipe || { id: '0', name: 'No Recipe', lastModified: '-' }}
|
||||
recipes={recipes}
|
||||
currentRecipe={currentRecipe}
|
||||
robotTarget={robotTarget}
|
||||
logs={logs}
|
||||
ioPoints={ioPoints}
|
||||
config={config}
|
||||
isConfigRefreshing={isConfigRefreshing}
|
||||
doorStates={doorStates}
|
||||
isLowPressure={isLowPressure}
|
||||
isEmergencyStop={isEmergencyStop}
|
||||
@@ -230,7 +200,6 @@ export default function App() {
|
||||
onMove={moveAxis}
|
||||
onControl={handleControl}
|
||||
onSaveConfig={handleSaveConfig}
|
||||
onFetchConfig={fetchConfig}
|
||||
onCloseTab={() => setActiveTab(null)}
|
||||
videoRef={videoRef}
|
||||
/>
|
||||
@@ -240,10 +209,7 @@ export default function App() {
|
||||
path="/io-monitor"
|
||||
element={
|
||||
<IOMonitorPage
|
||||
ioPoints={ioPoints}
|
||||
onToggle={toggleIO}
|
||||
activeIOTab={activeIOTab}
|
||||
onIOTabChange={setActiveIOTab}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user