Project structure:

DarkConsole/
├── old_scripts_js/
│   ├── OLDscript.js
│   └── style.css
├── static/
│   ├── css/
│   │   ├── base.css
│   │   ├── components.css
│   │   ├── layout.css
│   │   └── utilities.css
│   ├── images/
│   │   ├── DarkServer_Logo.png
│   │   ├── box_icon.webp
│   │   └── stack_icon.webp
│   ├── js/
│   │   ├── containerRenderer.js
│   │   ├── dialogManager.js
│   │   ├── intro.js
│   │   ├── main.js
│   │   ├── socketHandlers.js
│   │   ├── uiHandlers.js
│   │   └── utils.js
├── templates/
│   └── index.html
├── uploads/
├── ProjectOneFileOLD_WHERE_ONE_JS.txt
├── V2_GenerateProjectShort.py
├── aboba.py
├── app.py
├── main.py
└── requirements.txt


Project files:

aboba.py
```py
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/download')
def download_file():
    return send_file('D:\\Autodesk\\Maya 2022.3.zip', as_attachment=True)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081)
```


app.py
```py
import time
from threading import Thread

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit
import os
import docker
import datetime
import psutil

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
socketio = SocketIO(app)

client = docker.from_env()

@app.route('/')
def index():
    return render_template('index.html')


@socketio.on('connect')
def handle_connect():
    print('Client connected')
    emit('update_running_containers', get_containers_data())
    print("---=-=-=-2")
    emit('update_saved_images', get_saved_images())
    print("---=-=-=-3")

@socketio.on('disconnect')
def handle_disconnect():
    print('Client disconnected')
def get_containers_data():
    containers = client.containers.list(all=True)
    return [format_container_data(container) for container in containers]

def format_container_data(container):
    container_info = container.attrs
    try:
        # Try parsing with the format specific to your Docker version
        created_at = datetime.datetime.strptime(container_info['Created'][:-1],
                                                '%Y-%m-%dT%H:%M:%S.%fZ')  # Update this format
    except ValueError:
        # If parsing fails, set created_at to None
        created_at = None
    return {
        'id': container.id,
        'name': container_info['Name'][1:],
        'created_at': created_at.strftime('%Y-%m-%d %H:%M:%S') if created_at else "Unknown",
        'status': container_info['State']['Status'],
        'cpu_percent': calculate_cpu_usage(container),
        'memory_percent': calculate_memory_usage(container)
    }

def get_saved_images():
    images = client.images.list()
    return [{'id': image.id, 'tags': image.tags} for image in images if image.tags]


def calculate_cpu_usage(container):
    stats = container.stats(stream=False)
    cpu_delta = stats['cpu_stats']['cpu_usage']['total_usage'] - stats['precpu_stats']['cpu_usage']['total_usage']
    system_delta = stats['cpu_stats'].get('system_cpu_usage', 0) - stats['precpu_stats'].get('system_cpu_usage', 0)
    online_cpus = stats['cpu_stats'].get('online_cpus', len(psutil.cpu_percent(percpu=True)))

    if system_delta > 0.0 and cpu_delta > 0.0:
        cpu_percent = (cpu_delta / system_delta) * online_cpus * 100.0
    else:
        cpu_percent = 0.0

    return round(cpu_percent, 2)


def calculate_memory_usage(container):
    stats = container.stats(stream=False)
    memory_stats = stats.get('memory_stats', {})

    if 'usage' in memory_stats and 'limit' in memory_stats:
        memory_usage = memory_stats['usage'] - memory_stats.get('cache', 0)
        memory_limit = memory_stats['limit']
        memory_percent = (memory_usage / memory_limit) * 100.0
    else:
        memory_percent = 0.0

    return round(memory_percent, 2)


@socketio.on('get_container_stats')
def get_container_stats():
    containers = client.containers.list(all=True)
    container_data = []
    for container in containers:
        cpu_percent = calculate_cpu_usage(container)
        memory_percent = calculate_memory_usage(container)
        container_data.append({
            'id': container.id,
            'name': container.name,
            'status': container.status,
            'cpu_percent': cpu_percent,
            'memory_percent': memory_percent
        })
    emit('container_stats', container_data)


@socketio.on('get_saved_images')
def handle_get_saved_images():
    emit('saved_images', get_saved_images())

@socketio.on('get_container_logs')
def get_container_logs(container_id):
    try:
        container = client.containers.get(container_id)
        logs = container.logs(stream=True)
        for log in logs:
            emit('container_log', {'id': container_id, 'log': log.decode('utf-8')})
    except docker.errors.NotFound:
        emit('container_log', {'id': container_id, 'log': 'Container not found'})
    except Exception as e:
        emit('container_log', {'id': container_id, 'log': f'Error: {e}'})

@app.route('/upload', methods=['POST'])
def upload_container():
    if 'file' in request.files:
        file = request.files['file']
        filename = file.filename
        file.save(os.path.join('uploads', filename))
        container_name = request.form['container_name']
        try:
            with open(os.path.join('uploads', filename), 'rb') as f:
                image = client.images.load(f)[0]
            socketio.emit('image_added', get_saved_images())
            return jsonify({'message': 'Container uploaded successfully'})
        except Exception as e:
            return jsonify({'message': f'Error uploading container: {e}'})
    elif 'docker_command' in request.form:
        docker_command = request.form['docker_command']
        try:
            image = client.images.pull(docker_command)
            socketio.emit('image_added', get_saved_images())
            return jsonify({'message': f'Docker image pulled successfully: {image.tags}'})
        except Exception as e:
            return jsonify({'message': f'Error executing Docker command: {e}'})
    else:
        return jsonify({'message': 'No file or command provided'})

@app.route('/delete_container', methods=['POST'])
def delete_container():
    container_id = request.form.get('container_id')
    try:
        container = client.containers.get(container_id)
        container.remove(force=True)
        socketio.emit('container_removed', container_id)
        return jsonify({'message': 'Container deleted successfully'})
    except docker.errors.NotFound:
        return jsonify({'message': 'Container not found'}), 404
    except Exception as e:
        return jsonify({'message': f'Error deleting container: {e}'}), 500


@socketio.on('OLDstop_container')
def handle_stop_container(container_id):
    try:
        container = client.containers.get(container_id)
        container.stop()
        container_data = format_container_data(container)

        emit('container_updated', container_data)
    except Exception as e:
        print(f"Error stopping container: {e}")

@socketio.on('OLDrestart_container')
def handle_restart_container(container_id):
    try:
        container = client.containers.get(container_id)
        container.restart()
        container_data = format_container_data(container)
        print(f"container_data = {container_data}")
        emit('container_updated', container_data)
    except Exception as e:
        print(f"Error restarting container: {e}")


@socketio.on('run_container')
def handle_run_container(data):
    image_id = data.get('imageId')
    container_name = data.get('containerName')

    try:
        container = client.containers.run(image_id, name=container_name, detach=True)
        container_data = format_container_data(container)
        emit('container_added', get_containers_data())
    except Exception as e:
        print(f"Error running container: {e}")

@socketio.on('delete_image')
def handle_delete_image(image_id):
    try:
        image = client.images.get(image_id)
        client.images.remove(image.id, force=True)
        emit('image_removed', image_id)
    except docker.errors.ImageNotFound:
        emit('error', {'message': 'Image not found'})
    except Exception as e:
        emit('error', {'message': f'Error deleting image: {e}'})


@socketio.on('get_server_stats')
def get_server_stats():
    cpu_percent = psutil.cpu_percent(interval=1)
    memory = psutil.virtual_memory()
    memory_percent = memory.percent

    print(f"cpu_percent = {cpu_percent}")
    print(f"memory_percent = {memory_percent}")

    emit('server_stats', {
        'cpu_percent': cpu_percent,
        'memory_percent': memory_percent
    })


previous_status = {}
previous_cpu_usage = {}
previous_memory_usage = {}


def emit_container_updates():
    while True:
        containers = client.containers.list(all=True)
        for container in containers:
            container_id = container.id

            # Проверка изменения статуса
            container_status = container.status
            if previous_status.get(container_id) != container_status:
                previous_status[container_id] = container_status
                socketio.emit('update_container_status', {
                    'id': container_id,
                    'status': container_status
                })

            # Проверка изменения CPU и RAM
            cpu_percent = calculate_cpu_usage(container)
            memory_percent = calculate_memory_usage(container)

            if (previous_cpu_usage.get(container_id) != cpu_percent or
                    previous_memory_usage.get(container_id) != memory_percent):
                previous_cpu_usage[container_id] = cpu_percent
                previous_memory_usage[container_id] = memory_percent
                socketio.emit('update_container_resources', {
                    'id': container_id,
                    'cpu_percent': cpu_percent,
                    'memory_percent': memory_percent
                })

        time.sleep(2)  # Периодическое обновление каждые 2 секунды


# Функция для отслеживания статуса запуска контейнера
def monitor_container_start(container_id):
    while True:
        container = client.containers.get(container_id)
        container_status = container.status
        if container_status != 'created':
            previous_status[container_id] = container_status
            socketio.emit('update_container_status', {
                'id': container_id,
                'status': container_status
            })
            socketio.emit('hideLoadingOverlay', container_id)
            break
        print("=-===")
        time.sleep(0.5)


# Добавление запуска мониторинга при старте контейнера
@socketio.on('restart_container')
def handle_restart_container(container_id):
    container = client.containers.get(container_id)
    container.start()
    socketio.emit('update_container_status', {
        'id': container_id,
        'status': "starting"
    })
    Thread(target=monitor_container_start, args=(container_id,)).start()


# Функция для синхронизации остановки и обновления данных
@socketio.on('stop_container')
def handle_stop_container(container_id):
    container = client.containers.get(container_id)
    container.stop()
    container_status = container.status
    previous_status[container_id] = container_status
    socketio.emit('update_container_status', {
        'id': container_id,
        'status': "stopping"
    })
    emit('hideLoadingOverlay', container_id)


# Запуск потока для обновления данных
def start_update_thread():
    thread = Thread(target=emit_container_updates)
    thread.daemon = True
    thread.start()


if __name__ == '__main__':
    start_update_thread()
    socketio.run(app, host='0.0.0.0', port=8081, allow_unsafe_werkzeug=True)
```


