Refactor code structure for improved readability and maintainability
This commit is contained in:
parent
bed4fcde1f
commit
a655e68b71
59
app/app.py
59
app/app.py
|
@ -221,6 +221,45 @@ def register_routes(app):
|
||||||
user_language=user_language,
|
user_language=user_language,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route("/script/<int:script_id>/loading")
|
||||||
|
@login_required
|
||||||
|
def script_loading_page(script_id):
|
||||||
|
"""
|
||||||
|
Página de loading intermedia que se muestra mientras el script se inicia
|
||||||
|
"""
|
||||||
|
script = Script.query.get_or_404(script_id)
|
||||||
|
|
||||||
|
# Check if user can access this script
|
||||||
|
if not can_access_script(current_user.user_level, script.required_level):
|
||||||
|
flash("Insufficient permissions to access this script", "error")
|
||||||
|
return redirect(url_for("dashboard"))
|
||||||
|
|
||||||
|
# Get active project for this script's group
|
||||||
|
active_project_id = session.get("active_project_id")
|
||||||
|
project = None
|
||||||
|
|
||||||
|
if active_project_id:
|
||||||
|
project = UserProject.query.filter_by(
|
||||||
|
id=active_project_id,
|
||||||
|
user_id=current_user.id,
|
||||||
|
group_id=script.group_id,
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not project:
|
||||||
|
flash("No active project found for this script group", "error")
|
||||||
|
return redirect(url_for("script_group_view", group_id=script.group_id))
|
||||||
|
|
||||||
|
# Generate proxy URL
|
||||||
|
proxy_url = f"/project/{project.id}/script/{script.id}/user/{current_user.id}/"
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"script_loading.html",
|
||||||
|
script=script,
|
||||||
|
script_group=script.script_group,
|
||||||
|
project=project,
|
||||||
|
proxy_url=proxy_url,
|
||||||
|
)
|
||||||
|
|
||||||
# Administration routes
|
# Administration routes
|
||||||
@app.route("/admin")
|
@app.route("/admin")
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -568,7 +607,10 @@ def register_routes(app):
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"[API_EXEC] Script executor result: {result}")
|
print(f"[API_EXEC] Script executor result: {result}")
|
||||||
return jsonify(result)
|
print(f"[API_EXEC] About to return JSON response...")
|
||||||
|
response = jsonify(result)
|
||||||
|
print(f"[API_EXEC] JSON response created successfully")
|
||||||
|
return response
|
||||||
|
|
||||||
@app.route("/api/scripts/<int:script_id>/stop", methods=["POST"])
|
@app.route("/api/scripts/<int:script_id>/stop", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -1105,7 +1147,20 @@ def create_app(config_name="default"):
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Load configuration
|
# Load configuration
|
||||||
app.config.from_object(config[config_name])
|
config_obj = config[config_name]
|
||||||
|
app.config.from_object(config_obj)
|
||||||
|
|
||||||
|
# Apply security configuration if present
|
||||||
|
if hasattr(config_obj, 'SECURITY_CONFIG'):
|
||||||
|
security_config = config_obj.SECURITY_CONFIG
|
||||||
|
|
||||||
|
# Apply session cookie settings
|
||||||
|
if 'session_cookie_secure' in security_config:
|
||||||
|
app.config['SESSION_COOKIE_SECURE'] = security_config['session_cookie_secure']
|
||||||
|
if 'session_cookie_httponly' in security_config:
|
||||||
|
app.config['SESSION_COOKIE_HTTPONLY'] = security_config['session_cookie_httponly']
|
||||||
|
if 'session_cookie_samesite' in security_config:
|
||||||
|
app.config['SESSION_COOKIE_SAMESITE'] = security_config['session_cookie_samesite']
|
||||||
|
|
||||||
# Add custom Jinja2 filters
|
# Add custom Jinja2 filters
|
||||||
@app.template_filter("fromjson")
|
@app.template_filter("fromjson")
|
||||||
|
|
|
@ -126,6 +126,14 @@ class DevelopmentConfig(Config):
|
||||||
'pool_pre_ping': True,
|
'pool_pre_ping': True,
|
||||||
'echo': True, # Log SQL queries in development
|
'echo': True, # Log SQL queries in development
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Development security config - allow HTTP cookies
|
||||||
|
SECURITY_CONFIG = {
|
||||||
|
**Config.SECURITY_CONFIG,
|
||||||
|
"session_cookie_secure": False, # Allow HTTP cookies in development
|
||||||
|
"session_cookie_httponly": True,
|
||||||
|
"session_cookie_samesite": "Lax",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(Config):
|
class ProductionConfig(Config):
|
||||||
|
|
|
@ -79,9 +79,12 @@ class DataManager:
|
||||||
print(f"Error saving config file {config_file}: {e}")
|
print(f"Error saving config file {config_file}: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def list_user_projects(self, user_id: int, group_id: int) -> List[Dict]:
|
def list_user_projects(self, user_id: int, group_id: int = None) -> List[Dict]:
|
||||||
"""List all projects for user in specific group."""
|
"""List all projects for user in specific group or all groups if group_id is None."""
|
||||||
projects = UserProject.query.filter_by(user_id=user_id, group_id=group_id).all()
|
if group_id is None:
|
||||||
|
projects = UserProject.query.filter_by(user_id=user_id).all()
|
||||||
|
else:
|
||||||
|
projects = UserProject.query.filter_by(user_id=user_id, group_id=group_id).all()
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for project in projects:
|
for project in projects:
|
||||||
|
@ -89,7 +92,7 @@ class DataManager:
|
||||||
|
|
||||||
# Add file system information
|
# Add file system information
|
||||||
project_path = self.get_user_project_path(
|
project_path = self.get_user_project_path(
|
||||||
user_id, group_id, project.project_name
|
user_id, project.group_id, project.project_name
|
||||||
)
|
)
|
||||||
|
|
||||||
if project_path.exists():
|
if project_path.exists():
|
||||||
|
|
|
@ -799,32 +799,11 @@
|
||||||
class ScriptGroupManager {
|
class ScriptGroupManager {
|
||||||
async runScript(scriptId, parameters = {}) {
|
async runScript(scriptId, parameters = {}) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/scripts/${scriptId}/execute`, {
|
// Redirect immediately to loading page - it will handle script execution
|
||||||
method: 'POST',
|
window.location.href = `/script/${scriptId}/loading`;
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
parameters: parameters
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
ScriptsManager.showNotification('Script started successfully', 'success');
|
|
||||||
this.updateScriptStatus(scriptId, 'running');
|
|
||||||
|
|
||||||
// If the script has an interface URL, wait for it to be ready before opening
|
|
||||||
if (result.interface_url) {
|
|
||||||
this.waitForScriptAndOpen(result.interface_url, scriptId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ScriptsManager.showNotification(result.message || 'Failed to start script', 'error');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error running script:', error);
|
console.error('Error redirecting to loading page:', error);
|
||||||
ScriptsManager.showNotification('Error running script', 'error');
|
ScriptsManager.showNotification('Error starting script', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Loading Script - ScriptsManager</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<!-- Bootstrap Icons -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.loading-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-card {
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 3rem;
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar-container {
|
||||||
|
background-color: #e9ecef;
|
||||||
|
border-radius: 10px;
|
||||||
|
height: 8px;
|
||||||
|
margin: 2rem 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
background: linear-gradient(90deg, #667eea, #764ba2);
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.7; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-info {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-info h5 {
|
||||||
|
color: #495057;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-info p {
|
||||||
|
color: #6c757d;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
color: #721c24;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.open-anyway-btn {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="loading-container">
|
||||||
|
<div class="loading-card">
|
||||||
|
<!-- Loading Spinner -->
|
||||||
|
<div class="spinner-border text-primary loading-spinner" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Text -->
|
||||||
|
<h3 class="mb-3" id="loading-title">Starting Script...</h3>
|
||||||
|
<p class="status-text" id="status-text">Initializing script environment...</p>
|
||||||
|
|
||||||
|
<!-- Progress Bar -->
|
||||||
|
<div class="progress-bar-container">
|
||||||
|
<div class="progress-bar" id="progress-bar" style="width: 10%;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Script Information -->
|
||||||
|
<div class="script-info">
|
||||||
|
<h5>{{ script.display_name or script.filename }}</h5>
|
||||||
|
<p>{{ script.description or "Running script..." }}</p>
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="bi bi-folder me-1"></i>{{ script_group.name }} |
|
||||||
|
<i class="bi bi-person me-1"></i>{{ current_user.username }} |
|
||||||
|
<i class="bi bi-briefcase me-1"></i>{{ project.project_name }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error Container (hidden by default) -->
|
||||||
|
<div id="error-container" class="error-message" style="display: none;">
|
||||||
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||||
|
<span id="error-text"></span>
|
||||||
|
<button type="button" class="btn btn-outline-danger btn-sm open-anyway-btn" onclick="openScriptAnyway()">
|
||||||
|
<i class="bi bi-box-arrow-up-right me-1"></i>
|
||||||
|
Open Script Anyway
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap JS -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Configuration from backend
|
||||||
|
const SCRIPT_CONFIG = {
|
||||||
|
scriptId: {{ script.id }},
|
||||||
|
projectId: {{ project.id }},
|
||||||
|
userId: {{ current_user.id }},
|
||||||
|
proxyUrl: "{{ proxy_url }}",
|
||||||
|
fullProxyUrl: "{{ request.url_root.rstrip('/') }}{{ proxy_url }}",
|
||||||
|
maxAttempts: 30,
|
||||||
|
checkInterval: 2000
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loading states and messages
|
||||||
|
const LOADING_STATES = [
|
||||||
|
{ progress: 10, title: "Starting Script...", message: "Initializing script environment..." },
|
||||||
|
{ progress: 25, title: "Loading Dependencies...", message: "Setting up required libraries..." },
|
||||||
|
{ progress: 40, title: "Configuring Environment...", message: "Preparing script workspace..." },
|
||||||
|
{ progress: 55, title: "Starting Web Server...", message: "Launching script interface..." },
|
||||||
|
{ progress: 70, title: "Checking Connectivity...", message: "Verifying script availability..." },
|
||||||
|
{ progress: 85, title: "Finalizing Setup...", message: "Almost ready..." },
|
||||||
|
{ progress: 95, title: "Script Ready!", message: "Redirecting to script interface..." }
|
||||||
|
];
|
||||||
|
|
||||||
|
let currentStateIndex = 0;
|
||||||
|
let attempts = 0;
|
||||||
|
let checkingStarted = false;
|
||||||
|
|
||||||
|
// DOM elements
|
||||||
|
const progressBar = document.getElementById('progress-bar');
|
||||||
|
const loadingTitle = document.getElementById('loading-title');
|
||||||
|
const statusText = document.getElementById('status-text');
|
||||||
|
const errorContainer = document.getElementById('error-container');
|
||||||
|
const errorText = document.getElementById('error-text');
|
||||||
|
|
||||||
|
// Update loading state
|
||||||
|
function updateLoadingState(stateIndex) {
|
||||||
|
if (stateIndex < LOADING_STATES.length) {
|
||||||
|
const state = LOADING_STATES[stateIndex];
|
||||||
|
progressBar.style.width = state.progress + '%';
|
||||||
|
loadingTitle.textContent = state.title;
|
||||||
|
statusText.textContent = state.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show error message
|
||||||
|
function showError(message) {
|
||||||
|
errorText.textContent = message;
|
||||||
|
errorContainer.style.display = 'block';
|
||||||
|
loadingTitle.textContent = "Error Starting Script";
|
||||||
|
statusText.textContent = "There was an issue starting the script.";
|
||||||
|
progressBar.style.width = '100%';
|
||||||
|
progressBar.style.backgroundColor = '#dc3545';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open script anyway (fallback)
|
||||||
|
function openScriptAnyway() {
|
||||||
|
window.location.href = SCRIPT_CONFIG.fullProxyUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if script is ready
|
||||||
|
async function checkScriptStatus() {
|
||||||
|
attempts++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Update UI state periodically
|
||||||
|
if (!checkingStarted) {
|
||||||
|
checkingStarted = true;
|
||||||
|
// Start advancing through loading states
|
||||||
|
const stateInterval = setInterval(() => {
|
||||||
|
if (currentStateIndex < LOADING_STATES.length - 1) {
|
||||||
|
currentStateIndex++;
|
||||||
|
updateLoadingState(currentStateIndex);
|
||||||
|
} else {
|
||||||
|
clearInterval(stateInterval);
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if script is responding
|
||||||
|
const response = await fetch(SCRIPT_CONFIG.fullProxyUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
cache: 'no-cache'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// Script is ready!
|
||||||
|
updateLoadingState(LOADING_STATES.length - 1);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = SCRIPT_CONFIG.fullProxyUrl;
|
||||||
|
}, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Attempt ${attempts}: Script not ready yet`, error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we've exceeded max attempts
|
||||||
|
if (attempts >= SCRIPT_CONFIG.maxAttempts) {
|
||||||
|
showError("Script is taking longer than expected to start. You can try opening it manually.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try again after interval
|
||||||
|
setTimeout(checkScriptStatus, SCRIPT_CONFIG.checkInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start checking when page loads
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Start with first loading state
|
||||||
|
updateLoadingState(0);
|
||||||
|
|
||||||
|
// Start script execution via AJAX first
|
||||||
|
startScriptExecution();
|
||||||
|
|
||||||
|
// Begin checking script status after a short delay
|
||||||
|
setTimeout(checkScriptStatus, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to start script execution
|
||||||
|
async function startScriptExecution() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/scripts/${SCRIPT_CONFIG.scriptId}/execute`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
parameters: {}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
console.log('Script execution started successfully:', result);
|
||||||
|
} else {
|
||||||
|
console.error('Failed to start script:', result.message);
|
||||||
|
showError(result.message || 'Failed to start script');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error starting script execution:', error);
|
||||||
|
showError('Error starting script: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"created_at": "2025-09-14T08:09:16.779232",
|
||||||
|
"last_modified": "2025-09-14T08:09:16.779241",
|
||||||
|
"project_settings": {},
|
||||||
|
"user_preferences": {}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"created_at": "2025-09-14T08:01:20.986814",
|
||||||
|
"last_modified": "2025-09-14T08:01:20.986822",
|
||||||
|
"project_settings": {},
|
||||||
|
"user_preferences": {}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"created_at": "2025-09-14T07:57:47.252787",
|
||||||
|
"last_modified": "2025-09-14T07:57:47.252795",
|
||||||
|
"project_settings": {},
|
||||||
|
"user_preferences": {}
|
||||||
|
}
|
|
@ -87,7 +87,6 @@ services:
|
||||||
- scriptsmanager_network
|
- scriptsmanager_network
|
||||||
ports:
|
ports:
|
||||||
- "5003:5003"
|
- "5003:5003"
|
||||||
- "5200-5400:5200-5400"
|
|
||||||
- "5678:5678" # Debug port
|
- "5678:5678" # Debug port
|
||||||
environment:
|
environment:
|
||||||
# Database Configuration (same as production for parity)
|
# Database Configuration (same as production for parity)
|
||||||
|
@ -115,20 +114,21 @@ services:
|
||||||
- SIDEL_LOGO_PATH=/app/app/static/images/SIDEL.png
|
- SIDEL_LOGO_PATH=/app/app/static/images/SIDEL.png
|
||||||
- CORPORATE_BRANDING=true
|
- CORPORATE_BRANDING=true
|
||||||
volumes:
|
volumes:
|
||||||
# Hot reload: mount entire codebase
|
# Hot reload: mount entire codebase excluding workspaces
|
||||||
- .:/app
|
- .:/app
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
- ./backup:/app/backup
|
- ./backup:/app/backup
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
# Workspaces for proxy scripts
|
# Workspaces for proxy scripts (mounted separately to avoid hot-reload)
|
||||||
- ./workspaces:/app/workspaces
|
- ./workspaces:/app/workspaces:delegated
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
command: >
|
command: >
|
||||||
bash -c "source activate scriptsmanager &&
|
bash -c "source activate scriptsmanager &&
|
||||||
echo '=== SIDEL ScriptsManager Development Environment ===' &&
|
echo '=== SIDEL ScriptsManager Development Environment ===' &&
|
||||||
echo 'Hot reload enabled - code changes will be reflected automatically' &&
|
echo 'Development mode with stable container (hot reload disabled for stability)' &&
|
||||||
echo 'Application will be available at: http://localhost:5003' &&
|
echo 'Application will be available at: http://localhost:5003' &&
|
||||||
echo 'Debug port available at: 5678' &&
|
echo 'Debug port available at: 5678' &&
|
||||||
python scripts/init_db.py &&
|
python scripts/init_db.py &&
|
||||||
|
|
|
@ -30,11 +30,22 @@ def init_database():
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
try:
|
try:
|
||||||
# Drop all tables (for fresh start)
|
# Check if database is already initialized
|
||||||
print("Dropping existing tables...")
|
from sqlalchemy import inspect
|
||||||
db.drop_all()
|
inspector = inspect(db.engine)
|
||||||
|
existing_tables = inspector.get_table_names()
|
||||||
# Create all tables
|
|
||||||
|
if existing_tables:
|
||||||
|
print(f"Database already initialized with {len(existing_tables)} tables.")
|
||||||
|
print("Skipping table creation and data initialization.")
|
||||||
|
|
||||||
|
# Still discover script groups in case new ones were added
|
||||||
|
print("Updating script group discovery...")
|
||||||
|
discover_script_groups()
|
||||||
|
print("Database update completed successfully!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Only create tables if database is empty
|
||||||
print("Creating database tables...")
|
print("Creating database tables...")
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
|
|
|
@ -25,15 +25,29 @@ def run_app():
|
||||||
port = int(os.environ.get('PORT', 5003 if os.environ.get('DEBUG') == 'true' else 5002))
|
port = int(os.environ.get('PORT', 5003 if os.environ.get('DEBUG') == 'true' else 5002))
|
||||||
debug = os.environ.get('DEBUG', 'false').lower() == 'true'
|
debug = os.environ.get('DEBUG', 'false').lower() == 'true'
|
||||||
|
|
||||||
|
# For development: disable auto-reloader to prevent container restarts when workspaces change
|
||||||
|
# This avoids the issue where script execution causes Flask to restart
|
||||||
|
use_reloader = False if debug else False
|
||||||
|
|
||||||
# Run with SocketIO support
|
# Run with SocketIO support
|
||||||
socketio.run(app, host="0.0.0.0", port=port, debug=debug)
|
socketio.run(
|
||||||
|
app,
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=port,
|
||||||
|
debug=debug,
|
||||||
|
use_reloader=use_reloader
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
port = int(os.environ.get('PORT', 5003 if os.environ.get('DEBUG') == 'true' else 5002))
|
port = int(os.environ.get('PORT', 5003 if os.environ.get('DEBUG') == 'true' else 5002))
|
||||||
print("Starting ScriptsManager...")
|
print("Starting ScriptsManager...")
|
||||||
print(f"🚀 Application will be available at: http://localhost:{port}")
|
print(f"🚀 Application will be available at: http://localhost:{port}")
|
||||||
print("🔄 HOT-RELOAD ENABLED - Modify files and they will update automatically!")
|
if os.environ.get('DEBUG') == 'true':
|
||||||
|
print("<EFBFBD> DEVELOPMENT MODE - Auto-reloader disabled for container stability")
|
||||||
|
print(" Manual restart required for code changes")
|
||||||
|
else:
|
||||||
|
print("🏭 PRODUCTION MODE")
|
||||||
print("Press Ctrl+C to stop the server")
|
print("Press Ctrl+C to stop the server")
|
||||||
print("-" * 50)
|
print("-" * 50)
|
||||||
run_app()
|
run_app()
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
"CONDA_DEFAULT_ENV": "tsnet",
|
"CONDA_DEFAULT_ENV": "tsnet",
|
||||||
"USER_LEVEL": "admin",
|
"USER_LEVEL": "admin",
|
||||||
"PROJECT_ID": "1",
|
"PROJECT_ID": "1",
|
||||||
"PROJECT_NAME": "test",
|
"PROJECT_NAME": "Hola",
|
||||||
"USER_THEME": "light",
|
"USER_THEME": "light",
|
||||||
"USER_LANGUAGE": "en",
|
"USER_LANGUAGE": "en",
|
||||||
"SCRIPT_GROUP_NAME": "Hydraulic Analysis Tools"
|
"SCRIPT_GROUP_NAME": "Hydraulic Analysis Tools"
|
||||||
},
|
},
|
||||||
"created_at": "2025-09-14T07:35:04.965536"
|
"created_at": "2025-09-14T10:08:46.733111"
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ os.chdir(WORKSPACE_PATH)
|
||||||
# Variables disponibles para el script del usuario
|
# Variables disponibles para el script del usuario
|
||||||
PROJECT_WORKSPACE = WORKSPACE_PATH
|
PROJECT_WORKSPACE = WORKSPACE_PATH
|
||||||
PARAMETERS = {}
|
PARAMETERS = {}
|
||||||
ENVIRONMENT = {'CONDA_DEFAULT_ENV': 'tsnet', 'USER_LEVEL': 'admin', 'PROJECT_ID': '1', 'PROJECT_NAME': 'test', 'USER_THEME': 'light', 'USER_LANGUAGE': 'en', 'SCRIPT_GROUP_NAME': 'Hydraulic Analysis Tools'}
|
ENVIRONMENT = {'CONDA_DEFAULT_ENV': 'tsnet', 'USER_LEVEL': 'admin', 'PROJECT_ID': '1', 'PROJECT_NAME': 'Hola', 'USER_THEME': 'light', 'USER_LANGUAGE': 'en', 'SCRIPT_GROUP_NAME': 'Hydraulic Analysis Tools'}
|
||||||
|
|
||||||
# Importar Flask y configurar aplicación
|
# Importar Flask y configurar aplicación
|
||||||
from flask import Flask, request, jsonify, render_template, send_file, redirect, url_for
|
from flask import Flask, request, jsonify, render_template, send_file, redirect, url_for
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"port": 5201,
|
||||||
|
"workspace": "/app/workspaces/user_1/project_1/script_8",
|
||||||
|
"parameters": null,
|
||||||
|
"environment": null,
|
||||||
|
"created_at": "2025-09-14T07:38:22.462360"
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue