HEX
Server: LiteSpeed
System: Linux php-prod-1.spaceapp.ru 5.15.0-157-generic #167-Ubuntu SMP Wed Sep 17 21:35:53 UTC 2025 x86_64
User: xnsbb3110 (1041)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: //usr/local/CyberCP/manageServices/templates/manageServices/applications.html
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% block title %}{% trans "Manage Applications - CyberPanel" %}{% endblock %}

{% block header_scripts %}
<style>
    /* Manage Applications Specific Styles */
    .applications-wrapper {
        background: transparent;
        padding: 20px;
    }
    
    .applications-container {
        max-width: 1200px;
        margin: 0 auto;
    }
    
    /* Page Header */
    .page-header {
        background: var(--bg-primary, white);
        border-radius: 12px;
        padding: 25px;
        margin-bottom: 25px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.08);
        border: 1px solid var(--border-color, #e8e9ff);
    }
    
    .page-header h1 {
        font-size: 28px;
        font-weight: 700;
        color: var(--text-primary, #2f3640);
        margin: 0 0 10px 0;
        display: flex;
        align-items: center;
        gap: 15px;
    }
    
    .page-header .icon {
        width: 48px;
        height: 48px;
        background: #5856d6;
        border-radius: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 24px;
        box-shadow: 0 4px 12px rgba(88,86,214,0.3);
    }
    
    .page-header p {
        font-size: 15px;
        color: var(--text-secondary, #64748b);
        margin: 0;
    }
    
    /* Content Section */
    .content-section {
        background: var(--bg-primary, white);
        border-radius: 12px;
        padding: 25px;
        margin-bottom: 25px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.08);
        border: 1px solid var(--border-color, #e8e9ff);
    }
    
    .section-title {
        font-size: 18px;
        font-weight: 700;
        color: var(--text-primary, #2f3640);
        margin-bottom: 20px;
        display: flex;
        align-items: center;
        gap: 10px;
    }
    
    .section-title::before {
        content: '';
        width: 4px;
        height: 24px;
        background: #5856d6;
        border-radius: 2px;
    }
    
    /* Applications Grid */
    .applications-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        gap: 20px;
    }
    
    .app-card {
        background: var(--bg-primary, white);
        border: 1px solid var(--border-color, #e8e9ff);
        border-radius: 12px;
        padding: 25px;
        transition: all 0.3s ease;
        position: relative;
        overflow: hidden;
    }
    
    .app-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 8px 24px rgba(0,0,0,0.1);
        border-color: #5856d6;
    }
    
    .app-card::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 4px;
        background: linear-gradient(90deg, #5856d6, #4a90e2);
        transform: translateX(-100%);
        transition: transform 0.3s ease;
    }
    
    .app-card:hover::before {
        transform: translateX(0);
    }
    
    .app-header {
        display: flex;
        align-items: center;
        gap: 20px;
        margin-bottom: 20px;
    }
    
    .app-icon {
        width: 64px;
        height: 64px;
        border-radius: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        overflow: hidden;
        background: var(--bg-secondary, #f8f9ff);
        padding: 12px;
    }
    
    .app-icon img {
        width: 100%;
        height: 100%;
        object-fit: contain;
    }
    
    .app-info {
        flex: 1;
    }
    
    .app-name {
        font-size: 20px;
        font-weight: 700;
        color: var(--text-primary, #2f3640);
        margin-bottom: 5px;
    }
    
    .app-status {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 4px 12px;
        border-radius: 6px;
        font-size: 13px;
        font-weight: 600;
    }
    
    .app-status.installed {
        background: var(--success-bg, #d1fae5);
        color: var(--success-text, #065f46);
    }
    
    .app-status.installed i {
        color: #10b981;
    }
    
    .app-status.not-installed {
        background: var(--danger-bg, #fee2e2);
        color: var(--danger-text, #991b1b);
    }
    
    .app-status.not-installed i {
        color: #ef4444;
    }
    
    .app-description {
        font-size: 14px;
        color: var(--text-secondary, #64748b);
        line-height: 1.6;
        margin-bottom: 20px;
    }
    
    .app-actions {
        display: flex;
        gap: 10px;
    }
    
    .action-btn {
        flex: 1;
        padding: 10px 20px;
        border-radius: 8px;
        font-weight: 600;
        font-size: 14px;
        cursor: pointer;
        transition: all 0.3s ease;
        border: none;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
    }
    
    .action-btn.install {
        background: #10b981;
        color: white;
    }
    
    .action-btn.install:hover {
        background: #059669;
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(16,185,129,0.3);
    }
    
    .action-btn.remove {
        background: #ef4444;
        color: white;
    }
    
    .action-btn.remove:hover {
        background: #dc2626;
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(239,68,68,0.3);
    }
    
    /* Modal Styles */
    .modal-content {
        border: none;
        border-radius: 12px;
        box-shadow: 0 10px 40px rgba(0,0,0,0.15);
    }
    
    .modal-header {
        background: var(--bg-secondary, #f8f9ff);
        border-bottom: 1px solid var(--border-color, #e8e9ff);
        border-radius: 12px 12px 0 0;
        padding: 20px;
    }
    
    .modal-title {
        font-size: 20px;
        font-weight: 700;
        color: var(--text-primary, #2f3640);
        display: flex;
        align-items: center;
        gap: 10px;
    }
    
    .modal-body {
        padding: 25px;
    }
    
    .install-log {
        background: var(--bg-secondary, #f8f9ff);
        border: 1px solid var(--border-color, #e8e9ff);
        border-radius: 8px;
        padding: 15px;
    }
    
    .log-textarea {
        width: 100%;
        padding: 12px 15px;
        border: 1px solid var(--border-color, #e8e9ff);
        border-radius: 8px;
        font-size: 13px;
        color: var(--text-primary, #2f3640);
        background: var(--bg-primary, white);
        resize: vertical;
        font-family: 'Monaco', 'Consolas', monospace;
        line-height: 1.5;
    }
    
    /* Loading Spinner */
    .loading-spinner {
        width: 24px;
        height: 24px;
        border: 3px solid var(--border-color, #e8e9ff);
        border-top-color: #5856d6;
        border-radius: 50%;
        animation: spin 1s linear infinite;
        display: inline-block;
    }
    
    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }
    
    /* Empty State */
    .empty-state {
        text-align: center;
        padding: 60px 20px;
    }
    
    .empty-icon {
        width: 80px;
        height: 80px;
        background: var(--bg-secondary, #f8f9ff);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 0 auto 20px;
        font-size: 36px;
        color: var(--text-muted, #94a3b8);
    }
    
    .empty-title {
        font-size: 20px;
        font-weight: 700;
        color: var(--text-primary, #2f3640);
        margin-bottom: 10px;
    }
    
    .empty-description {
        font-size: 15px;
        color: var(--text-secondary, #64748b);
    }
    
    /* Responsive */
    @media (max-width: 768px) {
        .applications-wrapper {
            padding: 15px;
        }
        
        .page-header h1 {
            font-size: 24px;
            flex-direction: column;
            text-align: center;
        }
        
        .content-section {
            padding: 20px;
        }
        
        .applications-grid {
            grid-template-columns: 1fr;
        }
    }
</style>
{% endblock %}

{% block content %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}

<div class="applications-wrapper">
    <div class="applications-container" ng-controller="manageApplications">
        <!-- Page Header -->
        <div class="page-header">
            <h1>
                <div class="icon">
                    <i class="fas fa-puzzle-piece"></i>
                </div>
                {% trans "Manage Applications" %}
            </h1>
            <p>{% trans "Install or remove applications from your server" %}</p>
        </div>

        <!-- Applications Section -->
        <div class="content-section">
            <h2 class="section-title">
                {% trans "Available Applications" %}
                <span ng-hide="cyberpanelLoading" class="loading-spinner"></span>
            </h2>

            {% if services %}
            <div class="applications-grid">
                {% for service in services %}
                <div class="app-card">
                    <div class="app-header">
                        <div class="app-icon">
                            <img src="{{ service.image }}" alt="{{ service.name }}">
                        </div>
                        <div class="app-info">
                            <h3 class="app-name">{{ service.name }}</h3>
                            {% if service.installed == 'Installed' %}
                            <span class="app-status installed">
                                <i class="fas fa-check-circle"></i>
                                {% trans "Installed" %}
                            </span>
                            {% else %}
                            <span class="app-status not-installed">
                                <i class="fas fa-times-circle"></i>
                                {% trans "Not Installed" %}
                            </span>
                            {% endif %}
                        </div>
                    </div>
                    
                    <div class="app-description">
                        {% if service.name == 'Elasticsearch' %}
                            {% trans "A distributed, RESTful search and analytics engine capable of addressing a growing number of use cases." %}
                        {% elif service.name == 'Redis' %}
                            {% trans "An in-memory data structure store, used as a database, cache, and message broker." %}
                        {% else %}
                            {% trans "Powerful application for your server infrastructure." %}
                        {% endif %}
                    </div>
                    
                    <div class="app-actions">
                        {% if service.installed == 'Installed' %}
                        <button type="button" 
                                class="action-btn remove" 
                                data-toggle="modal" 
                                data-target="#settings"
                                ng-click="removeInstall('{{ service.name }}', 'Removing')">
                            <i class="fas fa-trash-alt"></i>
                            {% trans "Remove" %}
                        </button>
                        {% else %}
                        <button type="button" 
                                class="action-btn install" 
                                data-toggle="modal" 
                                data-target="#settings"
                                ng-click="removeInstall('{{ service.name }}', 'Installing')">
                            <i class="fas fa-download"></i>
                            {% trans "Install" %}
                        </button>
                        {% endif %}
                    </div>
                </div>
                {% endfor %}
            </div>
            {% else %}
            <div class="empty-state">
                <div class="empty-icon">
                    <i class="fas fa-box-open"></i>
                </div>
                <h3 class="empty-title">{% trans "No Applications Available" %}</h3>
                <p class="empty-description">{% trans "There are no applications available at this time." %}</p>
            </div>
            {% endif %}
        </div>

        <!-- Installation/Removal Modal -->
        <div id="settings" class="modal fade" role="dialog">
            <div class="modal-dialog modal-lg">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">
                            {$ status $} {$ appName $}
                            <span ng-hide="cyberpanelLoading" class="loading-spinner"></span>
                        </h4>
                        <button type="button" class="close" data-dismiss="modal">&times;</button>
                    </div>
                    <div class="modal-body">
                        <div class="install-log">
                            <textarea ng-model="requestData" rows="15" class="log-textarea" readonly></textarea>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- Manage Applications JS -->
<script src="{% static 'manageServices/manageServices.js' %}"></script>
{% endblock %}