fix logic
This commit is contained in:
parent
99470f501a
commit
4a8d3d294b
118
DYNAMIC_SHEET_FIX.md
Normal file
118
DYNAMIC_SHEET_FIX.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Dynamic Sheet Handling Fix
|
||||
|
||||
## Problem
|
||||
The application was failing with "Sheet 'US URGENT' not found in data" error when working with Excel files that don't contain a sheet named 'US URGENT'. The code needed to be made dynamic to work with any sheet names.
|
||||
|
||||
## Root Cause
|
||||
The issue was in the web interface JavaScript where:
|
||||
1. On page load, `analyzeData()` was called immediately
|
||||
2. The sheet filter dropdown was empty at that time
|
||||
3. An empty string was being sent as `sheet_filter` to the backend
|
||||
4. The backend wasn't properly handling empty strings
|
||||
|
||||
## Fixes Applied
|
||||
|
||||
### 1. Frontend JavaScript Improvements (web_gui.py)
|
||||
|
||||
#### Fixed `analyzeData()` function:
|
||||
```javascript
|
||||
// Before: const sheetFilter = document.getElementById('sheetFilter').value;
|
||||
// After:
|
||||
const sheetFilterElement = document.getElementById('sheetFilter');
|
||||
const sheetFilter = sheetFilterElement.value || null; // Use null if empty
|
||||
```
|
||||
|
||||
#### Improved `updateSheetFilter()` function:
|
||||
- Added handling for empty sheet lists
|
||||
- Added loading state for sheet dropdown
|
||||
- Better initialization logic
|
||||
|
||||
#### Enhanced page load handling:
|
||||
```javascript
|
||||
window.onload = function() {
|
||||
// Initialize sheet filter with loading state
|
||||
updateSheetFilter([], null);
|
||||
analyzeData();
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Backend Improvements (web_gui.py)
|
||||
|
||||
#### Enhanced request handling:
|
||||
```python
|
||||
# Handle empty string as None
|
||||
if sheet_filter == '' or sheet_filter == 'undefined':
|
||||
sheet_filter = None
|
||||
```
|
||||
|
||||
#### Added debugging information:
|
||||
```python
|
||||
# Debug: Print available sheets
|
||||
available_sheets = list(comparator_instance.data.keys())
|
||||
print(f"Available sheets: {available_sheets}")
|
||||
print(f"Requested sheet_filter: {repr(sheet_filter)}")
|
||||
```
|
||||
|
||||
### 3. Core Logic Improvements (data_comparator.py)
|
||||
|
||||
#### Enhanced error handling:
|
||||
```python
|
||||
# Validate that the requested sheet exists
|
||||
if sheet_filter not in sheet_names:
|
||||
raise ValueError(f"Sheet '{sheet_filter}' not found in data. Available sheets: {sheet_names}")
|
||||
```
|
||||
|
||||
## How It Works Now
|
||||
|
||||
1. **Page Load**:
|
||||
- Sheet dropdown shows "Loading sheets..."
|
||||
- `analyzeData()` is called with `sheet_filter = null`
|
||||
|
||||
2. **Backend Processing**:
|
||||
- Loads Excel file and gets available sheet names
|
||||
- If `sheet_filter` is `null` or empty, defaults to first sheet
|
||||
- Validates sheet exists before processing
|
||||
|
||||
3. **Response**:
|
||||
- Returns results with `sheet_names` array and `current_sheet_filter`
|
||||
- Frontend populates dropdown with actual sheet names
|
||||
- User can then select different sheets
|
||||
|
||||
4. **Sheet Selection**:
|
||||
- User selects different sheet from dropdown
|
||||
- `filterBySheet()` calls `analyzeData()` with selected sheet
|
||||
- Backend processes the specific sheet
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Dynamic**: Works with any Excel file regardless of sheet names
|
||||
✅ **Robust**: Handles empty/invalid sheet names gracefully
|
||||
✅ **User-friendly**: Shows available sheets in dropdown
|
||||
✅ **Error-resistant**: Provides clear error messages
|
||||
✅ **Backward compatible**: Still works with existing functionality
|
||||
|
||||
## Test Coverage
|
||||
|
||||
Created `test_dynamic_sheets.py` to verify:
|
||||
- Default sheet selection (no filter)
|
||||
- Each available sheet works
|
||||
- Invalid sheet names are handled
|
||||
- Empty string sheet names default properly
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```python
|
||||
# Works with any Excel file
|
||||
comparator = KSTCoordiComparator("any-file.xlsx")
|
||||
comparator.load_data()
|
||||
|
||||
# Auto-selects first sheet
|
||||
summary = comparator.get_comparison_summary()
|
||||
|
||||
# Or specify any existing sheet
|
||||
summary = comparator.get_comparison_summary("Sheet1")
|
||||
summary = comparator.get_comparison_summary("Data")
|
||||
summary = comparator.get_comparison_summary("US URGENT") # Only if it exists
|
||||
```
|
||||
|
||||
The application now dynamically adapts to any Excel file structure!
|
||||
Binary file not shown.
@ -341,6 +341,10 @@ class KSTCoordiComparator:
|
||||
if not sheet_filter:
|
||||
raise ValueError("No sheets available or sheet filter not specified")
|
||||
|
||||
# Validate that the requested sheet exists
|
||||
if sheet_filter not in sheet_names:
|
||||
raise ValueError(f"Sheet '{sheet_filter}' not found in data. Available sheets: {sheet_names}")
|
||||
|
||||
# Extract data for the specific sheet only
|
||||
sheet_data = self.extract_kst_coordi_items_for_sheet(sheet_filter)
|
||||
|
||||
|
||||
@ -390,8 +390,8 @@
|
||||
document.getElementById('filePath').value = data.file_path;
|
||||
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
||||
|
||||
// Analyze the uploaded file
|
||||
const sheetFilter = document.getElementById('sheetFilter').value;
|
||||
// Analyze the uploaded file (use default sheet for new uploads)
|
||||
const sheetFilter = null; // Always use default (first sheet) for new uploads
|
||||
return fetch('/analyze', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
56
web_gui.py
56
web_gui.py
@ -26,6 +26,10 @@ def analyze_data():
|
||||
file_path = request.json.get('file_path', 'data/sample-data.xlsx')
|
||||
sheet_filter = request.json.get('sheet_filter', None)
|
||||
|
||||
# Handle empty string as None
|
||||
if sheet_filter == '' or sheet_filter == 'undefined':
|
||||
sheet_filter = None
|
||||
|
||||
if not Path(file_path).exists():
|
||||
return jsonify({'error': f'File not found: {file_path}'}), 400
|
||||
|
||||
@ -34,6 +38,11 @@ def analyze_data():
|
||||
if not comparator_instance.load_data():
|
||||
return jsonify({'error': 'Failed to load Excel data'}), 500
|
||||
|
||||
# Debug: Print available sheets
|
||||
available_sheets = list(comparator_instance.data.keys())
|
||||
print(f"Available sheets: {available_sheets}")
|
||||
print(f"Requested sheet_filter: {repr(sheet_filter)}")
|
||||
|
||||
# Get comparison results with optional sheet filtering
|
||||
comparison_results = comparator_instance.get_comparison_summary(sheet_filter)
|
||||
|
||||
@ -93,6 +102,31 @@ def get_results():
|
||||
return jsonify({'error': 'No analysis results available'}), 404
|
||||
return jsonify(comparison_results)
|
||||
|
||||
@app.route('/get_sheets', methods=['POST'])
|
||||
def get_sheets():
|
||||
"""Get available sheet names from an Excel file"""
|
||||
try:
|
||||
file_path = request.json.get('file_path', 'data/sample-data.xlsx')
|
||||
|
||||
if not Path(file_path).exists():
|
||||
return jsonify({'error': f'File not found: {file_path}'}), 400
|
||||
|
||||
# Create comparator and load data to get sheet names
|
||||
temp_comparator = KSTCoordiComparator(file_path)
|
||||
if not temp_comparator.load_data():
|
||||
return jsonify({'error': 'Failed to load Excel data'}), 500
|
||||
|
||||
available_sheets = list(temp_comparator.data.keys())
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'sheets': available_sheets,
|
||||
'default_sheet': available_sheets[0] if available_sheets else None
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
def create_templates_dir():
|
||||
"""Create templates directory and HTML file"""
|
||||
templates_dir = Path('templates')
|
||||
@ -379,7 +413,8 @@ def create_templates_dir():
|
||||
|
||||
function analyzeData() {
|
||||
const filePath = document.getElementById('filePath').value;
|
||||
const sheetFilter = document.getElementById('sheetFilter').value;
|
||||
const sheetFilterElement = document.getElementById('sheetFilter');
|
||||
const sheetFilter = sheetFilterElement.value || null; // Use null if empty
|
||||
const statusDiv = document.getElementById('status');
|
||||
const analyzeBtn = document.getElementById('analyzeBtn');
|
||||
|
||||
@ -428,6 +463,18 @@ def create_templates_dir():
|
||||
const select = document.getElementById('sheetFilter');
|
||||
select.innerHTML = '';
|
||||
|
||||
// Add a default option if no sheets are available yet
|
||||
if (!sheetNames || sheetNames.length === 0) {
|
||||
const option = document.createElement('option');
|
||||
option.value = '';
|
||||
option.textContent = 'Loading sheets...';
|
||||
option.disabled = true;
|
||||
option.selected = true;
|
||||
select.appendChild(option);
|
||||
select.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
sheetNames.forEach((sheetName, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = sheetName;
|
||||
@ -490,8 +537,9 @@ def create_templates_dir():
|
||||
document.getElementById('filePath').value = data.file_path;
|
||||
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
||||
|
||||
// Analyze the uploaded file
|
||||
const sheetFilter = document.getElementById('sheetFilter').value;
|
||||
// Clear sheet filter for new file (let it default to first sheet)
|
||||
const sheetFilterElement = document.getElementById('sheetFilter');
|
||||
const sheetFilter = null; // Always use default (first sheet) for new uploads
|
||||
return fetch('/analyze', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -675,6 +723,8 @@ def create_templates_dir():
|
||||
|
||||
// Auto-analyze on page load with default file
|
||||
window.onload = function() {
|
||||
// Initialize sheet filter with loading state
|
||||
updateSheetFilter([], null);
|
||||
analyzeData();
|
||||
};
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user