From 479c2b600a16295c7248081fea9686bedc7e3752 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Sat, 15 Aug 2026 01:19:29 +0200 Subject: [PATCH] fix(accounts): unlock parent provider when enabling rows Make individual Debrid-Link and Mega-Debrid switches express an explicit enabled target. Enabling a row now clears both its own disabled identifier and the effective provider lock; Mega-Debrid also re-enables the selected API or web mode. Keep row-level disabling scoped to the selected account, align the legacy key view with the effective provider state, and cover the provider-plus-account lock combination with a regression test. --- CHANGELOG.md | 1 + src/renderer/App.tsx | 57 ++++++++++++++++++++++-------------- src/renderer/account-ui.ts | 18 ++++++++++++ tests/settings-view.test.tsx | 26 ++++++++++++++++ 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb2e090..ecd516b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to Multi-Debrid Downloader are documented in this file. - Split account refresh into active-account and all-account checks with matching result counts. - Show failed check results for disabled accounts when all configured accounts are refreshed. - Apply individual and bulk account enablement changes immediately while settings are saved, with automatic rollback after a failed save. +- Re-enable parent providers and Mega-Debrid modes when an individual disabled account or API key is enabled. ## [2.0.40] - 2026-08-15 diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 8c7a92a..5d678ac 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -40,7 +40,7 @@ import { } from "../shared/provider-daily-limits"; import { preservePackageOrderForDisplay, sortPackageOrderByName } from "./package-order"; import { pruneSelection, shouldClearDownloadSelection, shouldClearDownloadSelectionOnEscape } from "./selection"; -import { buildBulkAccountEnabledState, buildConfiguredProviderOrder, getAccountDialogSelectableOptions, matchesAccountModeFilter, pruneAccountRowSelection, resolveAccountStatusState, resolveAccountUsername, resolveVisibleAccountKind, runOptimisticAccountUpdate } from "./account-ui"; +import { buildBulkAccountEnabledState, buildConfiguredProviderOrder, buildScopedAccountEnabledState, getAccountDialogSelectableOptions, matchesAccountModeFilter, pruneAccountRowSelection, resolveAccountStatusState, resolveAccountUsername, resolveVisibleAccountKind, runOptimisticAccountUpdate } from "./account-ui"; import type { AccountModeFilter } from "./account-ui"; import { buildAccountDeleteCommand, buildAccountReplaceCommand, createAccountEditState, validateAccountEdit } from "./account-edit"; import type { AccountEditState, AccountEditTarget, AccountKind, AccountService, SingleAccountKind } from "./account-edit"; @@ -2319,8 +2319,8 @@ export function App(): ReactElement { accountId: acc.accountId, checkable: true, disabled: entry.disabled || (entry.kind === "megadebrid-api" - ? settingsDraft.megaDebridApiDisabledAccountIds.includes(acc.accountId) - : settingsDraft.megaDebridWebDisabledAccountIds.includes(acc.accountId)), + ? !settingsDraft.megaDebridApiEnabled || settingsDraft.megaDebridApiDisabledAccountIds.includes(acc.accountId) + : !settingsDraft.megaDebridWebEnabled || settingsDraft.megaDebridWebDisabledAccountIds.includes(acc.accountId)), dailyUsedBytes: used, dailyLimitBytes: limit, dailyRemainingBytes: limit > 0 ? Math.max(0, limit - used) : 0, @@ -2820,20 +2820,23 @@ export function App(): ReactElement { ); }; - const onToggleDebridLinkApiKeyEnabled = async (entry: ConfiguredAccountEntry, key: DebridLinkAccountKeyEntry): Promise => { + const onToggleDebridLinkApiKeyEnabled = async (entry: ConfiguredAccountEntry, key: DebridLinkAccountKeyEntry, enabled: boolean): Promise => { await performQuickAction(async () => { - const currentDisabledIds = settingsDraft.debridLinkDisabledKeyIds || []; - const currentlyDisabled = currentDisabledIds.includes(key.id); - const nextDisabledIds = currentlyDisabled - ? currentDisabledIds.filter((existingId) => existingId !== key.id) - : [...currentDisabledIds, key.id]; + const nextState = buildScopedAccountEnabledState( + settingsDraft.disabledProviders || [], + ["debridlink"], + settingsDraft.debridLinkDisabledKeyIds || [], + key.id, + enabled + ); const nextDraft: RendererSettingsDraft = { ...settingsDraft, - debridLinkDisabledKeyIds: nextDisabledIds + disabledProviders: nextState.disabledProviders, + debridLinkDisabledKeyIds: nextState.disabledAccountIds }; await persistAccountToggle(nextDraft); showToast( - currentlyDisabled + enabled ? `${entry.serviceLabel} ${key.label} aktiviert` : `${entry.serviceLabel} ${key.label} deaktiviert`, 2200 @@ -2855,20 +2858,30 @@ export function App(): ReactElement { }); }; - const onToggleMegaAccountEnabled = async (kind: "megadebrid-api" | "megadebrid-web", accountId: string, currentlyDisabled: boolean): Promise => { + const onToggleMegaAccountEnabled = async (kind: "megadebrid-api" | "megadebrid-web", accountId: string, enabled: boolean): Promise => { await performQuickAction(async () => { const mode = kind === "megadebrid-web" ? "web" : "api"; const current = mode === "api" ? settingsDraft.megaDebridApiDisabledAccountIds : settingsDraft.megaDebridWebDisabledAccountIds; - const next = currentlyDisabled ? current.filter((id) => id !== accountId) : [...current, accountId]; + const nextState = buildScopedAccountEnabledState( + settingsDraft.disabledProviders || [], + ["megadebrid", kind], + current, + accountId, + enabled + ); + const next = nextState.disabledAccountIds; const apiDisabledIds = mode === "api" ? next : settingsDraft.megaDebridApiDisabledAccountIds; const webDisabledIds = mode === "web" ? next : settingsDraft.megaDebridWebDisabledAccountIds; await persistAccountToggle({ ...settingsDraft, + disabledProviders: nextState.disabledProviders, + megaDebridApiEnabled: mode === "api" && enabled ? true : settingsDraft.megaDebridApiEnabled, + megaDebridWebEnabled: mode === "web" && enabled ? true : settingsDraft.megaDebridWebEnabled, megaDebridDisabledAccountIds: [...new Set([...apiDisabledIds, ...webDisabledIds])], megaDebridApiDisabledAccountIds: apiDisabledIds, megaDebridWebDisabledAccountIds: webDisabledIds }); - showToast(currentlyDisabled ? "Account aktiviert" : "Account deaktiviert", 2000); + showToast(enabled ? "Account aktiviert" : "Account deaktiviert", 2000); }, (error) => { showToast(`Umschalten fehlgeschlagen: ${String(error)}`, 3200); }); @@ -2913,7 +2926,7 @@ export function App(): ReactElement { if (row.toggleKind === "mega" && row.accountId) { void onToggleMegaAccountEnabled(row.entry.kind as "megadebrid-api" | "megadebrid-web", row.accountId, row.disabled); } else if (row.toggleKind === "dl" && row.dlKey) { - void onToggleDebridLinkApiKeyEnabled(row.entry, row.dlKey); + void onToggleDebridLinkApiKeyEnabled(row.entry, row.dlKey, row.disabled); } else { void onToggleAccountEnabled(row.entry); } @@ -6175,7 +6188,7 @@ export function App(): ReactElement { {entry.debridLinkKeys.map((key, ki) => ( -
+
{(() => { const hostInfo = debridLinkHostLimits[key.id]; const statusDisplay = getDebridLinkKeyStatusDisplay(key, hostInfo); @@ -6196,17 +6209,17 @@ export function App(): ReactElement { {key.masked} {humanSize(key.dailyUsedBytes)} - {key.disabled ? "Deaktiviert" : key.dailyLimitBytes > 0 ? humanSize(key.dailyLimitBytes) : "Kein Limit"} + {entry.disabled || key.disabled ? "Deaktiviert" : key.dailyLimitBytes > 0 ? humanSize(key.dailyLimitBytes) : "Kein Limit"} {statusDisplay.label} {formatDebridLinkTraffic(hostInfo)} {formatDebridLinkCountQuota(hostInfo)}