try fix download cleaner again

This commit is contained in:
Flaminel
2025-06-11 00:28:29 +03:00
parent 0ab5c01ebc
commit d73cb46006
3 changed files with 80 additions and 59 deletions

View File

@@ -68,7 +68,7 @@ export class DownloadCleanerConfigStore {
this._saving.set(true);
this._error.set(null);
return new Promise<boolean>((resolve) => {
return new Promise<boolean>((resolve, reject) => {
// API call to update download cleaner config
this.http.put<any>(`${this.apiUrl}/download_cleaner`, config)
.pipe(
@@ -87,9 +87,8 @@ export class DownloadCleanerConfigStore {
console.error('Error saving download cleaner config', error);
const errorMessage = error.error?.message || error.message || 'Unknown error';
this._error.set(`Failed to save download cleaner configuration: ${errorMessage}`);
// Show error notification
this.notificationService.showError(`Failed to save: ${errorMessage}`);
resolve(false);
// Let the component handle the error notification
reject(error); // Pass the original error to preserve all details
}
});
});

View File

@@ -132,8 +132,8 @@
decrementButtonClass="p-button-danger" incrementButtonClass="p-button-success" incrementButtonIcon="pi pi-plus"
decrementButtonIcon="pi pi-minus">
</p-inputNumber>
<small class="form-helper-text">Maximum ratio to seed before removing (<code>-1</code> means disabled)</small>
<small *ngIf="hasCategoryError(i, 'maxRatio', 'min')" class="p-error block">Min value is -1</small>
<small class="form-helper-text">Maximum ratio to seed before removing (<code>-1</code> means disabled)</small>
</div>
</div>
@@ -145,6 +145,7 @@
decrementButtonIcon="pi pi-minus">
</p-inputNumber>
<small *ngIf="hasCategoryError(i, 'minSeedTime', 'min')" class="p-error block">Min value is 0</small>
<small class="form-helper-text">Minimum time to seed before removing a download that has reached the max ratio (<code>0</code> means disabled)</small>
</div>
</div>
@@ -162,6 +163,10 @@
</div>
</div>
</div>
<!-- Error for both maxRatio and maxSeedTime disabled -->
<small *ngIf="hasCategoryGroupError(i, 'bothDisabled')" class="p-error block">
Both max ratio and max seed time cannot be disabled at the same time
</small>
</div>
</div>

View File

@@ -1,6 +1,6 @@
import { Component, EventEmitter, OnDestroy, Output, inject, effect } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormArray, FormBuilder, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms";
import { FormArray, FormBuilder, FormGroup, ReactiveFormsModule, ValidationErrors, Validators } from "@angular/forms";
import { Subject, takeUntil } from "rxjs";
import { DownloadCleanerConfigStore } from "./download-cleaner-config.store";
import { CanComponentDeactivate } from "../../core/guards";
@@ -165,19 +165,40 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
/**
* Add a new category to the form array
*/
addCategory(): void {
const defaultCategory = createDefaultCategory();
const categoryGroup = this.formBuilder.group({
name: [defaultCategory.name, [Validators.required]],
maxRatio: [defaultCategory.maxRatio, [Validators.min(-1)]],
minSeedTime: [defaultCategory.minSeedTime, [Validators.min(0)]],
maxSeedTime: [defaultCategory.maxSeedTime, [Validators.min(-1)]]
});
addCategory(category: CleanCategory = createDefaultCategory()): void {
// Create a form group for the category with validation and add it to the form array
const categoryGroup = this.createCategoryFormGroup(category);
this.categoriesFormArray.push(categoryGroup);
this.downloadCleanerForm.markAsDirty();
}
/**
* Create a category form group with validation
*/
private createCategoryFormGroup(category: CleanCategory): FormGroup {
return this.formBuilder.group({
name: [category.name, Validators.required],
maxRatio: [category.maxRatio],
minSeedTime: [category.minSeedTime, [Validators.min(0)]],
maxSeedTime: [category.maxSeedTime],
}, { validators: this.validateCategory });
}
/**
* Custom validator for the "both disabled" rule in categories
*/
private validateCategory(group: FormGroup): ValidationErrors | null {
const maxRatio = group.get('maxRatio')?.value;
const maxSeedTime = group.get('maxSeedTime')?.value;
if (maxRatio < 0 && maxSeedTime < 0) {
return { bothDisabled: true };
}
return null;
}
/**
* Helper method to get a category control as FormGroup for the template
*/
@@ -193,26 +214,19 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
this.downloadCleanerForm.markAsDirty();
}
/**
* Update the form with values from the configuration
*/
private updateForm(config: DownloadCleanerConfig): void {
// Clear existing categories
while (this.categoriesFormArray.length > 0) {
this.categoriesFormArray.removeAt(0);
}
// Reset any existing categories
this.categoriesFormArray.clear();
// Add categories from config
// Add categories from config with validation
if (config.categories && config.categories.length > 0) {
config.categories.forEach(category => {
const categoryGroup = this.formBuilder.group({
name: [category.name, [Validators.required]],
maxRatio: [category.maxRatio, [Validators.min(-1)]],
minSeedTime: [category.minSeedTime, [Validators.min(0)]],
maxSeedTime: [category.maxSeedTime, [Validators.min(-1)]]
});
this.categoriesFormArray.push(categoryGroup);
this.addCategory(category);
});
}
@@ -461,42 +475,37 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
// Save the configuration
this.downloadCleanerStore.saveDownloadCleanerConfig(config)
.then(success => {
if (success) {
// Show success message
this.notificationService.showSuccess('Download cleaner configuration saved successfully.');
// Emit saved event for parent components
this.saved.emit();
// Setup a one-time check to mark form as pristine after successful save
const checkSaveCompletion = () => {
const saving = this.downloadCleanerSaving();
const error = this.downloadCleanerError();
if (!saving && !error) {
// Reset form state after successful save
this.downloadCleanerForm.markAsPristine();
this.storeOriginalValues();
} else if (!saving && error) {
// If there's an error, we can stop checking
// No need to show error toast here, it's handled by the LoadingErrorStateComponent
} else {
// If still saving, check again in a moment
setTimeout(checkSaveCompletion, 100);
}
};
// Start checking for save completion
checkSaveCompletion();
.then(() => {
this.notificationService.showSuccess('Download cleaner configuration saved successfully');
this.saved.emit();
this.storeOriginalValues();
this.downloadCleanerForm.markAsPristine();
this.hasActualChanges = false;
})
.catch((err) => {
console.error('Failed to save download cleaner config', err);
// Extract meaningful message from error response for toast notification
let errorMessage = 'Failed to save download cleaner configuration';
// If it's a 400 error with a message, use that message
if (err && err.status === 400) {
if (typeof err.error === 'string') {
errorMessage = err.error;
} else if (err.error && err.error.message) {
errorMessage = err.error.message;
} else if (err.error && err.error.title) {
errorMessage = err.error.title;
} else if (err.message) {
errorMessage = err.message;
}
}
this.notificationService.showError(errorMessage);
this.error.emit(errorMessage);
});
} else {
// Form is invalid, show error message
this.notificationService.showValidationError();
// Emit error for parent components
this.error.emit("Please fix validation errors before saving.");
}
}
@@ -600,6 +609,14 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
const control = categoryGroup.get(controlName);
return control ? control.touched && control.hasError(errorName) : false;
}
/**
* Check if a category form group itself has an error (not tied to a specific control)
*/
hasCategoryGroupError(categoryIndex: number, errorName: string): boolean {
const categoryGroup = this.categoriesFormArray.at(categoryIndex);
return categoryGroup ? categoryGroup.touched && categoryGroup.hasError(errorName) : false;
}
/**
* Update the state of unlinked controls based on whether unlinked handling is enabled