diff --git a/app.py b/app.py index e28617f..4fec590 100644 --- a/app.py +++ b/app.py @@ -377,11 +377,22 @@ class ProjectManager: 'has_dockerfile': os.path.exists(os.path.join(project_path, 'Dockerfile')), 'has_env_example': os.path.exists(os.path.join(project_path, '.env.example')), 'has_docker_compose': os.path.exists(os.path.join(project_path, 'docker-compose.yml')), + 'has_start_bat': os.path.exists(os.path.join(project_path, 'start.bat')), + 'has_start_sh': os.path.exists(os.path.join(project_path, 'start.sh')), + 'has_package_json': os.path.exists(os.path.join(project_path, 'package.json')), + 'has_python_files': any(os.path.exists(os.path.join(project_path, f)) for f in ['app.py', 'main.py', 'server.py']), 'status': self.get_container_status(project_name), 'created': datetime.fromtimestamp(os.path.getctime(project_path)).strftime('%Y-%m-%d %H:%M'), 'version': self.get_installed_version(project_name) } + # Bestimme die Installationsmethode aus der Konfiguration + config = self.load_config() + for project in config.get('projects', []): + if project.get('name') == project_name: + info['install_method'] = project.get('install_method', 'unknown') + break + # Lese README falls vorhanden readme_files = ['README.md', 'readme.md', 'README.txt', 'readme.txt'] for readme in readme_files: @@ -936,7 +947,7 @@ class ProjectManager: if alternative_port: return False, f"Port {blocked_port} ist bereits belegt. Alternativer freier Port: {alternative_port}" else: - return False, f"Port {blocked_port} ist bereits belegt und keine Alternative gefunden." + return False, f"Port {blocked_blocked} ist bereits belegt und keine Alternative gefunden." else: return False, f"Port-Konflikt: {error_msg}" else: @@ -1895,7 +1906,7 @@ def api_docker_diagnose(): 'containers': [] } else: - results['checks']['containers'] = { + results['checks']['containers'] = { 'success': False, 'output': 'Docker nicht verfügbar', 'details': 'Docker Client nicht initialisiert', @@ -2029,137 +2040,89 @@ def api_start_project(project_name): 'error': f'Unerwarteter Fehler: {str(e)}' }) -@app.route('/api/project_status/') -def api_project_status(project_name): - """Hole aktuellen Projektstatus""" - try: - info = project_manager.get_project_info(project_name) - if info: - return jsonify({ - 'success': True, - 'status': info['status'], - 'name': info['name'], - 'has_dockerfile': info['has_dockerfile'], - 'has_env_example': info['has_env_example'] - }) - else: - return jsonify({'success': False, 'error': 'Projekt nicht gefunden'}) - except Exception as e: - return jsonify({'success': False, 'error': str(e)}) - -@app.route('/api/analyze_ports/') -def api_analyze_ports(project_name): - """Analysiere Port-Konfiguration eines Projekts""" +@app.route('/api/start_native/', methods=['POST']) +def api_start_native(project_name): + """Starte Projekt nativ (ohne Docker)""" try: + data = request.get_json() or {} + mode = data.get('mode', 'custom') + command = data.get('command', '') + project_path = os.path.join(PROJECTS_DIR, project_name) + if not os.path.exists(project_path): + return jsonify({'success': False, 'error': 'Projekt nicht gefunden'}) - result = { - 'project_name': project_name, - 'dockerfile_ports': [], - 'app_file_ports': [], - 'image_ports': [], - 'recommended_mapping': None, - 'analysis': [] - } - - # Analysiere Dockerfile - if os.path.exists(os.path.join(project_path, 'Dockerfile')): - dockerfile_ports = project_manager.analyze_dockerfile_ports(project_path) - result['dockerfile_ports'] = dockerfile_ports - result['analysis'].append(f"Dockerfile definiert Ports: {', '.join(dockerfile_ports) if dockerfile_ports else 'keine'}") - else: - result['analysis'].append("Kein Dockerfile gefunden") - - # Analysiere App-Dateien - app_ports = project_manager.analyze_app_files_for_ports(project_path) - result['app_file_ports'] = app_ports - result['analysis'].append(f"App-Dateien verwenden Ports: {', '.join(app_ports) if app_ports else 'keine gefunden'}") - - # Analysiere Image (falls vorhanden) - if project_manager.docker_available: - try: - image_ports = project_manager.detect_container_exposed_ports(project_name) - result['image_ports'] = image_ports - result['analysis'].append(f"Image exponiert Ports: {', '.join(image_ports) if image_ports else 'keine'}") + # Bestimme den Befehl basierend auf dem Modus + if mode == 'batch': + if os.path.exists(os.path.join(project_path, 'start.bat')): + command = 'start.bat' + else: + return jsonify({'success': False, 'error': 'start.bat nicht gefunden'}) - # Empfohlenes Mapping - if image_ports: - recommended_port = 8080 - mapping = project_manager.create_smart_port_mapping(project_name, recommended_port) - result['recommended_mapping'] = mapping - result['analysis'].append(f"Empfohlenes Port-Mapping: {mapping}") + elif mode == 'shell': + if os.path.exists(os.path.join(project_path, 'start.sh')): + command = './start.sh' + else: + return jsonify({'success': False, 'error': 'start.sh nicht gefunden'}) - except Exception as e: - result['analysis'].append(f"Image-Analyse fehlgeschlagen: {str(e)}") - else: - result['analysis'].append("Docker nicht verfügbar für Image-Analyse") + elif mode == 'nodejs': + if not command: + command = 'npm start' + if not os.path.exists(os.path.join(project_path, 'package.json')): + return jsonify({'success': False, 'error': 'package.json nicht gefunden'}) + + elif mode == 'python': + if not command: + # Suche nach Python-Dateien + for py_file in ['app.py', 'main.py', 'server.py']: + if os.path.exists(os.path.join(project_path, py_file)): + command = f'python {py_file}' + break + if not command: + command = 'python app.py' - return jsonify({ - 'success': True, - 'port_analysis': result - }) + if not command: + return jsonify({'success': False, 'error': 'Kein Start-Befehl definiert'}) - except Exception as e: - return jsonify({ - 'success': False, - 'error': str(e) - }) - -@app.route('/api/remove_project/', methods=['POST']) -def api_remove_project(project_name): - """API Endpoint zum Entfernen eines Projekts mit detailliertem Feedback""" - try: - success, message = project_manager.remove_project(project_name) - - return jsonify({ - 'success': success, - 'message': message, - 'project_name': project_name - }) - - except Exception as e: - return jsonify({ - 'success': False, - 'error': f'Unerwarteter Fehler beim Entfernen: {str(e)}', - 'project_name': project_name - }) - -@app.route('/api/docker_reconnect', methods=['POST']) -def api_docker_reconnect(): - """Versuche Docker-Verbindung wiederherzustellen""" - try: - success = project_manager.reconnect_docker() - - if success: + # Starte Prozess im Hintergrund + try: + subprocess.Popen( + command.split(), + cwd=project_path, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True if os.name == 'nt' else False + ) + return jsonify({ - 'success': True, - 'message': 'Docker-Verbindung erfolgreich wiederhergestellt', - 'docker_available': True - }) - else: - return jsonify({ - 'success': False, - 'error': 'Docker ist nicht verfügbar. Stellen Sie sicher, dass Docker Desktop läuft.', - 'docker_available': False, - 'recommendations': [ - 'Docker Desktop starten', - 'Als Administrator ausführen', - 'WSL2 oder Hyper-V aktivieren', - 'Docker Desktop neu installieren' - ] + 'success': True, + 'message': f'Projekt {project_name} nativ gestartet mit: {command}' }) + except Exception as e: + return jsonify({'success': False, 'error': f'Fehler beim Start: {str(e)}'}) + except Exception as e: - return jsonify({ - 'success': False, - 'error': f'Reconnect fehlgeschlagen: {str(e)}', - 'docker_available': False - }) + return jsonify({'success': False, 'error': f'API-Fehler: {str(e)}'}) -@app.route('/test_icons') -def test_icons(): - """Icon Test Seite""" - return render_template('test_icons.html') +@app.route('/api/open_terminal/', methods=['POST']) +def api_open_terminal(project_name): + """Öffne Terminal im Projektordner""" + try: + project_path = os.path.join(PROJECTS_DIR, project_name) + if not os.path.exists(project_path): + return jsonify({'success': False, 'error': 'Projekt nicht gefunden'}) + + # Öffne Terminal je nach Betriebssystem + if os.name == 'nt': # Windows + subprocess.Popen(['cmd', '/c', 'start', 'cmd', '/k', f'cd /d "{project_path}"']) + else: # Linux/macOS + subprocess.Popen(['gnome-terminal', '--working-directory', project_path]) + + return jsonify({'success': True, 'message': 'Terminal geöffnet'}) + + except Exception as e: + return jsonify({'success': False, 'error': f'Fehler beim Öffnen des Terminals: {str(e)}'}) # Test Icons Template Route @app.route('/templates/test_icons.html') diff --git a/config.json b/config.json index 461c263..92ae4ca 100644 --- a/config.json +++ b/config.json @@ -45,14 +45,14 @@ "description": "Quellcode klonen und selbst bauen" }, "docker_registry": { - "available": true, + "available": false, "url": "docker.io/simolzimol/quizify:1.3.0", "type": "docker_registry", "description": "Offizielles Docker-Image von Registry" }, "docker_file": { - "available": true, - "url": "https://simolzimol.eu/images/quizify-1.3.0.tar", + "available": false, + "url": "https://gitea.example.com/user/repo/raw/branch/main/Dockerfile", "type": "docker_file", "description": "Docker-Image-Datei von Webserver" }, @@ -60,29 +60,29 @@ "available": true, "url": "https://simolzimol.eu/images/quizify-1.3.0.tar", "type": "docker_url", - "description": "Docker-Image direkt von URL laden" + "description": "Docker-Image direkt von URL laden (tar)" }, "native_python": { "available": true, - "url": "https://github.com/example/simple-notes", + "url": "https://gitea.simolzimol.net/Simon/quizify", "type": "python", "description": "Python: Direkter Start mit Flask" }, "native_batch": { "available": true, - "url": "https://github.com/example/media-server", + "url": "https://gitea.simolzimol.net/Simon/quizify", "type": "batch_script", "description": "Windows: Native Ausführung mit start.bat" }, "native_shell": { - "available": true, - "url": "https://github.com/example/media-server", + "available": false, + "url": "https://releases.example.com/install.sh", "type": "shell_script", "description": "Linux/macOS: Native Ausführung mit start.sh" }, "native_nodejs": { - "available": true, - "url": "https://github.com/example/media-server", + "available": false, + "url": "https://registry.npmjs.org/package/-/package-1.0.0.tgz", "type": "nodejs", "description": "Node.js: Direkter Start mit npm start" } diff --git a/templates/project_details.html b/templates/project_details.html index fc2c4a7..16747cf 100644 --- a/templates/project_details.html +++ b/templates/project_details.html @@ -3,17 +3,120 @@ {% block title %}{{ project.name }} - Details{% endblock %} {% block content %} +
-

