- Исправлена незакрытая скобка в _build_test_command (строка 745) - Добавлена поддержка k8s preset'ов: выполнение create_k8s_cluster.py перед create.yml - Обновлены образы в k8s preset'ах: заменен недоступный ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy на inecs/ansible-lab:ubuntu22-latest - Обновлены preset'ы в базе данных через SQL - Обновлены файлы: k8s-single.yml, k8s-multi.yml, k8s-istio-full.yml
205 lines
8.6 KiB
HTML
205 lines
8.6 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Dockerfile - DevOpsLab{% endblock %}
|
||
{% block page_title %}Dockerfile{% endblock %}
|
||
|
||
{% block header_actions %}
|
||
<div class="d-flex gap-2">
|
||
<a href="/dockerfiles/create" class="btn btn-primary btn-sm">
|
||
<i class="fas fa-plus me-2"></i>
|
||
Создать Dockerfile
|
||
</a>
|
||
<a href="/dockerfiles/build-logs" class="btn btn-outline-primary btn-sm">
|
||
<i class="fas fa-history me-2"></i>
|
||
Логи сборок
|
||
</a>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Список Dockerfile</h5>
|
||
</div>
|
||
<div class="card-body p-0">
|
||
{% if dockerfiles %}
|
||
<div class="table-responsive">
|
||
<table class="table table-hover mb-0">
|
||
<thead class="table-light">
|
||
<tr>
|
||
<th>Название</th>
|
||
<th>Описание</th>
|
||
<th>Базовый образ</th>
|
||
<th>Теги</th>
|
||
<th>Статус</th>
|
||
<th style="min-width: 140px;">Действия</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for dockerfile in dockerfiles %}
|
||
<tr>
|
||
<td class="align-middle">
|
||
<i class="fas fa-file-code me-2 text-primary"></i>
|
||
<a href="/dockerfiles/{{ dockerfile.id }}" class="text-decoration-none fw-semibold">
|
||
{{ dockerfile.name }}
|
||
</a>
|
||
</td>
|
||
<td class="align-middle">
|
||
{% if dockerfile.description %}
|
||
<span class="text-truncate d-inline-block" style="max-width: 300px;" title="{{ dockerfile.description }}">
|
||
{{ dockerfile.description }}
|
||
</span>
|
||
{% else %}
|
||
<span class="text-muted">—</span>
|
||
{% endif %}
|
||
</td>
|
||
<td class="align-middle">
|
||
{% if dockerfile.base_image %}
|
||
<span class="badge bg-info">{{ dockerfile.base_image }}</span>
|
||
{% else %}
|
||
<span class="text-muted">—</span>
|
||
{% endif %}
|
||
</td>
|
||
<td class="align-middle">
|
||
{% if dockerfile.tags %}
|
||
{% for tag in dockerfile.tags %}
|
||
<span class="badge bg-secondary me-1">{{ tag }}</span>
|
||
{% endfor %}
|
||
{% else %}
|
||
<span class="text-muted">—</span>
|
||
{% endif %}
|
||
</td>
|
||
<td class="align-middle">
|
||
<span class="badge {% if dockerfile.status == 'active' %}bg-success{% else %}bg-secondary{% endif %}">
|
||
{{ dockerfile.status }}
|
||
</span>
|
||
</td>
|
||
<td class="align-middle">
|
||
<div class="btn-group btn-group-sm">
|
||
<a
|
||
href="/dockerfiles/{{ dockerfile.id }}/edit"
|
||
class="btn btn-outline-primary"
|
||
title="Редактировать"
|
||
>
|
||
<i class="fas fa-edit"></i>
|
||
</a>
|
||
<a
|
||
href="/dockerfiles/{{ dockerfile.id }}"
|
||
class="btn btn-outline-info"
|
||
title="Детали"
|
||
>
|
||
<i class="fas fa-info-circle"></i>
|
||
</a>
|
||
<button
|
||
onclick="deleteDockerfile({{ dockerfile.id }}, '{{ dockerfile.name }}', this)"
|
||
class="btn btn-outline-danger"
|
||
title="Удалить"
|
||
>
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<div class="text-center py-5">
|
||
<i class="fas fa-inbox fa-3x text-muted mb-3"></i>
|
||
<p class="text-muted mb-3">Dockerfile'ов пока нет</p>
|
||
<a href="/dockerfiles/create" class="btn btn-primary">
|
||
<i class="fas fa-plus me-2"></i>
|
||
Создать первый Dockerfile
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
async function deleteDockerfile(dockerfileId, dockerfileName, button) {
|
||
// Показываем модальное окно подтверждения
|
||
const confirmed = await showConfirmModal(
|
||
`Вы уверены, что хотите удалить Dockerfile '${dockerfileName}'?`,
|
||
'Подтверждение удаления'
|
||
);
|
||
|
||
if (!confirmed) {
|
||
return;
|
||
}
|
||
|
||
// Отключаем кнопку во время запроса
|
||
button.disabled = true;
|
||
const originalHTML = button.innerHTML;
|
||
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
|
||
|
||
try {
|
||
const response = await fetch(`/api/v1/dockerfiles/${dockerfileId}`, {
|
||
method: 'DELETE',
|
||
credentials: 'include',
|
||
headers: {
|
||
'Accept': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
if (data.success) {
|
||
// Показываем модальное окно с успешным сообщением
|
||
if (window.showMessageModal) {
|
||
window.showMessageModal(
|
||
data.message || `Dockerfile '${dockerfileName}' успешно удален`,
|
||
'success',
|
||
'Успешно',
|
||
function() {
|
||
// После закрытия модального окна удаляем строку из таблицы
|
||
const row = button.closest('tr');
|
||
if (row) {
|
||
row.remove();
|
||
}
|
||
}
|
||
);
|
||
} else {
|
||
// Если функция недоступна, просто удаляем строку
|
||
const row = button.closest('tr');
|
||
if (row) {
|
||
row.remove();
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// Ошибка - показываем в модальном окне
|
||
try {
|
||
const errorData = await response.json();
|
||
const errorMessage = errorData.detail || errorData.message || 'Ошибка при удалении Dockerfile';
|
||
if (window.showMessageModal) {
|
||
window.showMessageModal(errorMessage, 'error');
|
||
} else {
|
||
alert(errorMessage);
|
||
}
|
||
} catch (e) {
|
||
if (window.showMessageModal) {
|
||
window.showMessageModal('Ошибка при удалении Dockerfile', 'error');
|
||
} else {
|
||
alert('Ошибка при удалении Dockerfile');
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка при удалении Dockerfile:', error);
|
||
if (window.showMessageModal) {
|
||
window.showMessageModal('Ошибка при удалении Dockerfile', 'error');
|
||
} else {
|
||
alert('Ошибка при удалении Dockerfile');
|
||
}
|
||
} finally {
|
||
// Восстанавливаем кнопку
|
||
button.disabled = false;
|
||
button.innerHTML = originalHTML;
|
||
}
|
||
}
|
||
</script>
|
||
{% endblock %}
|