mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-03-04 14:27:52 -05:00
try fix settings enablement
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": true,
|
||||
|
||||
@@ -19,16 +19,14 @@
|
||||
[min]="1"
|
||||
[max]="59"
|
||||
buttonLayout="horizontal"
|
||||
inputStyleClass="schedule-value"
|
||||
[disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
inputStyleClass="schedule-value">
|
||||
</p-inputNumber>
|
||||
|
||||
<p-selectButton
|
||||
formControlName="type"
|
||||
[options]="scheduleUnitOptions"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
[disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
optionValue="value">
|
||||
</p-selectButton>
|
||||
</div>
|
||||
<small class="form-helper-text">How often the queue cleaner should run</small>
|
||||
@@ -37,7 +35,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Run Sequentially</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="runSequentially" [binary]="true" inputId="qcRunSequentially" [disabled]="!queueCleanerForm.get('enabled')?.value"></p-checkbox>
|
||||
<p-checkbox formControlName="runSequentially" [binary]="true" inputId="qcRunSequentially"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, jobs will run one after another instead of in parallel</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +43,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Ignored Downloads Path</label>
|
||||
<div class="field-input">
|
||||
<input pInputText formControlName="ignoredDownloadsPath" [disabled]="!queueCleanerForm.get('enabled')?.value" />
|
||||
<input pInputText formControlName="ignoredDownloadsPath" />
|
||||
<small class="form-helper-text">Path to the file containing ignored downloads</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,7 +51,7 @@
|
||||
<!-- Detailed Settings in Accordion -->
|
||||
<p-accordion [multiple]="true" styleClass="mt-3">
|
||||
<!-- Failed Import Settings -->
|
||||
<p-accordionTab header="Failed Import Settings" [disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
<p-accordionTab header="Failed Import Settings">
|
||||
<div class="field-row">
|
||||
<label class="field-label">Max Strikes</label>
|
||||
<div class="field-input">
|
||||
@@ -71,7 +69,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Ignore Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="failedImportIgnorePrivate" [binary]="true" [disabled]="queueCleanerForm.get('failedImportMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="failedImportIgnorePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be ignored</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,7 +77,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Delete Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="failedImportDeletePrivate" [binary]="true" [disabled]="queueCleanerForm.get('failedImportMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="failedImportDeletePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be deleted</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,14 +85,14 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Ignore Patterns</label>
|
||||
<div class="field-input">
|
||||
<p-chips formControlName="failedImportIgnorePatterns" [disabled]="queueCleanerForm.get('failedImportMaxStrikes')?.value < 3" placeholder="Add pattern and press Enter"></p-chips>
|
||||
<p-chips formControlName="failedImportIgnorePatterns" placeholder="Add pattern and press Enter"></p-chips>
|
||||
<small class="form-helper-text">Patterns to ignore (e.g., *sample*)</small>
|
||||
</div>
|
||||
</div>
|
||||
</p-accordionTab>
|
||||
|
||||
<!-- Stalled Settings -->
|
||||
<p-accordionTab header="Stalled Download Settings" [disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
<p-accordionTab header="Stalled Download Settings">
|
||||
<div class="field-row">
|
||||
<label class="field-label">Max Strikes</label>
|
||||
<div class="field-input">
|
||||
@@ -112,7 +110,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Reset Strikes On Progress</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="stalledResetStrikesOnProgress" [binary]="true" [disabled]="queueCleanerForm.get('stalledMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="stalledResetStrikesOnProgress" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, strikes will be reset if download progress is made</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -120,7 +118,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Ignore Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="stalledIgnorePrivate" [binary]="true" [disabled]="queueCleanerForm.get('stalledMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="stalledIgnorePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be ignored</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,14 +126,14 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Delete Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="stalledDeletePrivate" [binary]="true" [disabled]="queueCleanerForm.get('stalledMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="stalledDeletePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be deleted</small>
|
||||
</div>
|
||||
</div>
|
||||
</p-accordionTab>
|
||||
|
||||
<!-- Downloading Metadata Settings -->
|
||||
<p-accordionTab header="Downloading Metadata Settings" [disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
<p-accordionTab header="Downloading Metadata Settings">
|
||||
<div class="field-row">
|
||||
<label class="field-label">Max Strikes</label>
|
||||
<div class="field-input">
|
||||
@@ -152,7 +150,7 @@
|
||||
</p-accordionTab>
|
||||
|
||||
<!-- Slow Download Settings -->
|
||||
<p-accordionTab header="Slow Download Settings" [disabled]="!queueCleanerForm.get('enabled')?.value">
|
||||
<p-accordionTab header="Slow Download Settings">
|
||||
<div class="field-row">
|
||||
<label class="field-label">Max Strikes</label>
|
||||
<div class="field-input">
|
||||
@@ -170,7 +168,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Reset Strikes On Progress</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="slowResetStrikesOnProgress" [binary]="true" [disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="slowResetStrikesOnProgress" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, strikes will be reset if download progress is made</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,7 +176,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Ignore Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="slowIgnorePrivate" [binary]="true" [disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="slowIgnorePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be ignored</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -186,7 +184,7 @@
|
||||
<div class="field-row">
|
||||
<label class="field-label">Delete Private</label>
|
||||
<div class="field-input">
|
||||
<p-checkbox formControlName="slowDeletePrivate" [binary]="true" [disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3"></p-checkbox>
|
||||
<p-checkbox formControlName="slowDeletePrivate" [binary]="true"></p-checkbox>
|
||||
<small class="form-helper-text">When enabled, private torrents will be deleted</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +194,6 @@
|
||||
<div class="field-input">
|
||||
<app-byte-size-input
|
||||
formControlName="slowMinSpeed"
|
||||
[disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3"
|
||||
[min]="0"
|
||||
placeholder="Enter minimum speed"
|
||||
helpText="Minimum speed threshold for slow downloads (e.g., 100KB/s)">
|
||||
@@ -212,8 +209,7 @@
|
||||
[showButtons]="true"
|
||||
[min]="0"
|
||||
[max]="168"
|
||||
buttonLayout="horizontal"
|
||||
[disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3">
|
||||
buttonLayout="horizontal">
|
||||
</p-inputNumber>
|
||||
<small class="form-helper-text">Maximum time allowed for slow downloads (in hours)</small>
|
||||
</div>
|
||||
@@ -224,7 +220,6 @@
|
||||
<div class="field-input">
|
||||
<app-byte-size-input
|
||||
formControlName="slowIgnoreAboveSize"
|
||||
[disabled]="queueCleanerForm.get('slowMaxStrikes')?.value < 3"
|
||||
[min]="0"
|
||||
placeholder="Enter size threshold"
|
||||
helpText="Size threshold above which slow downloads are ignored">
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import { Component, EventEmitter, OnInit, Output, effect, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { QueueCleanerConfigStore } from './queue-cleaner-config.store';
|
||||
import { QueueCleanerConfig, ScheduleUnit } from '../../shared/models/queue-cleaner-config.model';
|
||||
import { SettingsCardComponent } from '../components/settings-card/settings-card.component';
|
||||
import { ByteSizeInputComponent } from '../../shared/components/byte-size-input/byte-size-input.component';
|
||||
import { Component, EventEmitter, OnDestroy, Output, effect, inject } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { QueueCleanerConfigStore } from "./queue-cleaner-config.store";
|
||||
import { QueueCleanerConfig, ScheduleUnit } from "../../shared/models/queue-cleaner-config.model";
|
||||
import { SettingsCardComponent } from "../components/settings-card/settings-card.component";
|
||||
import { ByteSizeInputComponent } from "../../shared/components/byte-size-input/byte-size-input.component";
|
||||
|
||||
// PrimeNG Components
|
||||
import { CardModule } from 'primeng/card';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputNumberModule } from 'primeng/inputnumber';
|
||||
import { AccordionModule } from 'primeng/accordion';
|
||||
import { SelectButtonModule } from 'primeng/selectbutton';
|
||||
import { ChipsModule } from 'primeng/chips';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { CardModule } from "primeng/card";
|
||||
import { InputTextModule } from "primeng/inputtext";
|
||||
import { CheckboxModule } from "primeng/checkbox";
|
||||
import { ButtonModule } from "primeng/button";
|
||||
import { InputNumberModule } from "primeng/inputnumber";
|
||||
import { AccordionModule } from "primeng/accordion";
|
||||
import { SelectButtonModule } from "primeng/selectbutton";
|
||||
import { ChipsModule } from "primeng/chips";
|
||||
import { ToastModule } from "primeng/toast";
|
||||
import { MessageService } from "primeng/api";
|
||||
|
||||
@Component({
|
||||
selector: 'app-queue-cleaner-settings',
|
||||
selector: "app-queue-cleaner-settings",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -34,75 +35,79 @@ import { MessageService } from 'primeng/api';
|
||||
SelectButtonModule,
|
||||
ChipsModule,
|
||||
ToastModule,
|
||||
ByteSizeInputComponent
|
||||
ByteSizeInputComponent,
|
||||
],
|
||||
providers: [QueueCleanerConfigStore, MessageService],
|
||||
templateUrl: './queue-cleaner-settings.component.html',
|
||||
styleUrls: ['./queue-cleaner-settings.component.scss']
|
||||
templateUrl: "./queue-cleaner-settings.component.html",
|
||||
styleUrls: ["./queue-cleaner-settings.component.scss"],
|
||||
})
|
||||
export class QueueCleanerSettingsComponent implements OnInit {
|
||||
export class QueueCleanerSettingsComponent implements OnDestroy {
|
||||
@Output() saved = new EventEmitter<void>();
|
||||
@Output() error = new EventEmitter<string>();
|
||||
|
||||
// Queue Cleaner Configuration Form
|
||||
queueCleanerForm: FormGroup;
|
||||
|
||||
|
||||
// Schedule unit options for job schedules
|
||||
scheduleUnitOptions = [
|
||||
{ label: 'Seconds', value: ScheduleUnit.Seconds },
|
||||
{ label: 'Minutes', value: ScheduleUnit.Minutes },
|
||||
{ label: 'Hours', value: ScheduleUnit.Hours }
|
||||
{ label: "Seconds", value: ScheduleUnit.Seconds },
|
||||
{ label: "Minutes", value: ScheduleUnit.Minutes },
|
||||
{ label: "Hours", value: ScheduleUnit.Hours },
|
||||
];
|
||||
|
||||
|
||||
// Inject the necessary services
|
||||
private formBuilder = inject(FormBuilder);
|
||||
private messageService = inject(MessageService);
|
||||
private queueCleanerStore = inject(QueueCleanerConfigStore);
|
||||
|
||||
|
||||
// Signals from the store
|
||||
readonly queueCleanerConfig = this.queueCleanerStore.config;
|
||||
readonly queueCleanerLoading = this.queueCleanerStore.loading;
|
||||
readonly queueCleanerSaving = this.queueCleanerStore.saving;
|
||||
readonly queueCleanerError = this.queueCleanerStore.error;
|
||||
|
||||
|
||||
// Subject for unsubscribing from observables when component is destroyed
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor() {
|
||||
// Initialize the queue cleaner form
|
||||
// Initialize the queue cleaner form with proper disabled states
|
||||
this.queueCleanerForm = this.formBuilder.group({
|
||||
enabled: [false],
|
||||
jobSchedule: this.formBuilder.group({
|
||||
every: [5, [Validators.required, Validators.min(1)]],
|
||||
type: [ScheduleUnit.Minutes]
|
||||
every: [{value: 5, disabled: true}, [Validators.required, Validators.min(1)]],
|
||||
type: [{value: ScheduleUnit.Minutes, disabled: true}],
|
||||
}),
|
||||
runSequentially: [false],
|
||||
ignoredDownloadsPath: [''],
|
||||
|
||||
runSequentially: [{value: false, disabled: true}],
|
||||
ignoredDownloadsPath: [{value: "", disabled: true}],
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: [0, [Validators.min(0)]],
|
||||
failedImportIgnorePrivate: [false],
|
||||
failedImportDeletePrivate: [false],
|
||||
failedImportIgnorePatterns: [[]],
|
||||
|
||||
failedImportIgnorePrivate: [{value: false, disabled: true}],
|
||||
failedImportDeletePrivate: [{value: false, disabled: true}],
|
||||
failedImportIgnorePatterns: [{value: [], disabled: true}],
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: [0, [Validators.min(0)]],
|
||||
stalledResetStrikesOnProgress: [false],
|
||||
stalledIgnorePrivate: [false],
|
||||
stalledDeletePrivate: [false],
|
||||
|
||||
stalledResetStrikesOnProgress: [{value: false, disabled: true}],
|
||||
stalledIgnorePrivate: [{value: false, disabled: true}],
|
||||
stalledDeletePrivate: [{value: false, disabled: true}],
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: [0, [Validators.min(0)]],
|
||||
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: [0, [Validators.min(0)]],
|
||||
slowResetStrikesOnProgress: [false],
|
||||
slowIgnorePrivate: [false],
|
||||
slowDeletePrivate: [false],
|
||||
slowMinSpeed: [''],
|
||||
slowMaxTime: [0, [Validators.min(0)]],
|
||||
slowIgnoreAboveSize: ['']
|
||||
slowResetStrikesOnProgress: [{value: false, disabled: true}],
|
||||
slowIgnorePrivate: [{value: false, disabled: true}],
|
||||
slowDeletePrivate: [{value: false, disabled: true}],
|
||||
slowMinSpeed: [{value: "", disabled: true}],
|
||||
slowMaxTime: [{value: 0, disabled: true}],
|
||||
slowIgnoreAboveSize: [{value: "", disabled: true}],
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
// Set up form control value change subscriptions to manage dependent control states
|
||||
this.setupFormValueChangeListeners();
|
||||
|
||||
// Create an effect to update the form when the configuration changes
|
||||
effect(() => {
|
||||
const config = this.queueCleanerConfig();
|
||||
@@ -112,22 +117,22 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
enabled: config.enabled,
|
||||
runSequentially: config.runSequentially,
|
||||
ignoredDownloadsPath: config.ignoredDownloadsPath,
|
||||
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: config.failedImportMaxStrikes,
|
||||
failedImportIgnorePrivate: config.failedImportIgnorePrivate,
|
||||
failedImportDeletePrivate: config.failedImportDeletePrivate,
|
||||
failedImportIgnorePatterns: config.failedImportIgnorePatterns,
|
||||
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: config.stalledMaxStrikes,
|
||||
stalledResetStrikesOnProgress: config.stalledResetStrikesOnProgress,
|
||||
stalledIgnorePrivate: config.stalledIgnorePrivate,
|
||||
stalledDeletePrivate: config.stalledDeletePrivate,
|
||||
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: config.downloadingMetadataMaxStrikes,
|
||||
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: config.slowMaxStrikes,
|
||||
slowResetStrikesOnProgress: config.slowResetStrikesOnProgress,
|
||||
@@ -135,16 +140,19 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
slowDeletePrivate: config.slowDeletePrivate,
|
||||
slowMinSpeed: config.slowMinSpeed,
|
||||
slowMaxTime: config.slowMaxTime,
|
||||
slowIgnoreAboveSize: config.slowIgnoreAboveSize
|
||||
slowIgnoreAboveSize: config.slowIgnoreAboveSize,
|
||||
});
|
||||
|
||||
|
||||
// Update job schedule if it exists
|
||||
if (config.jobSchedule) {
|
||||
this.queueCleanerForm.get('jobSchedule')?.patchValue({
|
||||
this.queueCleanerForm.get("jobSchedule")?.patchValue({
|
||||
every: config.jobSchedule.every,
|
||||
type: config.jobSchedule.type
|
||||
type: config.jobSchedule.type,
|
||||
});
|
||||
}
|
||||
|
||||
// Update form control disabled states based on the configuration
|
||||
this.updateFormControlDisabledStates(config);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -168,6 +176,185 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up subscriptions when component is destroyed
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up listeners for form control value changes to manage dependent control states
|
||||
*/
|
||||
private setupFormValueChangeListeners(): void {
|
||||
// Listen for changes on the 'enabled' control
|
||||
this.queueCleanerForm.get('enabled')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
this.updateMainControlsState(enabled);
|
||||
});
|
||||
|
||||
// Listen for changes on 'failedImportMaxStrikes' control
|
||||
this.queueCleanerForm.get('failedImportMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateFailedImportDependentControls(strikes);
|
||||
});
|
||||
|
||||
// Listen for changes on 'stalledMaxStrikes' control
|
||||
this.queueCleanerForm.get('stalledMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateStalledDependentControls(strikes);
|
||||
});
|
||||
|
||||
// Listen for changes on 'slowMaxStrikes' control
|
||||
this.queueCleanerForm.get('slowMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateSlowDependentControls(strikes);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update form control disabled states based on the configuration
|
||||
*/
|
||||
private updateFormControlDisabledStates(config: QueueCleanerConfig): void {
|
||||
const enabled = config.enabled;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
// Job schedule
|
||||
if (enabled) {
|
||||
this.queueCleanerForm.get("jobSchedule")?.enable(options);
|
||||
this.queueCleanerForm.get("runSequentially")?.enable(options);
|
||||
this.queueCleanerForm.get("ignoredDownloadsPath")?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get("jobSchedule")?.disable(options);
|
||||
this.queueCleanerForm.get("runSequentially")?.disable(options);
|
||||
this.queueCleanerForm.get("ignoredDownloadsPath")?.disable(options);
|
||||
}
|
||||
|
||||
// Failed Import settings
|
||||
const failedImportEnabled = enabled && config.failedImportMaxStrikes >= 3;
|
||||
if (failedImportEnabled) {
|
||||
this.queueCleanerForm.get("failedImportIgnorePrivate")?.enable(options);
|
||||
this.queueCleanerForm.get("failedImportDeletePrivate")?.enable(options);
|
||||
this.queueCleanerForm.get("failedImportIgnorePatterns")?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get("failedImportIgnorePrivate")?.disable(options);
|
||||
this.queueCleanerForm.get("failedImportDeletePrivate")?.disable(options);
|
||||
this.queueCleanerForm.get("failedImportIgnorePatterns")?.disable(options);
|
||||
}
|
||||
|
||||
// Stalled settings
|
||||
const stalledEnabled = enabled && config.stalledMaxStrikes >= 3;
|
||||
if (stalledEnabled) {
|
||||
this.queueCleanerForm.get("stalledResetStrikesOnProgress")?.enable(options);
|
||||
this.queueCleanerForm.get("stalledIgnorePrivate")?.enable(options);
|
||||
this.queueCleanerForm.get("stalledDeletePrivate")?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get("stalledResetStrikesOnProgress")?.disable(options);
|
||||
this.queueCleanerForm.get("stalledIgnorePrivate")?.disable(options);
|
||||
this.queueCleanerForm.get("stalledDeletePrivate")?.disable(options);
|
||||
}
|
||||
|
||||
// Slow Download settings
|
||||
const slowEnabled = enabled && config.slowMaxStrikes >= 3;
|
||||
if (slowEnabled) {
|
||||
this.queueCleanerForm.get("slowResetStrikesOnProgress")?.enable(options);
|
||||
this.queueCleanerForm.get("slowIgnorePrivate")?.enable(options);
|
||||
this.queueCleanerForm.get("slowDeletePrivate")?.enable(options);
|
||||
this.queueCleanerForm.get("slowMinSpeed")?.enable(options);
|
||||
this.queueCleanerForm.get("slowMaxTime")?.enable(options);
|
||||
this.queueCleanerForm.get("slowIgnoreAboveSize")?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get("slowResetStrikesOnProgress")?.disable(options);
|
||||
this.queueCleanerForm.get("slowIgnorePrivate")?.disable(options);
|
||||
this.queueCleanerForm.get("slowDeletePrivate")?.disable(options);
|
||||
this.queueCleanerForm.get("slowMinSpeed")?.disable(options);
|
||||
this.queueCleanerForm.get("slowMaxTime")?.disable(options);
|
||||
this.queueCleanerForm.get("slowIgnoreAboveSize")?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of main controls based on the 'enabled' control value
|
||||
*/
|
||||
private updateMainControlsState(enabled: boolean): void {
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enabled) {
|
||||
this.queueCleanerForm.get('jobSchedule')?.enable(options);
|
||||
this.queueCleanerForm.get('runSequentially')?.enable(options);
|
||||
this.queueCleanerForm.get('ignoredDownloadsPath')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('jobSchedule')?.disable(options);
|
||||
this.queueCleanerForm.get('runSequentially')?.disable(options);
|
||||
this.queueCleanerForm.get('ignoredDownloadsPath')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Failed Import dependent controls based on the 'failedImportMaxStrikes' value
|
||||
*/
|
||||
private updateFailedImportDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('failedImportIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('failedImportDeletePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('failedImportIgnorePatterns')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('failedImportIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('failedImportDeletePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('failedImportIgnorePatterns')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Stalled dependent controls based on the 'stalledMaxStrikes' value
|
||||
*/
|
||||
private updateStalledDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('stalledResetStrikesOnProgress')?.enable(options);
|
||||
this.queueCleanerForm.get('stalledIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('stalledDeletePrivate')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('stalledResetStrikesOnProgress')?.disable(options);
|
||||
this.queueCleanerForm.get('stalledIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('stalledDeletePrivate')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Slow Download dependent controls based on the 'slowMaxStrikes' value
|
||||
*/
|
||||
private updateSlowDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('slowResetStrikesOnProgress')?.enable(options);
|
||||
this.queueCleanerForm.get('slowIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('slowDeletePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('slowMinSpeed')?.enable(options);
|
||||
this.queueCleanerForm.get('slowMaxTime')?.enable(options);
|
||||
this.queueCleanerForm.get('slowIgnoreAboveSize')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('slowResetStrikesOnProgress')?.disable(options);
|
||||
this.queueCleanerForm.get('slowIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('slowDeletePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('slowMinSpeed')?.disable(options);
|
||||
this.queueCleanerForm.get('slowMaxTime')?.disable(options);
|
||||
this.queueCleanerForm.get('slowIgnoreAboveSize')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the queue cleaner configuration
|
||||
*/
|
||||
@@ -176,55 +363,55 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
// Mark all fields as touched to show validation errors
|
||||
this.markFormGroupTouched(this.queueCleanerForm);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Validation Error',
|
||||
detail: 'Please correct the errors in the form before saving.',
|
||||
life: 5000
|
||||
severity: "error",
|
||||
summary: "Validation Error",
|
||||
detail: "Please correct the errors in the form before saving.",
|
||||
life: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get the form values
|
||||
const formValues = this.queueCleanerForm.value;
|
||||
|
||||
const formValues = this.queueCleanerForm.getRawValue(); // Get values including disabled fields
|
||||
|
||||
// Build the configuration object
|
||||
const config: QueueCleanerConfig = {
|
||||
enabled: formValues.enabled,
|
||||
// The cronExpression will be generated from the jobSchedule when saving
|
||||
cronExpression: '',
|
||||
cronExpression: "",
|
||||
jobSchedule: formValues.jobSchedule,
|
||||
runSequentially: formValues.runSequentially,
|
||||
ignoredDownloadsPath: formValues.ignoredDownloadsPath || '',
|
||||
|
||||
ignoredDownloadsPath: formValues.ignoredDownloadsPath || "",
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: formValues.failedImportMaxStrikes,
|
||||
failedImportIgnorePrivate: formValues.failedImportIgnorePrivate,
|
||||
failedImportDeletePrivate: formValues.failedImportDeletePrivate,
|
||||
failedImportIgnorePatterns: formValues.failedImportIgnorePatterns || [],
|
||||
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: formValues.stalledMaxStrikes,
|
||||
stalledResetStrikesOnProgress: formValues.stalledResetStrikesOnProgress,
|
||||
stalledIgnorePrivate: formValues.stalledIgnorePrivate,
|
||||
stalledDeletePrivate: formValues.stalledDeletePrivate,
|
||||
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: formValues.downloadingMetadataMaxStrikes,
|
||||
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: formValues.slowMaxStrikes,
|
||||
slowResetStrikesOnProgress: formValues.slowResetStrikesOnProgress,
|
||||
slowIgnorePrivate: formValues.slowIgnorePrivate,
|
||||
slowDeletePrivate: formValues.slowDeletePrivate,
|
||||
slowMinSpeed: formValues.slowMinSpeed || '',
|
||||
slowMinSpeed: formValues.slowMinSpeed || "",
|
||||
slowMaxTime: formValues.slowMaxTime,
|
||||
slowIgnoreAboveSize: formValues.slowIgnoreAboveSize || ''
|
||||
slowIgnoreAboveSize: formValues.slowIgnoreAboveSize || "",
|
||||
};
|
||||
|
||||
|
||||
// Save the configuration
|
||||
this.queueCleanerStore.saveConfig(config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset the queue cleaner configuration form to default values
|
||||
*/
|
||||
@@ -233,50 +420,56 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
enabled: false,
|
||||
jobSchedule: {
|
||||
every: 5,
|
||||
type: ScheduleUnit.Minutes
|
||||
type: ScheduleUnit.Minutes,
|
||||
},
|
||||
runSequentially: false,
|
||||
ignoredDownloadsPath: '',
|
||||
|
||||
ignoredDownloadsPath: "",
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: 0,
|
||||
failedImportIgnorePrivate: false,
|
||||
failedImportDeletePrivate: false,
|
||||
failedImportIgnorePatterns: [],
|
||||
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: 0,
|
||||
stalledResetStrikesOnProgress: false,
|
||||
stalledIgnorePrivate: false,
|
||||
stalledDeletePrivate: false,
|
||||
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: 0,
|
||||
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: 0,
|
||||
slowResetStrikesOnProgress: false,
|
||||
slowIgnorePrivate: false,
|
||||
slowDeletePrivate: false,
|
||||
slowMinSpeed: '',
|
||||
slowMinSpeed: "",
|
||||
slowMaxTime: 0,
|
||||
slowIgnoreAboveSize: ''
|
||||
slowIgnoreAboveSize: "",
|
||||
});
|
||||
|
||||
// Manually update control states after reset
|
||||
this.updateMainControlsState(false);
|
||||
this.updateFailedImportDependentControls(0);
|
||||
this.updateStalledDependentControls(0);
|
||||
this.updateSlowDependentControls(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark all controls in a form group as touched
|
||||
*/
|
||||
private markFormGroupTouched(formGroup: FormGroup): void {
|
||||
Object.values(formGroup.controls).forEach(control => {
|
||||
Object.values(formGroup.controls).forEach((control) => {
|
||||
control.markAsTouched();
|
||||
|
||||
|
||||
if ((control as any).controls) {
|
||||
this.markFormGroupTouched(control as FormGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a form control has an error after it's been touched
|
||||
*/
|
||||
@@ -284,7 +477,7 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
const control = this.queueCleanerForm.get(controlName);
|
||||
return control ? control.touched && control.hasError(errorName) : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get nested form control errors
|
||||
*/
|
||||
@@ -293,7 +486,7 @@ export class QueueCleanerSettingsComponent implements OnInit {
|
||||
if (!parentControl || !(parentControl instanceof FormGroup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const control = parentControl.get(controlName);
|
||||
return control ? control.touched && control.hasError(errorName) : false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
import { Component, EventEmitter, OnDestroy, Output, effect, inject } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { QueueCleanerConfigStore } from "./queue-cleaner-config.store";
|
||||
import { QueueCleanerConfig, ScheduleUnit } from "../../shared/models/queue-cleaner-config.model";
|
||||
import { SettingsCardComponent } from "../components/settings-card/settings-card.component";
|
||||
import { ByteSizeInputComponent } from "../../shared/components/byte-size-input/byte-size-input.component";
|
||||
|
||||
// PrimeNG Components
|
||||
import { CardModule } from "primeng/card";
|
||||
import { InputTextModule } from "primeng/inputtext";
|
||||
import { CheckboxModule } from "primeng/checkbox";
|
||||
import { ButtonModule } from "primeng/button";
|
||||
import { InputNumberModule } from "primeng/inputnumber";
|
||||
import { AccordionModule } from "primeng/accordion";
|
||||
import { SelectButtonModule } from "primeng/selectbutton";
|
||||
import { ChipsModule } from "primeng/chips";
|
||||
import { ToastModule } from "primeng/toast";
|
||||
import { MessageService } from "primeng/api";
|
||||
|
||||
@Component({
|
||||
selector: "app-queue-cleaner-settings",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
SettingsCardComponent,
|
||||
CardModule,
|
||||
InputTextModule,
|
||||
CheckboxModule,
|
||||
ButtonModule,
|
||||
InputNumberModule,
|
||||
AccordionModule,
|
||||
SelectButtonModule,
|
||||
ChipsModule,
|
||||
ToastModule,
|
||||
ByteSizeInputComponent,
|
||||
],
|
||||
providers: [QueueCleanerConfigStore, MessageService],
|
||||
templateUrl: "./queue-cleaner-settings.component.html",
|
||||
styleUrls: ["./queue-cleaner-settings.component.scss"],
|
||||
})
|
||||
export class QueueCleanerSettingsComponent implements OnDestroy {
|
||||
@Output() saved = new EventEmitter<void>();
|
||||
@Output() error = new EventEmitter<string>();
|
||||
|
||||
// Queue Cleaner Configuration Form
|
||||
queueCleanerForm: FormGroup;
|
||||
|
||||
// Schedule unit options for job schedules
|
||||
scheduleUnitOptions = [
|
||||
{ label: "Seconds", value: ScheduleUnit.Seconds },
|
||||
{ label: "Minutes", value: ScheduleUnit.Minutes },
|
||||
{ label: "Hours", value: ScheduleUnit.Hours },
|
||||
];
|
||||
|
||||
// Inject the necessary services
|
||||
private formBuilder = inject(FormBuilder);
|
||||
private messageService = inject(MessageService);
|
||||
private queueCleanerStore = inject(QueueCleanerConfigStore);
|
||||
|
||||
// Signals from the store
|
||||
readonly queueCleanerConfig = this.queueCleanerStore.config;
|
||||
readonly queueCleanerLoading = this.queueCleanerStore.loading;
|
||||
readonly queueCleanerSaving = this.queueCleanerStore.saving;
|
||||
readonly queueCleanerError = this.queueCleanerStore.error;
|
||||
|
||||
// Subject for unsubscribing from observables when component is destroyed
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor() {
|
||||
// Initialize the queue cleaner form with proper disabled states
|
||||
this.queueCleanerForm = this.formBuilder.group({
|
||||
enabled: [false],
|
||||
jobSchedule: this.formBuilder.group({
|
||||
every: [{value: 5, disabled: true}, [Validators.required, Validators.min(1)]],
|
||||
type: [{value: ScheduleUnit.Minutes, disabled: true}],
|
||||
}),
|
||||
runSequentially: [{value: false, disabled: true}],
|
||||
ignoredDownloadsPath: [{value: "", disabled: true}],
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: [0, [Validators.min(0)]],
|
||||
failedImportIgnorePrivate: [{value: false, disabled: true}],
|
||||
failedImportDeletePrivate: [{value: false, disabled: true}],
|
||||
failedImportIgnorePatterns: [{value: [], disabled: true}],
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: [0, [Validators.min(0)]],
|
||||
stalledResetStrikesOnProgress: [{value: false, disabled: true}],
|
||||
stalledIgnorePrivate: [{value: false, disabled: true}],
|
||||
stalledDeletePrivate: [{value: false, disabled: true}],
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: [0, [Validators.min(0)]],
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: [0, [Validators.min(0)]],
|
||||
slowResetStrikesOnProgress: [{value: false, disabled: true}],
|
||||
slowIgnorePrivate: [{value: false, disabled: true}],
|
||||
slowDeletePrivate: [{value: false, disabled: true}],
|
||||
slowMinSpeed: [{value: "", disabled: true}],
|
||||
slowMaxTime: [{value: 0, disabled: true}],
|
||||
slowIgnoreAboveSize: [{value: "", disabled: true}],
|
||||
});
|
||||
|
||||
// Set up form control value change subscriptions to manage dependent control states
|
||||
this.setupFormValueChangeListeners();
|
||||
|
||||
// Create an effect to update the form when the configuration changes
|
||||
effect(() => {
|
||||
const config = this.queueCleanerConfig();
|
||||
if (config) {
|
||||
// Update the form with the current configuration
|
||||
this.queueCleanerForm.patchValue({
|
||||
enabled: config.enabled,
|
||||
runSequentially: config.runSequentially,
|
||||
ignoredDownloadsPath: config.ignoredDownloadsPath,
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: config.failedImportMaxStrikes,
|
||||
failedImportIgnorePrivate: config.failedImportIgnorePrivate,
|
||||
failedImportDeletePrivate: config.failedImportDeletePrivate,
|
||||
failedImportIgnorePatterns: config.failedImportIgnorePatterns,
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: config.stalledMaxStrikes,
|
||||
stalledResetStrikesOnProgress: config.stalledResetStrikesOnProgress,
|
||||
stalledIgnorePrivate: config.stalledIgnorePrivate,
|
||||
stalledDeletePrivate: config.stalledDeletePrivate,
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: config.downloadingMetadataMaxStrikes,
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: config.slowMaxStrikes,
|
||||
slowResetStrikesOnProgress: config.slowResetStrikesOnProgress,
|
||||
slowIgnorePrivate: config.slowIgnorePrivate,
|
||||
slowDeletePrivate: config.slowDeletePrivate,
|
||||
slowMinSpeed: config.slowMinSpeed,
|
||||
slowMaxTime: config.slowMaxTime,
|
||||
slowIgnoreAboveSize: config.slowIgnoreAboveSize,
|
||||
});
|
||||
|
||||
// Update job schedule if it exists
|
||||
if (config.jobSchedule) {
|
||||
this.queueCleanerForm.get("jobSchedule")?.patchValue({
|
||||
every: config.jobSchedule.every,
|
||||
type: config.jobSchedule.type,
|
||||
});
|
||||
}
|
||||
|
||||
// Update form control disabled states based on the configuration
|
||||
this.updateFormControlDisabledStates(config);
|
||||
}
|
||||
});
|
||||
|
||||
// Effect to emit events when save operation completes or errors
|
||||
effect(() => {
|
||||
const error = this.queueCleanerError();
|
||||
if (error) {
|
||||
this.error.emit(error);
|
||||
}
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const saving = this.queueCleanerSaving();
|
||||
if (saving === false) {
|
||||
// This will run after a save operation is completed (whether successful or not)
|
||||
// We check if there's no error to determine if it was successful
|
||||
if (!this.queueCleanerError()) {
|
||||
this.saved.emit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up subscriptions when component is destroyed
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up listeners for form control value changes to manage dependent control states
|
||||
*/
|
||||
private setupFormValueChangeListeners(): void {
|
||||
// Listen for changes on the 'enabled' control
|
||||
this.queueCleanerForm.get('enabled')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
this.updateMainControlsState(enabled);
|
||||
});
|
||||
|
||||
// Listen for changes on 'failedImportMaxStrikes' control
|
||||
this.queueCleanerForm.get('failedImportMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateFailedImportDependentControls(strikes);
|
||||
});
|
||||
|
||||
// Listen for changes on 'stalledMaxStrikes' control
|
||||
this.queueCleanerForm.get('stalledMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateStalledDependentControls(strikes);
|
||||
});
|
||||
|
||||
// Listen for changes on 'slowMaxStrikes' control
|
||||
this.queueCleanerForm.get('slowMaxStrikes')?.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((strikes: number) => {
|
||||
this.updateSlowDependentControls(strikes);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update form control disabled states based on the configuration
|
||||
*/
|
||||
private updateFormControlDisabledStates(config: QueueCleanerConfig): void {
|
||||
const enabled = config.enabled;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
// Job schedule
|
||||
if (enabled) {
|
||||
this.queueCleanerForm.get("jobSchedule")?.enable(options);
|
||||
this.queueCleanerForm.get("runSequentially")?.enable(options);
|
||||
this.queueCleanerForm.get("ignoredDownloadsPath")?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get("jobSchedule")?.disable(options);
|
||||
this.queueCleanerForm.get("runSequentially")?.disable(options);
|
||||
this.queueCleanerForm.get("ignoredDownloadsPath")?.disable(options);
|
||||
}
|
||||
|
||||
// Failed Import settings
|
||||
const failedImportEnabled = enabled && config.failedImportMaxStrikes >= 3;
|
||||
this.queueCleanerForm.get("failedImportIgnorePrivate")?.setDisabled(!failedImportEnabled, options);
|
||||
this.queueCleanerForm.get("failedImportDeletePrivate")?.setDisabled(!failedImportEnabled, options);
|
||||
this.queueCleanerForm.get("failedImportIgnorePatterns")?.setDisabled(!failedImportEnabled, options);
|
||||
|
||||
// Stalled settings
|
||||
const stalledEnabled = enabled && config.stalledMaxStrikes >= 3;
|
||||
this.queueCleanerForm.get("stalledResetStrikesOnProgress")?.setDisabled(!stalledEnabled, options);
|
||||
this.queueCleanerForm.get("stalledIgnorePrivate")?.setDisabled(!stalledEnabled, options);
|
||||
this.queueCleanerForm.get("stalledDeletePrivate")?.setDisabled(!stalledEnabled, options);
|
||||
|
||||
// Slow Download settings
|
||||
const slowEnabled = enabled && config.slowMaxStrikes >= 3;
|
||||
this.queueCleanerForm.get("slowResetStrikesOnProgress")?.setDisabled(!slowEnabled, options);
|
||||
this.queueCleanerForm.get("slowIgnorePrivate")?.setDisabled(!slowEnabled, options);
|
||||
this.queueCleanerForm.get("slowDeletePrivate")?.setDisabled(!slowEnabled, options);
|
||||
this.queueCleanerForm.get("slowMinSpeed")?.setDisabled(!slowEnabled, options);
|
||||
this.queueCleanerForm.get("slowMaxTime")?.setDisabled(!slowEnabled, options);
|
||||
this.queueCleanerForm.get("slowIgnoreAboveSize")?.setDisabled(!slowEnabled, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of main controls based on the 'enabled' control value
|
||||
*/
|
||||
private updateMainControlsState(enabled: boolean): void {
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enabled) {
|
||||
this.queueCleanerForm.get('jobSchedule')?.enable(options);
|
||||
this.queueCleanerForm.get('runSequentially')?.enable(options);
|
||||
this.queueCleanerForm.get('ignoredDownloadsPath')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('jobSchedule')?.disable(options);
|
||||
this.queueCleanerForm.get('runSequentially')?.disable(options);
|
||||
this.queueCleanerForm.get('ignoredDownloadsPath')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Failed Import dependent controls based on the 'failedImportMaxStrikes' value
|
||||
*/
|
||||
private updateFailedImportDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('failedImportIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('failedImportDeletePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('failedImportIgnorePatterns')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('failedImportIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('failedImportDeletePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('failedImportIgnorePatterns')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Stalled dependent controls based on the 'stalledMaxStrikes' value
|
||||
*/
|
||||
private updateStalledDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('stalledResetStrikesOnProgress')?.enable(options);
|
||||
this.queueCleanerForm.get('stalledIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('stalledDeletePrivate')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('stalledResetStrikesOnProgress')?.disable(options);
|
||||
this.queueCleanerForm.get('stalledIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('stalledDeletePrivate')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of Slow Download dependent controls based on the 'slowMaxStrikes' value
|
||||
*/
|
||||
private updateSlowDependentControls(strikes: number): void {
|
||||
const enable = strikes >= 3;
|
||||
const options = { onlySelf: true };
|
||||
|
||||
if (enable) {
|
||||
this.queueCleanerForm.get('slowResetStrikesOnProgress')?.enable(options);
|
||||
this.queueCleanerForm.get('slowIgnorePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('slowDeletePrivate')?.enable(options);
|
||||
this.queueCleanerForm.get('slowMinSpeed')?.enable(options);
|
||||
this.queueCleanerForm.get('slowMaxTime')?.enable(options);
|
||||
this.queueCleanerForm.get('slowIgnoreAboveSize')?.enable(options);
|
||||
} else {
|
||||
this.queueCleanerForm.get('slowResetStrikesOnProgress')?.disable(options);
|
||||
this.queueCleanerForm.get('slowIgnorePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('slowDeletePrivate')?.disable(options);
|
||||
this.queueCleanerForm.get('slowMinSpeed')?.disable(options);
|
||||
this.queueCleanerForm.get('slowMaxTime')?.disable(options);
|
||||
this.queueCleanerForm.get('slowIgnoreAboveSize')?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the queue cleaner configuration
|
||||
*/
|
||||
saveQueueCleanerConfig(): void {
|
||||
if (this.queueCleanerForm.invalid) {
|
||||
// Mark all fields as touched to show validation errors
|
||||
this.markFormGroupTouched(this.queueCleanerForm);
|
||||
this.messageService.add({
|
||||
severity: "error",
|
||||
summary: "Validation Error",
|
||||
detail: "Please correct the errors in the form before saving.",
|
||||
life: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the form values
|
||||
const formValues = this.queueCleanerForm.getRawValue(); // Get values including disabled fields
|
||||
|
||||
// Build the configuration object
|
||||
const config: QueueCleanerConfig = {
|
||||
enabled: formValues.enabled,
|
||||
// The cronExpression will be generated from the jobSchedule when saving
|
||||
cronExpression: "",
|
||||
jobSchedule: formValues.jobSchedule,
|
||||
runSequentially: formValues.runSequentially,
|
||||
ignoredDownloadsPath: formValues.ignoredDownloadsPath || "",
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: formValues.failedImportMaxStrikes,
|
||||
failedImportIgnorePrivate: formValues.failedImportIgnorePrivate,
|
||||
failedImportDeletePrivate: formValues.failedImportDeletePrivate,
|
||||
failedImportIgnorePatterns: formValues.failedImportIgnorePatterns || [],
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: formValues.stalledMaxStrikes,
|
||||
stalledResetStrikesOnProgress: formValues.stalledResetStrikesOnProgress,
|
||||
stalledIgnorePrivate: formValues.stalledIgnorePrivate,
|
||||
stalledDeletePrivate: formValues.stalledDeletePrivate,
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: formValues.downloadingMetadataMaxStrikes,
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: formValues.slowMaxStrikes,
|
||||
slowResetStrikesOnProgress: formValues.slowResetStrikesOnProgress,
|
||||
slowIgnorePrivate: formValues.slowIgnorePrivate,
|
||||
slowDeletePrivate: formValues.slowDeletePrivate,
|
||||
slowMinSpeed: formValues.slowMinSpeed || "",
|
||||
slowMaxTime: formValues.slowMaxTime,
|
||||
slowIgnoreAboveSize: formValues.slowIgnoreAboveSize || "",
|
||||
};
|
||||
|
||||
// Save the configuration
|
||||
this.queueCleanerStore.saveConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the queue cleaner configuration form to default values
|
||||
*/
|
||||
resetQueueCleanerConfig(): void {
|
||||
this.queueCleanerForm.reset({
|
||||
enabled: false,
|
||||
jobSchedule: {
|
||||
every: 5,
|
||||
type: ScheduleUnit.Minutes,
|
||||
},
|
||||
runSequentially: false,
|
||||
ignoredDownloadsPath: "",
|
||||
|
||||
// Failed Import settings
|
||||
failedImportMaxStrikes: 0,
|
||||
failedImportIgnorePrivate: false,
|
||||
failedImportDeletePrivate: false,
|
||||
failedImportIgnorePatterns: [],
|
||||
|
||||
// Stalled settings
|
||||
stalledMaxStrikes: 0,
|
||||
stalledResetStrikesOnProgress: false,
|
||||
stalledIgnorePrivate: false,
|
||||
stalledDeletePrivate: false,
|
||||
|
||||
// Downloading Metadata settings
|
||||
downloadingMetadataMaxStrikes: 0,
|
||||
|
||||
// Slow Download settings
|
||||
slowMaxStrikes: 0,
|
||||
slowResetStrikesOnProgress: false,
|
||||
slowIgnorePrivate: false,
|
||||
slowDeletePrivate: false,
|
||||
slowMinSpeed: "",
|
||||
slowMaxTime: 0,
|
||||
slowIgnoreAboveSize: "",
|
||||
});
|
||||
|
||||
// Manually update control states after reset
|
||||
this.updateMainControlsState(false);
|
||||
this.updateFailedImportDependentControls(0);
|
||||
this.updateStalledDependentControls(0);
|
||||
this.updateSlowDependentControls(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all controls in a form group as touched
|
||||
*/
|
||||
private markFormGroupTouched(formGroup: FormGroup): void {
|
||||
Object.values(formGroup.controls).forEach((control) => {
|
||||
control.markAsTouched();
|
||||
|
||||
if ((control as any).controls) {
|
||||
this.markFormGroupTouched(control as FormGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a form control has an error after it's been touched
|
||||
*/
|
||||
hasError(controlName: string, errorName: string): boolean {
|
||||
const control = this.queueCleanerForm.get(controlName);
|
||||
return control ? control.touched && control.hasError(errorName) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nested form control errors
|
||||
*/
|
||||
hasNestedError(parentName: string, controlName: string, errorName: string): boolean {
|
||||
const parentControl = this.queueCleanerForm.get(parentName);
|
||||
if (!parentControl || !(parentControl instanceof FormGroup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const control = parentControl.get(controlName);
|
||||
return control ? control.touched && control.hasError(errorName) : false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user