qbit_manage/web-ui/js/utils/utils.js
bobokun 3fa5fcee3b
v4.5.0 (#862)
# Requirements Updated
- fastapi==0.116.0
- retrying==1.4.0
- uvicorn==0.35.0

# New Features
- **Web UI**: Introduced a new Web UI for configuring and managing qBit
Manage.
  - Visual Configuration Editor for YAML files.
  - Command Execution directly from the UI.
  - Undo/Redo History for changes.
  - Theme Support (light/dark mode).
  - Responsive Design for desktop and mobile.
  - Real-time YAML Preview.
- Pass skip qbitorrent check as optional parameter to the API (Adds
#860)\


**Full Changelog**:
https://github.com/StuffAnThings/qbit_manage/compare/v4.4.0...v4.5.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ineednewpajamas <73252768+ineednewpajamas@users.noreply.github.com>
2025-07-11 19:13:41 -04:00

67 lines
2.3 KiB
JavaScript

/**
* General Utility Module
* Provides common utility functions.
*/
/**
* Gets a nested value from an object using a dot-separated path.
* @param {object} obj - The object to query.
* @param {string} path - The dot-separated path (e.g., 'parent.child.property').
* @returns {*} The value at the specified path, or undefined if not found.
*/
export function getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
/**
* Sets a nested value in an object using a dot-separated path.
* Creates intermediate objects if they don't exist.
* If the value is null, undefined, or an empty string, the property is deleted.
* @param {object} obj - The object to modify.
* @param {string} path - The dot-separated path (e.g., 'parent.child.property').
* @param {*} value - The value to set.
*/
export function setNestedValue(obj, path, value) {
const keys = path.split('.');
const lastKey = keys.pop();
const target = keys.reduce((current, key) => {
if (!current[key] || typeof current[key] !== 'object') {
current[key] = {};
}
return current[key];
}, obj);
if (value === null || value === undefined || value === '') {
delete target[lastKey];
} else {
target[lastKey] = value;
}
}
/**
* Basic host validation - IP address or hostname
* @param {string} host - The host string to validate.
* @returns {boolean} True if the host is valid, false otherwise.
*/
export function isValidHost(host) {
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/;
return ipRegex.test(host) || hostnameRegex.test(host) || host === 'localhost';
}
/**
* Debounces a function, so it only runs after a specified delay.
* @param {function} func - The function to debounce.
* @param {number} delay - The delay in milliseconds.
* @returns {function} The debounced function.
*/
export function debounce(func, delay) {
let timeout;
return function(...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
}