155 lines
5.8 KiB
HTML
155 lines
5.8 KiB
HTML
{% extends "layout.html" %}
|
|
{% set active_page = 'users' %}
|
|
{% block title %}Dashboard Users - {{ super() }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2 id="page-title" class="mb-0">Dashboard Users</h2>
|
|
</div>
|
|
<div class="row align-items-end">
|
|
<div class="col-md-4" id="dashboard-select-wrapper">
|
|
<label for="dashboard-select" class="form-label">HPE P5G Dashboard</label>
|
|
<select class="form-select" id="dashboard-select">
|
|
<option selected>Triton</option>
|
|
<option>Star</option>
|
|
<option>Bluebonnet</option>
|
|
<option>Lonestar</option>
|
|
<option>Production</option>
|
|
<option>Test (future)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div id="users-view">
|
|
<p>Retrieve a list of all users from the selected dashboard.</p>
|
|
<button class="btn btn-primary" id="listUsersBtn">List Users</button>
|
|
</div>
|
|
|
|
<div class="row g-3 my-3 align-items-end">
|
|
<div class="col-md-6">
|
|
<label for="tenant-filter" class="form-label">Filter by Tenant</label>
|
|
<select id="tenant-filter" class="form-select"></select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="search-input" class="form-label">Search Results</label>
|
|
<input type="text" id="search-input" class="form-control" placeholder="Search any column...">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<div id="spinner" class="d-none spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>
|
|
<div id="results-output" class="p-3"></div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_scripts %}
|
|
<script defer>
|
|
let fullUsersData = [];
|
|
let currentSort = { column: 'fullname', direction: 'asc' };
|
|
|
|
const searchInput = document.getElementById('search-input');
|
|
const tenantFilter = document.getElementById('tenant-filter');
|
|
|
|
function getRoleClass(role) {
|
|
switch (role) {
|
|
case 'OWNER': return 'bg-primary';
|
|
case 'ADMIN': return 'bg-danger';
|
|
case 'EDITOR': return 'bg-info text-dark';
|
|
case 'VIEWER': return 'bg-success';
|
|
default: return 'bg-light text-dark';
|
|
}
|
|
}
|
|
|
|
function renderTable(data) {
|
|
let tableHtml = `<table class="table table-dark table-hover table-sm table-compact">
|
|
<thead>
|
|
<tr>
|
|
<th class="tree-item" data-sort="fullname">Full Name <i class="bi bi-arrow-down-up"></i></th>
|
|
<th class="tree-item" data-sort="email">Email <i class="bi bi-arrow-down-up"></i></th>
|
|
<th class="tree-item" data-sort="role">Role <i class="bi bi-arrow-down-up"></i></th>
|
|
<th class="tree-item" data-sort="tenant">Tenant <i class="bi bi-arrow-down-up"></i></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>`;
|
|
|
|
data.forEach(user => {
|
|
const roleClass = getRoleClass(user.role);
|
|
tableHtml += `<tr>
|
|
<td>${user.fullname || 'N/A'}</td>
|
|
<td>${user.email || 'N/A'}</td>
|
|
<td><span class="badge ${roleClass}">${user.role || 'N/A'}</span></td>
|
|
<td>${user.tenant || 'N/A'}</td>
|
|
</tr>`;
|
|
});
|
|
|
|
tableHtml += '</tbody></table>';
|
|
resultsOutput.innerHTML = tableHtml;
|
|
}
|
|
|
|
function populateTenantFilter(data) {
|
|
const tenants = [...new Set(data.map(item => item.tenant))].sort();
|
|
tenantFilter.innerHTML = '<option value="">All Tenants</option>';
|
|
tenants.forEach(tenant => {
|
|
const option = document.createElement('option');
|
|
option.value = tenant;
|
|
option.textContent = tenant;
|
|
tenantFilter.appendChild(option);
|
|
});
|
|
}
|
|
|
|
function applyFiltersAndSort() {
|
|
let filteredData = [...fullUsersData];
|
|
const searchTerm = searchInput.value.toLowerCase();
|
|
const selectedTenant = tenantFilter.value;
|
|
|
|
if (selectedTenant) {
|
|
filteredData = filteredData.filter(item => item.tenant === selectedTenant);
|
|
}
|
|
|
|
if (searchTerm) {
|
|
filteredData = filteredData.filter(item =>
|
|
Object.values(item).some(value =>
|
|
String(value).toLowerCase().includes(searchTerm)
|
|
)
|
|
);
|
|
}
|
|
|
|
filteredData.sort((a, b) => {
|
|
const valA = a[currentSort.column] || '';
|
|
const valB = b[currentSort.column] || '';
|
|
if (valA < valB) return currentSort.direction === 'asc' ? -1 : 1;
|
|
if (valA > valB) return currentSort.direction === 'asc' ? 1 : -1;
|
|
return 0;
|
|
});
|
|
|
|
renderTable(filteredData);
|
|
}
|
|
|
|
document.getElementById('listUsersBtn').addEventListener('click', async () => {
|
|
const dashboard = document.getElementById('dashboard-select').value;
|
|
const users = await apiCall('/api/users/list', { dashboard });
|
|
if (users) {
|
|
fullUsersData = users;
|
|
populateTenantFilter(fullUsersData);
|
|
applyFiltersAndSort();
|
|
}
|
|
});
|
|
|
|
searchInput.addEventListener('input', applyFiltersAndSort);
|
|
tenantFilter.addEventListener('change', applyFiltersAndSort);
|
|
|
|
resultsOutput.addEventListener('click', (event) => {
|
|
const header = event.target.closest('th[data-sort]');
|
|
if (header) {
|
|
const sortColumn = header.dataset.sort;
|
|
if (currentSort.column === sortColumn) {
|
|
currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
currentSort.column = sortColumn;
|
|
currentSort.direction = 'asc';
|
|
}
|
|
applyFiltersAndSort();
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |