feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
243
app/templates/pages/dockerfiles/build-logs.html
Normal file
243
app/templates/pages/dockerfiles/build-logs.html
Normal file
@@ -0,0 +1,243 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}История сборок - {{ dockerfile.name }} - DevOpsLab{% endblock %}
|
||||
{% block page_title %}История сборок: {{ dockerfile.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-history me-2"></i>
|
||||
История сборок Dockerfile
|
||||
</h5>
|
||||
<div>
|
||||
<button type="button" class="btn btn-danger btn-sm" onclick="clearLogs()">
|
||||
<i class="fas fa-trash me-2"></i>
|
||||
Очистить логи
|
||||
</button>
|
||||
<a href="/dockerfiles/{{ dockerfile.id }}/edit" class="btn btn-secondary btn-sm">
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
Назад
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if logs %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Образ</th>
|
||||
<th>Тип</th>
|
||||
<th>Платформы</th>
|
||||
<th>Статус</th>
|
||||
<th>Начало</th>
|
||||
<th>Длительность</th>
|
||||
<th>Пользователь</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td>{{ log.id }}</td>
|
||||
<td>
|
||||
<code>{{ log.image_name }}{% if log.tag %}:{{ log.tag }}{% endif %}</code>
|
||||
</td>
|
||||
<td>
|
||||
{% if log.extra_data and log.extra_data.get('type') == 'push' %}
|
||||
<span class="badge bg-info">
|
||||
<i class="fas fa-upload me-1"></i>Push
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">
|
||||
<i class="fas fa-hammer me-1"></i>Build
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.extra_data and log.extra_data.get('type') == 'push' %}
|
||||
{# Для push показываем registry вместо платформ #}
|
||||
{% if log.extra_data.get('registry') %}
|
||||
<span class="badge bg-primary">
|
||||
<i class="fas fa-server me-1"></i>{{ log.extra_data.get('registry') }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
{% elif log.platforms %}
|
||||
{% for platform in log.platforms %}
|
||||
<span class="badge bg-info me-1">{{ platform }}</span>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.status == "success" %}
|
||||
<span class="badge bg-success">Успешно</span>
|
||||
{% elif log.status == "failed" %}
|
||||
<span class="badge bg-danger">Ошибка</span>
|
||||
{% else %}
|
||||
<span class="badge bg-warning">Выполняется</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.started_at %}
|
||||
{{ log.started_at.strftime('%Y-%m-%d %H:%M:%S') }}
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.duration %}
|
||||
{{ log.duration }} сек
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ log.user or '-' }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-primary" onclick="showLogDetail({{ log.id }})">
|
||||
<i class="fas fa-eye me-1"></i>
|
||||
Просмотр
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-danger" onclick="deleteLog({{ log.id }})">
|
||||
<i class="fas fa-trash me-1"></i>
|
||||
Удалить
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Пагинация -->
|
||||
{% if total_pages > 1 %}
|
||||
<nav aria-label="Навигация по страницам">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page > 1 %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page - 1 }}">Предыдущая</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for p in range(1, total_pages + 1) %}
|
||||
{% if p == page %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ p }}</span>
|
||||
</li>
|
||||
{% elif p <= 3 or p >= total_pages - 2 or (p >= page - 1 and p <= page + 1) %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ p }}">{{ p }}</a>
|
||||
</li>
|
||||
{% elif p == 4 or p == total_pages - 3 %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">...</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page < total_pages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page + 1 }}">Следующая</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
Логи сборки отсутствуют
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Модальное окно для просмотра лога -->
|
||||
<div class="modal fade" id="logDetailModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Детали лога сборки</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="log-detail-content" class="log-container" style="height: 500px; overflow-y: auto; background: #1e1e1e; color: #d4d4d4; padding: 1rem; font-family: 'Courier New', monospace; font-size: 0.875rem; white-space: pre-wrap;">
|
||||
Загрузка...
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function showLogDetail(logId) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('logDetailModal'));
|
||||
const content = document.getElementById('log-detail-content');
|
||||
content.textContent = 'Загрузка...';
|
||||
modal.show();
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/dockerfiles/build-logs/${logId}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.logs) {
|
||||
content.textContent = data.logs;
|
||||
} else {
|
||||
content.textContent = 'Логи не найдены';
|
||||
}
|
||||
} catch (error) {
|
||||
content.textContent = `Ошибка загрузки: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteLog(logId) {
|
||||
const confirmed = await showConfirmModal('Вы уверены, что хотите удалить этот лог?');
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/dockerfiles/build-logs/${logId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Ошибка при удалении лога');
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`Ошибка: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function clearLogs() {
|
||||
const confirmed = await showConfirmModal('Вы уверены, что хотите очистить все логи сборки для этого Dockerfile?');
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/dockerfiles/{{ dockerfile.id }}/build-logs`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Ошибка при очистке логов');
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`Ошибка: ${error.message}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user