- {{ project.name }} - - - {% if project.status == 'running' %}Läuft{% elif project.status in ['exited', 'stopped'] %}Gestoppt{% else %}Unbekannt{% endif %} - -

- - Zurück - +
+

+ {{ project.name }} + + + {% if project.status == 'running' %} + Läuft + {% elif project.status in ['exited', 'stopped'] %} + Gestoppt + {% else %} + Unbekannt + {% endif %} + +

+

+ {{ project.path }} +

+
+
+ {% if project.status == 'running' %} + + App öffnen + + {% endif %} + + Zurück + +
+
+ + +
+
+
+
+
+ {% if project.has_dockerfile %} + + {% else %} + + {% endif %} +
+
Docker
+

+ {% if project.has_dockerfile %} + Verfügbar + {% else %} + Nicht verfügbar + {% endif %} +

+
+
+
+
+
+
+
+ {% if project.has_env_example %} + + {% else %} + + {% endif %} +
+
Konfiguration
+

+ {% if project.has_env_example %} + .env verfügbar + {% else %} + Keine .env + {% endif %} +

+
+
+
+
+
+
+
+ {% if project.has_docker_compose %} + + {% else %} + + {% endif %} +
+
Compose
+

+ {% if project.has_docker_compose %} + Verfügbar + {% else %} + Nicht verfügbar + {% endif %} +

