Default offline cleanup dialog to entire packages first
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ All notable changes to Multi-Debrid Downloader are documented in this file.
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add “Remove packages with offline links …” to the download context menu. The confirmation defaults to removing only affected archive sets, with an option to remove entire parent packages. One offline part removes all parts of that archive while other episodes remain in archive-set mode. Both modes cover the entire queue regardless of filters or selection, keep downloaded files, and recheck the confirmed package IDs before removal.
|
- Add “Remove packages with offline links …” to the download context menu. The confirmation lists entire parent packages first and selects that option by default; affected archive sets are available as the second option. One offline part removes all parts of that archive while other episodes remain in archive-set mode. Both modes cover the entire queue regardless of filters or selection, keep downloaded files, and recheck the confirmed package IDs before removal.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,8 @@ Diese Datei hält den verifizierten technischen Arbeitsstand fest. Sie enthält
|
|||||||
|
|
||||||
### Unveröffentlichte Offline-Paketbereinigung vom 4. September 2026
|
### Unveröffentlichte Offline-Paketbereinigung vom 4. September 2026
|
||||||
|
|
||||||
|
- Aktuelle Bedienvorgabe: „Ganze Pakete“ steht im Bestätigungsdialog oben und wird bei jedem Öffnen vorausgewählt. „Nur betroffene Archivsätze“ folgt darunter. Beide Modi bleiben wählbar; der gewählte Scope wird ausdrücklich an das Backend übergeben. Browserprüfung bestätigt Reihenfolge `package`, `archive` und ausschließlich `package` als vorausgewählt; TypeScript fehlerfrei. Änderung per Hot-Reload in der Dev-App geladen.
|
||||||
|
|
||||||
- Erweiterung nach Saschas Rückmeldung: Die Bestätigung enthält jetzt zwei Radiooptionen. Standard bei jedem Öffnen ist „Nur betroffene Archivsätze“; alternativ „Ganze Pakete“. Im Archivsatz-Modus entfernt ein Offline-Part alle zusammengehörigen Parts derselben Folge, einschließlich bereits abgeschlossener Queue-Einträge; andere Folgen bleiben im Oberpaket. Leere Oberpakete verschwinden automatisch. Dateien bleiben in beiden Modi erhalten. Der Scope wird separat vom automatischen Offline-Überspringen übergeben und verändert dessen Einstellung nicht.
|
- Erweiterung nach Saschas Rückmeldung: Die Bestätigung enthält jetzt zwei Radiooptionen. Standard bei jedem Öffnen ist „Nur betroffene Archivsätze“; alternativ „Ganze Pakete“. Im Archivsatz-Modus entfernt ein Offline-Part alle zusammengehörigen Parts derselben Folge, einschließlich bereits abgeschlossener Queue-Einträge; andere Folgen bleiben im Oberpaket. Leere Oberpakete verschwinden automatisch. Dateien bleiben in beiden Modi erhalten. Der Scope wird separat vom automatischen Offline-Überspringen übergeben und verändert dessen Einstellung nicht.
|
||||||
- Die vorhandene Offline-Archivzuordnung wurde in `src/shared/offline-archive-items.ts` gemeinsam nutzbar gemacht; der bisherige Main-Export bleibt kompatibel. Die Zuordnung unterstützt `partN.rar`, `.rar`/`.rNN`, `.zip.NNN`, `.7z.NNN` und generische `.NNN`-Teile. Einzeldateien ohne passende Geschwister werden einzeln entfernt. Main und visuelle Test-API verwenden denselben Matcher.
|
- Die vorhandene Offline-Archivzuordnung wurde in `src/shared/offline-archive-items.ts` gemeinsam nutzbar gemacht; der bisherige Main-Export bleibt kompatibel. Die Zuordnung unterstützt `partN.rar`, `.rar`/`.rNN`, `.zip.NNN`, `.7z.NNN` und generische `.NNN`-Teile. Einzeldateien ohne passende Geschwister werden einzeln entfernt. Main und visuelle Test-API verwenden denselben Matcher.
|
||||||
- Erweiterung verifiziert: 175 fokussierte Tests und 30 bestehende Offline-/Archivzuordnungs-/Abbruch-/Entfernungsfälle erfolgreich, TypeScript sowie Main-/Renderer-Build erfolgreich. Fünf neue Manager-/Dateisystemfälle bestätigen die Archivformate, den Erhalt anderer Folgen und unveränderte Dateien. Browserprüfung unter `?motion=on&offline-cleanup=multipart` bestätigt vorausgewählten Archivsatz-Modus, Folge 3 entfernt/Folge 4 erhalten und alternativ vollständige Paketentfernung. Dialoglayout im Dark-Theme geprüft. Dev-App für den aktualisierten Main-/Preload-Pfad regulär neu gestartet; weiterhin unveröffentlicht.
|
- Erweiterung verifiziert: 175 fokussierte Tests und 30 bestehende Offline-/Archivzuordnungs-/Abbruch-/Entfernungsfälle erfolgreich, TypeScript sowie Main-/Renderer-Build erfolgreich. Fünf neue Manager-/Dateisystemfälle bestätigen die Archivformate, den Erhalt anderer Folgen und unveränderte Dateien. Browserprüfung unter `?motion=on&offline-cleanup=multipart` bestätigt vorausgewählten Archivsatz-Modus, Folge 3 entfernt/Folge 4 erhalten und alternativ vollständige Paketentfernung. Dialoglayout im Dark-Theme geprüft. Dev-App für den aktualisierten Main-/Preload-Pfad regulär neu gestartet; weiterhin unveröffentlicht.
|
||||||
|
|||||||
@@ -1921,7 +1921,7 @@ export function App(): ReactElement {
|
|||||||
const [startConflictPrompt, setStartConflictPrompt] = useState<StartConflictPromptState | null>(null);
|
const [startConflictPrompt, setStartConflictPrompt] = useState<StartConflictPromptState | null>(null);
|
||||||
const startConflictResolverRef = useRef<((result: { policy: Extract<DuplicatePolicy, "skip" | "overwrite">; applyToAll: boolean } | null) => void) | null>(null);
|
const startConflictResolverRef = useRef<((result: { policy: Extract<DuplicatePolicy, "skip" | "overwrite">; applyToAll: boolean } | null) => void) | null>(null);
|
||||||
const [confirmPrompt, setConfirmPrompt] = useState<ConfirmPromptState | null>(null);
|
const [confirmPrompt, setConfirmPrompt] = useState<ConfirmPromptState | null>(null);
|
||||||
const offlineRemovalScopeRef = useRef<OfflineSkipScope>("archive");
|
const offlineRemovalScopeRef = useRef<OfflineSkipScope>("package");
|
||||||
const [backupPassphraseMode, setBackupPassphraseMode] = useState<BackupPassphraseMode | null>(null);
|
const [backupPassphraseMode, setBackupPassphraseMode] = useState<BackupPassphraseMode | null>(null);
|
||||||
const [onlineBackupDialog, setOnlineBackupDialog] = useState<OnlineBackupDialogState | null>(null);
|
const [onlineBackupDialog, setOnlineBackupDialog] = useState<OnlineBackupDialogState | null>(null);
|
||||||
const [remoteDiag, setRemoteDiag] = useState<RemoteDiagnosticsInfo | null>(null);
|
const [remoteDiag, setRemoteDiag] = useState<RemoteDiagnosticsInfo | null>(null);
|
||||||
@@ -4864,9 +4864,9 @@ export function App(): ReactElement {
|
|||||||
const english = normalizeLanguage(settings.language) === "en";
|
const english = normalizeLanguage(settings.language) === "en";
|
||||||
const count = candidates.length.toLocaleString(english ? "en-US" : "de-DE");
|
const count = candidates.length.toLocaleString(english ? "en-US" : "de-DE");
|
||||||
const packageLabel = english ? (candidates.length === 1 ? "package" : "packages") : (candidates.length === 1 ? "Paket" : "Pakete");
|
const packageLabel = english ? (candidates.length === 1 ? "package" : "packages") : (candidates.length === 1 ? "Paket" : "Pakete");
|
||||||
offlineRemovalScopeRef.current = "archive";
|
offlineRemovalScopeRef.current = "package";
|
||||||
const confirmed = await askConfirmPrompt({
|
const confirmed = await askConfirmPrompt({
|
||||||
offlineScope: "archive",
|
offlineScope: "package",
|
||||||
title: english ? "Remove packages with offline links" : "Pakete mit Offline-Links entfernen",
|
title: english ? "Remove packages with offline links" : "Pakete mit Offline-Links entfernen",
|
||||||
message: english
|
message: english
|
||||||
? `${count} ${packageLabel} with offline links in the entire queue. This applies regardless of filters or selection.`
|
? `${count} ${packageLabel} with offline links in the entire queue. This applies regardless of filters or selection.`
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ export function OfflineRemovalScopeChoice({ scope, english, onChange }: {
|
|||||||
return (
|
return (
|
||||||
<fieldset style={{ border: 0, padding: 0, margin: "16px 0", display: "grid", gap: 14 }}>
|
<fieldset style={{ border: 0, padding: 0, margin: "16px 0", display: "grid", gap: 14 }}>
|
||||||
<legend style={{ marginBottom: 12 }}>{english ? "What should be removed?" : "Was soll entfernt werden?"}</legend>
|
<legend style={{ marginBottom: 12 }}>{english ? "What should be removed?" : "Was soll entfernt werden?"}</legend>
|
||||||
<label style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
|
|
||||||
<input type="radio" name="offline-removal-scope" value="archive" checked={scope === "archive"} onChange={() => onChange("archive")} />
|
|
||||||
<span><strong>{english ? "Only affected archive sets" : "Nur betroffene Archivsätze"}</strong><br />
|
|
||||||
{english ? "Remove all parts of the affected episode or archive. Other episodes in the package remain." : "Alle Parts der betroffenen Folge oder des Archivs entfernen. Andere Folgen im Paket bleiben erhalten."}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<label style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
|
<label style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
|
||||||
<input type="radio" name="offline-removal-scope" value="package" checked={scope === "package"} onChange={() => onChange("package")} />
|
<input type="radio" name="offline-removal-scope" value="package" checked={scope === "package"} onChange={() => onChange("package")} />
|
||||||
<span><strong>{english ? "Entire packages" : "Ganze Pakete"}</strong><br />
|
<span><strong>{english ? "Entire packages" : "Ganze Pakete"}</strong><br />
|
||||||
{english ? "Remove the entire parent package as soon as one link is offline." : "Das gesamte übergeordnete Paket entfernen, sobald ein Link offline ist."}
|
{english ? "Remove the entire parent package as soon as one link is offline." : "Das gesamte übergeordnete Paket entfernen, sobald ein Link offline ist."}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
|
||||||
|
<input type="radio" name="offline-removal-scope" value="archive" checked={scope === "archive"} onChange={() => onChange("archive")} />
|
||||||
|
<span><strong>{english ? "Only affected archive sets" : "Nur betroffene Archivsätze"}</strong><br />
|
||||||
|
{english ? "Remove all parts of the affected episode or archive. Other episodes in the package remain." : "Alle Parts der betroffenen Folge oder des Archivs entfernen. Andere Folgen im Paket bleiben erhalten."}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
<p style={{ margin: 0 }}>{english ? "Active downloads being removed will stop. Downloaded files are kept in both cases." : "Die zu entfernenden laufenden Downloads werden gestoppt. Heruntergeladene Dateien bleiben in beiden Fällen erhalten."}</p>
|
<p style={{ margin: 0 }}>{english ? "Active downloads being removed will stop. Downloaded files are kept in both cases." : "Die zu entfernenden laufenden Downloads werden gestoppt. Heruntergeladene Dateien bleiben in beiden Fällen erhalten."}</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user