12 KiB
12 KiB
Design Document
Overview
This design document outlines the replacement of the Blessed-based TUI with a Windows-compatible alternative using Ink (React for CLI) as the primary library choice. Ink provides excellent cross-platform support, modern React-based component architecture, and superior Windows compatibility compared to Blessed. The design maintains all existing functionality while improving performance, maintainability, and user experience across all platforms.
Architecture
Library Selection: Ink (React for CLI)
Primary Choice: Ink v4.x
- Rationale: Ink is built on React principles, providing a modern component-based architecture
- Windows Compatibility: Excellent support for Windows Terminal, Command Prompt, and PowerShell
- Performance: Uses React's reconciliation for efficient updates, reducing flicker
- Ecosystem: Large ecosystem of pre-built components and utilities
- Maintenance: Actively maintained by Vercel with strong community support
Alternative Considerations:
- Blessed: Current library with Windows issues (being replaced)
- Terminal-kit: Good Windows support but more complex API
- Enquirer: Limited to prompts, not full TUI applications
- Neo-blessed: Fork of Blessed with some improvements but still has Windows issues
Component Architecture
TuiApplication (Root)
├── AppProvider (Context/State Management)
├── Router (Screen Management)
├── StatusBar (Global Status)
└── Screens/
├── MainMenuScreen
├── ConfigurationScreen
├── OperationScreen
├── SchedulingScreen
├── LogViewerScreen
└── TagAnalysisScreen
State Management
Using React Context API with custom hooks for:
- Application state (current screen, navigation history)
- Configuration state (environment variables, settings)
- Operation state (progress, results, errors)
- UI state (focus, selections, modal states)
Components and Interfaces
Core Components
1. TuiApplication (Root Component)
const TuiApplication = () => {
return (
<AppProvider>
<Box flexDirection="column" height="100%">
<StatusBar />
<Router />
</Box>
</AppProvider>
);
};
2. AppProvider (State Management)
const AppProvider = ({ children }) => {
const [appState, setAppState] = useState({
currentScreen: "main-menu",
navigationHistory: [],
configuration: {},
operationState: null,
});
return (
<AppContext.Provider value={{ appState, setAppState }}>
{children}
</AppContext.Provider>
);
};
3. Router (Screen Management)
const Router = () => {
const { appState } = useContext(AppContext);
const screens = {
"main-menu": MainMenuScreen,
configuration: ConfigurationScreen,
operation: OperationScreen,
scheduling: SchedulingScreen,
logs: LogViewerScreen,
"tag-analysis": TagAnalysisScreen,
};
const CurrentScreen = screens[appState.currentScreen];
return <CurrentScreen />;
};
4. StatusBar (Global Status Display)
const StatusBar = () => {
const { connectionStatus, operationProgress } = useAppState();
return (
<Box borderStyle="single" paddingX={1}>
<Text color="green">● Connected</Text>
<Text> | </Text>
<Text>Progress: {operationProgress}%</Text>
</Box>
);
};
Screen Components
MainMenuScreen
- Navigation menu with keyboard shortcuts
- Current configuration summary
- Quick action buttons
- Help information
ConfigurationScreen
- Environment variable editor
- Input validation with real-time feedback
- API connection testing
- Save/cancel operations
OperationScreen
- Operation type selection (update/rollback)
- Real-time progress display
- Product processing information
- Error handling and display
SchedulingScreen
- Date/time picker interface
- Schedule management
- Countdown display
- Cancellation controls
LogViewerScreen
- Paginated log display
- Search and filtering
- Log entry details
- Export functionality
TagAnalysisScreen
- Tag listing and statistics
- Product count per tag
- Sample product display
- Recommendations
Reusable UI Components
ProgressBar
const ProgressBar = ({ progress, label, color = "blue" }) => {
const width = 40;
const filled = Math.round((progress / 100) * width);
return (
<Box flexDirection="column">
<Text>{label}</Text>
<Box>
<Text color={color}>{"█".repeat(filled)}</Text>
<Text color="gray">{"░".repeat(width - filled)}</Text>
<Text> {progress}%</Text>
</Box>
</Box>
);
};
InputField
const InputField = ({ label, value, onChange, validation, placeholder }) => {
const [isValid, setIsValid] = useState(true);
return (
<Box flexDirection="column" marginY={1}>
<Text>{label}:</Text>
<TextInput
value={value}
onChange={(val) => {
onChange(val);
setIsValid(validation ? validation(val) : true);
}}
placeholder={placeholder}
/>
{!isValid && <Text color="red">Invalid input</Text>}
</Box>
);
};
MenuList
const MenuList = ({ items, selectedIndex, onSelect }) => {
return (
<Box flexDirection="column">
{items.map((item, index) => (
<Box key={index} paddingX={2}>
<Text color={index === selectedIndex ? "blue" : "white"}>
{index === selectedIndex ? "► " : " "}
{item.label}
</Text>
</Box>
))}
</Box>
);
};
Data Models
Application State
interface AppState {
currentScreen: string;
navigationHistory: string[];
configuration: ConfigurationState;
operationState: OperationState | null;
uiState: UIState;
}
interface ConfigurationState {
shopifyDomain: string;
accessToken: string;
targetTag: string;
priceAdjustment: number;
operationMode: "update" | "rollback";
isValid: boolean;
lastTested: Date | null;
}
interface OperationState {
type: "update" | "rollback" | "scheduled";
status: "idle" | "running" | "completed" | "error";
progress: number;
currentProduct: string | null;
results: OperationResults | null;
errors: Error[];
}
interface UIState {
focusedComponent: string;
modalOpen: boolean;
selectedMenuIndex: number;
scrollPosition: number;
}
Service Integration
interface ServiceIntegration {
shopifyService: ShopifyService;
productService: ProductService;
progressService: ProgressService;
configService: ConfigurationService;
}
Error Handling
Error Categories
- Configuration Errors: Invalid environment variables, API credentials
- Network Errors: Connection failures, timeout issues
- API Errors: Shopify API rate limits, authentication failures
- UI Errors: Component rendering issues, state inconsistencies
- System Errors: File system access, permission issues
Error Display Strategy
const ErrorBoundary = ({ children }) => {
const [error, setError] = useState(null);
if (error) {
return (
<Box
flexDirection="column"
padding={2}
borderStyle="single"
borderColor="red"
>
<Text color="red" bold>
Error Occurred
</Text>
<Text>{error.message}</Text>
<Text color="gray">Press 'r' to retry or 'q' to quit</Text>
</Box>
);
}
return children;
};
Graceful Degradation
- Fallback to basic text display if advanced features fail
- Automatic retry mechanisms for network operations
- State persistence to recover from crashes
- Clear error messages with suggested actions
Testing Strategy
Component Testing
// Example test using Ink's testing utilities
import { render } from "ink-testing-library";
import { MainMenuScreen } from "../screens/MainMenuScreen";
test("renders main menu with correct options", () => {
const { lastFrame } = render(<MainMenuScreen />);
expect(lastFrame()).toContain("Price Update Operations");
expect(lastFrame()).toContain("Configuration");
expect(lastFrame()).toContain("View Logs");
});
Integration Testing
- Test service integration with mock services
- Verify state management across screen transitions
- Test keyboard navigation and input handling
- Validate error handling scenarios
Cross-Platform Testing
- Automated testing on Windows, macOS, and Linux
- Terminal compatibility testing (Windows Terminal, Command Prompt, PowerShell)
- Unicode and color support verification
- Performance testing with large datasets
Migration Strategy
Phase 1: Setup and Core Infrastructure
- Install Ink and related dependencies
- Create basic application structure
- Implement state management system
- Set up routing and navigation
Phase 2: Screen Implementation
- Implement MainMenuScreen (simplest)
- Create ConfigurationScreen with form handling
- Build OperationScreen with progress display
- Add remaining screens (Scheduling, Logs, TagAnalysis)
Phase 3: Component Migration
- Replace Blessed ProgressBar with Ink version
- Migrate form components and input handling
- Update navigation and keyboard shortcuts
- Implement error handling and validation
Phase 4: Testing and Refinement
- Comprehensive testing on Windows systems
- Performance optimization and bug fixes
- Documentation updates
- Legacy code cleanup
Dependency Changes
{
"dependencies": {
"ink": "^4.4.1",
"react": "^18.2.0",
"@ink/text-input": "^5.0.1",
"@ink/select-input": "^5.0.1",
"@ink/spinner": "^5.0.1"
},
"devDependencies": {
"ink-testing-library": "^3.0.0"
}
}
File Structure Changes
src/
├── tui/
│ ├── components/
│ │ ├── common/
│ │ │ ├── ProgressBar.jsx
│ │ │ ├── InputField.jsx
│ │ │ ├── MenuList.jsx
│ │ │ └── ErrorBoundary.jsx
│ │ ├── screens/
│ │ │ ├── MainMenuScreen.jsx
│ │ │ ├── ConfigurationScreen.jsx
│ │ │ ├── OperationScreen.jsx
│ │ │ ├── SchedulingScreen.jsx
│ │ │ ├── LogViewerScreen.jsx
│ │ │ └── TagAnalysisScreen.jsx
│ │ └── providers/
│ │ ├── AppProvider.jsx
│ │ └── ServiceProvider.jsx
│ ├── hooks/
│ │ ├── useAppState.js
│ │ ├── useNavigation.js
│ │ └── useServices.js
│ ├── utils/
│ │ ├── keyboardHandlers.js
│ │ └── validation.js
│ └── TuiApplication.jsx
└── tui-entry.js (new entry point)
Performance Considerations
Rendering Optimization
- Use React.memo for expensive components
- Implement virtual scrolling for large lists
- Debounce rapid state updates
- Minimize re-renders with proper state structure
Memory Management
- Clean up event listeners and timers
- Implement proper component unmounting
- Use weak references for large data structures
- Monitor memory usage during long operations
Windows-Specific Optimizations
- Use Windows-compatible Unicode characters
- Optimize for Windows Terminal performance
- Handle Windows-specific keyboard events
- Ensure proper color rendering in different terminals
Security Considerations
Input Validation
- Sanitize all user inputs
- Validate configuration values
- Prevent injection attacks through input fields
- Secure handling of API credentials
State Security
- Encrypt sensitive data in state
- Clear sensitive information on exit
- Prevent credential logging
- Secure temporary file handling
This design provides a robust foundation for replacing Blessed with Ink, ensuring excellent Windows compatibility while maintaining all existing functionality and improving the overall user experience.