Skip to main content

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 EsriCustomPopup component
  • AssetEditDialog: Full dialog component with tabbed interface
  • Dynamic Form System: Complete form generation based on field schemas
  • API Integration: PUT request integration with ApiPut hook
  • 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)

FormFieldTypeAPI Endpoint
QualityInitialQualitynumber/api/quality
EmitterCoefficientnumber/api/emitter

Multi-Field Forms (Separate Tabs)

FormFieldsAPI Endpoint
DemandDemandValue, PatternId, Category/api/demand
SourceSourceType, Strength, PatternId/api/source
TankMixingMixingModel, 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.