old_scripts_js/OLDscript.js
```js
// static/OLDscript.js
$(document).ready(function () {
    alert("OLD script loaded!")
    const socket = io();

    const containerSelectors = {
        running: '#running-containers',
        saved: '#saved-containers',
        console: '#console-content',
        uploadDialog: '#upload-dialog',
        containerConsole: '#container-console',
        closeConsole: '#close-console',
        clearConsole: '#clear-console',
        addContainerButton: '.add-container-button',
    };

    const showLoadingOverlay = (containerId) =>
        $(`.docker-container-tile[data-container-id="${containerId}"] .loading-overlay`).show();

    const hideLoadingOverlay = (containerId) =>
        $(`.docker-container-tile[data-container-id="${containerId}"] .loading-overlay`).fadeOut();

    const renderContainers = (containers, selector) => {
        $(selector).empty();
        containers.forEach(container => {
            const statusClass = container.status === 'running' ? 'running' : 'exited';
            const tile = `
                <div class="docker-container-tile" data-container-id="${container.id}">
                    <div class="info">
                        <h3>${container.name}</h3>
                        <p>Created at: ${container.created_at}</p>
                        <p>CPU: ${container.cpu_percent}%</p>
                        <p>Memory: ${container.memory_percent}%</p>
                    </div>
                    <div class="controls">
                        <span class="status ${statusClass}">${container.status}</span>
                        <button class="output-button">Output</button>
                        <button class="restart-button">Restart</button>
                        <button class="stop-button">Stop</button>
                        <button class="delete-button"><i class="fas fa-trash"></i></button>         
                    </div>
                    <div class="loading-overlay" style="display: none;">
                        <div class="loading-spinner"></div>
                    </div>
                </div>
            `;
            $(selector).append(tile);
        });
    };

    const renderSavedImages = (images) => {
        $(containerSelectors.saved).empty();
        images.forEach(image => {
            const tile = `
                <div class="docker-container-tile" data-image-id="${image.id}">
                    <h3>${image.tags.join(', ')}</h3>
                    <div class="controls">
                        <button class="run-button">Run</button>
                        <button class="delete-button">Delete</button>
                    </div>
                </div>
            `;
            $(containerSelectors.saved).append(tile);
        });
    };

    const updateContainerStats = () => socket.emit('get_container_stats');

    const getSavedImages = () => socket.emit('get_saved_images');

    const getContainerLogs = (containerId) => socket.emit('get_container_logs', containerId);

    const deleteContainer = (containerId) => {
        $.ajax({
            url: '/delete_container',
            type: 'POST',
            data: { container_id: containerId },
            success: function () {
                hideLoadingOverlay(containerId);
                updateContainerStats();
            },
            error: function (xhr, status, error) {
                hideLoadingOverlay(containerId);
                showDialog("Error", `Error deleting container: ${error}`);
            }
        });
    };

    const executeDockerCommand = () => {
        const dockerCommand = $('.custom-dialog .dialog-content #docker-command').val();
        console.log("dockerCommand", dockerCommand);
        $.ajax({
            url: '/upload',
            type: 'POST',
            data: { docker_command: dockerCommand },
            success: function (response) {
                showDialog("Success", response.message);
            },
            error: function (xhr, status, error) {
                showDialog("Error", `Error executing Docker command: ${error}`);
            }
        });
    };

    const uploadContainer = () => {
        const file = $('#container-file').prop('files')[0];
        const containerName = $('#container-name').val();

        const formData = new FormData();
        formData.append('file', file);
        formData.append('container_name', containerName);

        $.ajax({
            url: '/upload',
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function () { /* Handle success */ },
            error: function () { /* Handle error */ }
        });
    };

    const showDialog = (title, content, callback) => {
        const dialog = `
            <div class="custom-dialog">
                <div class="dialog-header">
                    <h3>${title}</h3>
                    <button class="close-dialog"><i class="fas fa-times"></i></button>
                </div>
                <div class="dialog-content">${content}</div>
                <div class="dialog-footer">
                    <button class="confirm-dialog">Confirm</button>
                </div>
            </div>
        `;
        $('body').append(dialog);
        $('.custom-dialog').css("display", "flex");
        $('.blur-background').addClass("active")

        $('.close-dialog').click(closeDialog);
        $('.confirm-dialog').click(function () {
            const inputValue = $('#dialog-input').val();
            if (callback) callback(inputValue);
            closeDialog();
        });
    };

    const closeDialog = () => {
        $('.blur-background').removeClass("active")
        $('.custom-dialog').fadeOut(100, function() {
            $(this).remove();
        });
    };

    // Event Listeners
    $('.sidebar .tab').click(function () {
        $('.sidebar .tab').removeClass('active');
        $(this).addClass('active');
        $('.tab-content').removeClass('active');
        $(`#${$(this).data('target')}`).addClass('active');
    });

    $(containerSelectors.running).on('click', '.output-button', function () {
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        getContainerLogs(containerId);
        $(containerSelectors.containerConsole).show();
    });

    $(containerSelectors.running).on('click', '.stop-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showLoadingOverlay(containerId);
        socket.emit('stop_container', containerId);
    });

    $(containerSelectors.running).on('click', '.restart-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showLoadingOverlay(containerId);
        socket.emit('restart_container', containerId);
    });

    $(containerSelectors.running).on('click', '.delete-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showDialog("Confirm Delete", "Are you sure you want to delete this container?", function () {
            showLoadingOverlay(containerId);
            deleteContainer(containerId);
        });
    });

    $(containerSelectors.saved).on('click', '.run-button', function () {
        const imageId = $(this).closest('.docker-container-tile').data('image-id');
        showDialog("Run Container", `<label>Enter a name for the new container:</label><input type="text" id="dialog-input" placeholder="Container Name">`, function (containerName) {
            if (containerName) socket.emit('run_container', { imageId, containerName });
        });
    });

    $(containerSelectors.saved).on('click', '.delete-button', function () {
        const imageId = $(this).closest('.docker-container-tile').data('image-id');
        showDialog("Confirm Delete", "Are you sure you want to delete this image?", function () {
            socket.emit('delete_image', imageId);
        });
    });

    $(containerSelectors.closeConsole).click(() => $(containerSelectors.containerConsole).hide());
    $(containerSelectors.clearConsole).click(() => $(containerSelectors.console).empty());
    $(containerSelectors.addContainerButton).click(() => showDialog("Add Container", $(containerSelectors.uploadDialog).html()));

    // Socket event handlers
    socket.on('container_stats', data => renderContainers(data, containerSelectors.running));
    socket.on('saved_images', renderSavedImages);
    socket.on('container_log', data => $(containerSelectors.console).append(`<p>${data.log}</p>`));
    socket.on('update_containers', updateContainerStats);

    // Initial data fetch
    getSavedImages();
    updateContainerStats();
});

