Вот код отправки:
```js
export function uploadContainer() {
    const file = $('#container-file').prop('files')[0];

    if (!file) {
        showDialog("Error", "Please select a file to upload.");
        return;
    }

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

    $.ajax({
        url: '/upload',
        type: 'POST',
        data: formData,
        processData: false,
        contentType: false,
        success: function (response) {
            showDialog("Success", response.message);
        },
        error: function (xhr, status, error) {
            showDialog("Error", `Error uploading container: ${error}`);
        }
    });
}

```
Вот код сервера:
```py
import time
from threading import Thread

from flask import Flask, render_template, request, jsonify, copy_current_request_context
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")

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}'})

clients = {}

@socketio.on('start_container_logs')
def start_container_logs(data):
    container_id = data.get('container_id')
    sid = request.sid

    if sid not in clients:
        clients[sid] = {'containers': set()}

    clients[sid]['containers'].add(container_id)

    @copy_current_request_context
    def stream_logs(container_id, sid):
        try:
            container = client.containers.get(container_id)
            for log in container.logs(stream=True, follow=True):
                socketio.emit('container_log', {'id': container_id, 'log': log.decode('utf-8')}, room=sid)
                if container_id not in clients.get(sid, {}).get('containers', set()):
                    break
        except Exception as e:
            socketio.emit('container_log', {'id': container_id, 'log': f'Error: {e}'}, room=sid)

    socketio.start_background_task(stream_logs, container_id, sid)

@socketio.on('stop_container_logs')
def stop_container_logs(data):
    container_id = data.get('container_id')
    sid = request.sid

    if sid in clients and container_id in clients[sid]['containers']:
          clients[sid]['containers'].remove(container_id)

@socketio.on('disconnect')
def handle_disconnect():
    sid = request.sid
    if sid in clients:
        del clients[sid]

@app.route('/upload', methods=['POST'])
def upload_container():
    if 'file' in request.files:
        file = request.files['file']
        filename = file.filename
        file_path = os.path.join('uploads', filename)
        file.save(file_path)
        try:
            with open(file_path, 'rb') as f:
                images = client.images.load(f)
            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}")


# app.py
@socketio.on('run_container')
def handle_run_container(data):
    image_id = data.get('imageId')
    options = data.get('options', {})

    print("run_container")
    print(f"image_id = {image_id}")
    print(f"options = {options}")

    try:
        run_options = {}

        # Process options
        if options.get('containerName'):
            run_options['name'] = options['containerName']

        # Ports
        if options.get('ports'):
            ports = {}
            for port_mapping in options['ports'].split(','):
                host_port, container_port = port_mapping.strip().split(':')
                ports[int(container_port)] = int(host_port)
            run_options['ports'] = ports

        # Volumes
        if options.get('volumes'):
            volumes = {}
            for volume_mapping in options['volumes'].split(','):
                host_path, container_path = volume_mapping.strip().split(':')
                volumes[host_path] = {'bind': container_path, 'mode': 'rw'}
            run_options['volumes'] = volumes

        # Environment variables
        if options.get('envVars'):
            env_vars = [env.strip() for env in options['envVars']]
            run_options['environment'] = env_vars

        # Command
        if options.get('command'):
            command = options['command']
        else:
            command = None

        # Interactive and Detached
        run_options['detach'] = options.get('detached', False)
        run_options['stdin_open'] = options.get('interactive', False)
        run_options['tty'] = options.get('interactive', False)

        container = client.containers.run(image_id, command=command, **run_options)
        container_data = format_container_data(container)
        emit('container_added', get_containers_data())
    except Exception as e:
        print(f"Error running container: {e}")
        emit('error', {'message': 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)

# app.py
@app.route('/pull_image', methods=['POST'])
def pull_image():
    image_name = request.form.get('image_name')
    username = request.form.get('docker_username')
    password = request.form.get('docker_password')

    if not image_name:
        return jsonify({'message': 'No image name provided'}), 400

    try:
        if username and password:
            auth_config = {'username': username, 'password': password}
            image = client.images.pull(image_name, auth_config=auth_config)
        else:
            image = client.images.pull(image_name)
        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 pulling image: {e}'}), 500

# Запуск потока для обновления данных
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)
```

Почему контейнер не добавляется