157 lines
7.5 KiB
Twig
157 lines
7.5 KiB
Twig
{% extends "layout.twig" %}
|
|
|
|
{% block content %}
|
|
<div class="container mt-4">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1>{{ 'Сценарии установки протоколов' | trans }}</h1>
|
|
<div class="btn-group">
|
|
<a href="/admin/scenario/create" class="btn btn-primary">
|
|
<i class="fas fa-plus"></i> {{ 'Новый сценарий' | trans }}
|
|
</a>
|
|
<button class="btn btn-success" id="btnImport">
|
|
<i class="fas fa-upload"></i> {{ 'Импорт' | trans }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{% if scenarios | length > 0 %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover table-sm">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>{{ 'Протокол' | trans }}</th>
|
|
<th>{{ 'Описание' | trans }}</th>
|
|
<th>{{ 'Движок' | trans }}</th>
|
|
<th>{{ 'Статус' | trans }}</th>
|
|
<th>{{ 'Действия' | trans }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for scenario in scenarios %}
|
|
<tr>
|
|
<td>
|
|
<strong>{{ scenario.name }}</strong>
|
|
<br>
|
|
<small class="text-muted">{{ scenario.slug }}</small>
|
|
</td>
|
|
<td>{{ scenario.description | default('-') }}</td>
|
|
<td>
|
|
<span class="badge bg-info">
|
|
{{ scenario.definition.engine | default('unknown') }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if scenario.is_active %}
|
|
<span class="badge bg-success">{{ 'Активный' | trans }}</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">{{ 'Отключен' | trans }}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm" role="group">
|
|
<a href="/admin/scenario/{{ scenario.id }}" class="btn btn-info" title="{{ 'Просмотр' | trans }}">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a href="/admin/scenario/{{ scenario.id }}/edit" class="btn btn-warning" title="{{ 'Редактировать' | trans }}">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<a href="/admin/scenario/{{ scenario.id }}/export" class="btn btn-secondary" title="{{ 'Экспорт' | trans }}">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
{% if scenario.slug != 'amnezia-wg' %}
|
|
<button class="btn btn-danger delete-scenario" data-id="{{ scenario.id }}" data-name="{{ scenario.name }}" title="{{ 'Удалить' | trans }}">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="alert alert-info" role="alert">
|
|
{{ 'Нет доступных сценариев' | trans }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Import Modal -->
|
|
<div class="modal fade" id="importModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">{{ 'Импорт сценария' | trans }}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form id="importForm" enctype="multipart/form-data">
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label for="importFile" class="form-label">{{ 'JSON файл сценария' | trans }}</label>
|
|
<input type="file" class="form-control" id="importFile" name="file" accept=".json" required>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'Отмена' | trans }}</button>
|
|
<button type="submit" class="btn btn-primary">{{ 'Импортировать' | trans }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Import button handler
|
|
document.getElementById('btnImport').addEventListener('click', function() {
|
|
new bootstrap.Modal(document.getElementById('importModal')).show();
|
|
});
|
|
|
|
// Import form handler
|
|
document.getElementById('importForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const formData = new FormData(this);
|
|
|
|
fetch('/admin/scenario/import', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
window.location.href = data.redirect;
|
|
} else {
|
|
alert('{{ "Ошибка импорта:" | trans }} ' + data.message);
|
|
}
|
|
})
|
|
.catch(err => alert('{{ "Ошибка:" | trans }} ' + err));
|
|
});
|
|
|
|
// Delete buttons
|
|
document.querySelectorAll('.delete-scenario').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const id = this.dataset.id;
|
|
const name = this.dataset.name;
|
|
|
|
if (confirm(`{{ "Удалить сценарий" | trans }}: ${name}?`)) {
|
|
fetch(`/admin/scenario/${id}/delete`, {method: 'POST'})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
window.location.href = data.redirect;
|
|
} else {
|
|
alert('{{ "Ошибка удаления:" | trans }} ' + data.message);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|