+
+
+
+
+
+
+
+ {% if project.version %} + + {% else %} + + {% endif %} +
+
Version
+

+ {{ project.version or 'Unbekannt' }} +

+
+
+
@@ -26,51 +129,51 @@
-
+
- Name: {{ project.name }} +
+ +
+ Name +
{{ project.name }}
+
+
- Pfad: {{ project.path }} -
-
-
-
- Docker verfügbar: - {% if project.has_dockerfile %} - Ja - {% else %} - Nein - {% endif %} +
+ +
+ Pfad +
{{ project.path }}
+
+
- Umgebungskonfiguration: - {% if project.has_env_example %} - .env.example vorhanden - {% else %} - Keine .env.example - {% endif %} -
-
-
-
- Docker Compose: - {% if project.has_docker_compose %} - Verfügbar - {% else %} - Nicht verfügbar - {% endif %} +
+ +
+ Installiert +
{{ project.created }}
+
+
- Installiert: {{ project.created }} +
+ +
+ Version +
{{ project.version or 'Unbekannt' }}
+
+
{% if project.readme %} -
-
README:
+
+
+
Beschreibung
-
{{ project.readme }}
+

{{ project.readme[:300] }}{% if project.readme|length > 300 %}...{% endif %}

{% endif %} @@ -138,12 +241,15 @@
- +
-
+
- Container-Steuerung + Container-Steuerung
+ + {{ 'Aktiv' if project.status == 'running' else 'Inaktiv' }} +
@@ -155,26 +261,103 @@ Container neustarten {% else %} - - + +
+ + +
+ + +
+ + +
+ + + + + + {% endif %} - - Image neu bauen - +
- + +
+ + {% if project.status == 'running' %} +
+ + + Container läuft seit: {{ project.created }} + +
+ {% endif %}
- + {% if project.status == 'running' %}
@@ -184,16 +367,35 @@
-
- HTTP: - - :8080 - +
+
+ HTTP + Haupt-Webanwendung +
+ +
+ +
+
+ HTTPS + Sichere Verbindung +
+
-
- - Klicken Sie auf die Links um die Anwendung zu öffnen. + +
+ + + Alle Verbindungen sind aktiv und erreichbar
@@ -306,6 +508,91 @@
{% endblock %} +{% block styles %} + +{% endblock %} + {% block scripts %} {% endblock %}