From cefbcfb278902cd4b42aaedb180f0be636adc6da Mon Sep 17 00:00:00 2001
From: Diego Rodrigues de Sa e Souza
<8016841+diegosouzapw@users.noreply.github.com>
Date: Sun, 5 Jul 2026 07:46:18 -0300
Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20routing/settings=20UX=20clar?=
=?UTF-8?q?ity=20=E2=80=94=20share=20%,=20Cloud=20Sync=20rename,=20base-UR?=
=?UTF-8?q?L=20override=20(#6147)=20(#6253)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
feat(dashboard): routing/settings UX clarity (#6147) — effective share %, Cloud Sync→Remote Settings Sync rename, opt-in advanced base-URL override. TDD guard routing-settings-ux-6147.test.ts (6/6). Base-reds only. Integrated into release/v3.8.45.
---
CHANGELOG.md | 1 +
.../dashboard/combos/WeightTotalBar.tsx | 24 +++++++++
.../components/modals/EditConnectionModal.tsx | 53 ++++++++++++++++---
.../providers/[id]/providerPageHelpers.ts | 19 +++++++
src/i18n/messages/en.json | 2 +
src/shared/components/CloudSyncStatus.tsx | 14 +++--
tests/unit/routing-settings-ux-6147.test.ts | 53 +++++++++++++++++++
7 files changed, 154 insertions(+), 12 deletions(-)
create mode 100644 tests/unit/routing-settings-ux-6147.test.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21bc85eae7..12ff5708ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- **feat(providers):** add **Yuanbao (web)** as a cookie-session provider ([#6196](https://github.com/diegosouzapw/OmniRoute/issues/6196)) — `yuanbao-web` (Tencent Yuanbao, `yuanbao.tencent.com`) with cookie-only auth (`hy_user`/`hy_token` + public agent id), SSE→OpenAI translation incl. `reasoning_content`, exposing DeepSeek V3/R1 + Hunyuan / Hunyuan-T1. Regression guard: `tests/unit/providers-yuanbao-web.test.ts`. `together-web` was **deferred** (no verifiable web-session endpoint — needs a captured request) and `huggingchat-web` **dropped** (the existing `huggingchat` already is a web-cookie provider). (thanks @chirag127)
- **feat(providers):** route the built-in **agentrouter** through the dynamic Claude-Code wire image ([#6056](https://github.com/diegosouzapw/OmniRoute/issues/6056)) — a small static allow-set (`CC_WIRE_IMAGE_BUILTINS` in `open-sse/services/ccWireImageBuiltins.ts`), consulted by `isClaudeCodeCompatible` / `isClaudeCodeCompatibleProvider` / `applyFingerprint`, makes agentrouter adopt the CC wire-image headers + fingerprint **while guarding the CC baseUrl/auth branches** so it keeps its own registry `baseUrl` and `x-api-key` auth. Regression guard: `tests/unit/agentrouter-cc-wire-image.test.ts` (asserts the wire image is applied AND agentrouter's baseUrl/auth are preserved). Live WAF-acceptance against agentrouter.org is a VPS validation follow-up (Hard Rule #18).
- **feat(providers):** **bulk-add API keys for Cloudflare Workers AI** ([#6174](https://github.com/diegosouzapw/OmniRoute/issues/6174)) — `cloudflare-ai` is removed from the bulk-add exclusion list and the bulk parser gains a 3-field `name|accountId|apiKey` mode; the bulk route now builds a **per-entry** `providerSpecificData` so each key carries its own `accountId` (fixing the previous shared-object reuse), and both the create + key-validation paths receive it. Regression guard: `tests/unit/bulk-api-key-parser-cloudflare.test.ts`. (thanks @muflifadla38)
+- **feat(dashboard):** routing/settings UX clarity ([#6147](https://github.com/diegosouzapw/OmniRoute/issues/6147)) — (1) weighted combos show the **effective routing share %** next to each weight when weights don't sum to 100 (`WeightTotalBar.tsx`); (2) the status widget's user-facing **"Cloud Sync" label is renamed** to "Remote Settings Sync" (`CloudSyncStatus.tsx`; internal ids/state untouched); (3) built-in providers gain an **opt-in advanced base-URL override** (`isBaseUrlOverrideEligibleProvider`, hidden behind an "Advanced" toggle, reusing the existing `providerSpecificData.baseUrl` persistence — not globally widened). Regression guard: `tests/unit/routing-settings-ux-6147.test.ts`.
### 🐛 Bug Fixes
diff --git a/src/app/(dashboard)/dashboard/combos/WeightTotalBar.tsx b/src/app/(dashboard)/dashboard/combos/WeightTotalBar.tsx
index 3d0a6cbe65..bacb890994 100644
--- a/src/app/(dashboard)/dashboard/combos/WeightTotalBar.tsx
+++ b/src/app/(dashboard)/dashboard/combos/WeightTotalBar.tsx
@@ -20,6 +20,20 @@ const WEIGHT_COLORS = [
"bg-indigo-500",
];
+/**
+ * #6147 — effective routing share of a weighted target.
+ *
+ * The per-target `weight` values do not have to sum to 100; at routing time each
+ * target is picked with probability `weight / Σweights`. So a raw weight of 30
+ * with a total of 60 is an *effective* 50% share. This pure helper computes that
+ * share (0-100) and guards the `total === 0` case so the UI never renders NaN.
+ */
+export function effectiveSharePercent(weight: number, total: number): number {
+ if (!weight || weight <= 0) return 0;
+ if (!total || total <= 0) return 0;
+ return (weight / total) * 100;
+}
+
export default function WeightTotalBar({ models }: WeightTotalBarProps) {
const total = models.reduce((sum, m) => sum + (m.weight || 0), 0);
const isValid = total === 100;
@@ -49,6 +63,16 @@ export default function WeightTotalBar({ models }: WeightTotalBarProps) {
className={`inline-block w-1.5 h-1.5 rounded-full ${WEIGHT_COLORS[i % WEIGHT_COLORS.length]}`}
/>
{m.weight}%
+ {/* #6147 — show the *effective* routing share when weights don't sum to 100 */}
+ {total > 0 && total !== 100 && (
+
+ {" → "}
+ {Math.round(effectiveSharePercent(m.weight, total))}%
+
+ )}
)
)}
diff --git a/src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx b/src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx
index d4a7d3ea6c..5e409ba84f 100644
--- a/src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx
+++ b/src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx
@@ -23,6 +23,7 @@ import { isClaudeExtraUsageBlockEnabled } from "@/lib/providers/claudeExtraUsage
import { resolveDashboardProviderInfo } from "../../../providerPageUtils";
import {
isBaseUrlConfigurableProvider,
+ isBaseUrlOverrideEligibleProvider,
getProviderBaseUrlDefault,
getProviderBaseUrlHint,
getProviderBaseUrlPlaceholder,
@@ -153,7 +154,19 @@ export default function EditConnectionModal({
const [showAdvanced, setShowAdvanced] = useState(false);
const showEmail = useEmailPrivacyStore((state) => state.emailsVisible);
- const usesBaseUrl = isBaseUrlConfigurableProvider(provider);
+ // #6147 — built-in providers can opt in to an advanced base-URL override.
+ // OAuth connections are excluded: their save path does not persist
+ // providerSpecificData.baseUrl.
+ const isConfigurableBaseUrl = isBaseUrlConfigurableProvider(provider);
+ const isBaseUrlOverrideEligible =
+ connection.authType !== "oauth" && isBaseUrlOverrideEligibleProvider(provider);
+ const [showBaseUrlOverride, setShowBaseUrlOverride] = useState(
+ () =>
+ typeof connection.providerSpecificData?.baseUrl === "string" &&
+ connection.providerSpecificData.baseUrl.trim().length > 0
+ );
+ const usesBaseUrl =
+ isConfigurableBaseUrl || (isBaseUrlOverrideEligible && showBaseUrlOverride);
const defaultBaseUrl = getProviderBaseUrlDefault(provider);
const isVertex = provider === "vertex" || provider === "vertex-partner";
const isBedrock = provider === "bedrock";
@@ -441,12 +454,18 @@ export default function EditConnectionModal({
let validatedBaseUrl = null;
if (usesBaseUrl) {
- const checked = normalizeAndValidateHttpBaseUrl(formData.baseUrl, defaultBaseUrl);
- if (checked.error) {
- setSaveError(checked.error);
- return;
+ // #6147 — an opt-in override left blank clears it (no default to fall
+ // back to). Configurable providers keep their existing default-fallback.
+ if (!isConfigurableBaseUrl && !formData.baseUrl.trim()) {
+ validatedBaseUrl = null;
+ } else {
+ const checked = normalizeAndValidateHttpBaseUrl(formData.baseUrl, defaultBaseUrl);
+ if (checked.error) {
+ setSaveError(checked.error);
+ return;
+ }
+ validatedBaseUrl = checked.value;
}
- validatedBaseUrl = checked.value;
}
if (!isOAuth && formData.apiKey) {
@@ -937,13 +956,33 @@ export default function EditConnectionModal({
>
)}
+ {/* #6147 — opt-in "Advanced → override base URL" for eligible built-ins */}
+ {!usesBaseUrl && isBaseUrlOverrideEligible && (
+
+ )}
+
{usesBaseUrl && (
setFormData({ ...formData, baseUrl: e.target.value })}
placeholder={getProviderBaseUrlPlaceholder(provider)}
- hint={getProviderBaseUrlHint(provider, t)}
+ hint={
+ getProviderBaseUrlHint(provider, t) ||
+ (isBaseUrlOverrideEligible
+ ? providerText(
+ t,
+ "overrideBaseUrlHint",
+ "Advanced: point this built-in provider at a custom endpoint. Leave blank to use the default."
+ )
+ : undefined)
+ }
/>
)}
diff --git a/src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts b/src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts
index c943720d12..aa8499e839 100644
--- a/src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts
+++ b/src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts
@@ -257,6 +257,25 @@ export function isBaseUrlConfigurableProvider(providerId?: string | null) {
);
}
+/**
+ * #6147 — whether a built-in provider is eligible for an OPT-IN "Advanced →
+ * override base URL" affordance in the edit-connection modal.
+ *
+ * This does NOT widen the always-on base-URL field: providers already covered by
+ * `isBaseUrlConfigurableProvider` (the configurable set + self-hosted) keep their
+ * existing dedicated field and return `false` here. Every *other* provider id is
+ * eligible to opt in per-connection so an operator can hot-fix a broken built-in
+ * preset by pointing it at a custom endpoint. The field stays hidden until the
+ * user explicitly reveals it (or an override was already saved), so nothing is
+ * exposed by default. OAuth connections are excluded at the call site, since
+ * their save path does not persist `providerSpecificData.baseUrl`.
+ */
+export function isBaseUrlOverrideEligibleProvider(providerId?: string | null): boolean {
+ if (!providerId) return false;
+ if (isBaseUrlConfigurableProvider(providerId)) return false;
+ return true;
+}
+
export function getProviderBaseUrlDefault(providerId?: string | null) {
const localProvider = getLocalProviderMetadata(providerId);
if (typeof localProvider?.localDefault === "string" && localProvider.localDefault.trim()) {
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index c676c7834c..98d387f1a8 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -4849,6 +4849,8 @@
"kimiWebDesc": "Moonshot AI consumer chat via www.kimi.com (international, Connect-RPC API)",
"doubaoWebLabel": "Dola Web",
"doubaoWebDesc": "ByteDance AI chat via dola.com",
+ "overrideBaseUrlAdvanced": "Advanced: override base URL",
+ "overrideBaseUrlHint": "Advanced: point this built-in provider at a custom endpoint. Leave blank to use the default.",
"bulkAddFormatHintCloudflare": "One key per line. Format: name|accountId|apiKey (Cloudflare account ID + API token)."
},
"settings": {
diff --git a/src/shared/components/CloudSyncStatus.tsx b/src/shared/components/CloudSyncStatus.tsx
index f01c7d9dab..aae7fa1b09 100644
--- a/src/shared/components/CloudSyncStatus.tsx
+++ b/src/shared/components/CloudSyncStatus.tsx
@@ -13,11 +13,15 @@
import { useState, useEffect, useRef, useCallback } from "react";
import { useRouter } from "next/navigation";
+// #6147 — user-facing labels renamed from "Cloud …" to "Remote Settings Sync"
+// wording (this feature syncs the operator's own settings to their own remote
+// store — it is not a cloud/telemetry service). Internal state keys, the
+// `cloud_*` material icons and the cloudSync.* wiring are intentionally kept.
const STATUS_CONFIG = {
- connected: { icon: "cloud_done", color: "text-green-500", label: "Cloud" },
+ connected: { icon: "cloud_done", color: "text-green-500", label: "Synced" },
syncing: { icon: "cloud_sync", color: "text-blue-400 animate-pulse", label: "Syncing..." },
- disconnected: { icon: "cloud_off", color: "text-amber-500", label: "Cloud Off" },
- error: { icon: "cloud_off", color: "text-red-400", label: "Cloud Error" },
+ disconnected: { icon: "cloud_off", color: "text-amber-500", label: "Sync Off" },
+ error: { icon: "cloud_off", color: "text-red-400", label: "Sync Error" },
disabled: { icon: "cloud_off", color: "text-text-muted/50", label: "Disabled" },
};
@@ -80,10 +84,10 @@ export default function CloudSyncStatus({ collapsed = false }) {
className="flex items-center gap-2 px-3 py-1.5 text-xs rounded-lg hover:bg-white/5 transition-colors cursor-pointer w-full"
title={
lastSync
- ? `Cloud ${status === "connected" ? "connected" : "disconnected"} — Last sync: ${lastSync.toLocaleTimeString()}`
+ ? `Remote settings sync ${status === "connected" ? "connected" : "disconnected"} — Last sync: ${lastSync.toLocaleTimeString()}`
: config.label
}
- aria-label={`Cloud sync status: ${config.label}`}
+ aria-label={`Remote settings sync status: ${config.label}`}
>
{config.icon}
diff --git a/tests/unit/routing-settings-ux-6147.test.ts b/tests/unit/routing-settings-ux-6147.test.ts
new file mode 100644
index 0000000000..8fff64d4dd
--- /dev/null
+++ b/tests/unit/routing-settings-ux-6147.test.ts
@@ -0,0 +1,53 @@
+// #6147 — routing/settings UX clarity. Pure-function guards for two of the three
+// sub-fixes:
+// 1. Weighted effective-share % (weight ÷ Σweights), incl. total===0 and sum≠100.
+// 3. Opt-in base-URL override eligibility predicate for built-in providers.
+// (Item 2 is a display-only label rename with no pure seam — manual verification.)
+import { test } from "node:test";
+import assert from "node:assert/strict";
+import { effectiveSharePercent } from "../../src/app/(dashboard)/dashboard/combos/WeightTotalBar.tsx";
+import {
+ isBaseUrlOverrideEligibleProvider,
+ isBaseUrlConfigurableProvider,
+} from "../../src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts";
+
+test("effectiveSharePercent — sum === 100 keeps raw weight", () => {
+ assert.equal(effectiveSharePercent(30, 100), 30);
+ assert.equal(effectiveSharePercent(70, 100), 70);
+});
+
+test("effectiveSharePercent — sum !== 100 rescales to the effective share", () => {
+ // Two equal weights of 30 (total 60) are each an effective 50%.
+ assert.equal(effectiveSharePercent(30, 60), 50);
+ // Over-100 total: 150 total, weight 75 → 50%.
+ assert.equal(effectiveSharePercent(75, 150), 50);
+});
+
+test("effectiveSharePercent — guards total === 0 and non-positive weight (no NaN)", () => {
+ assert.equal(effectiveSharePercent(0, 0), 0);
+ assert.equal(effectiveSharePercent(50, 0), 0);
+ assert.equal(effectiveSharePercent(0, 100), 0);
+ assert.equal(effectiveSharePercent(-10, 100), 0);
+ assert.ok(!Number.isNaN(effectiveSharePercent(10, 0)));
+});
+
+test("isBaseUrlOverrideEligibleProvider — built-in providers are opt-in eligible", () => {
+ // A plain built-in that has no dedicated base-URL field today.
+ assert.equal(isBaseUrlOverrideEligibleProvider("openai"), true);
+ assert.equal(isBaseUrlOverrideEligibleProvider("groq"), true);
+});
+
+test("isBaseUrlOverrideEligibleProvider — providers with an always-on field are NOT re-offered", () => {
+ // Everything already covered by the configurable set stays false here so the
+ // override does not double up on the existing dedicated field.
+ for (const id of ["azure-openai", "databricks", "siliconflow"]) {
+ assert.equal(isBaseUrlConfigurableProvider(id), true);
+ assert.equal(isBaseUrlOverrideEligibleProvider(id), false);
+ }
+});
+
+test("isBaseUrlOverrideEligibleProvider — empty/nullish ids are not eligible", () => {
+ assert.equal(isBaseUrlOverrideEligibleProvider(""), false);
+ assert.equal(isBaseUrlOverrideEligibleProvider(null), false);
+ assert.equal(isBaseUrlOverrideEligibleProvider(undefined), false);
+});