```


static/js/containerRenderer.js
```js
export function renderContainers(containers, selector) {
    $(selector).empty();
    containers.forEach(container => {
        const tile = createContainerTile(container);
        $(selector).append(tile);
    });
}

export function updateContainerTile(container, selector) {
    const existingTile = $(`${selector} [data-container-id="${container.id}"]`);
    if (existingTile.length > 0) {
        const updatedTile = createContainerTile(container);
        existingTile.replaceWith(updatedTile);
    }
}

function createContainerTile(container) {
    const statusClass = container.status === 'running' ? 'running' : 'exited';
    return `
        <div class="docker-container-tile" data-container-id="${container.id}">
            <div class="info">
                <h3>${container.name}</h3>
                <p>Created at: ${container.created_at}</p>
                <p>CPU: ${container.cpu_percent}%</p>
                <p>Memory: ${container.memory_percent}%</p>
            </div>
            <div class="controls">
                <span class="status ${statusClass}">${container.status}</span>
                <button class="output-button">Output</button>
                <button class="restart-button">Restart</button>
                <button class="stop-button">Stop</button>
                <button class="delete-button"><i class="fas fa-trash"></i></button>         
            </div>
            <div class="loading-overlay" style="display: none;">
                <div class="loading-spinner"></div>
            </div>
        </div>
    `;
}

