feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
217
app/templates/pages/playbooks/edit.html
Normal file
217
app/templates/pages/playbooks/edit.html
Normal file
@@ -0,0 +1,217 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Редактировать Playbook - DevOpsLab{% endblock %}
|
||||
{% block page_title %}Редактировать Playbook: {{ playbook.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<ul class="nav nav-tabs mb-3" id="playbook-tabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="info-tab" data-bs-toggle="tab" data-bs-target="#info" type="button" role="tab">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
Информация
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="content-tab" data-bs-toggle="tab" data-bs-target="#content" type="button" role="tab">
|
||||
<i class="fas fa-code me-2"></i>
|
||||
Playbook (YAML)
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="inventory-tab" data-bs-toggle="tab" data-bs-target="#inventory" type="button" role="tab">
|
||||
<i class="fas fa-server me-2"></i>
|
||||
Инвентарь
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="playbook-tab-content">
|
||||
<!-- Информация -->
|
||||
<div class="tab-pane fade show active" id="info" role="tabpanel">
|
||||
<form
|
||||
hx-put="/api/v1/playbooks/{{ playbook.id }}"
|
||||
hx-target="#info-result"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Название</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
class="form-control"
|
||||
value="{{ playbook.name }}"
|
||||
required
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Описание</label>
|
||||
<textarea
|
||||
name="description"
|
||||
class="form-control"
|
||||
rows="3"
|
||||
>{{ playbook.description or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Роли</label>
|
||||
<div class="row g-2">
|
||||
{% for role in all_roles %}
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="roles"
|
||||
value="{{ role }}"
|
||||
id="role-{{ role }}"
|
||||
{% if role in playbook.roles %}checked{% endif %}
|
||||
>
|
||||
<label class="form-check-label" for="role-{{ role }}">
|
||||
{{ role }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="info-result"></div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
Сохранить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Playbook YAML -->
|
||||
<div class="tab-pane fade" id="content" role="tabpanel">
|
||||
<form
|
||||
hx-put="/api/v1/playbooks/{{ playbook.id }}"
|
||||
hx-target="#content-result"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
<input type="hidden" name="content" id="playbook-content-hidden">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Playbook (YAML)</label>
|
||||
<textarea
|
||||
id="playbook-content-editor"
|
||||
class="form-control font-monospace"
|
||||
rows="20"
|
||||
>{{ playbook.content }}</textarea>
|
||||
<div class="form-text">
|
||||
<i class="fas fa-info-circle me-1"></i>
|
||||
Редактируйте YAML содержимое playbook. Валидация выполняется автоматически.
|
||||
</div>
|
||||
</div>
|
||||
<div id="content-result"></div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
Сохранить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Инвентарь -->
|
||||
<div class="tab-pane fade" id="inventory" role="tabpanel">
|
||||
<form
|
||||
hx-put="/api/v1/playbooks/{{ playbook.id }}"
|
||||
hx-target="#inventory-result"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
<input type="hidden" name="inventory" id="inventory-hidden">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Инвентарь (YAML или INI)</label>
|
||||
<textarea
|
||||
id="inventory-editor"
|
||||
class="form-control font-monospace"
|
||||
rows="20"
|
||||
>{{ playbook.inventory or '' }}</textarea>
|
||||
<div class="form-text">
|
||||
<i class="fas fa-info-circle me-1"></i>
|
||||
Инвентарь в формате YAML или INI. Редактор автоматически определит формат.
|
||||
</div>
|
||||
</div>
|
||||
<div id="inventory-result"></div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
Сохранить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Инициализация редакторов
|
||||
if (typeof CodeEditor !== 'undefined') {
|
||||
const playbookEditor = CodeEditor.init('playbook-content-editor', 'yaml', {
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
foldGutter: true
|
||||
});
|
||||
|
||||
const inventoryEditor = CodeEditor.init('inventory-editor', 'yaml', {
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
foldGutter: true
|
||||
});
|
||||
|
||||
// Валидация playbook при изменении
|
||||
if (playbookEditor) {
|
||||
playbookEditor.on('change', function() {
|
||||
const content = playbookEditor.getValue();
|
||||
const validation = CodeEditor.validateAnsible(content);
|
||||
if (!validation.valid) {
|
||||
CodeEditor.showErrors(playbookEditor, validation.errors);
|
||||
} else {
|
||||
// Очищаем ошибки если валидация прошла
|
||||
if (playbookEditor._validationMarkers) {
|
||||
playbookEditor._validationMarkers.forEach(m => m.clear());
|
||||
playbookEditor._validationMarkers = [];
|
||||
}
|
||||
}
|
||||
// Сохраняем в hidden поле для отправки формы
|
||||
document.getElementById('playbook-content-hidden').value = content;
|
||||
});
|
||||
}
|
||||
|
||||
// Валидация инвентаря
|
||||
if (inventoryEditor) {
|
||||
inventoryEditor.on('change', function() {
|
||||
const content = inventoryEditor.getValue();
|
||||
// Сохраняем в hidden поле для отправки формы
|
||||
document.getElementById('inventory-hidden').value = content;
|
||||
|
||||
if (content.trim()) {
|
||||
// Определяем формат (INI или YAML)
|
||||
const isINI = content.trim().startsWith('[') || content.includes('ansible_host=');
|
||||
let validation;
|
||||
if (isINI) {
|
||||
// Простая валидация INI
|
||||
validation = { valid: content.includes('[') && content.includes(']'), errors: [] };
|
||||
} else {
|
||||
validation = CodeEditor.validateYAML(content);
|
||||
}
|
||||
|
||||
if (!validation.valid) {
|
||||
CodeEditor.showErrors(inventoryEditor, validation.errors);
|
||||
} else {
|
||||
if (inventoryEditor._validationMarkers) {
|
||||
inventoryEditor._validationMarkers.forEach(m => m.clear());
|
||||
inventoryEditor._validationMarkers = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user