mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 13:29:15 +08:00
# Requirements Updated - "retrying==1.4.2", # New Features - **Web UI**: Implement dynamic schedule management via web UI/API - **Share Limits**: Add limit upload speed when share limits are reached (New config option: `upload_speed_on_limit_reached`) (Fixes #731, #737, #703) - **Share Limits**: Add min/max torrent size filters (New config option: `min_torrent_size` / `max_torrent_size`) (Fixes #472) - **Remove Unregistered**: Add grace period for unregistered torrent removal (New config option: `rem_unregistered_grace_minutes`) (Fixes #898) - **Scheduler (Web API)**: Implement dynamic schedule management via web API # Improvements - **Mover Script**: Allow granular control with pause, resume and move args - **web UI**: When saving, don’t delete config comments and empty lines (Fixes #890) # Bug Fixes - Fix Error acquiring lock: cannot assign to field '_last_run_start' (Fixes #895) - Fix remove_orphaned not working correctly with `remote_dir` and reporting 0 files removed - fix(web-ui): prevent XSS vulnerabilities and prototype pollution - Potential fix for code scanning alert no. 13: Client-side cross-site scripting (#896) **Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.5.2...v4.5.3 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
77 lines
2.3 KiB
JavaScript
77 lines
2.3 KiB
JavaScript
/**
|
||
* Toast Utility Module
|
||
* Manages the display of toast notifications.
|
||
*/
|
||
|
||
import { get, show, hide } from './dom.js';
|
||
import { CLOSE_ICON_SVG } from './icons.js';
|
||
|
||
const TOAST_CONTAINER_ID = 'toast-container';
|
||
|
||
/**
|
||
* Displays a toast notification.
|
||
* @param {string} message - The message to display in the toast.
|
||
* @param {'success'|'error'|'warning'|'info'} [type='info'] - The type of toast (for styling).
|
||
* @param {number} [duration=5000] - How long the toast should be visible in milliseconds.
|
||
*/
|
||
export function showToast(message, type = 'info', duration = 5000) {
|
||
const container = get(TOAST_CONTAINER_ID);
|
||
if (!container) {
|
||
console.warn('Toast container not found. Cannot display toast message.');
|
||
return;
|
||
}
|
||
|
||
const toast = document.createElement('div');
|
||
toast.className = `toast toast-${type}`;
|
||
|
||
const icons = {
|
||
success: '✓',
|
||
error: '✕',
|
||
warning: '⚠',
|
||
info: 'ℹ',
|
||
undo: '↶',
|
||
redo: '↷'
|
||
};
|
||
|
||
// Build static structure with innerHTML, then set message via textContent
|
||
toast.innerHTML = `
|
||
<div class="toast-icon">${icons[type] || icons.info}</div>
|
||
<div class="toast-content">
|
||
<div class="toast-message"></div>
|
||
</div>
|
||
<button class="btn btn-icon btn-close-icon toast-close">
|
||
${CLOSE_ICON_SVG}
|
||
</button>
|
||
`;
|
||
// Insert message safely without relying on HTML escaping
|
||
const msgNode = toast.querySelector('.toast-message');
|
||
if (msgNode) {
|
||
msgNode.textContent = message == null ? '' : String(message);
|
||
}
|
||
|
||
container.appendChild(toast);
|
||
|
||
// Show toast (add 'show' class to trigger transition)
|
||
setTimeout(() => {
|
||
toast.classList.add('show');
|
||
}, 100);
|
||
|
||
// Auto-hide toast
|
||
const hideToast = () => {
|
||
toast.classList.remove('show');
|
||
// Remove from DOM after transition
|
||
toast.addEventListener('transitionend', () => {
|
||
if (toast.parentElement) {
|
||
toast.remove();
|
||
}
|
||
}, { once: true });
|
||
};
|
||
|
||
setTimeout(hideToast, duration);
|
||
|
||
// Close button event
|
||
const closeButton = toast.querySelector('.toast-close');
|
||
if (closeButton) {
|
||
closeButton.addEventListener('click', hideToast);
|
||
}
|
||
}
|