export function renderSavedImages(images) {
    $('#saved-containers').empty();
    images.forEach(image => {
        const tile = `
            <div class="docker-container-tile" data-image-id="${image.id}">
                <h3>${image.tags.join(', ')}</h3>
                <div class="controls">
                    <button class="run-button">Run</button>
                    <button class="delete-button">Delete</button>
                </div>
            </div>
        `;
        $('#saved-containers').append(tile);
    });
}
```


static/js/dialogManager.js
```js
export function showDialog(title, content, callback) {
    const dialog = `
        <div class="custom-dialog">
            <div class="dialog-header">
                <h3>${title}</h3>
                <button class="close-dialog"><i class="fas fa-times"></i></button>
            </div>
            <div class="dialog-content">${content}</div>
            <div class="dialog-footer">
                <button class="confirm-dialog">Confirm</button>
            </div>
        </div>
    `;
    $('body').append(dialog);
    $('.custom-dialog').css("display", "flex");
    $('.blur-background').addClass("active")

    $('.close-dialog').click(closeDialog);
    $('.confirm-dialog').click(function () {
        const inputValue = $('#dialog-input').val();
        if (callback) {
            callback(inputValue);
        }
        closeDialog();
    });
}

export function closeDialog() {
    $('.blur-background').removeClass("active")
    $('.custom-dialog').fadeOut(100, function() {
        $(this).remove();
    });
}
```


static/js/intro.js
```js
$(document).ready(function() {
    setTimeout(function() {
        $(".loading-logo-container img").css({
            "transform": "translateX(-90px)",
            "transition": "transform 0.7s ease-in-out"
        });
        $(".logo-text").css({
            "transform": "translateX(90px)",
            "transition": "transform 0.7s ease-in-out"
        });
    }, 800);
});
```


static/js/main.js
```js
import { initSocketHandlers } from './socketHandlers.js';
import { initUIHandlers } from './uiHandlers.js';
import { updateServerStats_emit } from './utils.js';

