EPANET Forms Design Decisions
Overview
This document captures the key architectural and design decisions made during the implementation of EPANET forms in the HydroTrek DWD Suite frontend application.
Current Implementation Status
✅ Phase 1: Foundation (COMPLETED)
- Edit Asset Button: Integrated into
EsriCustomPopupcomponent - AssetEditDialog: Full dialog component with tabbed interface
- Dynamic Form System: Complete form generation based on field schemas
- API Integration: PUT request integration with
ApiPuthook - Form Pre-filling: Forms populate with existing asset values
- Save Functionality: Complete save workflow with table refresh
🔄 Phase 2: EPANET Forms Integration (IN PROGRESS)
- Form Integration Strategy: Hybrid approach combining dynamic and specialized forms
- API Architecture: Multiple API calls for different data sources
- Field Organization: Smart integration of single-field forms
Key Design Decisions
1. Form Integration Strategy
Decision: Hybrid approach combining dynamic forms with specialized EPANET forms
Rationale:
- Single-field forms (Quality, Emitter) integrate into existing "Basic Properties" tab
- Multi-field forms (Demand, Source, TankMixing) get separate tabs
- Maintains user experience while providing comprehensive editing
Implementation:
// Single-field forms integrated into basic properties
const JUNCTION_FIELDS = [
// Basic asset properties
{ name: 'Elevation', type: 'number', ... },
{ name: 'Base Demand', type: 'number', ... },
// EPANET single-field forms
{ name: 'Initial Quality', type: 'number', epanetField: 'quality', ... },
{ name: 'Emitter Coefficient', type: 'number', epanetField: 'emitter', ... }
];
// Multi-field forms as separate tabs
const DEMAND_FIELDS = [
{ name: 'Demand Value', type: 'number', ... },
{ name: 'Pattern ID', type: 'text', ... },
{ name: 'Category', type: 'text', ... }
];
2. API Architecture
Decision: Multiple API calls approach (no backend changes required)
Rationale:
- Leverages existing API endpoints
- No backend DTO changes needed
- Clear separation of concerns
- Incremental implementation possible
Implementation:
const handleSave = async () => {
const updates = [];
// Only update forms that have changes
if (formStates.asset.hasChanges) {
updates.push(() => ApiPut(`/api/${entityType.toLowerCase()}s/${id}`, formStates.asset.data));
}
if (formStates.demand.hasChanges) {
updates.push(() => ApiPut(`/api/demand/${id}`, formStates.demand.data));
}
if (formStates.quality.hasChanges) {
updates.push(() => ApiPut(`/api/quality/${id}`, formStates.quality.data));
}
// Execute all updates
await Promise.all(updates.map(update => update()));
};
3. Form State Management
Decision: Per-form change tracking with smart save logic
Rationale:
- Only calls APIs for forms that have changes
- Reduces unnecessary network requests
- Provides clear feedback on what's being updated
- Enables partial success handling
Implementation:
const [formStates, setFormStates] = useState({
asset: { hasChanges: false, data: {} },
demand: { hasChanges: false, data: {} },
quality: { hasChanges: false, data: {} },
emitter: { hasChanges: false, data: {} }
});
4. Field Schema Organization
Decision: Centralized field schemas with conditional display
Rationale:
- Single source of truth for field definitions
- Easy to maintain and update
- Supports dynamic form generation
- Enables conditional field display
Implementation:
// Field schemas in constants_schemas.jsx
export const JUNCTION_FIELDS = [
{ name: 'Elevation', type: 'number', required: true, apiField: 'elevation' },
{ name: 'Base Demand', type: 'number', required: false, apiField: 'baseDemand' },
{ name: 'Initial Quality', type: 'number', epanetField: 'quality', apiField: 'initialQuality' }
];
// Conditional field display
const getFieldsForEntityType = (entityType) => {
const baseFields = FIELD_SCHEMAS[entityType] || [];
return baseFields.filter(field => {
// Show EPANET fields only for relevant asset types
if (field.epanetField) {
return EPANET_FIELD_MAPPING[entityType]?.includes(field.epanetField);
}
return true;
});
};
5. Error Handling Strategy
Decision: Comprehensive error handling with partial success support
Rationale:
- Multiple API calls can have different outcomes
- Users need clear feedback on what succeeded/failed
- Partial success should be handled gracefully
Implementation:
const handleSave = async () => {
const results = [];
const errors = [];
for (const update of updates) {
try {
await update();
results.push('success');
} catch (error) {
errors.push(error.message);
}
}
if (errors.length === 0) {
setSaveSuccess(true);
} else if (results.length > 0) {
setSavePartialSuccess(`Some updates succeeded, but ${errors.length} failed`);
} else {
setSaveError(`All updates failed: ${errors.join(', ')}`);
}
};
Form Field Mapping
Single-Field Forms (Integrated into Basic Properties)
| Form | Field | Type | API Endpoint |
|---|---|---|---|
| Quality | InitialQuality | number | /api/quality |
| Emitter | Coefficient | number | /api/emitter |
Multi-Field Forms (Separate Tabs)
| Form | Fields | API Endpoint |
|---|---|---|
| Demand | DemandValue, PatternId, Category | /api/demand |
| Source | SourceType, Strength, PatternId | /api/source |
| TankMixing | MixingModel, Fraction | /api/tankmixing |
Implementation Phases
Phase 2A: Single-Field Forms Integration
- Integrate Quality form into Basic Properties tab
- Integrate Emitter form into Basic Properties tab
- Add conditional field display logic
- Test form pre-filling and saving
Phase 2B: Multi-Field Forms
- Implement DemandForm component
- Implement SourceForm component
- Implement TankMixingForm component
- Add separate tabs for multi-field forms
Phase 2C: Advanced Features
- Add form validation and dependencies
- Implement bulk editing capabilities
- Add undo/redo functionality
- Performance optimization
Technical Considerations
Performance
- Lazy Loading: Load form data only when needed
- Change Tracking: Only save forms that have changes
- Batch Operations: Group related API calls when possible
User Experience
- Clear Feedback: Show which forms are being updated
- Error Recovery: Allow retry of failed operations
- Progress Indicators: Show save progress for multiple forms
Maintainability
- Centralized Schemas: Single source of truth for field definitions
- Modular Components: Reusable form components
- Clear Separation: Distinct responsibilities for each form type
Future Considerations
Backend Optimization
- Aggregated Endpoints: Consider creating combined endpoints for better performance
- Transaction Support: Implement atomic updates across multiple forms
- Caching Strategy: Add intelligent caching for frequently accessed data
Advanced Features
- Form Dependencies: Implement field dependencies and conditional logic
- Bulk Operations: Support editing multiple assets simultaneously
- Audit Trail: Track changes and provide rollback capabilities
Known Issues and Limitations
3D Map Data Synchronization Issue
Problem: The 3D map page uses I3S layers (Indexed 3D Scene Layers) with embedded data rather than live API data. This means:
- Asset values shown in 3D map popups are static/embedded in the I3S layer files
- Changes made through the edit forms update the database but don't reflect in the 3D map popup
- The 3D map requires layer regeneration to show updated values
- This affects all asset types (Junction, Tank, Pipe, Pump, Valve, Reservoir)
Current Workaround:
- Use the 2D map page for editing assets (has live API data)
- 3D map is primarily for visualization with static data
Future Solution:
- Implement live API data fetching for 3D map popups
- Or implement layer refresh mechanism after asset updates
- This is a separate architectural issue from the EPANET forms implementation
Impact on EPANET Forms:
- EPANET forms work correctly on 2D map page
- Forms on 3D map page will save to database but popup won't refresh
- This is a limitation of the 3D map architecture, not the forms implementation
Conclusion
The hybrid approach provides the best balance of functionality, maintainability, and user experience. By integrating single-field forms into existing tabs and creating separate tabs for multi-field forms, we maintain a clean interface while providing comprehensive editing capabilities.
The multiple API calls approach allows for immediate implementation without backend changes, while the smart change tracking ensures optimal performance. This foundation supports future enhancements and provides a solid base for advanced features.
Note: The 3D map data synchronization issue is a separate architectural concern that should be addressed in a future iteration, but does not impact the core EPANET forms functionality on the 2D map.