The task-log and MJ task ID cells used a w-max wrapper, so long IDs
(and the platform/action subtitle) overflowed the column and rendered
under the adjacent Cost column. Constrain the cell to the column width
and let the badge label ellipsize; the copy button still copies the
full ID.
Merge origin/main (c36418c86, text protocol conversion and advanced
custom routing). Backend and most frontend changes merged cleanly;
conflicts resolved with refactor/ui as the design source of truth:
- advanced-custom-editor-dialog: keep main new routing/conversion
feature body, but use our design-system Button/Input imports and
plain button styling; add the Badge import the new body needs
- details-dialog: adopt main isUsageBillingPathLocal helper for the
billing path row, keep our muted icon styling
- i18n: union-merge of the new protocol-conversion keys across all
locales
* refactor: consolidate relay protocol converters
* refactor relayconvert text converters
* feat: refine relay converters and advanced custom routing
* refactor: enhance logging and add thought signature handling for Gemini requests
* refactor: enhance channel cache and pricing endpoint handling for advanced custom models
* feat: preserve billing usage semantics
* feat: add protocol-aware billing usage
* Delete useless files
* chore: update action versions in workflow files
* chore: update Docker action versions in workflow files
* fix: harden billing usage settlement and hot-path route matching
- estimate Gemini completion tokens locally when billable usageMetadata is
prompt-only but output content was received (e.g. client aborts the stream
before the final chunk), and rebuild the attached billing_usage as estimated
so settlement does not bill zero output tokens
- guard NewClaudeMessagesBillingUsage against all-zero ClaudeUsage, matching
the OpenAI/Gemini constructors, so a zero billing_usage cannot override a
non-zero top-level usage during settlement
- cache compiled advanced-custom route model regexes; they run on the request
hot path and were recompiled per request
- move the effectiveBillingUsage remap to PostTextConsumeQuota only, and
document that calculateTextQuotaSummary expects remapped usage
- document the updatePricingLock -> channelSyncLock lock ordering that
InitChannelCache/CacheUpdateChannel rely on, and the aux-struct pitfall in
GeminiChatResponse.UnmarshalJSON
Amends the merge resolution: drop the duplicated copy icon/tooltip block
that main reintroduced in ApiKeyCell (ours already declares it with the
text-success token), and port the functional change from main e40061965
that hides the Delete all stale button entirely when no stale instances
exist instead of rendering it disabled.
Merge origin/main while keeping this branch as the source of truth for
UI/UX. The design-system revert (337169e0a) and StatusBadge padding
revert (1b1b23d1d) from main were absorbed without applying them; only
functional additions were ported and re-styled with our primitives:
- usage-logs: Stream/Timing column split with new TimingMetricsCell and
StreamTpsCell (first-token latency + duration readout, t/s line),
admin All/Only Mine view scope (useLogsViewScope), and a mobile
filter-panel collapse toggle in DataTableFilterPanel
- keys: relative timestamps with absolute-time tooltip and stale-access
highlight via ApiKeyTimestampCell (auto-refreshing now ticker), and
copy button that resolves the real key on demand
- pricing: ModelBillingModeBadge distinguishing dynamic pricing from
token/per-request billing in the Type column
- i18n: First token translations for all locales
Rejected from main: icon-badge tones, overview accent theme colors,
bespoke mobile lists (redemptions/keys), and all other styling that
conflicts with the refactor/ui design language.
Keep truncated cells single-line across data tables, compact oversized quota figures, and replace loud avatar gradients with identity-tint styling that matches badges.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace self-hosted @font-face declarations (font-display: optional) with
direct Fontsource imports (swap), so the UI always settles on bundled
fonts instead of staying on system fonts after first paint
- Add JetBrains Mono (@fontsource-variable/jetbrains-mono) as the built-in
monospace face: it backs --font-mono, .font-mono utilities, and code/pre
- Add a "mono" option to the theme font axis (CSS token, ThemeFont type,
resolver, and config drawer with live preview); default body font stays
Public Sans, Anthropic preset keeps Lora serif
- Lighten --subtle-foreground/--faint-foreground in light mode to 60%/40%
translucent mixes of muted-foreground so secondary metadata (log
sub-labels, placeholders) reads properly grey; declare once since the
var() reference resolves per light/dark mode on <html>
Revert 6869cd94b (perf(web): align table badge spacing).
Restores px padding on status badges so usage-log timing/duration
pills are not flush against the edges.
The custom home page URL iframe only allows allow-forms/allow-popups/
allow-popups-to-escape-sandbox/allow-scripts, without allow-top-navigation*.
As a result, target="_top" nav/menu links inside the (admin-configured,
trusted) embedded page cannot navigate the top-level window on desktop
browsers, while some mobile browsers still allow it via allow-popups —
causing inconsistent behavior rather than an intended restriction.
Add allow-top-navigation-by-user-activation so user-clicked top-level
links work consistently across devices. This token only permits
user-activated top navigation and does NOT grant same-origin access,
so it avoids the security concern of allow-same-origin.
Co-authored-by: 贺. <kuang@M1.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace collapsible card details with always-visible label/value rows, add badge-list full display for cards, and polish pricing/channel toolbars and mobile cards.
- remove built-in horizontal padding from status badges so table columns align with headers.
- drop legacy negative-margin compensation from badge cells and affected table renderers.
- clean touched table components to satisfy lint rules around type imports, keys, and JSX flow.
- keep input focus and invalid rings inside the shared Input component to avoid clipping in constrained containers.
- make the sync channel selector table use a fixed header, internal body scrolling, and fixed pagination inside the dialog.
- align status cells with their header and translate channel status labels through existing i18n keys.
- batch select and unselect operations into single state updates to reduce lag with large model lists.
- align current price and upstream preset rows by rendering the same ordered field set.
- switch the table to a fixed header, internal body scrolling, and fixed pagination layout with compact upstream header counts.
- hide synthesized preset internal IDs and count only effective selectable resolutions.
- expose playground controls for sampling, penalty, token, and seed parameters.
- reuse the existing persisted config and parameter-enabled state so requests only send enabled values.
- add localized parameter copy and keep the panel scrollable on short screens.
- constrain the desktop selector panel so long group and model lists scroll within a shared height.
- make the selected model stand out with stronger row and label styling.
- scroll both lists to the active selections after the popover opens.
The ratio column normalized input to number on every keystroke, so
typing 0.05 got stuck at 0.0 which Number() collapses to 0. Keep the
value as a string draft like the top-up ratio column and only convert
to number when serializing.
Fixes#5986
* feat(subscription): add admin quota reset actions
* fix(subscription): keep quota reset in plan row actions
* refactor(subscription): move user subscription actions into menu
Thread int32 saturation clamps from tiered settlement and video task
recompute into the consume/task logs under admin_info, so oversized or
malformed billing inputs stay auditable. Clamp negative audio duration
before token conversion and gate the saturation UI markers on admin.
The sign-in route already redirects logged-in users to /dashboard in its
beforeLoad guard, but the sign-up route (and its /register alias) had no
such guard, leaving authenticated users on the registration form. This
mirrors the classic theme's AuthRedirect behavior. Add an equivalent
beforeLoad guard using the same useAuthStore, redirecting to /dashboard
for consistency with the sign-in route.
Closes#5908
Co-authored-by: 贺. <kuang@M1.local>
Shadow DOM 的样式隔离特性导致外部 html 元素上的 dark class 无法被
Shadow DOM 内部的 Tailwind dark: 选择器匹配到。通过 MutationObserver
监听 document.documentElement 的 class 变化,将 dark class 同步到
Shadow DOM 内的包装容器上,使深色模式样式正常生效。