diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 8e3b385..9626de6 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -975,16 +975,27 @@ const KNOWN_HOSTERS: { id: string; label: string }[] = [
{ id: "isra", label: "Isra.cloud" }
];
+export function buildProviderOrderEntry(provider: DebridProvider, settings: RendererSettings): {
+ id: DebridProvider;
+ label: string;
+ icon: string;
+} {
+ const legacyMegaService = settings.megaDebridPreferApi ? "megadebrid-api" : "megadebrid-web";
+ const service = provider === "megadebrid" ? legacyMegaService : provider as AccountService;
+ const kind = getConfiguredAccountKind(settings, service);
+ const option = kind ? ACCOUNT_OPTIONS.find((entry) => entry.kind === kind) : null;
+ const modeLabel = option?.modeLabel || (provider === "megadebrid" ? (settings.megaDebridPreferApi ? "API" : "Web-Login") : "");
+ const serviceLabel = option?.serviceLabel || providerLabels[provider];
+ return {
+ id: provider,
+ label: modeLabel ? `${serviceLabel} (${modeLabel})` : serviceLabel,
+ icon: ACCOUNT_SERVICE_ICONS[option?.service || service]
+ };
+}
+
function providerLabelWithMode(provider: DebridProvider, settings: RendererSettings): string {
- const base = providerLabels[provider];
- if (provider === "megadebrid" || provider === "megadebrid-api" || provider === "megadebrid-web") {
- return base;
- }
- const kind = getConfiguredAccountKind(settings, provider as AccountService);
- if (!kind) return base;
- const opt = ACCOUNT_OPTIONS.find((o) => o.kind === kind);
- return opt?.modeLabel ? `${base} (${opt.modeLabel})` : base;
-}
+ return buildProviderOrderEntry(provider, settings).label;
+}
function formatAllDebridSourceLabel(source: AllDebridHostInfo["source"]): string {
return source === "web" ? "Web-Login" : "API-Key";
@@ -5586,7 +5597,7 @@ export function App(): ReactElement {
statusSort: accountStatusSort,
runtime: accountRuntimeModel,
rules: {
- providerOrder: activeProviderOrder.map((provider) => providerLabelWithMode(provider, settingsDraft)),
+ providerOrder: activeProviderOrder.map((provider) => buildProviderOrderEntry(provider, settingsDraft)),
routing: routingEntries.map(([hosterId, provider]) => `${KNOWN_HOSTERS.find((hoster) => hoster.id === hosterId)?.label || hosterId} → ${providerLabelWithMode(provider, settingsDraft)}`),
autoFallback: settingsDraft.autoProviderFallback,
rememberCredentials: settingsDraft.rememberToken,
diff --git a/src/renderer/views/settings/AccountWorkspace.tsx b/src/renderer/views/settings/AccountWorkspace.tsx
index d036cba..ec31c63 100644
--- a/src/renderer/views/settings/AccountWorkspace.tsx
+++ b/src/renderer/views/settings/AccountWorkspace.tsx
@@ -81,7 +81,7 @@ function getAccountPanelNavigationIndex(currentIndex: number, key: string): numb
}
export interface AccountRulesViewModel {
- providerOrder: readonly string[];
+ providerOrder: readonly { id: string; label: string; icon: string }[];
routing: readonly string[];
autoFallback: boolean;
rememberCredentials?: boolean;
@@ -505,21 +505,24 @@ function AccountRules({ model, actions }: AccountWorkspaceProps): ReactElement {
Keine Provider konfiguriert.
) : (
- {model.rules.providerOrder.map((provider, index) => (
- - (
+
- actions.onProviderDragOver?.(event, index)}
onDragStart={(event) => actions.onProviderDragStart?.(event, index)}
onDrop={(event) => actions.onProviderDrop?.(event, index)}
- >
- {provider}
- {actions.onMoveProvider ? (
-
-
-
-
+ >
+
+
+ {provider.label}
+
+ {actions.onMoveProvider ? (
+
+
+
+
) : null}
))}
diff --git a/src/renderer/views/settings/settings.css b/src/renderer/views/settings/settings.css
index eda0b1c..214bec5 100644
--- a/src/renderer/views/settings/settings.css
+++ b/src/renderer/views/settings/settings.css
@@ -1067,6 +1067,19 @@
gap: 4px;
}
+.settings-provider-order-provider {
+ display: inline-flex;
+ align-items: center;
+ min-width: 0;
+ gap: 9px;
+ color: var(--ui-text);
+}
+
+.settings-provider-order-provider img {
+ flex: 0 0 auto;
+ object-fit: contain;
+}
+
.settings-provider-order-actions button {
width: 30px;
height: 28px;
diff --git a/tests/settings-view.test.tsx b/tests/settings-view.test.tsx
index f2a1575..4da0708 100644
--- a/tests/settings-view.test.tsx
+++ b/tests/settings-view.test.tsx
@@ -4,7 +4,7 @@ import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { defaultSettings } from "../src/main/constants";
import { createRendererSettings, createRendererState } from "../src/main/renderer-state";
-import { buildAccountAddFields, buildAccountCreateProviderOrderUpdate, createAccountDialogState, createDiscardedSettingsState, createSettingsDraft, resolveSettingsSaveCompletion } from "../src/renderer/App";
+import { buildAccountAddFields, buildAccountCreateProviderOrderUpdate, buildProviderOrderEntry, createAccountDialogState, createDiscardedSettingsState, createSettingsDraft, resolveSettingsSaveCompletion } from "../src/renderer/App";
import { buildAccountReplaceCommand, createAccountEditState, type AccountEditTarget } from "../src/renderer/account-edit";
import {
buildScopedAccountEnabledState,
@@ -292,7 +292,10 @@ function workspaceModel(): AccountWorkspaceViewModel {
selectedIds: [buildAccountRowId("megadebrid-api", "API", "mega-premium")],
busy: false,
rules: {
- providerOrder: ["Debrid-Link", "Real-Debrid"],
+ providerOrder: [
+ { id: "debridlink", label: "Debrid-Link (API)", icon: "./provider-icons/debrid-link.ico" },
+ { id: "realdebrid", label: "Real-Debrid (Web-Login)", icon: "./provider-icons/real-debrid.png" }
+ ],
routing: ["rapidgator.net → Debrid-Link"],
autoFallback: true
},
@@ -1146,6 +1149,10 @@ describe("account workspace", () => {
expect(html).toContain("Hoster-Routing");
expect(html).toContain("Automatischer Fallback");
expect(html).toContain("Provider-Laufzeit");
+ expect(html).toContain("Debrid-Link (API)");
+ expect(html).toContain("Real-Debrid (Web-Login)");
+ expect(html).toContain("./provider-icons/debrid-link.ico");
+ expect(html).toContain("./provider-icons/real-debrid.png");
});
it("keeps add and edit dialogs separate and every secret field protected", () => {
@@ -1347,6 +1354,27 @@ describe("account workspace", () => {
});
describe("settings App integration", () => {
+ it("projects provider order entries with logos and explicit login modes", () => {
+ const settings = createRendererSettings({
+ ...defaultSettings(),
+ megaDebridWebEnabled: true,
+ megaDebridWebCredentials: "member:password",
+ deepbridApiKey: "test-key",
+ providerOrder: ["megadebrid-web", "deepbrid"]
+ });
+
+ expect(buildProviderOrderEntry("megadebrid-web", settings)).toEqual({
+ id: "megadebrid-web",
+ label: "Mega-Debrid (Web-Login)",
+ icon: "./provider-icons/mega-debrid.png"
+ });
+ expect(buildProviderOrderEntry("deepbrid", settings)).toEqual({
+ id: "deepbrid",
+ label: "Deepbrid (API)",
+ icon: "./provider-icons/deepbrid.png"
+ });
+ });
+
it("preserves the write-only webhook during live snapshots and clears it for backup reseeding", () => {
const safe = createRendererSettings({ ...defaultSettings(), notifyUrl: "https://private.example.test/hook" });
const current = { ...safe, archivePasswordList: "loaded-password", notifyUrl: "https://private.example.test/hook" };