$(document).ready(function () {
    const socket = io();

    function hideServerStartingScreen() {
        const serverStartingScreen = document.getElementById('server-starting-screen');
        if (serverStartingScreen) {
            serverStartingScreen.style.display = 'none';
        }
    }

    // Скрыть экран после подключения к серверу
    socket.on('connect', () => {
        hideServerStartingScreen();
    });


    initSocketHandlers(socket);
    initUIHandlers(socket);

    // Initial server stats fetch
    updateServerStats_emit(socket);

    // Set up periodic updates for server stats only
    setInterval(() => {
        updateServerStats_emit(socket);
    }, 250);  // Update every 5 seconds
});
```


static/js/socketHandlers.js
```js
import {renderContainers, renderSavedImages, updateContainerTile} from './containerRenderer.js';
import {
    containerSelectors,
    hideLoadingOverlay,
    showLoadingOverlay,
    updateServerStats
} from './utils.js';

export function initSocketHandlers(socket) {
    socket.on('update_running_containers', data => renderContainers(data, containerSelectors.running));
    socket.on('update_saved_images', renderSavedImages);
    socket.on('container_log', data => $(containerSelectors.console).append(`<p>${data.log}</p>`));
    socket.on('server_stats', updateServerStats);

    // New event handlers for individual container updates
    socket.on('container_added', containers => {
        renderContainers(containers, containerSelectors.running);
    });

    socket.on('container_removed', containerId => {
        $(`${containerSelectors.running} [data-container-id="${containerId}"]`).remove();
    });

    //socket.on('container_updated', container => {
    //    const existingContainer = $(`${containerSelectors.running} [data-container-id="${container.id}"]`);
    //    if (existingContainer.length > 0) {
    //        existingContainer.replaceWith($(renderContainers([container], '')).html());
    //    }
    //});

    socket.on('image_added', images => {
        renderSavedImages(images);
    });

    socket.on('image_removed', imageId => {
        $(`${containerSelectors.saved} [data-image-id="${imageId}"]`).remove();
    });

    //socket.on('container_stats', data => renderContainers(data, containerSelectors.running));

    socket.on('container_updated', container => {
        updateContainerTile(container, containerSelectors.running);
        //hideLoadingOverlay(container.id);
    });
    socket.on('hideLoadingOverlay', id => {
        hideLoadingOverlay(id);
    });


    //
    //
    //
    //

    socket.on('update_container_status', function(data) {
        const containerId = data.id;
        const status = data.status;
        // Обновление статуса контейнера
        updateContainerStatus(containerId, status);
    });

    socket.on('update_container_resources', function(data) {
        const containerId = data.id;
        const cpuPercent = data.cpu_percent;
        const memoryPercent = data.memory_percent;
        // Обновление загрузки CPU и RAM контейнера
        updateContainerResources(containerId, cpuPercent, memoryPercent);
    });

    function updateContainerStatus(containerId, status) {
        const containerTile = $(`[data-container-id="${containerId}"]`);
        const statusElement = containerTile.find('.status');

        // Обновление класса статуса
        statusElement.removeClass('running exited').addClass(status === 'running' ? 'running' : 'exited');
        statusElement.text(status);
    }

    function updateContainerResources(containerId, cpuPercent, memoryPercent) {
        const containerTile = $(`[data-container-id="${containerId}"]`);

        // Обновление CPU и RAM
        containerTile.find('.cpu').text(`CPU: ${cpuPercent}%`);
        containerTile.find('.memory').text(`Memory: ${memoryPercent}%`);
    }

}
```


static/js/uiHandlers.js
```js
import { showDialog, closeDialog } from './dialogManager.js';
import { containerSelectors, showLoadingOverlay, hideLoadingOverlay, deleteContainer, executeDockerCommand, uploadContainer } from './utils.js';

