Files
DevOpsLab/app/templates/pages/playbooks/list.html
Сергей Антропов d4b0d6f848 Исправление синтаксической ошибки в molecule_executor.py и обновление k8s preset'ов
- Исправлена незакрытая скобка в _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
2026-02-16 00:31:09 +03:00

179 lines
6.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Playbook - DevOpsLab{% endblock %}
{% block page_title %}Playbook{% endblock %}
{% block header_actions %}
<a href="/playbooks/create" class="btn btn-primary btn-sm">
<i class="fas fa-plus me-2"></i>
Создать playbook
</a>
{% endblock %}
{% block content %}
<div class="row g-3" id="playbooks-list">
{% for playbook in playbooks %}
<div class="col-12 col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title mb-0">
<a href="/playbooks/{{ playbook.id }}" class="text-decoration-none">
{{ playbook.name }}
</a>
</h5>
<div class="btn-group">
<a
href="/playbooks/{{ playbook.id }}/edit"
class="btn btn-sm btn-outline-primary"
title="Редактировать"
>
<i class="fas fa-edit"></i>
</a>
<button
onclick="deletePlaybook({{ playbook.id }}, '{{ playbook.name }}', this)"
class="btn btn-sm btn-outline-danger"
title="Удалить"
>
<i class="fas fa-trash-alt"></i>
</button>
</div>
</div>
{% if playbook.description %}
<p class="card-text text-muted small mb-3">{{ playbook.description }}</p>
{% endif %}
<div class="small text-muted mb-2">
<i class="fas fa-tasks me-1"></i>
Ролей: <span class="fw-semibold">{{ playbook.roles|length }}</span>
</div>
{% if playbook.roles %}
<div class="small text-muted mb-2">
<i class="fas fa-list me-1"></i>
Роли:
{% for role in playbook.roles[:3] %}
<span class="badge bg-info me-1">{{ role }}</span>
{% endfor %}
{% if playbook.roles|length > 3 %}
<span class="text-muted">+{{ playbook.roles|length - 3 }}</span>
{% endif %}
</div>
{% endif %}
<div class="small text-muted mb-2">
<i class="fas fa-info-circle me-1"></i>
Статус:
<span class="badge {% if playbook.status == 'active' %}bg-success{% else %}bg-secondary{% endif %}">
{{ playbook.status }}
</span>
</div>
<div class="d-grid mt-3">
<a
href="/playbooks/{{ playbook.id }}"
class="btn btn-secondary btn-sm"
>
<i class="fas fa-info-circle me-1"></i>
Детали
</a>
</div>
</div>
</div>
</div>
{% else %}
<div class="col-12">
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
Playbook'ов пока нет. <a href="/playbooks/create">Создайте первый playbook</a>
</div>
</div>
{% endfor %}
</div>
{% block scripts %}
<script>
async function deletePlaybook(playbookId, playbookName, button) {
// Показываем модальное окно подтверждения
const confirmed = await showConfirmModal(
`Вы уверены, что хотите удалить playbook '${playbookName}'?`,
'Подтверждение удаления'
);
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/playbooks/${playbookId}`, {
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 || `Playbook '${playbookName}' успешно удален`,
'success',
'Успешно',
function() {
// После закрытия модального окна удаляем карточку
const card = button.closest('.col-12');
if (card) {
card.remove();
}
}
);
} else {
// Если функция недоступна, просто удаляем карточку
const card = button.closest('.col-12');
if (card) {
card.remove();
}
}
}
} else {
// Ошибка - показываем в модальном окне
try {
const errorData = await response.json();
const errorMessage = errorData.detail || errorData.message || 'Ошибка при удалении playbook';
if (window.showMessageModal) {
window.showMessageModal(errorMessage, 'error');
} else {
alert(errorMessage);
}
} catch (e) {
if (window.showMessageModal) {
window.showMessageModal('Ошибка при удалении playbook', 'error');
} else {
alert('Ошибка при удалении playbook');
}
}
}
} catch (error) {
console.error('Ошибка при удалении playbook:', error);
if (window.showMessageModal) {
window.showMessageModal('Ошибка при удалении playbook', 'error');
} else {
alert('Ошибка при удалении playbook');
}
} finally {
// Восстанавливаем кнопку
button.disabled = false;
button.innerHTML = originalHTML;
}
}
</script>
{% endblock %}