mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-30 17:58:59 +00:00
499 lines
26 KiB
Smarty
499 lines
26 KiB
Smarty
<div class="card">
|
|
<div class="card-header">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h4 class="mb-0">Deleted Users Management</h4>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
|
|
{if isset($smarty.session.success)}
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
{$smarty.session.success}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{/if}
|
|
{if isset($smarty.session.error)}
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
{$smarty.session.error}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{/if}
|
|
|
|
<form name="deletedusersearch" method="get" action="{{url("/admin/deleted-users")}}" id="deleted-user-search-form" class="mb-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
<div class="col-md-3">
|
|
<label for="username" class="form-label">Username:</label>
|
|
<input id="username" type="text" name="username" value="{$username}" class="form-control" placeholder="Username">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="email" class="form-label">Email:</label>
|
|
<input id="email" type="text" name="email" value="{$email}" class="form-control" placeholder="Email">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="host" class="form-label">Host:</label>
|
|
<input id="host" type="text" name="host" value="{$host}" class="form-control" placeholder="Host">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Created From:</label>
|
|
<input type="date" name="created_from" value="{$created_from}" class="form-control" placeholder="YYYY-MM-DD">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Created To:</label>
|
|
<input type="date" name="created_to" value="{$created_to}" class="form-control" placeholder="YYYY-MM-DD">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Deleted From:</label>
|
|
<input type="date" name="deleted_from" value="{$deleted_from}" class="form-control" placeholder="YYYY-MM-DD">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Deleted To:</label>
|
|
<input type="date" name="deleted_to" value="{$deleted_to}" class="form-control" placeholder="YYYY-MM-DD">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer d-flex gap-2">
|
|
<input type="submit" value="Search" class="btn btn-success">
|
|
<a href="{{url("/admin/deleted-users")}}" class="btn btn-secondary">Reset</a>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
{if $deletedusers|@count > 0}
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header d-flex flex-wrap align-items-center justify-content-between gap-2">
|
|
<h3 class="card-title mb-0">Soft-Deleted Users</h3>
|
|
<form id="bulk-action-form" method="post" action="{{url('/admin/deleted-users/bulk')}}" class="d-flex align-items-center gap-2 flex-wrap">
|
|
<input type="hidden" name="_token" value="{$csrf_token}">
|
|
<div class="input-group input-group-sm">
|
|
<label class="input-group-text" for="bulk-action-select">Bulk Action</label>
|
|
<select name="action" id="bulk-action-select" class="form-select form-select-sm">
|
|
<option value="" selected disabled>Choose...</option>
|
|
<option value="restore">Restore Selected</option>
|
|
<option value="delete">Permanently Delete Selected</option>
|
|
</select>
|
|
<button type="submit" class="btn btn-primary" id="bulk-action-submit" disabled>Apply</button>
|
|
</div>
|
|
<div class="btn-group btn-group-sm" role="group" aria-label="Selection controls">
|
|
<!-- Improved selection buttons -->
|
|
<div class="btn-group btn-group-sm selection-toolbar" role="group" aria-label="Selection controls">
|
|
<button type="button" class="btn btn-outline-primary" id="select-all" data-bs-toggle="tooltip" data-bs-title="Select every row">
|
|
<i class="fas fa-check-double me-1"></i><span class="d-none d-sm-inline">Select All</span>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" id="deselect-all" data-bs-toggle="tooltip" data-bs-title="Clear selection">
|
|
<i class="fas fa-ban me-1"></i><span class="d-none d-sm-inline">Clear</span>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning" id="invert-selection" data-bs-toggle="tooltip" data-bs-title="Invert current selection">
|
|
<i class="fas fa-exchange-alt me-1"></i><span class="d-none d-sm-inline">Invert</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="data table table-striped table-hover align-middle" id="deleted-users-table">
|
|
<thead>
|
|
<tr>
|
|
<th style="width:32px;" class="text-center"><input type="checkbox" id="master-checkbox" title="Select/Deselect All"></th>
|
|
<th>Username
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=username_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=username_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Email
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=email_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=email_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Role
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=role_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=role_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Host
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=host_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=host_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Created Date
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=createdat_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=createdat_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Deleted Date
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=deletedat_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=deletedat_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Last Login
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=lastlogin_asc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-up"></i></a>
|
|
<a href="{$smarty.const.WWW_TOP}/admin/deleted-users?ob=lastlogin_desc{if $queryString != ''}&{$queryString}{/if}"><i class="fas fa-sort-alpha-down"></i></a>
|
|
</th>
|
|
<th>Status</th>
|
|
<th>Options</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{foreach from=$deletedusers item=user}
|
|
<tr>
|
|
<td class="text-center"><input type="checkbox" class="row-checkbox" name="user_ids[]" form="bulk-action-form" value="{$user->id}" aria-label="Select {$user->username}"></td>
|
|
<td>{$user->username}</td>
|
|
<td>{$user->email}</td>
|
|
<td>
|
|
<span class="badge bg-{if $user->roles_id == 2}danger{elseif $user->roles_id == 3}warning{elseif $user->roles_id == 4}success{else}secondary{/if} rounded-pill">{$user->rolename}</span>
|
|
{if !empty($user->rolechangedate)}
|
|
<small class="d-block text-muted mt-1" title="Role expiration date">
|
|
<i class="fa fa-calendar me-1"></i>{$user->rolechangedate}
|
|
</small>
|
|
{/if}
|
|
</td>
|
|
<td>{$user->host}</td>
|
|
<td>{$user->created_at|date_format:"%Y-%m-%d %H:%M"}</td>
|
|
<td>{$user->deleted_at|date_format:"%Y-%m-%d %H:%M"}</td>
|
|
<td>{if $user->lastlogin != ""}{$user->lastlogin|date_format:"%Y-%m-%d %H:%M"}{else}Never{/if}</td>
|
|
<td class="text-center">
|
|
<div class="mb-2">
|
|
{if $user->verified == 1}
|
|
<span class="badge bg-success" data-bs-toggle="tooltip" data-bs-placement="top" title="Email verified"><i class="fa fa-check me-1"></i>Verified</span>
|
|
{else}
|
|
<span class="badge bg-warning text-dark" data-bs-toggle="tooltip" data-bs-placement="top" title="Email not verified"><i class="fa fa-exclamation-triangle me-1"></i>Unverified</span>
|
|
{/if}
|
|
</div>
|
|
<div>
|
|
{if $user->apiaccess}
|
|
<span class="badge bg-info" data-bs-toggle="tooltip" data-bs-placement="top" title="{$user->apiaccess}"><i class="fa fa-key me-1"></i>API Access</span>
|
|
{/if}
|
|
</div>
|
|
</td>
|
|
<td class="text-nowrap">
|
|
<button type="button" class="btn btn-success btn-sm me-2 restore-user"
|
|
data-user-id="{$user->id}"
|
|
data-username="{$user->username}"
|
|
title="Restore User">
|
|
<i class="fas fa-user-check"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-danger btn-sm delete-permanently"
|
|
data-user-id="{$user->id}"
|
|
data-username="{$user->username}"
|
|
title="Permanently Delete User">
|
|
<i class="fas fa-trash-alt"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{/foreach}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
|
|
<div><strong>Total:</strong> {$deletedusers->total()} user(s)</div>
|
|
<div>{if $deletedusers->hasPages()}{$deletedusers->links()}{/if}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{else}
|
|
<div class="alert alert-info">No soft-deleted users found.</div>
|
|
{/if}
|
|
|
|
</div> <!-- end of card-body -->
|
|
</div> <!-- end of card -->
|
|
|
|
<!-- Delete User Confirmation Modal -->
|
|
<div class="modal fade" id="deleteUserModal" tabindex="-1" aria-labelledby="deleteUserModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-danger text-white">
|
|
<h5 class="modal-title" id="deleteUserModalLabel">Confirm Permanent Deletion</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-exclamation-triangle"></i> Warning: This action cannot be undone!
|
|
</div>
|
|
<p>You are about to permanently delete user <strong id="deleteUserName"></strong>.</p>
|
|
<p>All user data including history, comments, and settings will be permanently removed from the database.</p>
|
|
<p>Are you sure you want to continue?</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<a href="#" id="confirmDeleteBtn" class="btn btn-danger">
|
|
<i class="fas fa-trash-alt"></i> Permanently Delete
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Restore User Confirmation Modal -->
|
|
<div class="modal fade" id="restoreUserModal" tabindex="-1" aria-labelledby="restoreUserModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-success text-white">
|
|
<h5 class="modal-title" id="restoreUserModalLabel">Confirm User Restoration</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle"></i> Please confirm this action
|
|
</div>
|
|
<p>You are about to restore user <strong id="restoreUserName"></strong>.</p>
|
|
<p>This will reactivate the user account and grant them access to the system again.</p>
|
|
<p>Are you sure you want to continue?</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<a href="#" id="confirmRestoreBtn" class="btn btn-success">
|
|
<i class="fas fa-user-check"></i> Restore User
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// --- Modal logic ---
|
|
const deleteUserModalEl = document.getElementById('deleteUserModal');
|
|
const restoreUserModalEl = document.getElementById('restoreUserModal');
|
|
const deleteUserModal = deleteUserModalEl ? new bootstrap.Modal(deleteUserModalEl) : null;
|
|
const restoreUserModal = restoreUserModalEl ? new bootstrap.Modal(restoreUserModalEl) : null;
|
|
|
|
const deleteUserNameEl = document.getElementById('deleteUserName');
|
|
const restoreUserNameEl = document.getElementById('restoreUserName');
|
|
const confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
|
|
const confirmRestoreBtn = document.getElementById('confirmRestoreBtn');
|
|
|
|
// Helper to submit bulk form via modal confirm
|
|
function attachBulkHandler(button, form) {
|
|
if (!button) return;
|
|
button.dataset.bulk = 'true';
|
|
// Make sure we don't navigate away accidentally
|
|
button.dataset.originalHref = button.getAttribute('href') || '';
|
|
button.setAttribute('href', '#');
|
|
}
|
|
function detachBulkHandler(button) {
|
|
if (!button || !button.dataset.bulk) return;
|
|
// Restore original href for single-item operations
|
|
if (button.dataset.originalHref !== undefined) {
|
|
button.setAttribute('href', button.dataset.originalHref);
|
|
}
|
|
delete button.dataset.bulk;
|
|
delete button.dataset.originalHref;
|
|
}
|
|
|
|
// Delete permanently buttons (single item)
|
|
document.querySelectorAll('.delete-permanently').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const userId = btn.getAttribute('data-user-id');
|
|
const username = btn.getAttribute('data-username');
|
|
|
|
if (deleteUserNameEl) deleteUserNameEl.textContent = username;
|
|
// Ensure single-item mode (remove bulk state if any)
|
|
detachBulkHandler(confirmDeleteBtn);
|
|
if (confirmDeleteBtn) {
|
|
confirmDeleteBtn.href = '{$smarty.const.WWW_TOP}/admin/deleted-users/permanent-delete/' + userId;
|
|
}
|
|
if (deleteUserModal) deleteUserModal.show();
|
|
});
|
|
});
|
|
|
|
// Restore user buttons (single item)
|
|
document.querySelectorAll('.restore-user').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const userId = btn.getAttribute('data-user-id');
|
|
const username = btn.getAttribute('data-username');
|
|
|
|
if (restoreUserNameEl) restoreUserNameEl.textContent = username;
|
|
detachBulkHandler(confirmRestoreBtn);
|
|
if (confirmRestoreBtn) {
|
|
confirmRestoreBtn.href = '{$smarty.const.WWW_TOP}/admin/deleted-users/restore/' + userId;
|
|
}
|
|
if (restoreUserModal) restoreUserModal.show();
|
|
});
|
|
});
|
|
|
|
// --- Bulk selection logic ---
|
|
const bulkForm = document.getElementById('bulk-action-form');
|
|
const bulkSelect = document.getElementById('bulk-action-select');
|
|
const bulkSubmit = document.getElementById('bulk-action-submit');
|
|
const masterCheckbox = document.getElementById('master-checkbox');
|
|
const selectAllBtn = document.getElementById('select-all');
|
|
const deselectAllBtn = document.getElementById('deselect-all');
|
|
const invertSelectionBtn = document.getElementById('invert-selection');
|
|
|
|
function getRowCheckboxes() {
|
|
return Array.from(document.querySelectorAll('.row-checkbox'));
|
|
}
|
|
|
|
function updateBulkSubmitState() {
|
|
if (!bulkSubmit || !bulkSelect) return;
|
|
const anyChecked = getRowCheckboxes().some(cb => cb.checked);
|
|
bulkSubmit.disabled = !anyChecked || !bulkSelect.value;
|
|
}
|
|
|
|
function updateMasterCheckbox() {
|
|
if (!masterCheckbox) return;
|
|
const checkboxes = getRowCheckboxes();
|
|
if (checkboxes.length === 0) {
|
|
masterCheckbox.checked = false;
|
|
masterCheckbox.indeterminate = false;
|
|
return;
|
|
}
|
|
|
|
const checkedCount = checkboxes.filter(cb => cb.checked).length;
|
|
if (checkedCount === 0) {
|
|
masterCheckbox.checked = false;
|
|
masterCheckbox.indeterminate = false;
|
|
} else if (checkedCount === checkboxes.length) {
|
|
masterCheckbox.checked = true;
|
|
masterCheckbox.indeterminate = false;
|
|
} else {
|
|
masterCheckbox.checked = false;
|
|
masterCheckbox.indeterminate = true;
|
|
}
|
|
}
|
|
|
|
// Master checkbox click handler
|
|
if (masterCheckbox) {
|
|
masterCheckbox.addEventListener('change', function() {
|
|
const checkboxes = getRowCheckboxes();
|
|
checkboxes.forEach(cb => cb.checked = this.checked);
|
|
updateBulkSubmitState();
|
|
});
|
|
}
|
|
|
|
// Individual checkbox change handler
|
|
document.addEventListener('change', function(e) {
|
|
if (e.target.classList.contains('row-checkbox')) {
|
|
updateMasterCheckbox();
|
|
updateBulkSubmitState();
|
|
}
|
|
});
|
|
|
|
// Select All button
|
|
if (selectAllBtn) {
|
|
selectAllBtn.addEventListener('click', function() {
|
|
const checkboxes = getRowCheckboxes();
|
|
checkboxes.forEach(cb => cb.checked = true);
|
|
updateMasterCheckbox();
|
|
updateBulkSubmitState();
|
|
});
|
|
}
|
|
|
|
// Deselect All button
|
|
if (deselectAllBtn) {
|
|
deselectAllBtn.addEventListener('click', function() {
|
|
const checkboxes = getRowCheckboxes();
|
|
checkboxes.forEach(cb => cb.checked = false);
|
|
updateMasterCheckbox();
|
|
updateBulkSubmitState();
|
|
});
|
|
}
|
|
|
|
// Invert Selection button
|
|
if (invertSelectionBtn) {
|
|
invertSelectionBtn.addEventListener('click', function() {
|
|
const checkboxes = getRowCheckboxes();
|
|
checkboxes.forEach(cb => cb.checked = !cb.checked);
|
|
updateMasterCheckbox();
|
|
updateBulkSubmitState();
|
|
});
|
|
}
|
|
|
|
// Bulk action select change handler
|
|
if (bulkSelect) {
|
|
bulkSelect.addEventListener('change', updateBulkSubmitState);
|
|
}
|
|
|
|
// Helper to gather usernames for selected user IDs
|
|
function getSelectedUsernames() {
|
|
const selected = getRowCheckboxes().filter(cb => cb.checked).map(cb => cb.value);
|
|
return selected.map(id => {
|
|
// Try to find a restore or delete button with matching user-id to read username
|
|
const btn = document.querySelector('.restore-user[data-user-id="' + id + '"]') || document.querySelector('.delete-permanently[data-user-id="' + id + '"]');
|
|
return btn ? btn.getAttribute('data-username') : null;
|
|
}).filter(Boolean);
|
|
}
|
|
|
|
// Intercept bulk form submission to use modals instead of window.confirm
|
|
if (bulkForm) {
|
|
bulkForm.addEventListener('submit', function(e) {
|
|
const action = bulkSelect ? bulkSelect.value : '';
|
|
if (!action) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
const selectedCheckboxes = getRowCheckboxes().filter(cb => cb.checked);
|
|
if (selectedCheckboxes.length === 0) {
|
|
e.preventDefault();
|
|
alert('Please select at least one user.');
|
|
return;
|
|
}
|
|
// We replace native confirm with bootstrap modal
|
|
e.preventDefault();
|
|
const usernames = getSelectedUsernames();
|
|
const multiple = usernames.length > 1;
|
|
if (action === 'restore') {
|
|
if (restoreUserNameEl) {
|
|
restoreUserNameEl.textContent = multiple ? usernames.length + ' selected user(s)' : (usernames[0] || '1 user');
|
|
}
|
|
attachBulkHandler(confirmRestoreBtn, bulkForm);
|
|
if (restoreUserModal) restoreUserModal.show();
|
|
} else if (action === 'delete') {
|
|
if (deleteUserNameEl) {
|
|
deleteUserNameEl.textContent = multiple ? usernames.length + ' selected user(s)' : (usernames[0] || '1 user');
|
|
}
|
|
attachBulkHandler(confirmDeleteBtn, bulkForm);
|
|
if (deleteUserModal) deleteUserModal.show();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Confirm buttons: handle bulk mode submission
|
|
if (confirmDeleteBtn) {
|
|
confirmDeleteBtn.addEventListener('click', function(e) {
|
|
if (this.dataset.bulk) {
|
|
e.preventDefault();
|
|
// Submit the form for bulk delete
|
|
if (bulkForm) bulkForm.submit();
|
|
// After submission (navigation imminent), clean up state just in case
|
|
detachBulkHandler(this);
|
|
}
|
|
});
|
|
}
|
|
if (confirmRestoreBtn) {
|
|
confirmRestoreBtn.addEventListener('click', function(e) {
|
|
if (this.dataset.bulk) {
|
|
e.preventDefault();
|
|
if (bulkForm) bulkForm.submit();
|
|
detachBulkHandler(this);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize states
|
|
updateMasterCheckbox();
|
|
updateBulkSubmitState();
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.selection-toolbar .btn {
|
|
--bs-btn-padding-y: .35rem;
|
|
--bs-btn-padding-x: .7rem;
|
|
--bs-btn-font-size: .75rem;
|
|
transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
|
|
}
|
|
.selection-toolbar .btn i { font-size: .9rem; }
|
|
.selection-toolbar .btn-outline-primary:hover { background:#0d6efd; color:#fff; }
|
|
.selection-toolbar .btn-outline-secondary:hover { background:#6c757d; color:#fff; }
|
|
.selection-toolbar .btn-outline-warning:hover { background:#ffc107; color:#212529; }
|
|
.selection-toolbar .btn:focus { box-shadow: 0 0 0 .15rem rgba(13,110,253,.25); }
|
|
@media (max-width: 575.98px){
|
|
.selection-toolbar .btn span { display:none; }
|
|
.selection-toolbar .btn { --bs-btn-padding-x: .55rem; }
|
|
}
|
|
</style>
|