wip wip wip
This commit is contained in:
@@ -24,12 +24,12 @@
|
||||
<div class="col-md-2">
|
||||
{% include 'components/control_panel.html' %}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Main Chart Area -->
|
||||
<div class="col-md-8">
|
||||
{% include 'components/chart_panel.html' %}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Right Sidebar - Annotations & Training -->
|
||||
<div class="col-md-2">
|
||||
{% include 'components/annotation_list.html' %}
|
||||
@@ -62,43 +62,43 @@
|
||||
window.appState = {
|
||||
currentSymbol: '{{ current_symbol }}',
|
||||
currentTimeframes: {{ timeframes | tojson }},
|
||||
annotations: {{ annotations | tojson }},
|
||||
pendingAnnotation: null,
|
||||
annotations: { { annotations | tojson } },
|
||||
pendingAnnotation: null,
|
||||
chartManager: null,
|
||||
annotationManager: null,
|
||||
timeNavigator: null,
|
||||
trainingController: null
|
||||
annotationManager: null,
|
||||
timeNavigator: null,
|
||||
trainingController: null
|
||||
};
|
||||
|
||||
// Initialize components when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize chart manager
|
||||
window.appState.chartManager = new ChartManager('chart-container', window.appState.currentTimeframes);
|
||||
|
||||
// Initialize annotation manager
|
||||
window.appState.annotationManager = new AnnotationManager(window.appState.chartManager);
|
||||
|
||||
// Initialize time navigator
|
||||
window.appState.timeNavigator = new TimeNavigator(window.appState.chartManager);
|
||||
|
||||
// Initialize training controller
|
||||
window.appState.trainingController = new TrainingController();
|
||||
|
||||
// Load initial data
|
||||
loadInitialData();
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
setupKeyboardShortcuts();
|
||||
|
||||
// Setup global functions
|
||||
setupGlobalFunctions();
|
||||
});
|
||||
|
||||
|
||||
// Initialize components when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Initialize chart manager
|
||||
window.appState.chartManager = new ChartManager('chart-container', window.appState.currentTimeframes);
|
||||
|
||||
// Initialize annotation manager
|
||||
window.appState.annotationManager = new AnnotationManager(window.appState.chartManager);
|
||||
|
||||
// Initialize time navigator
|
||||
window.appState.timeNavigator = new TimeNavigator(window.appState.chartManager);
|
||||
|
||||
// Initialize training controller
|
||||
window.appState.trainingController = new TrainingController();
|
||||
|
||||
// Setup global functions FIRST (before loading data)
|
||||
setupGlobalFunctions();
|
||||
|
||||
// Load initial data (may call renderAnnotationsList which needs deleteAnnotation)
|
||||
loadInitialData();
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
setupKeyboardShortcuts();
|
||||
});
|
||||
|
||||
function loadInitialData() {
|
||||
// Fetch initial chart data
|
||||
fetch('/api/chart-data', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
symbol: appState.currentSymbol,
|
||||
timeframes: appState.currentTimeframes,
|
||||
@@ -106,32 +106,32 @@
|
||||
end_time: null
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
window.appState.chartManager.initializeCharts(data.chart_data);
|
||||
|
||||
// Load existing annotations
|
||||
console.log('Loading', window.appState.annotations.length, 'existing annotations');
|
||||
window.appState.annotations.forEach(annotation => {
|
||||
window.appState.chartManager.addAnnotation(annotation);
|
||||
});
|
||||
|
||||
// Update annotation list
|
||||
if (typeof renderAnnotationsList === 'function') {
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
window.appState.chartManager.initializeCharts(data.chart_data);
|
||||
|
||||
// Load existing annotations
|
||||
console.log('Loading', window.appState.annotations.length, 'existing annotations');
|
||||
window.appState.annotations.forEach(annotation => {
|
||||
window.appState.chartManager.addAnnotation(annotation);
|
||||
});
|
||||
|
||||
// Update annotation list
|
||||
if (typeof renderAnnotationsList === 'function') {
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
}
|
||||
} else {
|
||||
showError('Failed to load chart data: ' + data.error.message);
|
||||
}
|
||||
} else {
|
||||
showError('Failed to load chart data: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function setupKeyboardShortcuts() {
|
||||
document.addEventListener('keydown', function(e) {
|
||||
document.addEventListener('keydown', function (e) {
|
||||
// Arrow left - navigate backward
|
||||
if (e.key === 'ArrowLeft') {
|
||||
e.preventDefault();
|
||||
@@ -172,7 +172,7 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function showError(message) {
|
||||
// Create toast notification
|
||||
const toast = document.createElement('div');
|
||||
@@ -187,16 +187,16 @@
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
// Add to page and show
|
||||
document.body.appendChild(toast);
|
||||
const bsToast = new bootstrap.Toast(toast);
|
||||
bsToast.show();
|
||||
|
||||
|
||||
// Remove after hidden
|
||||
toast.addEventListener('hidden.bs.toast', () => toast.remove());
|
||||
}
|
||||
|
||||
|
||||
function showSuccess(message) {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'toast align-items-center text-white bg-success border-0';
|
||||
@@ -210,13 +210,13 @@
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
document.body.appendChild(toast);
|
||||
const bsToast = new bootstrap.Toast(toast);
|
||||
bsToast.show();
|
||||
toast.addEventListener('hidden.bs.toast', () => toast.remove());
|
||||
}
|
||||
|
||||
|
||||
function setupGlobalFunctions() {
|
||||
// Make functions globally available
|
||||
window.showError = showError;
|
||||
@@ -224,14 +224,21 @@
|
||||
window.renderAnnotationsList = renderAnnotationsList;
|
||||
window.deleteAnnotation = deleteAnnotation;
|
||||
window.highlightAnnotation = highlightAnnotation;
|
||||
|
||||
// Verify functions are set
|
||||
console.log('Global functions setup complete:');
|
||||
console.log(' - window.deleteAnnotation:', typeof window.deleteAnnotation);
|
||||
console.log(' - window.renderAnnotationsList:', typeof window.renderAnnotationsList);
|
||||
console.log(' - window.showError:', typeof window.showError);
|
||||
console.log(' - window.showSuccess:', typeof window.showSuccess);
|
||||
}
|
||||
|
||||
|
||||
function renderAnnotationsList(annotations) {
|
||||
const listElement = document.getElementById('annotations-list');
|
||||
if (!listElement) return;
|
||||
|
||||
|
||||
listElement.innerHTML = '';
|
||||
|
||||
|
||||
annotations.forEach(annotation => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'annotation-item mb-2 p-2 border rounded';
|
||||
@@ -259,43 +266,67 @@
|
||||
listElement.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function deleteAnnotation(annotationId) {
|
||||
if (!confirm('Delete this annotation?')) return;
|
||||
|
||||
console.log('deleteAnnotation called with ID:', annotationId);
|
||||
|
||||
if (!confirm('Delete this annotation?')) {
|
||||
console.log('Delete cancelled by user');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Sending delete request to API...');
|
||||
fetch('/api/delete-annotation', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({annotation_id: annotationId})
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ annotation_id: annotationId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove from app state
|
||||
window.appState.annotations = window.appState.annotations.filter(a => a.annotation_id !== annotationId);
|
||||
|
||||
// Update UI
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
|
||||
// Remove from chart
|
||||
if (window.appState.chartManager) {
|
||||
window.appState.chartManager.removeAnnotation(annotationId);
|
||||
.then(response => {
|
||||
console.log('Delete response status:', response.status);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Delete response data:', data);
|
||||
|
||||
if (data.success) {
|
||||
// Remove from app state
|
||||
if (window.appState && window.appState.annotations) {
|
||||
window.appState.annotations = window.appState.annotations.filter(
|
||||
a => a.annotation_id !== annotationId
|
||||
);
|
||||
console.log('Removed from appState, remaining:', window.appState.annotations.length);
|
||||
}
|
||||
|
||||
// Update UI
|
||||
if (typeof renderAnnotationsList === 'function') {
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
console.log('UI updated');
|
||||
} else {
|
||||
console.error('renderAnnotationsList function not found');
|
||||
}
|
||||
|
||||
// Remove from chart
|
||||
if (window.appState && window.appState.chartManager) {
|
||||
window.appState.chartManager.removeAnnotation(annotationId);
|
||||
console.log('Removed from chart');
|
||||
}
|
||||
|
||||
showSuccess('Annotation deleted successfully');
|
||||
} else {
|
||||
console.error('Delete failed:', data.error);
|
||||
showError('Failed to delete annotation: ' + (data.error ? data.error.message : 'Unknown error'));
|
||||
}
|
||||
|
||||
showSuccess('Annotation deleted');
|
||||
} else {
|
||||
showError('Failed to delete annotation: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Delete error:', error);
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function highlightAnnotation(annotationId) {
|
||||
if (window.appState.chartManager) {
|
||||
window.appState.chartManager.highlightAnnotation(annotationId);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -5,6 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Manual Trade Annotation{% endblock %}</title>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23007bff'%3E%3Cpath d='M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z'/%3E%3C/svg%3E">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
|
||||
@@ -165,7 +165,15 @@
|
||||
|
||||
item.querySelector('.delete-annotation-btn').addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
deleteAnnotation(annotation.annotation_id);
|
||||
console.log('Delete button clicked for:', annotation.annotation_id);
|
||||
|
||||
// Use window.deleteAnnotation to ensure we get the global function
|
||||
if (typeof window.deleteAnnotation === 'function') {
|
||||
window.deleteAnnotation(annotation.annotation_id);
|
||||
} else {
|
||||
console.error('window.deleteAnnotation is not a function:', typeof window.deleteAnnotation);
|
||||
alert('Delete function not available. Please refresh the page.');
|
||||
}
|
||||
});
|
||||
|
||||
listContainer.appendChild(item);
|
||||
@@ -204,32 +212,5 @@
|
||||
});
|
||||
}
|
||||
|
||||
function deleteAnnotation(annotationId) {
|
||||
if (!confirm('Are you sure you want to delete this annotation?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/api/delete-annotation', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({annotation_id: annotationId})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove from UI
|
||||
appState.annotations = appState.annotations.filter(a => a.annotation_id !== annotationId);
|
||||
renderAnnotationsList(appState.annotations);
|
||||
if (appState.chartManager) {
|
||||
appState.chartManager.removeAnnotation(annotationId);
|
||||
}
|
||||
showSuccess('Annotation deleted');
|
||||
} else {
|
||||
showError('Failed to delete annotation: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
}
|
||||
// Note: deleteAnnotation is defined in annotation_dashboard.html to avoid duplication
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user