feat: Enhance system initialization and mock mode handling with improved UI feedback and error handling
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { Routes, Route, Navigate } from 'react-router-dom'
|
||||
import { useWebSocket } from './hooks/useWebSocket'
|
||||
import { useSystemStore } from './stores/systemStore'
|
||||
@@ -19,16 +19,19 @@ import ErrorBoundary from './components/common/ErrorBoundary'
|
||||
|
||||
function App() {
|
||||
const { connect, disconnect, isConnected } = useWebSocket()
|
||||
const { initializeSystem, isInitialized } = useSystemStore()
|
||||
const { initializeSystem, isInitialized, isLoading, error } = useSystemStore()
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize the system on app start
|
||||
// Initialize the system on app start (this will handle mock mode automatically)
|
||||
initializeSystem()
|
||||
|
||||
// Connect to WebSocket for real-time updates
|
||||
connect()
|
||||
// Try to connect to WebSocket for real-time updates (optional in mock mode)
|
||||
const timer = setTimeout(() => {
|
||||
connect()
|
||||
}, 1000) // Small delay to let system initialize first
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
disconnect()
|
||||
}
|
||||
}, [initializeSystem, connect, disconnect])
|
||||
@@ -37,13 +40,26 @@ function App() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-16 w-16 border-b-2 border-primary-600 mx-auto mb-4"></div>
|
||||
<div className="animate-spin rounded-full h-16 w-16 border-b-2 border-red-600 mx-auto mb-4"></div>
|
||||
<h2 className="text-xl font-semibold text-gray-900">
|
||||
Initializing Tempering System...
|
||||
{isLoading ? 'Initializing Tempering System...' : 'System Initialization'}
|
||||
</h2>
|
||||
<p className="text-gray-600 mt-2">
|
||||
Please wait while we connect to the hardware
|
||||
{error
|
||||
? `Error: ${error}`
|
||||
: isLoading
|
||||
? 'Connecting to backend services...'
|
||||
: 'Please wait while we set up the system'
|
||||
}
|
||||
</p>
|
||||
{error && (
|
||||
<button
|
||||
onClick={() => initializeSystem()}
|
||||
className="mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
|
||||
>
|
||||
Retry Connection
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useSystemStore } from '../../stores/systemStore'
|
||||
|
||||
export function MockModeIndicator() {
|
||||
const { systemInfo, isConnected } = useSystemStore()
|
||||
|
||||
const isMockMode = systemInfo?.environment === 'mock' || !isConnected
|
||||
|
||||
if (!isMockMode) return null
|
||||
|
||||
return (
|
||||
<div className="bg-yellow-100 border-l-4 border-yellow-500 p-3 mb-4">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="text-yellow-600 text-lg">⚠️</span>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<p className="text-sm text-yellow-700">
|
||||
<strong>Demo Mode:</strong> Running without hardware connection.
|
||||
All data is simulated for testing purposes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import React, { ReactNode } from 'react'
|
||||
import Header from './Header'
|
||||
import Sidebar from './Sidebar'
|
||||
import StatusBar from './StatusBar'
|
||||
import { MockModeIndicator } from '../common/MockModeIndicator'
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode
|
||||
@@ -21,6 +22,7 @@ const Layout: React.FC<LayoutProps> = ({ children, isConnected }) => {
|
||||
{/* Main content area */}
|
||||
<main className="flex-1 overflow-auto p-4">
|
||||
<div className="max-w-none">
|
||||
<MockModeIndicator />
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useWebSocket = (): UseWebSocketReturn => {
|
||||
const maxReconnectAttempts = 10
|
||||
|
||||
// Store actions
|
||||
const { updateSystemStatus, updateConnectionStatus, setError } = useSystemStore()
|
||||
const { updateSystemStatus, updateConnectionStatus } = useSystemStore()
|
||||
|
||||
// Get WebSocket URL from environment
|
||||
const getSocketUrl = useCallback(() => {
|
||||
@@ -31,8 +31,8 @@ export const useWebSocket = (): UseWebSocketReturn => {
|
||||
// Handle reconnection with exponential backoff
|
||||
const scheduleReconnect = useCallback(() => {
|
||||
if (reconnectAttempts.current >= maxReconnectAttempts) {
|
||||
console.error('Max reconnection attempts reached')
|
||||
setError('Lost connection to server. Please refresh the page.')
|
||||
console.warn('Max WebSocket reconnection attempts reached - continuing in mock mode')
|
||||
// Don't set error, just stop trying to reconnect
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export const useWebSocket = (): UseWebSocketReturn => {
|
||||
reconnectTimeoutRef.current = setTimeout(() => {
|
||||
connect()
|
||||
}, delay)
|
||||
}, [setError])
|
||||
}, [])
|
||||
|
||||
// Connect to WebSocket
|
||||
const connect = useCallback(() => {
|
||||
@@ -143,8 +143,9 @@ export const useWebSocket = (): UseWebSocketReturn => {
|
||||
},
|
||||
})
|
||||
} else if (data.overall_status === 'warning') {
|
||||
toast.warning('Safety warning', {
|
||||
toast('Safety warning', {
|
||||
duration: 5000,
|
||||
icon: '⚠️',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios, { AxiosResponse, AxiosError } from 'axios'
|
||||
import toast from 'react-hot-toast'
|
||||
import { mockApi } from './mockApi'
|
||||
import type {
|
||||
SystemInfo,
|
||||
SystemStatus,
|
||||
@@ -19,6 +20,15 @@ import type {
|
||||
ApiError,
|
||||
} from '../types'
|
||||
|
||||
// Global flag to track if we should use mock mode
|
||||
let useMockMode = false
|
||||
let mockModeDetected = false
|
||||
|
||||
// Check if we should use mock mode
|
||||
const shouldUseMockMode = () => {
|
||||
return useMockMode || import.meta.env.VITE_USE_MOCK_API === 'true'
|
||||
}
|
||||
|
||||
// Create axios instance with default configuration
|
||||
const apiClient = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000',
|
||||
@@ -81,6 +91,40 @@ apiClient.interceptors.response.use(
|
||||
}
|
||||
)
|
||||
|
||||
// Helper function to handle API responses with mock fallback
|
||||
const handleApiCall = async <T>(
|
||||
apiCall: () => Promise<T>,
|
||||
mockCall: () => Promise<T>,
|
||||
operationName: string
|
||||
): Promise<T> => {
|
||||
if (shouldUseMockMode()) {
|
||||
console.info(`[MOCK MODE] Using mock API for ${operationName}`)
|
||||
return await mockCall()
|
||||
}
|
||||
|
||||
try {
|
||||
return await apiCall()
|
||||
} catch (error) {
|
||||
// If we get a connection error, switch to mock mode
|
||||
if (error instanceof AxiosError && (!error.response || error.code === 'ECONNREFUSED' || error.code === 'ERR_NETWORK')) {
|
||||
if (!mockModeDetected) {
|
||||
console.warn('Backend unavailable, switching to mock mode')
|
||||
toast.error('Hardware backend unavailable - running in demo mode', {
|
||||
duration: 5000,
|
||||
icon: '⚠️',
|
||||
})
|
||||
mockModeDetected = true
|
||||
useMockMode = true
|
||||
}
|
||||
console.info(`[MOCK MODE] Backend unavailable, using mock API for ${operationName}`)
|
||||
return await mockCall()
|
||||
}
|
||||
|
||||
// Re-throw other errors
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to handle API responses
|
||||
const handleResponse = <T>(response: AxiosResponse<T>): T => {
|
||||
return response.data
|
||||
@@ -90,18 +134,36 @@ const handleResponse = <T>(response: AxiosResponse<T>): T => {
|
||||
class ApiService {
|
||||
// System endpoints
|
||||
async getSystemInfo(): Promise<SystemInfo> {
|
||||
const response = await apiClient.get('/api/v1/info')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get('/api/v1/info')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getSystemInfo(),
|
||||
'getSystemInfo'
|
||||
)
|
||||
}
|
||||
|
||||
async getSystemStatus(): Promise<SystemStatus> {
|
||||
const response = await apiClient.get('/api/v1/system/status')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get('/api/v1/system/status')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getSystemStatus(),
|
||||
'getSystemStatus'
|
||||
)
|
||||
}
|
||||
|
||||
async getHealthCheck(): Promise<{ status: string }> {
|
||||
const response = await apiClient.get('/health')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get('/health')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getHealthCheck(),
|
||||
'getHealthCheck'
|
||||
)
|
||||
}
|
||||
|
||||
// Recipe endpoints
|
||||
@@ -111,58 +173,124 @@ class ApiService {
|
||||
active_only?: boolean
|
||||
search?: string
|
||||
}): Promise<RecipeList> {
|
||||
const response = await apiClient.get('/api/v1/recipes', { params })
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get('/api/v1/recipes', { params })
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getRecipes(params),
|
||||
'getRecipes'
|
||||
)
|
||||
}
|
||||
|
||||
async getRecipe(id: number): Promise<Recipe> {
|
||||
const response = await apiClient.get(`/api/v1/recipes/${id}`)
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get(`/api/v1/recipes/${id}`)
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getRecipe(id),
|
||||
'getRecipe'
|
||||
)
|
||||
}
|
||||
|
||||
async createRecipe(recipe: RecipeCreate): Promise<Recipe> {
|
||||
const response = await apiClient.post('/api/v1/recipes', recipe)
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/recipes', recipe)
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.createRecipe(recipe),
|
||||
'createRecipe'
|
||||
)
|
||||
}
|
||||
|
||||
async updateRecipe(id: number, recipe: RecipeUpdate): Promise<Recipe> {
|
||||
const response = await apiClient.put(`/api/v1/recipes/${id}`, recipe)
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.put(`/api/v1/recipes/${id}`, recipe)
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.updateRecipe(id, recipe),
|
||||
'updateRecipe'
|
||||
)
|
||||
}
|
||||
|
||||
async deleteRecipe(id: number): Promise<void> {
|
||||
await apiClient.delete(`/api/v1/recipes/${id}`)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
await apiClient.delete(`/api/v1/recipes/${id}`)
|
||||
},
|
||||
() => mockApi.deleteRecipe(id),
|
||||
'deleteRecipe'
|
||||
)
|
||||
}
|
||||
|
||||
// Process control endpoints
|
||||
async getProcessStatus(): Promise<ProcessStatus> {
|
||||
const response = await apiClient.get('/api/v1/process/status')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.get('/api/v1/process/status')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.getProcessStatus(),
|
||||
'getProcessStatus'
|
||||
)
|
||||
}
|
||||
|
||||
async startProcess(request: ProcessStartRequest): Promise<ProcessActionResponse> {
|
||||
const response = await apiClient.post('/api/v1/process/start', request)
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/process/start', request)
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.startProcess(request),
|
||||
'startProcess'
|
||||
)
|
||||
}
|
||||
|
||||
async pauseProcess(): Promise<ProcessActionResponse> {
|
||||
const response = await apiClient.post('/api/v1/process/pause')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/process/pause')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.pauseProcess(),
|
||||
'pauseProcess'
|
||||
)
|
||||
}
|
||||
|
||||
async resumeProcess(): Promise<ProcessActionResponse> {
|
||||
const response = await apiClient.post('/api/v1/process/resume')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/process/resume')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.resumeProcess(),
|
||||
'resumeProcess'
|
||||
)
|
||||
}
|
||||
|
||||
async stopProcess(): Promise<ProcessActionResponse> {
|
||||
const response = await apiClient.post('/api/v1/process/stop')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/process/stop')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.stopProcess(),
|
||||
'stopProcess'
|
||||
)
|
||||
}
|
||||
|
||||
async emergencyStop(): Promise<ProcessActionResponse> {
|
||||
const response = await apiClient.post('/api/v1/process/emergency-stop')
|
||||
return handleResponse(response)
|
||||
return handleApiCall(
|
||||
async () => {
|
||||
const response = await apiClient.post('/api/v1/process/emergency-stop')
|
||||
return handleResponse(response)
|
||||
},
|
||||
() => mockApi.emergencyStop(),
|
||||
'emergencyStop'
|
||||
)
|
||||
}
|
||||
|
||||
// Hardware endpoints
|
||||
|
||||
@@ -204,7 +204,6 @@ const delay = (ms: number = 500) => new Promise(resolve => setTimeout(resolve, m
|
||||
|
||||
// Mock API service class
|
||||
class MockApiService {
|
||||
private currentUser: User = mockUsers[0]
|
||||
private recipes: Recipe[] = [...mockRecipes]
|
||||
private processStatus: ProcessStatus = { ...mockProcessStatus }
|
||||
private hardwareStatus: HardwareStatus = { ...mockHardwareStatus }
|
||||
@@ -244,7 +243,7 @@ class MockApiService {
|
||||
const search = params.search.toLowerCase()
|
||||
filteredRecipes = filteredRecipes.filter(r =>
|
||||
r.name.toLowerCase().includes(search) ||
|
||||
r.description.toLowerCase().includes(search)
|
||||
(r.description && r.description.toLowerCase().includes(search))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -273,6 +272,7 @@ class MockApiService {
|
||||
const newRecipe: Recipe = {
|
||||
...recipe,
|
||||
id: Math.max(...this.recipes.map(r => r.id)) + 1,
|
||||
is_active: true,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
}
|
||||
@@ -309,12 +309,8 @@ class MockApiService {
|
||||
async getProcessStatus(): Promise<ProcessStatus> {
|
||||
await delay(200)
|
||||
// Simulate temperature fluctuations if process is running
|
||||
if (this.processStatus.is_running) {
|
||||
const temps = this.processStatus.current_temperatures
|
||||
temps.tank_bottom += (Math.random() - 0.5) * 0.2
|
||||
temps.tank_wall += (Math.random() - 0.5) * 0.2
|
||||
temps.pump += (Math.random() - 0.5) * 0.1
|
||||
temps.fountain += (Math.random() - 0.5) * 0.1
|
||||
if (this.processStatus.is_running && this.processStatus.current_temperature !== null) {
|
||||
this.processStatus.current_temperature += (Math.random() - 0.5) * 0.2
|
||||
}
|
||||
return { ...this.processStatus }
|
||||
}
|
||||
@@ -329,21 +325,15 @@ class MockApiService {
|
||||
this.processStatus = {
|
||||
...this.processStatus,
|
||||
is_running: true,
|
||||
status: 'running',
|
||||
current_phase: 'heating',
|
||||
recipe_id: recipe.id,
|
||||
recipe_name: recipe.name,
|
||||
progress_percentage: 0,
|
||||
phase_time_remaining: recipe.heating_time,
|
||||
total_time_remaining: recipe.heating_time + recipe.cooling_time + recipe.working_time,
|
||||
target_temperatures: {
|
||||
tank_bottom: recipe.heating_temp,
|
||||
tank_wall: recipe.heating_temp,
|
||||
pump: recipe.heating_temp,
|
||||
fountain: recipe.heating_temp,
|
||||
},
|
||||
target_temperature: recipe.target_temperature_c,
|
||||
duration_seconds: 0,
|
||||
session_id: `mock-session-${Date.now()}`,
|
||||
started_at: new Date().toISOString(),
|
||||
estimated_completion: new Date(Date.now() + (recipe.heating_time + recipe.cooling_time + recipe.working_time) * 1000).toISOString(),
|
||||
started_by: request.user_id || 'mock-user',
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -355,7 +345,7 @@ class MockApiService {
|
||||
|
||||
async pauseProcess(): Promise<ProcessActionResponse> {
|
||||
await delay(300)
|
||||
this.processStatus.current_phase = 'paused'
|
||||
this.processStatus.status = 'paused'
|
||||
return {
|
||||
success: true,
|
||||
message: 'Process paused successfully',
|
||||
@@ -364,7 +354,7 @@ class MockApiService {
|
||||
|
||||
async resumeProcess(): Promise<ProcessActionResponse> {
|
||||
await delay(300)
|
||||
this.processStatus.current_phase = 'heating' // or whatever phase it was in
|
||||
this.processStatus.status = 'running'
|
||||
return {
|
||||
success: true,
|
||||
message: 'Process resumed successfully',
|
||||
@@ -388,7 +378,7 @@ class MockApiService {
|
||||
this.processStatus = {
|
||||
...mockProcessStatus,
|
||||
session_id: null,
|
||||
error: 'Emergency stop activated',
|
||||
status: 'error',
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
@@ -404,27 +394,33 @@ class MockApiService {
|
||||
|
||||
async getTemperatures(): Promise<any[]> {
|
||||
await delay(200)
|
||||
return [
|
||||
{ sensor: 'tank_bottom', temperature: this.hardwareStatus.temperatures.tank_bottom, timestamp: new Date().toISOString() },
|
||||
{ sensor: 'tank_wall', temperature: this.hardwareStatus.temperatures.tank_wall, timestamp: new Date().toISOString() },
|
||||
{ sensor: 'pump', temperature: this.hardwareStatus.temperatures.pump, timestamp: new Date().toISOString() },
|
||||
{ sensor: 'fountain', temperature: this.hardwareStatus.temperatures.fountain, timestamp: new Date().toISOString() },
|
||||
]
|
||||
return this.hardwareStatus.temperature_sensors.map(sensor => ({
|
||||
sensor: sensor.id,
|
||||
temperature: sensor.current_temp_c,
|
||||
timestamp: new Date().toISOString(),
|
||||
}))
|
||||
}
|
||||
|
||||
async getMotorStatus(): Promise<any[]> {
|
||||
await delay(200)
|
||||
return [
|
||||
{ motor: 'mixer', ...this.hardwareStatus.motors.mixer },
|
||||
{ motor: 'pump', ...this.hardwareStatus.motors.pump },
|
||||
]
|
||||
return this.hardwareStatus.motors.map(motor => ({
|
||||
motor: motor.id,
|
||||
name: motor.name,
|
||||
is_running: motor.is_running,
|
||||
current_speed_rpm: motor.current_speed_rpm,
|
||||
target_speed_rpm: motor.target_speed_rpm,
|
||||
current_amps: motor.current_amps,
|
||||
status: motor.status,
|
||||
}))
|
||||
}
|
||||
|
||||
async setMotorSpeed(motorId: string, speed: number): Promise<void> {
|
||||
await delay(400)
|
||||
if (motorId in this.hardwareStatus.motors) {
|
||||
(this.hardwareStatus.motors as any)[motorId].speed = speed
|
||||
;(this.hardwareStatus.motors as any)[motorId].running = speed > 0
|
||||
const motor = this.hardwareStatus.motors.find(m => m.id === motorId)
|
||||
if (motor) {
|
||||
motor.target_speed_rpm = speed
|
||||
motor.current_speed_rpm = speed
|
||||
motor.is_running = speed > 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +430,7 @@ class MockApiService {
|
||||
return mockSafetyStatus
|
||||
}
|
||||
|
||||
async acknowledgeAlarm(alarmId: string): Promise<void> {
|
||||
async acknowledgeAlarm(_alarmId: string): Promise<void> {
|
||||
await delay(300)
|
||||
// Mock alarm acknowledgment
|
||||
}
|
||||
@@ -481,8 +477,9 @@ class MockApiService {
|
||||
const newUser: User = {
|
||||
...user,
|
||||
id: (mockUsers.length + 1).toString(),
|
||||
is_active: true,
|
||||
created_at: new Date().toISOString(),
|
||||
last_login: null,
|
||||
last_login: undefined,
|
||||
}
|
||||
mockUsers.push(newUser)
|
||||
return newUser
|
||||
@@ -558,7 +555,7 @@ class MockApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async getProcessMetrics(days: number = 30): Promise<any> {
|
||||
async getProcessMetrics(_days: number = 30): Promise<any> {
|
||||
await delay(500)
|
||||
return {
|
||||
total_sessions: 42,
|
||||
|
||||
@@ -33,29 +33,46 @@ export const useSystemStore = create<SystemState>()(
|
||||
isLoading: false,
|
||||
error: null,
|
||||
|
||||
// Initialize system - called on app startup
|
||||
// Initialize system - called on app startup
|
||||
initializeSystem: async () => {
|
||||
const { isInitialized } = get()
|
||||
if (isInitialized) return
|
||||
|
||||
console.log('Starting system initialization...')
|
||||
set({ isLoading: true, error: null })
|
||||
|
||||
try {
|
||||
// Fetch system information
|
||||
console.log('Fetching system info...')
|
||||
const systemInfo = await api.getSystemInfo()
|
||||
console.log('System info received:', systemInfo)
|
||||
|
||||
// Fetch initial system status
|
||||
console.log('Fetching system status...')
|
||||
const systemStatus = await api.getSystemStatus()
|
||||
console.log('System status received:', systemStatus)
|
||||
|
||||
// Check if we're in mock mode based on the system info
|
||||
const isMockMode = systemInfo.environment === 'mock' || systemStatus.hardware_status === 'disconnected'
|
||||
console.log('Mock mode detected:', isMockMode)
|
||||
|
||||
set({
|
||||
systemInfo,
|
||||
systemStatus,
|
||||
isInitialized: true,
|
||||
isConnected: !isMockMode, // Set connection status based on mock mode
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
|
||||
// Show mock mode warning if applicable
|
||||
if (isMockMode && systemInfo.environment === 'mock') {
|
||||
console.info('✅ Running in mock mode - no hardware required')
|
||||
}
|
||||
|
||||
console.log('✅ System initialization completed successfully')
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize system:', error)
|
||||
console.error('❌ Failed to initialize system:', error)
|
||||
set({
|
||||
isLoading: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to initialize system',
|
||||
|
||||
Reference in New Issue
Block a user