mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-10 14:00:12 +08:00
feat(ui): add quick action settings persistence and improve command form handling
- Add localStorage persistence for quick action checkboxes and log level - Implement collectAllFormValues method for comprehensive form data collection - Simplify config initialization to create empty config.yml instead of copying sample - Update command section handling to use all form values for proper saving
This commit is contained in:
parent
b2ee109dfe
commit
0b540b8d8a
5 changed files with 136 additions and 13 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
4.5.6-develop5
|
4.5.6-develop6
|
||||||
|
|
|
@ -300,7 +300,7 @@ def ensure_config_dir_initialized(config_dir) -> str:
|
||||||
Ensure the config directory exists and is initialized:
|
Ensure the config directory exists and is initialized:
|
||||||
- Creates the config directory
|
- Creates the config directory
|
||||||
- Creates logs/ and .backups/ subdirectories
|
- Creates logs/ and .backups/ subdirectories
|
||||||
- Seeds a default config.yml from bundled config/config.yml.sample if no *.yml/*.yaml present
|
- Creates an empty config.yml if no *.yml/*.yaml present
|
||||||
Returns the absolute config directory as a string.
|
Returns the absolute config directory as a string.
|
||||||
"""
|
"""
|
||||||
p = Path(config_dir).expanduser().resolve()
|
p = Path(config_dir).expanduser().resolve()
|
||||||
|
@ -310,14 +310,12 @@ def ensure_config_dir_initialized(config_dir) -> str:
|
||||||
|
|
||||||
has_yaml = any(p.glob("*.yml")) or any(p.glob("*.yaml"))
|
has_yaml = any(p.glob("*.yml")) or any(p.glob("*.yaml"))
|
||||||
if not has_yaml:
|
if not has_yaml:
|
||||||
sample = runtime_path("config", "config.yml.sample")
|
dest = p / "config.yml"
|
||||||
if sample.exists():
|
try:
|
||||||
dest = p / "config.yml"
|
dest.touch() # Create empty file
|
||||||
try:
|
except Exception:
|
||||||
shutil.copyfile(sample, dest)
|
# Non-fatal; if creation fails, user can create a config manually
|
||||||
except Exception:
|
pass
|
||||||
# Non-fatal; if copy fails, user can create a config manually
|
|
||||||
pass
|
|
||||||
|
|
||||||
return str(p)
|
return str(p)
|
||||||
|
|
||||||
|
|
|
@ -225,8 +225,6 @@ class QbitManageApp {
|
||||||
this.backupConfig();
|
this.backupConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Theme toggle is handled by ThemeManager
|
|
||||||
|
|
||||||
// Undo button
|
// Undo button
|
||||||
const undoBtn = get('undo-btn');
|
const undoBtn = get('undo-btn');
|
||||||
if (undoBtn) {
|
if (undoBtn) {
|
||||||
|
@ -442,7 +440,15 @@ class QbitManageApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const processedData = this.configForm._postprocessDataForSave(this.currentSection, this.configForm.currentData);
|
// For commands section, collect all form values since commands should override env vars
|
||||||
|
let dataToProcess;
|
||||||
|
if (this.currentSection === 'commands') {
|
||||||
|
dataToProcess = this.configForm.collectAllFormValues(this.currentSection);
|
||||||
|
} else {
|
||||||
|
dataToProcess = this.configForm.currentData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedData = this.configForm._postprocessDataForSave(this.currentSection, dataToProcess);
|
||||||
|
|
||||||
const isMultiRoot = this.configForm.schemas[this.currentSection]?.type === 'multi-root-object';
|
const isMultiRoot = this.configForm.schemas[this.currentSection]?.type === 'multi-root-object';
|
||||||
const dataToSave = isMultiRoot ? processedData : { [this.currentSection]: processedData };
|
const dataToSave = isMultiRoot ? processedData : { [this.currentSection]: processedData };
|
||||||
|
|
|
@ -141,6 +141,9 @@ class CommandPanel {
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Load saved quick action values after rendering
|
||||||
|
this.loadQuickActionValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
|
@ -175,6 +178,9 @@ class CommandPanel {
|
||||||
this.showRunCommandsModal();
|
this.showRunCommandsModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bind quick action input change events for persistence
|
||||||
|
this.bindQuickActionPersistence();
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeQuickCommand(command) {
|
async executeQuickCommand(command) {
|
||||||
|
@ -475,6 +481,74 @@ class CommandPanel {
|
||||||
this.show();
|
this.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load saved quick action values from localStorage
|
||||||
|
loadQuickActionValues() {
|
||||||
|
if (!this.drawerContainer) return;
|
||||||
|
|
||||||
|
// Get saved values, defaulting dry run to true if not previously saved
|
||||||
|
const savedDryRunValue = localStorage.getItem('qbm-quick-dry-run');
|
||||||
|
const savedDryRun = savedDryRunValue !== null ? savedDryRunValue === 'true' : true; // Default to true
|
||||||
|
const savedSkipCleanup = localStorage.getItem('qbm-quick-skip-cleanup') === 'true';
|
||||||
|
const savedSkipQbVersionCheck = localStorage.getItem('qbm-quick-skip-qb-version-check') === 'true';
|
||||||
|
const savedLogLevel = localStorage.getItem('qbm-quick-log-level') || '';
|
||||||
|
|
||||||
|
const dryRunCheckbox = this.drawerContainer.querySelector('#dry-run-checkbox');
|
||||||
|
const skipCleanupCheckbox = this.drawerContainer.querySelector('#quick-skip-cleanup-checkbox');
|
||||||
|
const skipQbVersionCheckCheckbox = this.drawerContainer.querySelector('#quick-skip-qb-version-check-checkbox');
|
||||||
|
const logLevelSelect = this.drawerContainer.querySelector('#quick-log-level-select');
|
||||||
|
|
||||||
|
if (dryRunCheckbox) dryRunCheckbox.checked = savedDryRun;
|
||||||
|
if (skipCleanupCheckbox) skipCleanupCheckbox.checked = savedSkipCleanup;
|
||||||
|
if (skipQbVersionCheckCheckbox) skipQbVersionCheckCheckbox.checked = savedSkipQbVersionCheck;
|
||||||
|
if (logLevelSelect) logLevelSelect.value = savedLogLevel;
|
||||||
|
|
||||||
|
// Save the default value if it was set
|
||||||
|
if (savedDryRunValue === null) {
|
||||||
|
localStorage.setItem('qbm-quick-dry-run', 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save quick action values to localStorage
|
||||||
|
saveQuickActionValues() {
|
||||||
|
if (!this.drawerContainer) return;
|
||||||
|
|
||||||
|
const dryRunCheckbox = this.drawerContainer.querySelector('#dry-run-checkbox');
|
||||||
|
const skipCleanupCheckbox = this.drawerContainer.querySelector('#quick-skip-cleanup-checkbox');
|
||||||
|
const skipQbVersionCheckCheckbox = this.drawerContainer.querySelector('#quick-skip-qb-version-check-checkbox');
|
||||||
|
const logLevelSelect = this.drawerContainer.querySelector('#quick-log-level-select');
|
||||||
|
|
||||||
|
const dryRun = dryRunCheckbox ? dryRunCheckbox.checked : false;
|
||||||
|
const skipCleanup = skipCleanupCheckbox ? skipCleanupCheckbox.checked : false;
|
||||||
|
const skipQbVersionCheck = skipQbVersionCheckCheckbox ? skipQbVersionCheckCheckbox.checked : false;
|
||||||
|
const logLevel = logLevelSelect ? logLevelSelect.value : '';
|
||||||
|
|
||||||
|
localStorage.setItem('qbm-quick-dry-run', dryRun);
|
||||||
|
localStorage.setItem('qbm-quick-skip-cleanup', skipCleanup);
|
||||||
|
localStorage.setItem('qbm-quick-skip-qb-version-check', skipQbVersionCheck);
|
||||||
|
localStorage.setItem('qbm-quick-log-level', logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind event listeners for quick action persistence
|
||||||
|
bindQuickActionPersistence() {
|
||||||
|
if (!this.drawerContainer) return;
|
||||||
|
|
||||||
|
// Bind checkbox change events
|
||||||
|
const checkboxes = this.drawerContainer.querySelectorAll('#dry-run-checkbox, #quick-skip-cleanup-checkbox, #quick-skip-qb-version-check-checkbox');
|
||||||
|
checkboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', () => {
|
||||||
|
this.saveQuickActionValues();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind select change event
|
||||||
|
const logLevelSelect = this.drawerContainer.querySelector('#quick-log-level-select');
|
||||||
|
if (logLevelSelect) {
|
||||||
|
logLevelSelect.addEventListener('change', () => {
|
||||||
|
this.saveQuickActionValues();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CommandPanel };
|
export { CommandPanel };
|
||||||
|
|
|
@ -1302,6 +1302,51 @@ class ConfigForm {
|
||||||
* @param {object} obj - The object to clean up.
|
* @param {object} obj - The object to clean up.
|
||||||
* @returns {object} The cleaned up object.
|
* @returns {object} The cleaned up object.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Collects all current form values for a section, not just dirty ones
|
||||||
|
* This is used for sections like commands where we want to save all values
|
||||||
|
*/
|
||||||
|
collectAllFormValues(sectionName) {
|
||||||
|
const sectionConfig = this.schemas[sectionName];
|
||||||
|
if (!sectionConfig || !sectionConfig.fields) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const allValues = {};
|
||||||
|
|
||||||
|
// Iterate through all fields in the schema
|
||||||
|
sectionConfig.fields.forEach(field => {
|
||||||
|
if (field.name && field.type !== 'documentation' && field.type !== 'section_header') {
|
||||||
|
// Find the corresponding form input
|
||||||
|
const input = this.container.querySelector(`[name="${field.name}"]`);
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if (input.type === 'checkbox') {
|
||||||
|
value = input.checked;
|
||||||
|
} else if (input.type === 'number') {
|
||||||
|
value = input.value ? parseFloat(input.value) : null;
|
||||||
|
} else {
|
||||||
|
value = input.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle default values for boolean fields
|
||||||
|
if (field.type === 'boolean' && value === null) {
|
||||||
|
value = field.default || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
allValues[field.name] = value;
|
||||||
|
} else if (field.default !== undefined) {
|
||||||
|
// Use default value if input not found
|
||||||
|
allValues[field.name] = field.default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return allValues;
|
||||||
|
}
|
||||||
|
|
||||||
cleanupEmptyValues(obj) {
|
cleanupEmptyValues(obj) {
|
||||||
if (obj === null || obj === undefined) {
|
if (obj === null || obj === undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Add table
Reference in a new issue