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:
|
if not sheet_filter:
|
||||||
raise ValueError("No sheets available or sheet filter not specified")
|
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
|
# Extract data for the specific sheet only
|
||||||
sheet_data = self.extract_kst_coordi_items_for_sheet(sheet_filter)
|
sheet_data = self.extract_kst_coordi_items_for_sheet(sheet_filter)
|
||||||
|
|
||||||
|
|||||||
@ -390,8 +390,8 @@
|
|||||||
document.getElementById('filePath').value = data.file_path;
|
document.getElementById('filePath').value = data.file_path;
|
||||||
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
||||||
|
|
||||||
// Analyze the uploaded file
|
// Analyze the uploaded file (use default sheet for new uploads)
|
||||||
const sheetFilter = document.getElementById('sheetFilter').value;
|
const sheetFilter = null; // Always use default (first sheet) for new uploads
|
||||||
return fetch('/analyze', {
|
return fetch('/analyze', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
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')
|
file_path = request.json.get('file_path', 'data/sample-data.xlsx')
|
||||||
sheet_filter = request.json.get('sheet_filter', None)
|
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():
|
if not Path(file_path).exists():
|
||||||
return jsonify({'error': f'File not found: {file_path}'}), 400
|
return jsonify({'error': f'File not found: {file_path}'}), 400
|
||||||
|
|
||||||
@ -34,6 +38,11 @@ def analyze_data():
|
|||||||
if not comparator_instance.load_data():
|
if not comparator_instance.load_data():
|
||||||
return jsonify({'error': 'Failed to load Excel data'}), 500
|
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
|
# Get comparison results with optional sheet filtering
|
||||||
comparison_results = comparator_instance.get_comparison_summary(sheet_filter)
|
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({'error': 'No analysis results available'}), 404
|
||||||
return jsonify(comparison_results)
|
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():
|
def create_templates_dir():
|
||||||
"""Create templates directory and HTML file"""
|
"""Create templates directory and HTML file"""
|
||||||
templates_dir = Path('templates')
|
templates_dir = Path('templates')
|
||||||
@ -379,7 +413,8 @@ def create_templates_dir():
|
|||||||
|
|
||||||
function analyzeData() {
|
function analyzeData() {
|
||||||
const filePath = document.getElementById('filePath').value;
|
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 statusDiv = document.getElementById('status');
|
||||||
const analyzeBtn = document.getElementById('analyzeBtn');
|
const analyzeBtn = document.getElementById('analyzeBtn');
|
||||||
|
|
||||||
@ -428,6 +463,18 @@ def create_templates_dir():
|
|||||||
const select = document.getElementById('sheetFilter');
|
const select = document.getElementById('sheetFilter');
|
||||||
select.innerHTML = '';
|
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) => {
|
sheetNames.forEach((sheetName, index) => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = sheetName;
|
option.value = sheetName;
|
||||||
@ -490,8 +537,9 @@ def create_templates_dir():
|
|||||||
document.getElementById('filePath').value = data.file_path;
|
document.getElementById('filePath').value = data.file_path;
|
||||||
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
statusDiv.innerHTML = '<div class="loading">File uploaded! Analyzing data...</div>';
|
||||||
|
|
||||||
// Analyze the uploaded file
|
// Clear sheet filter for new file (let it default to first sheet)
|
||||||
const sheetFilter = document.getElementById('sheetFilter').value;
|
const sheetFilterElement = document.getElementById('sheetFilter');
|
||||||
|
const sheetFilter = null; // Always use default (first sheet) for new uploads
|
||||||
return fetch('/analyze', {
|
return fetch('/analyze', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -675,6 +723,8 @@ def create_templates_dir():
|
|||||||
|
|
||||||
// Auto-analyze on page load with default file
|
// Auto-analyze on page load with default file
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
// Initialize sheet filter with loading state
|
||||||
|
updateSheetFilter([], null);
|
||||||
analyzeData();
|
analyzeData();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user