664 lines
29 KiB
HTML
664 lines
29 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Ansible Management Dashboard - Server Monitoring{% endblock %}
|
|
|
|
{% block page_title %}Ansible Management Dashboard{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
|
|
|
|
.card-stat {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 15px;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.card-stat:hover {
|
|
transform: translateY(-5px);
|
|
}
|
|
|
|
.card-stat h3 {
|
|
font-size: 2.5rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.device-card {
|
|
border: none;
|
|
border-radius: 12px;
|
|
box-shadow: 0 2px 15px rgba(0,0,0,0.08);
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.device-card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
|
|
}
|
|
|
|
.device-card.selected {
|
|
border: 2px solid #28a745;
|
|
background-color: #f8fff9;
|
|
}
|
|
|
|
.playbook-card {
|
|
border: none;
|
|
border-radius: 12px;
|
|
box-shadow: 0 2px 15px rgba(0,0,0,0.08);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.playbook-card:hover {
|
|
transform: translateY(-3px);
|
|
}
|
|
|
|
.execution-card {
|
|
border: none;
|
|
border-radius: 15px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
|
transition: transform 0.2s;
|
|
}
|
|
|
|
.execution-card:hover {
|
|
transform: translateY(-5px);
|
|
}
|
|
|
|
.status-running { color: #0d6efd; }
|
|
.status-completed { color: #198754; }
|
|
.status-failed { color: #dc3545; }
|
|
|
|
/* Tab styles */
|
|
.nav-tabs .nav-link {
|
|
border: none;
|
|
border-radius: 25px 25px 0 0;
|
|
margin-right: 5px;
|
|
padding: 12px 20px;
|
|
font-weight: 500;
|
|
color: #6c757d;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.nav-tabs .nav-link:hover {
|
|
background-color: #e9ecef;
|
|
color: #495057;
|
|
}
|
|
|
|
.nav-tabs .nav-link.active {
|
|
background-color: #3498db;
|
|
color: white;
|
|
border: none;
|
|
}
|
|
|
|
.tab-content {
|
|
border: 1px solid #dee2e6;
|
|
border-top: none;
|
|
border-radius: 0 15px 15px 15px;
|
|
background-color: white;
|
|
min-height: 400px;
|
|
}
|
|
|
|
/* Button styles */
|
|
.btn-custom {
|
|
border-radius: 25px;
|
|
padding: 10px 20px;
|
|
font-weight: 500;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-custom:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Flash Messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
{% for category, message in messages %}
|
|
<div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<!-- Ansible Management Tabs -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<ul class="nav nav-tabs" id="ansibleTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="automation-tab" data-bs-toggle="tab" data-bs-target="#automation" type="button" role="tab">
|
|
<i class="fas fa-robot"></i> Automation Overview
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="devices-tab" data-bs-toggle="tab" data-bs-target="#devices" type="button" role="tab">
|
|
<i class="fas fa-network-wired"></i> Remote Devices
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="playbooks-tab" data-bs-toggle="tab" data-bs-target="#playbooks" type="button" role="tab">
|
|
<i class="fas fa-play"></i> Playbook Management
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="execution-tab" data-bs-toggle="tab" data-bs-target="#execution" type="button" role="tab">
|
|
<i class="fas fa-cogs"></i> Execution
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Content -->
|
|
<div class="tab-content" id="ansibleTabContent">
|
|
<!-- Automation Overview Tab -->
|
|
<div class="tab-pane fade show active" id="automation" role="tabpanel">
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card card-stat">
|
|
<div class="card-body text-center">
|
|
<i class="fas fa-server fa-2x mb-2"></i>
|
|
<h3>{{ stats.get('total_devices', 0) }}</h3>
|
|
<p>Devices</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card card-stat" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
|
<div class="card-body text-center">
|
|
<i class="fas fa-play-circle fa-2x mb-2"></i>
|
|
<h3>{{ ((playbooks|default([])|length) + (builtin_playbooks|default([])|length)) }}</h3>
|
|
<p>Playbooks</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card card-stat" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
|
<div class="card-body text-center">
|
|
<i class="fas fa-tasks fa-2x mb-2"></i>
|
|
<h3>{{ (executions|default([]))|length }}</h3>
|
|
<p>Executions</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card card-stat" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
|
<div class="card-body text-center">
|
|
<i class="fas fa-check-circle fa-2x mb-2"></i>
|
|
<h3>{{ (executions|default([]) | selectattr('status', 'equalto', 'completed') | list | length) }}</h3>
|
|
<p>Success Rate</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Quick Actions</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<button class="btn btn-primary btn-custom w-100" onclick="executeQuickPlaybook()">
|
|
<i class="fas fa-play"></i> Quick Execute
|
|
</button>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-success btn-custom w-100" onclick="refreshAll()">
|
|
<i class="fas fa-sync"></i> Refresh All
|
|
</button>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-info btn-custom w-100" data-bs-toggle="modal" data-bs-target="#addDeviceModal">
|
|
<i class="fas fa-plus"></i> Add Device
|
|
</button>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-warning btn-custom w-100" data-bs-toggle="modal" data-bs-target="#uploadPlaybookModal">
|
|
<i class="fas fa-upload"></i> Upload Playbook
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Remote Devices Tab -->
|
|
<div class="tab-pane fade" id="devices" role="tabpanel">
|
|
<div class="row mb-4">
|
|
<div class="col-md-8">
|
|
<h4>Managed Devices</h4>
|
|
<small class="text-muted">Configure and manage devices through Ansible</small>
|
|
</div>
|
|
<div class="col-md-4 text-end">
|
|
<button class="btn btn-primary btn-custom" data-bs-toggle="modal" data-bs-target="#addDeviceModal">
|
|
<i class="fas fa-plus"></i> Add Device
|
|
</button>
|
|
<button class="btn btn-success btn-custom" onclick="refreshInventory()">
|
|
<i class="fas fa-sync"></i> Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Device Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Total Devices</h5>
|
|
<h2>{{ (devices|default([]))|length }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Online</h5>
|
|
<h2>{{ (devices|default([]) | selectattr('status', 'equalto', 'active') | list | length) }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-warning text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Offline</h5>
|
|
<h2>{{ (devices|default([]) | selectattr('status', 'equalto', 'inactive') | list | length) }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Groups</h5>
|
|
<h2>{{ (device_groups|default([]))|length }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Devices Table -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Device List</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if devices|default([]) %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Host</th>
|
|
<th>Group</th>
|
|
<th>Status</th>
|
|
<th>Last Check</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for device in devices|default([]) %}
|
|
<tr>
|
|
<td>{{ device.name }}</td>
|
|
<td>{{ device.host }}</td>
|
|
<td><span class="badge bg-secondary">{{ device.group }}</span></td>
|
|
<td>
|
|
{% if device.status == 'active' %}
|
|
<span class="badge bg-success">Online</span>
|
|
{% else %}
|
|
<span class="badge bg-danger">Offline</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ device.last_check | local_dt if device.last_check else 'Never' }}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="testDevice('{{ device.name }}')">
|
|
<i class="fas fa-plug"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-danger" onclick="removeDevice('{{ device.name }}')">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-server fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No devices configured</h5>
|
|
<p class="text-muted">Add your first device to start managing infrastructure.</p>
|
|
<button class="btn btn-primary btn-custom" data-bs-toggle="modal" data-bs-target="#addDeviceModal">
|
|
<i class="fas fa-plus"></i> Add Device
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Playbook Management Tab -->
|
|
<div class="tab-pane fade" id="playbooks" role="tabpanel">
|
|
<div class="row mb-4">
|
|
<div class="col-md-8">
|
|
<h4>Playbook Management</h4>
|
|
<small class="text-muted">Manage and execute Ansible playbooks</small>
|
|
</div>
|
|
<div class="col-md-4 text-end">
|
|
<button class="btn btn-primary btn-custom" data-bs-toggle="modal" data-bs-target="#uploadPlaybookModal">
|
|
<i class="fas fa-upload"></i> Upload Playbook
|
|
</button>
|
|
<button class="btn btn-success btn-custom" onclick="refreshPlaybooks()">
|
|
<i class="fas fa-sync"></i> Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Playbook Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Total Playbooks</h5>
|
|
<h2>{{ ((playbooks|default([]))|length + (builtin_playbooks|default([]))|length) }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Custom</h5>
|
|
<h2>{{ (playbooks|default([]))|length }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Built-in</h5>
|
|
<h2>{{ (builtin_playbooks|default([]))|length }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-warning text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Recent Runs</h5>
|
|
<h2>{{ (executions|default([]))|length }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Playbooks Grid -->
|
|
<div class="row">
|
|
{% if (builtin_playbooks|default([])) or (playbooks|default([])) %}
|
|
{% for playbook in (builtin_playbooks|default([])) + (playbooks|default([])) %}
|
|
<div class="col-md-6 col-lg-4 mb-3">
|
|
<div class="card playbook-card">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{{ playbook.name }}</h6>
|
|
<p class="card-text text-muted small">{{ playbook.description | default('No description available') }}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<small class="text-muted">
|
|
{% if playbook.type == 'builtin' %}
|
|
<span class="badge bg-primary">Built-in</span>
|
|
{% else %}
|
|
<span class="badge bg-info">Custom</span>
|
|
{% endif %}
|
|
</small>
|
|
<div class="btn-group btn-group-sm">
|
|
<button class="btn btn-outline-primary" onclick="viewPlaybook('{{ playbook.name }}')">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<button class="btn btn-outline-success" onclick="executePlaybook('{{ playbook.name }}')">
|
|
<i class="fas fa-play"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<div class="col-12">
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-play fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No playbooks available</h5>
|
|
<p class="text-muted">Upload a custom playbook to get started.</p>
|
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadPlaybookModal">
|
|
<i class="fas fa-upload"></i> Upload Playbook
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Execution Tab -->
|
|
<div class="tab-pane fade" id="execution" role="tabpanel">
|
|
<div class="row mb-4">
|
|
<div class="col-md-8">
|
|
<h4>Playbook Execution</h4>
|
|
<small class="text-muted">Execute playbooks on selected devices</small>
|
|
</div>
|
|
<div class="col-md-4 text-end">
|
|
<button class="btn btn-primary btn-custom" onclick="executeQuickPlaybook()">
|
|
<i class="fas fa-play"></i> Quick Execute
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Executions -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Recent Executions</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if executions|default([]) %}
|
|
<div class="row">
|
|
{% for execution in (executions|default([]))[:6] %}
|
|
<div class="col-md-6 mb-3">
|
|
<div class="card execution-card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<h6 class="card-title mb-0">{{ execution.playbook_name }}</h6>
|
|
<span class="badge
|
|
{% if execution.status == 'running' %}bg-primary status-running{% endif %}
|
|
{% if execution.status == 'completed' %}bg-success status-completed{% endif %}
|
|
{% if execution.status == 'failed' %}bg-danger status-failed{% endif %}">
|
|
{{ execution.status | title }}
|
|
</span>
|
|
</div>
|
|
<p class="card-text text-muted small">
|
|
<i class="fas fa-clock"></i>
|
|
{{ execution.start_time | local_dt('%Y-%m-%d %H:%M:%S') if execution.start_time else 'N/A' }}
|
|
</p>
|
|
<div class="row text-center">
|
|
<div class="col">
|
|
<small class="text-success">
|
|
<i class="fas fa-check"></i> {{ execution.successful_hosts or 0 }}
|
|
</small>
|
|
</div>
|
|
<div class="col">
|
|
<small class="text-danger">
|
|
<i class="fas fa-times"></i> {{ execution.failed_hosts or 0 }}
|
|
</small>
|
|
</div>
|
|
<div class="col">
|
|
<small class="text-warning">
|
|
<i class="fas fa-question"></i> {{ execution.unreachable_hosts or 0 }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<div class="mt-2">
|
|
<button class="btn btn-outline-primary btn-sm" onclick="viewExecution('{{ execution.id }}')">
|
|
<i class="fas fa-eye"></i> Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-tasks fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No executions yet</h5>
|
|
<p class="text-muted">Execute your first playbook to see results here.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modals -->
|
|
<!-- Add Device Modal -->
|
|
<div class="modal fade" id="addDeviceModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Add New Device</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="addDeviceForm">
|
|
<div class="mb-3">
|
|
<label class="form-label">Device Name</label>
|
|
<input type="text" class="form-control" name="name" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Host/IP Address</label>
|
|
<input type="text" class="form-control" name="host" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Group</label>
|
|
<select class="form-control" name="group">
|
|
<option value="servers">Servers</option>
|
|
<option value="workstations">Workstations</option>
|
|
<option value="routers">Network Devices</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">SSH User</label>
|
|
<input type="text" class="form-control" name="user" value="ansible">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" onclick="addDevice()">Add Device</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload Playbook Modal -->
|
|
<div class="modal fade" id="uploadPlaybookModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Upload Playbook</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="uploadPlaybookForm" enctype="multipart/form-data">
|
|
<div class="mb-3">
|
|
<label class="form-label">Playbook File (.yml/.yaml)</label>
|
|
<input type="file" class="form-control" name="playbook_file" accept=".yml,.yaml" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Description</label>
|
|
<textarea class="form-control" name="description" rows="3"></textarea>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" onclick="uploadPlaybook()">Upload</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function executeQuickPlaybook() {
|
|
// Implementation for quick playbook execution
|
|
alert('Quick execute functionality');
|
|
}
|
|
|
|
function refreshAll() {
|
|
location.reload();
|
|
}
|
|
|
|
function refreshInventory() {
|
|
// Implementation for refreshing inventory
|
|
alert('Refreshing inventory...');
|
|
}
|
|
|
|
function refreshPlaybooks() {
|
|
// Implementation for refreshing playbooks
|
|
alert('Refreshing playbooks...');
|
|
}
|
|
|
|
function testDevice(deviceName) {
|
|
// Implementation for testing device connection
|
|
alert('Testing connection to ' + deviceName);
|
|
}
|
|
|
|
function removeDevice(deviceName) {
|
|
if (confirm('Are you sure you want to remove device: ' + deviceName + '?')) {
|
|
// Implementation for removing device
|
|
alert('Removing device: ' + deviceName);
|
|
}
|
|
}
|
|
|
|
function viewPlaybook(playbookName) {
|
|
// Implementation for viewing playbook details
|
|
alert('Viewing playbook: ' + playbookName);
|
|
}
|
|
|
|
function executePlaybook(playbookName) {
|
|
// Implementation for executing playbook
|
|
alert('Executing playbook: ' + playbookName);
|
|
}
|
|
|
|
function viewExecution(executionId) {
|
|
// Implementation for viewing execution details
|
|
alert('Viewing execution: ' + executionId);
|
|
}
|
|
|
|
function addDevice() {
|
|
// Implementation for adding device
|
|
const form = document.getElementById('addDeviceForm');
|
|
const formData = new FormData(form);
|
|
|
|
// Convert to JSON and submit
|
|
alert('Adding device...');
|
|
// Close modal
|
|
bootstrap.Modal.getInstance(document.getElementById('addDeviceModal')).hide();
|
|
}
|
|
|
|
function uploadPlaybook() {
|
|
// Implementation for uploading playbook
|
|
const form = document.getElementById('uploadPlaybookForm');
|
|
const formData = new FormData(form);
|
|
|
|
alert('Uploading playbook...');
|
|
// Close modal
|
|
bootstrap.Modal.getInstance(document.getElementById('uploadPlaybookModal')).hide();
|
|
}
|
|
</script>
|
|
{% endblock %} |