export function initUIHandlers(socket) {
    $('.sidebar .tab-btn').click(function () {
        $('.sidebar .tab-btn').removeClass('active');
        $(this).addClass('active');
        $('.tab-content').removeClass('active');
        $(`#${$(this).data('target')}`).addClass('active');
    });

    $(containerSelectors.running).on('click', '.output-button', function () {
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        socket.emit('get_container_logs', containerId);
        $(containerSelectors.containerConsole).show();
    });

    $(containerSelectors.running).on('click', '.stop-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showLoadingOverlay(containerId);
        socket.emit('stop_container', containerId);
    });

    $(containerSelectors.running).on('click', '.restart-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showLoadingOverlay(containerId);
        socket.emit('restart_container', containerId);
    });

    $(containerSelectors.running).on('click', '.delete-button', function (event) {
        event.stopPropagation();
        const containerId = $(this).closest('.docker-container-tile').data('container-id');
        showDialog("Confirm Delete", "Are you sure you want to delete this container?", function () {
            showLoadingOverlay(containerId);
            deleteContainer(containerId, socket);
        });
    });

    $(containerSelectors.saved).on('click', '.run-button', function () {
        const imageId = $(this).closest('.docker-container-tile').data('image-id');
        const dialog_content = `
            <div class="dialog-line">
                <label>Enter a name for the new container:</label>
                <input type="text" id="dialog-input" placeholder="Container Name">
            </div>
        `;
        showDialog("Run Container", dialog_content, function (containerName) {
            if (containerName) socket.emit('run_container', {imageId, containerName});
        });
    });

    $(containerSelectors.saved).on('click', '.delete-button', function () {
        const imageId = $(this).closest('.docker-container-tile').data('image-id');
        showDialog("Confirm Delete", "Are you sure you want to delete this image?", function () {
            socket.emit('delete_image', imageId);
        });
    });

    $(document).on('click', containerSelectors.executeDockerCommandButton, function () {
        executeDockerCommand()
    });
    $(containerSelectors.closeConsole).click(() => $(containerSelectors.containerConsole).hide());
    $(containerSelectors.clearConsole).click(() => $(containerSelectors.console).empty());

    $(containerSelectors.addContainerButton).on('click', function () {
        const dialog_content = `
            <div className="dialog-line">
                <input type="file" name="file" id="container-file"/>
                <input type="text" name="container_name" id="container-name" placeholder="Container Name"/>
                <button id="upload-container-button">Upload</button>
            </div>
            <div className="dialog-line">
                <input type="text" name="docker_command" id="docker-command"
                       placeholder="Enter Docker Command (e.g., docker pull image:tag)"/>
                <button id="execute-docker-command-button">Execute Command</button>
            </div>
        `;
        showDialog("Add Container", dialog_content)
    });
}
```


static/js/utils.js
```js
import { showDialog } from "./dialogManager.js";

export const containerSelectors = {
    running: '#running-containers',
    saved: '#saved-containers',
    console: '#console-content',
    uploadDialog: '#upload-dialog',
    containerConsole: '#container-console',
    closeConsole: '#close-console',
    clearConsole: '#clear-console',
    addContainerButton: '.add-container-button',
    executeDockerCommandButton: '#execute-docker-command-button',
};

export const showLoadingOverlay = (containerId) =>
    $(`.docker-container-tile[data-container-id="${containerId}"] .loading-overlay`).show();

export const hideLoadingOverlay = (containerId) =>
    $(`.docker-container-tile[data-container-id="${containerId}"] .loading-overlay`).fadeOut();

export function deleteContainer(containerId, socket) {
    $.ajax({
        url: '/delete_container',
        type: 'POST',
        data: { container_id: containerId },
        success: function () {
            hideLoadingOverlay(containerId);
        },
        error: function (xhr, status, error) {
            hideLoadingOverlay(containerId);
            showDialog("Error", `Error deleting container: ${error}`);
        }
    });
}

export function executeDockerCommand() {
    showLoadingOverlay("executeDockerCommand");
    const dockerCommand = $('.custom-dialog .dialog-content #docker-command').val();
    console.log("dockerCommand", dockerCommand);
    $.ajax({
        url: '/upload',
        type: 'POST',
        data: { docker_command: dockerCommand },
        success: function (response) {
            hideLoadingOverlay("executeDockerCommand");
            showDialog("Success", response.message);
        },
        error: function (xhr, status, error) {
            hideLoadingOverlay("executeDockerCommand");
            showDialog("Error", `Error executing Docker command: ${error}`);
        }
    });
}

export function uploadContainer() {
    const file = $('#container-file').prop('files')[0];
    const containerName = $('#container-name').val();

    const formData = new FormData();
    formData.append('file', file);
    formData.append('container_name', containerName);

    $.ajax({
        url: '/upload',
        type: 'POST',
        data: formData,
        processData: false,
        contentType: false,
        success: function () { /* Handle success */ },
        error: function () { /* Handle error */ }
    });
}

export const updateServerStats_emit = (socket) => socket.emit('get_server_stats');

export function updateServerStats(data) {
    updateCircleProgress('#cpu-circle', '#cpu-text', data.cpu_percent);
    updateCircleProgress('#ram-circle', '#ram-text', data.memory_percent);
}

function updateCircleProgress(circleSelector, textSelector, percent) {
    const circle = document.querySelector(circleSelector);
    const text = document.querySelector(textSelector);
    const radius = circle.r.baseVal.value;
    const circumference = radius * 2 * Math.PI;
    const offset = circumference * (1 - percent / 100);
    circle.style.strokeDasharray = `${circumference} ${circumference}`;
    circle.style.strokeDashoffset = offset;
    text.textContent = `${percent.toFixed(1)}%`;
}

```


templates/index.html
```html
<!DOCTYPE html>
<html>
<head>
    <title>Dark Console</title>
    <link rel="stylesheet" href="../static/css/base.css">
    <link rel="stylesheet" href="../static/css/layout.css">
    <link rel="stylesheet" href="../static/css/components.css">
    <link rel="stylesheet" href="../static/css/utilities.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
    <div id="server-starting-screen" class="loading-screen">
        <div class="loading-logo-container">
            <img src="../static/images/DarkServer_Logo.png">
            <div class="logo-text">
                <div>DarkServer</div>
                <div>Console.</div>
            </div>
        </div>
        <div class="loading-message">
            <p>Getting Docker containers...</p>
        </div>
    </div>

    <div class="container">
        <div class="sidebar">
            <div class="tab-btn active" data-target="tab1">
                <img src="../static/images/box_icon.webp">
            </div>
            <div class="tab-btn" data-target="tab2">
                <img src="../static/images/stack_icon.webp">
            </div>
        </div>

        <div class="tabs-container">
            <div class="tab-content active" id="tab1">
                <h2>Current server usage:</h2>
                <div class="progress-bars">
                    <div class="progress-bar">
                        <svg class="progress-circle">
                            <circle class="progress-background" r="45" cx="50" cy="50"></circle>
                            <circle class="progress-circle-stroke" id="cpu-circle" r="45" cx="50" cy="50"></circle>
                            <text class="progress-text" id="cpu-text" x="50" y="50" text-anchor="middle" dominant-baseline="central">0%</text>
                        </svg>
                        <span>CPU</span>
                    </div>
                    <div class="progress-bar">
                        <svg class="progress-circle">
                            <circle class="progress-background" r="45" cx="50" cy="50"></circle>
                            <circle class="progress-circle-stroke" id="ram-circle" r="45" cx="50" cy="50"></circle>
                            <text class="progress-text" id="ram-text" x="50" y="50" text-anchor="middle" dominant-baseline="central">0%</text>
                        </svg>
                        <span>RAM</span>
                    </div>
                </div>

                <h2>Running containers:</h2>
                <div class="docker-containers" id="running-containers">
                    <!-- Container tiles will be added here -->
                </div>
            </div>

            <div class="tab-content" id="tab2">
                <h2>Saved Containers:</h2>
                <div class="docker-containers" id="saved-containers">
                    <!-- Container tiles will be added here -->
                </div>

                <button class="add-container-button">Add</button>
            </div>
        </div>
    </div>

    <div class="docker-container-console" id="container-console">
        <div class="console-header">
            <span id="console-title"></span>
            <button id="close-console"><i class="fas fa-times"></i></button>
            <button id="clear-console">Clear Console</button>
        </div>
        <div class="console-content" id="console-content">
            <!-- Container logs will be displayed here -->
        </div>
    </div>

    <div class="blur-background"></div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script type="module" src="../static/js/main.js"></script>
    <script src="../static/js/intro.js"></script>
</body>
</html>
```


Это мой проект для простого управления докер контейнерами на удаленном сервере.
Сейчас он работает, но его функционал крайне мал.

Можешь пожалуйста сделать это:
1) Нормальное окно для запуска контейнера с передачей всех нужных аргументов.
При добавлении аргументов через интерфейс, снизу будет текстовое поле, которое будет изменяться в реальном времени, если вносить изменения в параметры запуска в интерфейсе.
Это текстовое поле будет содержать сгенерированную команду запуска. Если ее вручную изменить, то сверху, интерфейс автоматически подстроится.

2) Сделай обновление output в реальном времени через socketio.

3) Реализуй полноценную загрузку контейнера из файла, чтобы она работала.
4) Допили загрузку контейнера с DockerHub, добавь больше полей необходимых

Пиши пожалуйста качественный код!
Соблюдай мой стиль написания кода, чтобы я смог в этом разобраться.

Спасибо большое!