@jingyi0605/codingns4dsh 0.2.1-rc.2 → 0.2.1-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +6 -4
- package/README.md +6 -6
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
- package/data/build/dist/bootstrap/index.d.ts +1 -1
- package/data/build/dist/client/bundle.js +5224 -290
- package/data/build/dist/client/bundle.js.map +1 -1
- package/data/build/dist/client/client.magpie-model-tag.js +155 -5
- package/data/build/dist/client/client.magpie-model-tag.js.map +1 -1
- package/data/build/dist/client/client.native-workspace-store.js +30 -4
- package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
- package/data/build/dist/client/client.transport.js +747 -48
- package/data/build/dist/client/client.transport.js.map +1 -1
- package/data/build/dist/client/desktop-assistant.js +953 -185
- package/data/build/dist/client/feature-requirement.d.ts +43 -0
- package/data/build/dist/client/feature-requirement.d.ts.map +1 -0
- package/data/build/dist/client/feature-requirement.js +105 -0
- package/data/build/dist/client/feature-requirement.js.map +1 -0
- package/data/build/dist/client/features/index.d.ts +1 -0
- package/data/build/dist/client/features/index.d.ts.map +1 -1
- package/data/build/dist/client/features/index.js +3 -0
- package/data/build/dist/client/features/index.js.map +1 -1
- package/data/build/dist/client/features/magpie-management-controls.d.ts +46 -0
- package/data/build/dist/client/features/magpie-management-controls.d.ts.map +1 -0
- package/data/build/dist/client/features/magpie-management-controls.js +794 -0
- package/data/build/dist/client/features/magpie-management-controls.js.map +1 -0
- package/data/build/dist/client/features/magpie-management-page.d.ts +129 -0
- package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -0
- package/data/build/dist/client/features/magpie-management-page.js +1279 -0
- package/data/build/dist/client/features/magpie-management-page.js.map +1 -0
- package/data/build/dist/client/features/magpie-management.d.ts +7 -0
- package/data/build/dist/client/features/magpie-management.d.ts.map +1 -0
- package/data/build/dist/client/features/magpie-management.js +154 -0
- package/data/build/dist/client/features/magpie-management.js.map +1 -0
- package/data/build/dist/client/features/magpie-mark.d.ts +10 -0
- package/data/build/dist/client/features/magpie-mark.d.ts.map +1 -0
- package/data/build/dist/client/features/magpie-mark.js +21 -0
- package/data/build/dist/client/features/magpie-mark.js.map +1 -0
- package/data/build/dist/client/features/magpie-provider-logo.d.ts +11 -0
- package/data/build/dist/client/features/magpie-provider-logo.d.ts.map +1 -0
- package/data/build/dist/client/features/magpie-provider-logo.js +35 -0
- package/data/build/dist/client/features/magpie-provider-logo.js.map +1 -0
- package/data/build/dist/client/features/subscription-quota-groups.d.ts +193 -0
- package/data/build/dist/client/features/subscription-quota-groups.d.ts.map +1 -0
- package/data/build/dist/client/features/subscription-quota-groups.js +548 -0
- package/data/build/dist/client/features/subscription-quota-groups.js.map +1 -0
- package/data/build/dist/client/git-management.d.ts.map +1 -1
- package/data/build/dist/client/git-management.js +11 -9
- package/data/build/dist/client/git-management.js.map +1 -1
- package/data/build/dist/client/git-panel-styles.js +1 -0
- package/data/build/dist/client/git-panel-styles.js.map +1 -1
- package/data/build/dist/client/index.d.ts +1 -1
- package/data/build/dist/client/index.d.ts.map +1 -1
- package/data/build/dist/client/index.js +1 -1
- package/data/build/dist/client/index.js.map +1 -1
- package/data/build/dist/client/locale.d.ts.map +1 -1
- package/data/build/dist/client/locale.js +7 -0
- package/data/build/dist/client/locale.js.map +1 -1
- package/data/build/dist/client/locales/magpie.d.ts +4 -0
- package/data/build/dist/client/locales/magpie.d.ts.map +1 -0
- package/data/build/dist/client/locales/magpie.js +644 -0
- package/data/build/dist/client/locales/magpie.js.map +1 -0
- package/data/build/dist/client/locales/usage.d.ts.map +1 -1
- package/data/build/dist/client/locales/usage.js +52 -0
- package/data/build/dist/client/locales/usage.js.map +1 -1
- package/data/build/dist/client/magpie-model-tag.d.ts +9 -1
- package/data/build/dist/client/magpie-model-tag.d.ts.map +1 -1
- package/data/build/dist/client/magpie-model-tag.js +15 -3
- package/data/build/dist/client/magpie-model-tag.js.map +1 -1
- package/data/build/dist/client/provider-icons.d.ts +8 -0
- package/data/build/dist/client/provider-icons.d.ts.map +1 -1
- package/data/build/dist/client/provider-icons.js +122 -2
- package/data/build/dist/client/provider-icons.js.map +1 -1
- package/data/build/dist/client/settings-bridge.d.ts +1 -0
- package/data/build/dist/client/settings-bridge.d.ts.map +1 -1
- package/data/build/dist/client/settings-bridge.js +29 -10
- package/data/build/dist/client/settings-bridge.js.map +1 -1
- package/data/build/dist/client/settings-section.d.ts.map +1 -1
- package/data/build/dist/client/settings-section.js +21 -3
- package/data/build/dist/client/settings-section.js.map +1 -1
- package/data/build/dist/client/style.css +224 -221
- package/data/build/dist/client/subscription-slot.d.ts +22 -1
- package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
- package/data/build/dist/client/subscription-slot.js +374 -25
- package/data/build/dist/client/subscription-slot.js.map +1 -1
- package/data/build/dist/dsh-capabilities/client/global-panel-adapter.d.ts +27 -0
- package/data/build/dist/dsh-capabilities/client/global-panel-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/global-panel-adapter.js +109 -0
- package/data/build/dist/dsh-capabilities/client/global-panel-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-title-adapter.d.ts +2 -1
- package/data/build/dist/dsh-capabilities/host/session-title-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/host/session-title-adapter.js +32 -2
- package/data/build/dist/dsh-capabilities/host/session-title-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.js +12 -11
- package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.js +12 -9
- package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/types.js.map +1 -1
- package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +27 -0
- package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/acp-cli-driver.js +88 -13
- package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts +10 -0
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/codex-driver.js +32 -1
- package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts +6 -5
- package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/command-code-acp-loader.js +72 -12
- package/data/build/dist/host/cli-adapters/command-code-acp-loader.js.map +1 -1
- package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/command-code-driver.js +26 -1
- package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +15 -2
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.d.ts +13 -0
- package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.js +438 -6
- package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
- package/data/build/dist/host/cli-adapters/grok-driver.js +5 -0
- package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-detection.d.ts +72 -0
- package/data/build/dist/host/cli-adapters/magpie-detection.d.ts.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-detection.js +312 -0
- package/data/build/dist/host/cli-adapters/magpie-detection.js.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-management.d.ts +50 -0
- package/data/build/dist/host/cli-adapters/magpie-management.d.ts.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-management.js +1343 -0
- package/data/build/dist/host/cli-adapters/magpie-management.js.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-update.d.ts +59 -0
- package/data/build/dist/host/cli-adapters/magpie-update.d.ts.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-update.js +249 -0
- package/data/build/dist/host/cli-adapters/magpie-update.js.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-usage.d.ts +70 -8
- package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-usage.js +1075 -125
- package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-web.d.ts +69 -0
- package/data/build/dist/host/cli-adapters/magpie-web.d.ts.map +1 -0
- package/data/build/dist/host/cli-adapters/magpie-web.js +485 -0
- package/data/build/dist/host/cli-adapters/magpie-web.js.map +1 -0
- package/data/build/dist/host/cli-adapters/process-utils.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/process-utils.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/process-utils.js +8 -0
- package/data/build/dist/host/cli-adapters/process-utils.js.map +1 -1
- package/data/build/dist/host/cli-adapters/session-performance-projection.d.ts +6 -0
- package/data/build/dist/host/cli-adapters/session-performance-projection.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/session-performance-projection.js +25 -0
- package/data/build/dist/host/cli-adapters/session-performance-projection.js.map +1 -1
- package/data/build/dist/host/dsh-gateway-feature.d.ts.map +1 -1
- package/data/build/dist/host/dsh-gateway-feature.js +26 -3
- package/data/build/dist/host/dsh-gateway-feature.js.map +1 -1
- package/data/build/dist/host/features/host-status.d.ts +25 -0
- package/data/build/dist/host/features/host-status.d.ts.map +1 -1
- package/data/build/dist/host/features/host-status.js +60 -6
- package/data/build/dist/host/features/host-status.js.map +1 -1
- package/data/build/dist/host/features/lan-access-dsh.d.ts.map +1 -1
- package/data/build/dist/host/features/lan-access-dsh.js +61 -10
- package/data/build/dist/host/features/lan-access-dsh.js.map +1 -1
- package/data/build/dist/host/features/session-translation-protection.d.ts.map +1 -1
- package/data/build/dist/host/features/session-translation-protection.js +2 -1
- package/data/build/dist/host/features/session-translation-protection.js.map +1 -1
- package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
- package/data/build/dist/host/lan-access-dsh.js +6 -2
- package/data/build/dist/host/lan-access-dsh.js.map +1 -1
- package/data/build/dist/host/modules/pwa/pwa-session-notifications.js +2 -1
- package/data/build/dist/host/modules/pwa/pwa-session-notifications.js.map +1 -1
- package/data/build/dist/host/rpc.d.ts +15 -2
- package/data/build/dist/host/rpc.d.ts.map +1 -1
- package/data/build/dist/host/rpc.js +47 -6
- package/data/build/dist/host/rpc.js.map +1 -1
- package/data/build/dist/host/settings.d.ts.map +1 -1
- package/data/build/dist/host/settings.js +5 -0
- package/data/build/dist/host/settings.js.map +1 -1
- package/data/build/dist/shared/contracts/config.d.ts +18 -0
- package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/config.js +8 -0
- package/data/build/dist/shared/contracts/config.js.map +1 -1
- package/data/build/dist/shared/contracts/errors.d.ts +2 -2
- package/data/build/dist/shared/contracts/feature.d.ts +7 -0
- package/data/build/dist/shared/contracts/feature.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/magpie-management.d.ts +414 -0
- package/data/build/dist/shared/contracts/magpie-management.d.ts.map +1 -0
- package/data/build/dist/shared/contracts/magpie-management.js +2 -0
- package/data/build/dist/shared/contracts/magpie-management.js.map +1 -0
- package/data/build/dist/shared/contracts/subscription.d.ts +77 -1
- package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/subscription.js.map +1 -1
- package/data/build/dist/shared/contracts/version.d.ts +4 -4
- package/data/build/dist/shared/contracts/version.js +3 -3
- package/data/build/dist/shared/index.d.ts +3 -1
- package/data/build/dist/shared/index.d.ts.map +1 -1
- package/data/build/dist/shared/index.js +2 -1
- package/data/build/dist/shared/index.js.map +1 -1
- package/data/build/dist/shared/magpie-provider-id.d.ts +12 -0
- package/data/build/dist/shared/magpie-provider-id.d.ts.map +1 -0
- package/data/build/dist/shared/magpie-provider-id.js +16 -0
- package/data/build/dist/shared/magpie-provider-id.js.map +1 -0
- package/data/build/dist/shared/session-title.d.ts.map +1 -1
- package/data/build/dist/shared/session-title.js +10 -4
- package/data/build/dist/shared/session-title.js.map +1 -1
- package/package.json +29 -29
- package/profile/README.md +2 -2
- package/profile/package.json +3 -3
- package/profile/version.json +3 -3
- package/version.json +3 -3
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { startSerialPolling } from './serial-polling.js';
|
|
2
|
-
import { createElement, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import { createElement, Fragment, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
3
4
|
import { isSubscriptionUsageFresh } from '../shared/contracts/subscription.js';
|
|
4
5
|
import { DEFAULT_SUBSCRIPTION_USAGE_SETTINGS } from '../shared/contracts/config.js';
|
|
5
6
|
import { callCliRpc } from './cli-catalog.js';
|
|
6
7
|
import { resolveCodingNsTranslator, useCodingNsTranslator } from './locale.js';
|
|
7
8
|
import { providerIconUrl } from './provider-icons.js';
|
|
9
|
+
import { MagpieProviderLogo } from './features/magpie-provider-logo.js';
|
|
10
|
+
import { MAGPIE_REQUESTS_PAGE_SIZE, RequestsPage, installMagpiePageStyles } from './features/magpie-management-page.js';
|
|
11
|
+
import { createQuotaAccountBlock, createQuotaGroupHeader, formatQuotaCredits, formatQuotaNumber, groupQuotasByProvider, readWindowCreditBalance, quotaWindowRemaining, resolveQuotaBalanceLabel, resolveQuotaCreditBalance, } from './features/subscription-quota-groups.js';
|
|
8
12
|
import { subscribeSessionAdapters } from './session-adapter-cache.js';
|
|
9
13
|
import { loadCliSessionConfig } from './cli-session-config-cache.js';
|
|
10
14
|
import { dshPopupSurfaceStyle, dshSettingsButtonStyle, dshSettingsPrimaryButtonStyle, dshThemeColor } from './theme.js';
|
|
11
|
-
import { useDismissOnOutsidePointer } from './popup-dismiss.js';
|
|
15
|
+
import { backdropPointerDownHandler, useDismissOnOutsidePointer } from './popup-dismiss.js';
|
|
16
|
+
import { callCodingNsRpcResult } from './rpc-call.js';
|
|
12
17
|
import { uiFontSize } from './font-scale.js';
|
|
13
18
|
const SUBSCRIPTION_STYLE_ID = 'codingns4dsh-subscription-responsive-style';
|
|
14
19
|
/**
|
|
@@ -57,6 +62,7 @@ function loadUsage(rpc, key, payload) {
|
|
|
57
62
|
/** 图标重置按钮的悬停/按下/聚焦/禁用只能由注入样式表表达,内联样式无法命中伪类。 */
|
|
58
63
|
const RESET_BUTTON_CSS = '.codingns4dsh-subscription-reset{display:inline-flex;align-items:center;justify-content:center;flex:none;width:26px;height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2,#d9d9d9);border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary,GrayText);cursor:pointer;transition:background .15s ease,color .15s ease}.codingns4dsh-subscription-reset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-subscription-reset:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active,rgba(127,127,127,.14))}.codingns4dsh-subscription-reset:focus-visible{outline:none;box-shadow:0 0 0 var(--dsw-focus-ring-width,2px) var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff))}.codingns4dsh-subscription-reset:disabled{opacity:.4;cursor:not-allowed}@media (prefers-reduced-motion: reduce){.codingns4dsh-subscription-reset{transition:none}}';
|
|
59
64
|
const MAGPIE_ROUTE_CSS = '@keyframes codingns4dsh-magpie-route-pulse{0%{transform:translateY(-120%);opacity:0}20%{opacity:1}80%{opacity:1}100%{transform:translateY(320%);opacity:0}}@keyframes codingns4dsh-magpie-route-breathe{0%,100%{box-shadow:0 0 0 0 rgba(22,119,255,0)}50%{box-shadow:0 0 0 4px rgba(22,119,255,.16)}}@keyframes codingns4dsh-magpie-route-step{from{opacity:0;transform:translateY(4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.codingns4dsh-magpie-route-pulse{animation:codingns4dsh-magpie-route-pulse 1.8s ease-in-out infinite}.codingns4dsh-magpie-route-node-active{animation:codingns4dsh-magpie-route-breathe 2s ease-in-out infinite}.codingns4dsh-magpie-route-step{animation:codingns4dsh-magpie-route-step .38s cubic-bezier(.2,.75,.25,1) both;transition:background .16s ease}.codingns4dsh-magpie-route-step:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.07))}.codingns4dsh-magpie-route-step:hover .codingns4dsh-magpie-route-node{box-shadow:0 0 0 1px var(--dsw-alias-state-business-primary,#1677ff),0 0 0 4px rgba(22,119,255,.1)}.codingns4dsh-magpie-route-node{transition:box-shadow .16s ease}.codingns4dsh-magpie-tab:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff)) inset}@media (prefers-reduced-motion:reduce){.codingns4dsh-magpie-route-pulse,.codingns4dsh-magpie-route-node-active,.codingns4dsh-magpie-route-step,.codingns4dsh-magpie-route-node{animation:none;transition:none}}';
|
|
65
|
+
const MAGPIE_REQUESTS_CSS = '.codingns4dsh-magpie-route-requests:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-magpie-route-requests:focus-visible,.codingns4dsh-magpie-requests-close:focus-visible,.codingns4dsh-magpie-requests-retry:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff))}.codingns4dsh-magpie-requests-close:hover,.codingns4dsh-magpie-requests-retry:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-magpie-requests-dialog:focus,.codingns4dsh-magpie-requests-dialog:focus-visible{outline:none}.codingns4dsh-magpie-requests-body{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.codingns4dsh-magpie-requests-view{display:block!important;width:100%;height:auto!important;min-height:0;padding-left:0!important;background:transparent}.codingns4dsh-magpie-requests-view .codingns-magpie-view{max-width:none;padding:0}@media (max-width:768px){.codingns4dsh-magpie-requests-overlay{align-items:flex-end!important;padding:12px!important}.codingns4dsh-magpie-requests-dialog{width:100%!important;max-height:78vh!important;max-height:78dvh!important}}@media (prefers-reduced-motion:reduce){.codingns4dsh-magpie-route-requests{transition:none}}';
|
|
60
66
|
export function calculateMagpiePopoverPlacement(rootLeft, viewportWidth, sidebarLeft) {
|
|
61
67
|
const margin = 12;
|
|
62
68
|
const boundary = Math.min(viewportWidth - margin, sidebarLeft === null ? viewportWidth - margin : sidebarLeft - margin);
|
|
@@ -64,14 +70,19 @@ export function calculateMagpiePopoverPlacement(rootLeft, viewportWidth, sidebar
|
|
|
64
70
|
const left = Math.max(margin, Math.min(rootLeft, boundary - width));
|
|
65
71
|
return { left: left - rootLeft, width };
|
|
66
72
|
}
|
|
67
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。
|
|
75
|
+
* 弹层高度上限固定为浏览器可视高度的 75%:先写 `vh` 兜底,再由 `dvh` 覆盖,
|
|
76
|
+
* 使移动端工具栏收展后仍按真实可视区计算;超出部分在弹层内部纵向滚动。
|
|
77
|
+
*/
|
|
78
|
+
export const SUBSCRIPTION_RESPONSIVE_CSS = '@media (max-width: 768px){.codingns4dsh-subscription-trigger{gap:0!important;padding-left:4px!important;padding-right:4px!important}.codingns4dsh-subscription-label,.codingns4dsh-subscription-value{display:none!important}.codingns4dsh-subscription-popover{position:fixed!important;left:12px!important;right:12px!important;bottom:48px!important;width:auto!important;min-width:0!important;max-width:none!important;max-height:75vh!important;max-height:75dvh!important;overflow-x:hidden!important;overflow-y:auto!important;overscroll-behavior:contain!important;box-sizing:border-box!important}}';
|
|
68
79
|
function installSubscriptionStyles() {
|
|
69
80
|
if (typeof document === 'undefined' || document.querySelector(`style[data-plugin-css="${SUBSCRIPTION_STYLE_ID}"]`) !== null)
|
|
70
81
|
return;
|
|
71
82
|
const style = document.createElement('style');
|
|
72
83
|
style.dataset.plugin = 'codingns4dsh';
|
|
73
84
|
style.dataset.pluginCss = SUBSCRIPTION_STYLE_ID;
|
|
74
|
-
style.textContent =
|
|
85
|
+
style.textContent = SUBSCRIPTION_RESPONSIVE_CSS + RESET_BUTTON_CSS + MAGPIE_ROUTE_CSS + MAGPIE_REQUESTS_CSS;
|
|
75
86
|
document.head.appendChild(style);
|
|
76
87
|
}
|
|
77
88
|
/** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
|
|
@@ -101,10 +112,19 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
101
112
|
const [open, setOpen] = useState(false);
|
|
102
113
|
const [loading, setLoading] = useState(false);
|
|
103
114
|
const [magpieTab, setMagpieTab] = useState('usage');
|
|
115
|
+
// 多账号厂商默认只展开会话实际使用的账号;展开状态挂在根组件上,
|
|
116
|
+
// 弹层内容本身不持有 Hook,便于无浏览器的组件测试直接展开内容树。
|
|
117
|
+
const [expandedQuotaGroups, setExpandedQuotaGroups] = useState([]);
|
|
118
|
+
const toggleQuotaGroup = (provider) => {
|
|
119
|
+
setExpandedQuotaGroups((current) => current.includes(provider)
|
|
120
|
+
? current.filter((item) => item !== provider)
|
|
121
|
+
: [...current, provider]);
|
|
122
|
+
};
|
|
104
123
|
const [magpiePlacement, setMagpiePlacement] = useState({ left: 0, width: 400 });
|
|
105
124
|
const [clock, setClock] = useState(() => Date.now());
|
|
106
125
|
const rootRef = useRef(null);
|
|
107
126
|
const magpiePopoverRef = useRef(null);
|
|
127
|
+
const magpieRequestsDialogRef = useRef(null);
|
|
108
128
|
const resetDialogRef = useRef(null);
|
|
109
129
|
// 重置成功后的刷新不能重跑加载 effect,否则 usage 会被清空导致底部入口闪断。
|
|
110
130
|
const refreshRef = useRef(null);
|
|
@@ -184,6 +204,9 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
184
204
|
return;
|
|
185
205
|
}
|
|
186
206
|
let active = true;
|
|
207
|
+
// 未解析的 Magpie 配额必须快速补读:官方余额一旦抢先显示,用户要等到下一次
|
|
208
|
+
// 轮询(默认 5 分钟)或整页刷新才会切到 Magpie。
|
|
209
|
+
let upstreamUnresolved = false;
|
|
187
210
|
setEligible(false);
|
|
188
211
|
setSnapshot(null);
|
|
189
212
|
setAdapterId(null);
|
|
@@ -249,6 +272,7 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
249
272
|
: await loadUsage(props.rpc, cacheKey, payload);
|
|
250
273
|
if (next !== null)
|
|
251
274
|
subscriptionUsageCache.set(cacheKey, { usage: next, capturedAt: Date.now() });
|
|
275
|
+
upstreamUnresolved = shouldResolveMagpieQuota(next?.magpie);
|
|
252
276
|
if (active)
|
|
253
277
|
setSnapshot(next);
|
|
254
278
|
}
|
|
@@ -267,7 +291,11 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
267
291
|
}
|
|
268
292
|
};
|
|
269
293
|
const intervalMins = props.getRefreshIntervalMins?.() ?? DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
|
|
270
|
-
const
|
|
294
|
+
const pollIntervalMs = Math.max(0, intervalMins) * 60_000;
|
|
295
|
+
const poll = startSerialPolling(refresh, pollIntervalMs, {
|
|
296
|
+
timeoutMs: 30_000,
|
|
297
|
+
getIntervalMs: () => upstreamUnresolved ? Math.min(pollIntervalMs, MAGPIE_QUOTA_RETRY_MS) : pollIntervalMs,
|
|
298
|
+
});
|
|
271
299
|
refreshRef.current = poll.refresh;
|
|
272
300
|
return () => {
|
|
273
301
|
active = false;
|
|
@@ -335,13 +363,13 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
335
363
|
}
|
|
336
364
|
})();
|
|
337
365
|
};
|
|
338
|
-
useDismissOnOutsidePointer(rootRef, open, () => setOpen(false));
|
|
366
|
+
useDismissOnOutsidePointer(rootRef, open, () => setOpen(false), { portal: magpieRequestsDialogRef });
|
|
339
367
|
useDismissOnOutsidePointer(resetDialogRef, resetOpen && !resetPending, closeResetDialog);
|
|
340
368
|
if (!eligible || snapshot === null)
|
|
341
369
|
return null;
|
|
342
370
|
if (snapshot.magpie !== null) {
|
|
343
371
|
const magpie = snapshot.magpie;
|
|
344
|
-
const
|
|
372
|
+
const readout = resolveMagpieTriggerReadout(magpie);
|
|
345
373
|
const label = t('usage.magpieUsageLabel');
|
|
346
374
|
return createElement('div', { ref: rootRef, style: subscriptionRootStyle }, createElement('button', {
|
|
347
375
|
type: 'button',
|
|
@@ -356,9 +384,18 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
356
384
|
width: 20,
|
|
357
385
|
height: 20,
|
|
358
386
|
style: magpieTriggerImageStyle,
|
|
359
|
-
})),
|
|
360
|
-
|
|
361
|
-
|
|
387
|
+
})), createMagpieTriggerReadout(readout, t)), open && createElement(MagpieUsagePopover, {
|
|
388
|
+
rpc: props.rpc,
|
|
389
|
+
usage: magpie,
|
|
390
|
+
t,
|
|
391
|
+
tab: magpieTab,
|
|
392
|
+
onTabChange: setMagpieTab,
|
|
393
|
+
expandedGroups: expandedQuotaGroups,
|
|
394
|
+
onToggleGroup: toggleQuotaGroup,
|
|
395
|
+
placement: magpiePlacement,
|
|
396
|
+
popoverRef: magpiePopoverRef,
|
|
397
|
+
requestsDialogRef: magpieRequestsDialogRef,
|
|
398
|
+
}));
|
|
362
399
|
}
|
|
363
400
|
const usage = snapshot.providerUsage;
|
|
364
401
|
// 未拿到真实订阅数据时不占用底部栏空间;加载状态不能伪装成订阅存在。
|
|
@@ -439,7 +476,7 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
439
476
|
dialogRef: resetDialogRef,
|
|
440
477
|
}));
|
|
441
478
|
}
|
|
442
|
-
function MagpieUsagePopover({ usage, t, tab = 'usage', onTabChange = () => { }, placement = { left: 0, width: 400 }, popoverRef }) {
|
|
479
|
+
function MagpieUsagePopover({ rpc, usage, t, tab = 'usage', onTabChange = () => { }, expandedGroups = [], onToggleGroup = () => { }, placement = { left: 0, width: 400 }, popoverRef, requestsDialogRef }) {
|
|
443
480
|
const aggregateRows = usage.aggregate === null ? [] : [
|
|
444
481
|
[t('usage.magpieRequests'), formatMagpieNumber(usage.aggregate.calls)],
|
|
445
482
|
[t('usage.magpieErrors'), formatMagpieNumber(usage.aggregate.errors)],
|
|
@@ -489,12 +526,14 @@ function MagpieUsagePopover({ usage, t, tab = 'usage', onTabChange = () => { },
|
|
|
489
526
|
'aria-labelledby': `codingns4dsh-magpie-tab-${tab}`,
|
|
490
527
|
style: magpieTabPanelStyle,
|
|
491
528
|
}, tab === 'usage' ? MagpieUsagePanel({ usage, aggregateRows, sessionRows, t })
|
|
492
|
-
: MagpieRoutePanel({ usage, quotas, t
|
|
529
|
+
: MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup,
|
|
530
|
+
...(requestsDialogRef === undefined ? {} : { requestsDialogRef }),
|
|
531
|
+
})));
|
|
493
532
|
}
|
|
494
533
|
function MagpieUsagePanel({ usage, aggregateRows, sessionRows, t }) {
|
|
495
534
|
return createElement('div', undefined, createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieAggregateTitle')), usage.usageStatus === 'available'
|
|
496
535
|
? createMagpieRows(aggregateRows)
|
|
497
|
-
: createElement('div', { style: magpieMutedTextStyle }, t('usage.magpieUsageUnavailable'))), createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieSessionTitle')), usage.sessionId !== null && createElement('div', { style: magpieSessionIdentityStyle }, createElement('span', undefined, t('usage.magpieAgent', { agent: usage.agent })), createElement('code', { style: magpieSessionIdStyle }, usage.sessionId)), usage.session === null
|
|
536
|
+
: createElement('div', { style: magpieMutedTextStyle }, t('usage.magpieUsageUnavailable'))), createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieSessionTitle')), usage.sessionId !== null && createElement('div', { style: magpieSessionIdentityStyle }, createElement('span', undefined, t('usage.magpieAgent', { agent: usage.agent })), usage.sessionName !== undefined && createElement('strong', { style: magpieSessionNameStyle, title: usage.sessionName }, usage.sessionName), createElement('code', { style: magpieSessionIdStyle }, usage.sessionId)), usage.session === null
|
|
498
537
|
? createElement('div', { style: magpieMutedTextStyle }, usage.sessionId === null ? t('usage.magpieSessionIdUnavailable') : t('usage.magpieSessionNoUsage'))
|
|
499
538
|
: createMagpieRows(sessionRows)));
|
|
500
539
|
}
|
|
@@ -512,16 +551,34 @@ function createMagpieProviderBadges(usage, style) {
|
|
|
512
551
|
return createElement('span', { style }, ...providers.map((provider) => createElement('span', { key: provider, style: magpieProviderBadgeStyle }, provider)));
|
|
513
552
|
}
|
|
514
553
|
function createMagpieQuotaCard(quota, t, index) {
|
|
515
|
-
return createElement('div', { key: `${quota.provider}-${quota.user ?? 'account'}-${index}`, style: magpieQuotaCardStyle }, createElement('div', { style: magpieQuotaCardHeadingStyle }, createElement('span', { style: magpieQuotaNameStyle }, quota.alias ?? quota.name), createElement('span', { style: magpieQuotaHeadingMetaStyle }, quota.plan ?? quota.provider)), (quota.user !== null || quota.balance !== null) && createElement('div', { style: magpieQuotaIdentityStyle }, quota.user !== null && createElement('span', { title: quota.user }, t('usage.magpieQuotaAccount', { account: quota.user })), quota.balance !== null && createElement('span', undefined, t('usage.magpieQuotaBalance', { balance: quota.balance }))), quota.windows.length === 0
|
|
554
|
+
return createElement('div', { key: `${quota.provider}-${quota.user ?? 'account'}-${index}`, style: magpieQuotaCardStyle }, createElement('div', { style: magpieQuotaCardHeadingStyle }, createElement('span', { style: magpieQuotaNameWithLogoStyle }, createElement(MagpieProviderLogo, { identities: [quota.provider, quota.name], logoDataUrl: quota.logoDataUrl, size: 20, className: 'codingns4dsh-magpie-quota-logo', fallback: 'none' }), createElement('span', { style: magpieQuotaNameStyle }, quota.alias ?? quota.name)), createElement('span', { style: magpieQuotaHeadingMetaStyle }, quota.plan ?? quota.provider)), (quota.user !== null || quota.balance !== null) && createElement('div', { style: magpieQuotaIdentityStyle }, quota.user !== null && createElement('span', { title: quota.user }, t('usage.magpieQuotaAccount', { account: quota.user })), quota.balance !== null && createElement('span', undefined, t('usage.magpieQuotaBalance', { balance: quota.balance }))), quota.windows.length === 0
|
|
516
555
|
? createElement('div', { style: magpieQuotaMetaStyle }, t('usage.magpieQuotaNoWindows'))
|
|
517
556
|
: quota.windows.map((window, windowIndex) => {
|
|
518
|
-
const remaining = window
|
|
557
|
+
const remaining = quotaWindowRemaining(window);
|
|
558
|
+
// 积分窗口(WorkBuddy 的 `0 / 350`)按数量读更准确:百分比在这里没有意义。
|
|
559
|
+
const credits = formatQuotaWindowCredits(window);
|
|
519
560
|
const amount = window.display ?? (window.amount !== null && window.limit !== null ? `${window.amount} / ${window.limit}${window.unit === null ? '' : ` ${window.unit}`}` : null);
|
|
520
|
-
return createElement('div', { key: `${window.name}-${windowIndex}`, style: magpieQuotaWindowStyle }, createElement('div', { style: windowHeadingStyle }, createElement('span', undefined, window.name),
|
|
561
|
+
return createElement('div', { key: `${window.name}-${windowIndex}`, style: magpieQuotaWindowStyle }, createElement('div', { style: windowHeadingStyle }, createElement('span', undefined, window.name), credits !== null
|
|
562
|
+
? createElement('strong', undefined, credits)
|
|
563
|
+
: remaining === null ? amount : createElement('strong', undefined, `${formatPercent(remaining)}%`)),
|
|
564
|
+
// 积分窗口用满格数量条展示已用比例,避免"0% 还能用"的误读。
|
|
565
|
+
remaining !== null && createElement('div', { role: 'progressbar', 'aria-label': t('usage.magpieQuotaRemaining', { name: window.name, percent: formatPercent(remaining) }), 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-valuenow': remaining, style: barStyle }, createElement('span', { style: { ...barFillStyle, width: `${remaining}%` } })), (amount !== null || window.resetsAt !== null) && createElement('div', { style: magpieQuotaFooterStyle }, amount !== null && createElement('span', undefined, amount), window.resetsAt !== null && createElement('span', undefined, t('usage.magpieQuotaResets', { time: formatMagpieTimestamp(window.resetsAt) }))));
|
|
521
566
|
}));
|
|
522
567
|
}
|
|
523
|
-
|
|
568
|
+
/**
|
|
569
|
+
* 单个窗口若是按积分计量,返回"剩余 / 上限"文本;普通百分比窗口返回 null。
|
|
570
|
+
*
|
|
571
|
+
* 卡片会为每个窗口单独调用一次,所以这里按窗口自治判断,不依赖账号整体状态。
|
|
572
|
+
*/
|
|
573
|
+
function formatQuotaWindowCredits(window) {
|
|
574
|
+
const credits = readWindowCreditBalance(window);
|
|
575
|
+
return credits === null ? null : formatQuotaCredits(credits);
|
|
576
|
+
}
|
|
577
|
+
function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup, requestsDialogRef }) {
|
|
524
578
|
const route = usage.route;
|
|
579
|
+
const groups = groupQuotasByProvider(quotas);
|
|
580
|
+
const sessionAccount = route?.providerAccount ?? null;
|
|
581
|
+
const requestSessionId = usage.requestSessionId ?? usage.session?.id ?? usage.sessionId;
|
|
525
582
|
const quotaMessage = magpieQuotaUnavailableMessage(usage, quotas, t);
|
|
526
583
|
const routeStatus = usage.routeStatus === 'no-route'
|
|
527
584
|
? t('usage.magpieRouteNoRequests')
|
|
@@ -543,7 +600,33 @@ function MagpieRoutePanel({ usage, quotas, t }) {
|
|
|
543
600
|
];
|
|
544
601
|
return createElement('div', undefined, createElement('section', { style: magpieSectionStyle }, createElement('div', { style: magpieQuotaHeadingStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieQuotaTitle')), createMagpieProviderBadges(usage, magpieProviderBadgesStyle)), quotaMessage !== null
|
|
545
602
|
? createElement('div', { style: magpieEmptyStateStyle }, quotaMessage)
|
|
546
|
-
:
|
|
603
|
+
: groups.map((group) => {
|
|
604
|
+
const expanded = expandedGroups.includes(group.provider);
|
|
605
|
+
const multiple = group.accounts.length > 1;
|
|
606
|
+
return createElement('div', { key: group.provider, style: magpieQuotaCardStyle }, createQuotaGroupHeader({
|
|
607
|
+
group,
|
|
608
|
+
t,
|
|
609
|
+
expanded,
|
|
610
|
+
onToggle: multiple ? () => onToggleGroup(group.provider) : null,
|
|
611
|
+
}), group.accounts.map((quota, index) => createElement('div', { key: `${group.provider}-${quota.user ?? 'account'}-${index}` }, createQuotaAccountBlock(quota, {
|
|
612
|
+
t,
|
|
613
|
+
nowMs: Date.now(),
|
|
614
|
+
// 单账号厂商由组头承担名称,账号块不再重复。
|
|
615
|
+
showAccountName: multiple,
|
|
616
|
+
// 组未展开时只留会话账号的明细,其余账号折叠成余量行。
|
|
617
|
+
compact: multiple && !expanded && quota.active !== true && (sessionAccount === null || quota.user !== sessionAccount),
|
|
618
|
+
fallbackName: group.name === '' ? group.provider : group.name,
|
|
619
|
+
}))));
|
|
620
|
+
})), createElement('section', { style: magpieSectionStyle }, createElement('div', { style: magpieRouteHeadingStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieRouteTitle')), route !== null && createElement('div', { style: magpieRouteHeadingActionsStyle },
|
|
621
|
+
// “查看请求”入口与状态徽标同高、同排:入口在左,状态在右。
|
|
622
|
+
createElement(MagpieRouteRequests, {
|
|
623
|
+
rpc,
|
|
624
|
+
sessionId: requestSessionId,
|
|
625
|
+
sessionName: usage.sessionName ?? null,
|
|
626
|
+
agent: usage.agent,
|
|
627
|
+
t,
|
|
628
|
+
...(requestsDialogRef === undefined ? {} : { requestsDialogRef }),
|
|
629
|
+
}), createElement('span', { className: active ? 'codingns4dsh-magpie-route-node-active' : undefined, style: magpieRouteStatusStyle }, createElement('span', { style: magpieRouteStatusDotStyle }), createElement('strong', undefined, route.done === true ? t('usage.magpieRouteComplete') : route.done === false ? t('usage.magpieRouteRunning').replace(/\s*·\s*$/u, '') : route.status ?? '--')))), route === null
|
|
547
630
|
? createElement('div', { style: magpieEmptyStateStyle }, routeStatus)
|
|
548
631
|
: createElement('div', { style: magpieRouteHeroStyle }, createElement('div', { style: magpieRouteTrackStyle, 'aria-label': t('usage.magpieRouteFlowTitle'), role: 'list' }, ...routeStages.map(([label, model], index) => createElement('div', {
|
|
549
632
|
key: `step-${index}`,
|
|
@@ -552,6 +635,203 @@ function MagpieRoutePanel({ usage, quotas, t }) {
|
|
|
552
635
|
style: { ...magpieRouteTrackItemStyle, animationDelay: `${index * 90}ms` },
|
|
553
636
|
}, createElement('div', { style: magpieRouteMarkerColumnStyle, 'aria-hidden': true }, createElement('div', { className: 'codingns4dsh-magpie-route-node', style: magpieRouteNodeStyle }, createElement('span', { style: magpieRouteNodeDotStyle })), index < routeStages.length - 1 && createElement('div', { style: magpieRouteConnectorStyle }, active && createElement('span', { className: 'codingns4dsh-magpie-route-pulse', style: magpieRoutePulseStyle }))), createElement('div', { style: magpieRouteStageCopyStyle }, createElement('span', { style: magpieRouteStageLabelStyle }, label), createElement('strong', { style: magpieRouteStageValueStyle, title: model }, model))))), routeRows.length > 0 && createElement('div', { style: magpieRouteMetaStyle }, ...routeRows.filter((row) => row[1] !== null).map(([label, value]) => createElement('div', { key: label, style: magpieRouteMetaItemStyle }, createElement('span', { style: magpieRouteMetaLabelStyle }, label), createElement('strong', { style: magpieRouteMetaValueStyle, title: value }, value)))), route.tries.length > 0 && createElement('div', { style: magpieAttemptsStyle }, ...route.tries.map((attempt, index) => createElement('div', { key: `${attempt.model ?? 'model'}-${index}`, style: magpieAttemptRowStyle }, createElement('span', { style: magpieAttemptModelStyle }, attempt.model ?? t('usage.magpieUnknownModel')), attempt.failed && createElement('span', { style: magpieFailedStyle }, t('usage.magpieFallback'))))))));
|
|
554
637
|
}
|
|
638
|
+
/**
|
|
639
|
+
* 路由标题栏的“查看请求”入口:按钮、模态框与读取状态放在同一个子组件里。
|
|
640
|
+
*
|
|
641
|
+
* 弹层内容本身不持有 Hook(无浏览器测试会直接展开内容树),因此这里只由
|
|
642
|
+
* `MagpieRoutePanel` 渲染元素,真正的状态留在本组件内部。模态框内的请求明细
|
|
643
|
+
* 直接复用管理页的 `RequestsPage`,只把会话筛选固定为当前会话。
|
|
644
|
+
*/
|
|
645
|
+
export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t, requestsDialogRef }) {
|
|
646
|
+
const enabled = canReadMagpieSessionRequests(sessionId, agent);
|
|
647
|
+
const [open, setOpen] = useState(false);
|
|
648
|
+
// 弹层固定筛选一个会话:这里持有从头累计的所有已加载请求,而不是只留当前一页。
|
|
649
|
+
const [page, setPage] = useState(null);
|
|
650
|
+
const [offset, setOffset] = useState(0);
|
|
651
|
+
const [loading, setLoading] = useState(false);
|
|
652
|
+
const [error, setError] = useState(false);
|
|
653
|
+
const [reloadKey, setReloadKey] = useState(0);
|
|
654
|
+
const controllerRef = useRef(null);
|
|
655
|
+
const sequenceRef = useRef(0);
|
|
656
|
+
useEffect(() => {
|
|
657
|
+
if (!open || !enabled)
|
|
658
|
+
return;
|
|
659
|
+
const controller = new AbortController();
|
|
660
|
+
controllerRef.current = controller;
|
|
661
|
+
// 只有一次请求在飞:更晚的请求序号作废更早的回包。
|
|
662
|
+
const sequence = sequenceRef.current + 1;
|
|
663
|
+
sequenceRef.current = sequence;
|
|
664
|
+
setLoading(true);
|
|
665
|
+
setError(false);
|
|
666
|
+
void readMagpieSessionRequestPage(rpc, sessionId, agent, offset, controller.signal).then((next) => {
|
|
667
|
+
if (controller.signal.aborted || sequence !== sequenceRef.current)
|
|
668
|
+
return;
|
|
669
|
+
if (next === null) {
|
|
670
|
+
setError(true);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
setPage((current) => current === null || offset === 0
|
|
674
|
+
? next
|
|
675
|
+
: { ...next, items: [...current.items, ...next.items] });
|
|
676
|
+
}).catch(() => {
|
|
677
|
+
if (!controller.signal.aborted && sequence === sequenceRef.current)
|
|
678
|
+
setError(true);
|
|
679
|
+
}).finally(() => {
|
|
680
|
+
if (!controller.signal.aborted && sequence === sequenceRef.current)
|
|
681
|
+
setLoading(false);
|
|
682
|
+
});
|
|
683
|
+
return () => {
|
|
684
|
+
controller.abort();
|
|
685
|
+
if (controllerRef.current === controller)
|
|
686
|
+
controllerRef.current = null;
|
|
687
|
+
};
|
|
688
|
+
}, [open, enabled, offset, reloadKey, rpc, sessionId, agent]);
|
|
689
|
+
// 滚到列表底部就自动追加下一页:149 条请求也能一口气看完,不必数着点“加载更多”。
|
|
690
|
+
// 用捕获阶段监听滚动,真实滚动容器(弹层主体、表格横向容器)都在子树里。
|
|
691
|
+
useEffect(() => {
|
|
692
|
+
if (!open || typeof document === 'undefined' || !enabled)
|
|
693
|
+
return;
|
|
694
|
+
const onScroll = (event) => {
|
|
695
|
+
const target = event.target;
|
|
696
|
+
if (!(target instanceof Element) || !target.closest('.codingns4dsh-magpie-requests-body'))
|
|
697
|
+
return;
|
|
698
|
+
if (target.scrollHeight - target.scrollTop - target.clientHeight > 160)
|
|
699
|
+
return;
|
|
700
|
+
if (loading || error || page === null || !page.hasMore)
|
|
701
|
+
return;
|
|
702
|
+
setOffset(page.items.length);
|
|
703
|
+
};
|
|
704
|
+
document.addEventListener('scroll', onScroll, true);
|
|
705
|
+
return () => document.removeEventListener('scroll', onScroll, true);
|
|
706
|
+
}, [open, enabled, loading, error, page]);
|
|
707
|
+
// 模态框覆盖整个视口,Esc 是移动端之外唯一的键盘关闭方式。
|
|
708
|
+
useEffect(() => {
|
|
709
|
+
if (!open || typeof document === 'undefined')
|
|
710
|
+
return;
|
|
711
|
+
// 捕获阶段拦截 Esc:只关闭模态框,不再让底部弹层的关闭监听把整个弹层一起收起。
|
|
712
|
+
const onKeyDown = (event) => {
|
|
713
|
+
if (event.key !== 'Escape')
|
|
714
|
+
return;
|
|
715
|
+
event.stopPropagation();
|
|
716
|
+
setOpen(false);
|
|
717
|
+
};
|
|
718
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
719
|
+
return () => document.removeEventListener('keydown', onKeyDown, true);
|
|
720
|
+
}, [open]);
|
|
721
|
+
const close = () => {
|
|
722
|
+
controllerRef.current?.abort();
|
|
723
|
+
controllerRef.current = null;
|
|
724
|
+
setOpen(false);
|
|
725
|
+
};
|
|
726
|
+
const openRequests = () => {
|
|
727
|
+
controllerRef.current?.abort();
|
|
728
|
+
setPage(null);
|
|
729
|
+
setOffset(0);
|
|
730
|
+
setError(false);
|
|
731
|
+
setLoading(true);
|
|
732
|
+
// 请求明细复用管理页组件,需要先装上管理页自己的样式表。
|
|
733
|
+
installMagpiePageStyles();
|
|
734
|
+
setOpen(true);
|
|
735
|
+
};
|
|
736
|
+
return createElement(Fragment, undefined, enabled && createElement('button', {
|
|
737
|
+
type: 'button',
|
|
738
|
+
className: 'codingns4dsh-magpie-route-requests',
|
|
739
|
+
onClick: openRequests,
|
|
740
|
+
'aria-haspopup': 'dialog',
|
|
741
|
+
title: t('usage.magpieViewRequests'),
|
|
742
|
+
style: magpieRouteRequestsButtonStyle,
|
|
743
|
+
}, t('usage.magpieViewRequests')), enabled && open && createElement(MagpieSessionRequestsDialog, {
|
|
744
|
+
sessionId,
|
|
745
|
+
sessionName,
|
|
746
|
+
agent,
|
|
747
|
+
page,
|
|
748
|
+
offset,
|
|
749
|
+
loading,
|
|
750
|
+
error,
|
|
751
|
+
t,
|
|
752
|
+
onClose: close,
|
|
753
|
+
...(requestsDialogRef === undefined ? {} : { dialogRef: requestsDialogRef }),
|
|
754
|
+
onOffsetChange: (value) => {
|
|
755
|
+
// 追加下一页;重试则从头重读,避免把同一页拼两遍。
|
|
756
|
+
if (value === 0)
|
|
757
|
+
setPage(null);
|
|
758
|
+
setOffset(value);
|
|
759
|
+
},
|
|
760
|
+
onRetry: () => { setLoading(true); setError(false); setReloadKey((value) => value + 1); },
|
|
761
|
+
}));
|
|
762
|
+
}
|
|
763
|
+
/** Host 只接受小写 Agent ID;会话与 Agent 必须成对出现,缺一不可。 */
|
|
764
|
+
function canReadMagpieSessionRequests(sessionId, agent) {
|
|
765
|
+
return sessionId !== null && sessionId.trim() !== '' && sessionId.length <= 512 && /^[a-z0-9][a-z0-9-]*$/u.test(agent);
|
|
766
|
+
}
|
|
767
|
+
/** 只读取今天的会话请求,与路由卡片和“当前 Agent 会话”用量保持同一时间口径。 */
|
|
768
|
+
async function readMagpieSessionRequestPage(rpc, sessionId, agent, offset, signal) {
|
|
769
|
+
const result = await callCodingNsRpcResult(rpc, 'magpie/usage/requests', {
|
|
770
|
+
period: 'today',
|
|
771
|
+
offset,
|
|
772
|
+
limit: MAGPIE_REQUESTS_PAGE_SIZE,
|
|
773
|
+
sessionId,
|
|
774
|
+
sessionAgent: agent,
|
|
775
|
+
}, signal);
|
|
776
|
+
if (!result.ok)
|
|
777
|
+
throw new Error(result.error.message);
|
|
778
|
+
const value = result.value;
|
|
779
|
+
return isRecord(value) && Array.isArray(value.items)
|
|
780
|
+
? value
|
|
781
|
+
: null;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* 请求模态框:外壳(遮罩、标题、关闭)由弹层提供,明细直接复用管理页的请求用量视图。
|
|
785
|
+
*
|
|
786
|
+
* 管理页视图自带统计条、桌面表格 / 移动卡片、分页和空状态,这里只负责把会话固定住,
|
|
787
|
+
* 不再维护一套重复的请求卡片渲染。
|
|
788
|
+
*/
|
|
789
|
+
function MagpieSessionRequestsDialog({ sessionId, sessionName, agent, page, offset, loading, error, t, onClose, dialogRef, onOffsetChange, onRetry }) {
|
|
790
|
+
const dialog = createElement('div', {
|
|
791
|
+
className: 'codingns4dsh-magpie-requests-overlay',
|
|
792
|
+
ref: dialogRef,
|
|
793
|
+
role: 'presentation',
|
|
794
|
+
style: magpieRequestsOverlayStyle,
|
|
795
|
+
// 只有按在遮罩自身时才关闭;从内容内部按下再拖到遮罩上不会误关。
|
|
796
|
+
onPointerDown: backdropPointerDownHandler(onClose),
|
|
797
|
+
}, createElement('div', {
|
|
798
|
+
role: 'dialog',
|
|
799
|
+
'aria-modal': true,
|
|
800
|
+
'aria-label': t('usage.magpieRequestsTitle'),
|
|
801
|
+
className: 'codingns4dsh-magpie-requests-dialog',
|
|
802
|
+
tabIndex: -1,
|
|
803
|
+
autoFocus: true,
|
|
804
|
+
style: magpieRequestsDialogStyle,
|
|
805
|
+
}, createElement('div', { style: magpieRequestsHeadingStyle }, createElement('strong', { style: magpieRequestsTitleStyle }, t('usage.magpieRequestsTitle')), createElement('div', { style: magpieRequestsHeadingActionsStyle }, error && createElement('button', {
|
|
806
|
+
type: 'button',
|
|
807
|
+
className: 'codingns4dsh-magpie-requests-retry',
|
|
808
|
+
onClick: onRetry,
|
|
809
|
+
style: magpieRequestsRetryStyle,
|
|
810
|
+
}, t('magpie.refresh')), createElement('button', {
|
|
811
|
+
type: 'button',
|
|
812
|
+
className: 'codingns4dsh-magpie-requests-close',
|
|
813
|
+
onClick: onClose,
|
|
814
|
+
'aria-label': t('usage.magpieRequestsClose'),
|
|
815
|
+
style: magpieRequestsCloseStyle,
|
|
816
|
+
}, '×'))), createElement('div', { className: 'codingns4dsh-magpie-requests-body', style: magpieRequestsBodyStyle },
|
|
817
|
+
// `.codingns-magpie-page` 提供管理页的 `--mp-*` 主题变量;外层样式再把它压进弹层尺寸。
|
|
818
|
+
createElement('div', { className: 'codingns-magpie-page codingns4dsh-magpie-requests-view' }, createElement(RequestsPage, {
|
|
819
|
+
page,
|
|
820
|
+
loading,
|
|
821
|
+
error,
|
|
822
|
+
selectedSession: { id: sessionId, agent, ...(sessionName === null ? {} : { dshSessionName: sessionName }) },
|
|
823
|
+
offset,
|
|
824
|
+
onOffsetChange,
|
|
825
|
+
onClearSession: null,
|
|
826
|
+
t,
|
|
827
|
+
// 弹层筛选的是单一会话,列表从头累计,直到整条会话的请求都加载完。
|
|
828
|
+
append: true,
|
|
829
|
+
})))));
|
|
830
|
+
// The usage popover has its own lower stacking context. Portaling the modal
|
|
831
|
+
// to body lets it actually cover the host sidebar instead of being clipped
|
|
832
|
+
// by the popover's parent context.
|
|
833
|
+
return typeof document === 'undefined' ? dialog : createPortal(dialog, document.body);
|
|
834
|
+
}
|
|
555
835
|
function createMagpieRows(rows) {
|
|
556
836
|
if (rows.length === 0)
|
|
557
837
|
return createElement('div', { style: magpieMutedTextStyle }, '--');
|
|
@@ -954,20 +1234,74 @@ function createModelRow(model, unit) {
|
|
|
954
1234
|
function resolveDisplayWindow(usage) {
|
|
955
1235
|
return usage.primary ?? usage.secondary ?? usage.monthly;
|
|
956
1236
|
}
|
|
1237
|
+
/** 配额解析完成前的补读间隔;与弹层打开时的路由读取共用串行轮询。 */
|
|
1238
|
+
const MAGPIE_QUOTA_RETRY_MS = 3_000;
|
|
1239
|
+
/**
|
|
1240
|
+
* Magpie 用量入口是否还需要带路由补读。
|
|
1241
|
+
*
|
|
1242
|
+
* Host 会为「已确认属于 Magpie、但会话身份还没写进账本」的模型下发带会话数据的
|
|
1243
|
+
* `provider-unavailable` 占位快照;还在启动中的网关则是 `unavailable`。
|
|
1244
|
+
* 两种状态都表示上游未知,必须按 `MAGPIE_QUOTA_RETRY_MS` 快速重新解析,否则首屏
|
|
1245
|
+
* 会一直停在官方余额或 Magpie 标签上,直到整页刷新。
|
|
1246
|
+
*
|
|
1247
|
+
* 上游已解析(`provider-unavailable` 但 `upstreamProvider` 有值,例如该厂商本来
|
|
1248
|
+
* 就不上报任何配额窗口)不再补读——再读也只是重复确认同一个结论。没有上游信息的
|
|
1249
|
+
* 占位快照才有资格要求补读,Host 也只在这种情况下才下发它。
|
|
1250
|
+
*/
|
|
957
1251
|
function shouldResolveMagpieQuota(usage) {
|
|
958
|
-
|
|
1252
|
+
if (usage === null || usage === undefined)
|
|
1253
|
+
return false;
|
|
1254
|
+
if (usage.quotaStatus !== 'available')
|
|
1255
|
+
return usage.upstreamProvider === null;
|
|
1256
|
+
return usage.sessionId !== null && usage.session !== null && (usage.quotas?.length ?? 0) === 0;
|
|
959
1257
|
}
|
|
960
1258
|
function resolveMagpieQuotaRemaining(usage) {
|
|
961
|
-
|
|
962
|
-
return null;
|
|
963
|
-
for (const quota of usage.quotas) {
|
|
1259
|
+
for (const quota of usage.quotas ?? []) {
|
|
964
1260
|
for (const window of quota.windows) {
|
|
965
|
-
|
|
966
|
-
|
|
1261
|
+
// A few Magpie responses report only `used`; the quota card derives the same
|
|
1262
|
+
// remaining share, so the compact trigger must use that normalized value too.
|
|
1263
|
+
const remaining = quotaWindowRemaining(window);
|
|
1264
|
+
if (remaining !== null)
|
|
1265
|
+
return remaining;
|
|
967
1266
|
}
|
|
968
1267
|
}
|
|
969
1268
|
return null;
|
|
970
1269
|
}
|
|
1270
|
+
function resolveMagpieTriggerReadout(usage) {
|
|
1271
|
+
const remaining = resolveMagpieQuotaRemaining(usage);
|
|
1272
|
+
if (remaining !== null)
|
|
1273
|
+
return { kind: 'ring', percent: remaining };
|
|
1274
|
+
const quotas = usage.quotas ?? [];
|
|
1275
|
+
const balance = resolveQuotaBalanceLabel(quotas);
|
|
1276
|
+
if (balance !== null)
|
|
1277
|
+
return { kind: 'money', text: balance };
|
|
1278
|
+
const credits = resolveQuotaCreditsLabel(quotas);
|
|
1279
|
+
if (credits !== null)
|
|
1280
|
+
return { kind: 'credits', text: credits };
|
|
1281
|
+
return { kind: 'label' };
|
|
1282
|
+
}
|
|
1283
|
+
/** 积分余额的展示文本:只给数量,单位放在 title 里,不占用底部栏宽度。 */
|
|
1284
|
+
function resolveQuotaCreditsLabel(quotas) {
|
|
1285
|
+
for (const quota of quotas) {
|
|
1286
|
+
const credits = resolveQuotaCreditBalance(quota);
|
|
1287
|
+
if (credits === null || !(credits.remaining > 0))
|
|
1288
|
+
continue;
|
|
1289
|
+
return formatQuotaNumber(credits.remaining);
|
|
1290
|
+
}
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
function createMagpieTriggerReadout(readout, t) {
|
|
1294
|
+
switch (readout.kind) {
|
|
1295
|
+
case 'ring':
|
|
1296
|
+
return createRemainingRing(readout.percent);
|
|
1297
|
+
case 'money':
|
|
1298
|
+
return createElement('span', { className: 'codingns4dsh-subscription-value', style: magpieBalanceStyle, title: t('usage.accountBalance') }, readout.text);
|
|
1299
|
+
case 'credits':
|
|
1300
|
+
return createElement('span', { className: 'codingns4dsh-subscription-value', style: magpieBalanceStyle, title: t('usage.creditBalanceLabel') }, readout.text);
|
|
1301
|
+
default:
|
|
1302
|
+
return createElement('span', { className: 'codingns4dsh-subscription-label', style: subscriptionLabelStyle }, t('usage.magpieShortLabel'));
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
971
1305
|
function selectDeepseekBalance(usage) {
|
|
972
1306
|
return usage.balances.find((balance) => balance.currency.toUpperCase() === 'USD') ?? usage.balances[0] ?? null;
|
|
973
1307
|
}
|
|
@@ -1103,6 +1437,8 @@ function formatCreditBalance(value) {
|
|
|
1103
1437
|
const subscriptionRootStyle = { position: 'relative', minWidth: 0, display: 'inline-flex', alignItems: 'center' };
|
|
1104
1438
|
const subscriptionTriggerStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, height: 28, border: 0, borderRadius: 14, padding: '0 8px 0 4px', color: dshThemeColor.labelSecondary, background: 'transparent', cursor: 'pointer', fontSize: uiFontSize(13), lineHeight: '20px' };
|
|
1105
1439
|
const subscriptionLabelStyle = { whiteSpace: 'nowrap' };
|
|
1440
|
+
// 余额金额与积分和百分比环并排/替换显示:数字用等宽字形,避免刷新时抖动。
|
|
1441
|
+
const magpieBalanceStyle = { display: 'inline-flex', alignItems: 'center', whiteSpace: 'nowrap', color: dshThemeColor.labelSecondary, fontSize: uiFontSize(12), fontWeight: 600, fontVariantNumeric: 'tabular-nums' };
|
|
1106
1442
|
const magpieTriggerIconStyle = { display: 'inline-flex', width: 20, height: 20, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', borderRadius: 6, background: dshThemeColor.surfaceSubtle };
|
|
1107
1443
|
const magpieTriggerImageStyle = { display: 'block', width: '100%', height: '100%', objectFit: 'cover' };
|
|
1108
1444
|
const magpieMutedTextStyle = { color: dshThemeColor.labelTertiary, fontSize: uiFontSize(12), lineHeight: '17px', overflowWrap: 'anywhere' };
|
|
@@ -1122,6 +1458,7 @@ const magpieStatStyle = { display: 'grid', alignContent: 'space-between', gap: 1
|
|
|
1122
1458
|
const magpieStatLabelStyle = { minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '13px', overflowWrap: 'anywhere' };
|
|
1123
1459
|
const magpieRowValueStyle = { color: dshThemeColor.labelPrimary, fontSize: uiFontSize(14), fontWeight: 650, lineHeight: '18px', textAlign: 'right', overflowWrap: 'anywhere' };
|
|
1124
1460
|
const magpieSessionIdentityStyle = { display: 'flex', flexWrap: 'wrap', alignItems: 'baseline', gap: '2px 10px', minWidth: 0, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(12), lineHeight: '16px' };
|
|
1461
|
+
const magpieSessionNameStyle = { maxWidth: '100%', overflow: 'hidden', color: dshThemeColor.labelPrimary, fontSize: uiFontSize(12), fontWeight: 650, textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
|
|
1125
1462
|
const magpieSessionIdStyle = { flex: '1 1 120px', minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '14px', whiteSpace: 'normal', overflowWrap: 'anywhere' };
|
|
1126
1463
|
const magpieAttemptsStyle = { display: 'grid', gap: 5, paddingTop: 6 };
|
|
1127
1464
|
const magpieAttemptRowStyle = { display: 'flex', justifyContent: 'space-between', gap: 14, fontSize: uiFontSize(12) };
|
|
@@ -1133,6 +1470,7 @@ const magpieProviderBadgeStyle = { flex: 'none', maxWidth: 220, overflow: 'hidde
|
|
|
1133
1470
|
const magpieEmptyStateStyle = { display: 'grid', placeItems: 'center', minHeight: 36, padding: '8px 10px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(12), lineHeight: '17px', textAlign: 'center' };
|
|
1134
1471
|
const magpieQuotaCardStyle = { display: 'grid', gap: 5, marginTop: 7, padding: '9px 10px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 9, background: dshThemeColor.surfaceSubtle };
|
|
1135
1472
|
const magpieQuotaCardHeadingStyle = { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 10 };
|
|
1473
|
+
const magpieQuotaNameWithLogoStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, minWidth: 0, overflow: 'hidden' };
|
|
1136
1474
|
const magpieQuotaNameStyle = { minWidth: 0, overflow: 'hidden', color: dshThemeColor.labelPrimary, fontSize: uiFontSize(13), fontWeight: 650, textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
|
|
1137
1475
|
const magpieQuotaHeadingMetaStyle = { flex: 'none', maxWidth: 160, overflow: 'hidden', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
|
|
1138
1476
|
const magpieQuotaIdentityStyle = { display: 'flex', flexWrap: 'wrap', gap: '3px 12px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), lineHeight: '15px', overflowWrap: 'anywhere' };
|
|
@@ -1141,7 +1479,7 @@ const magpieQuotaWindowStyle = { display: 'grid', gap: 4, paddingTop: 3 };
|
|
|
1141
1479
|
const magpieQuotaFooterStyle = { display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: '3px 10px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), lineHeight: '15px' };
|
|
1142
1480
|
const magpieRouteHeadingStyle = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10 };
|
|
1143
1481
|
const magpieRouteHeroStyle = { display: 'grid', gap: 11, padding: '12px 13px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 12, background: `linear-gradient(145deg, ${dshThemeColor.surfaceSubtle}, transparent)` };
|
|
1144
|
-
const magpieRouteStatusStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, width: 'fit-content', padding: '3px 8px', borderRadius: 999, background: dshThemeColor.surfaceSubtle, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), whiteSpace: 'nowrap' };
|
|
1482
|
+
const magpieRouteStatusStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, width: 'fit-content', boxSizing: 'border-box', padding: '3px 8px', borderRadius: 999, background: dshThemeColor.surfaceSubtle, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), lineHeight: '15px', whiteSpace: 'nowrap' };
|
|
1145
1483
|
const magpieRouteStatusDotStyle = { width: 8, height: 8, borderRadius: '50%', background: dshThemeColor.accent };
|
|
1146
1484
|
const magpieRouteTrackStyle = { display: 'grid', gap: 0, minWidth: 0, padding: '3px 0' };
|
|
1147
1485
|
const magpieRouteTrackItemStyle = { display: 'grid', gridTemplateColumns: '18px minmax(0, 1fr)', alignItems: 'start', gap: 12, minWidth: 0, padding: '5px 8px', margin: '0 -8px', borderRadius: 8 };
|
|
@@ -1157,6 +1495,17 @@ const magpieRouteMetaStyle = { display: 'grid', gridTemplateColumns: 'repeat(2,
|
|
|
1157
1495
|
const magpieRouteMetaItemStyle = { display: 'grid', alignContent: 'start', gap: 3, minWidth: 0, padding: '6px 8px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 8, background: dshThemeColor.menuBackground };
|
|
1158
1496
|
const magpieRouteMetaLabelStyle = { color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '13px' };
|
|
1159
1497
|
const magpieRouteMetaValueStyle = { color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), fontWeight: 550, lineHeight: '15px', overflowWrap: 'anywhere' };
|
|
1498
|
+
// 请求入口与请求模态框:入口与状态徽标同高并排在标题栏,模态框覆盖视口并在内部滚动。
|
|
1499
|
+
const magpieRouteHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, minWidth: 0 };
|
|
1500
|
+
const magpieRouteRequestsButtonStyle = { flex: 'none', display: 'inline-flex', alignItems: 'center', gap: 4, boxSizing: 'border-box', padding: '2px 8px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 999, background: dshThemeColor.menuBackground, color: dshThemeColor.labelSecondary, fontFamily: 'inherit', fontSize: uiFontSize(11), lineHeight: '15px', cursor: 'pointer', whiteSpace: 'nowrap', transition: 'background .15s ease,color .15s ease' };
|
|
1501
|
+
const magpieRequestsOverlayStyle = { position: 'fixed', inset: 0, zIndex: 2147483000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16, boxSizing: 'border-box', background: dshThemeColor.overlay };
|
|
1502
|
+
const magpieRequestsDialogStyle = { ...dshPopupSurfaceStyle, display: 'flex', flexDirection: 'column', gap: 10, width: 'min(96vw, 1320px)', maxHeight: 'min(88vh, 820px)', boxSizing: 'border-box', padding: 14, borderRadius: 14 };
|
|
1503
|
+
const magpieRequestsHeadingStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, paddingBottom: 10, borderBottom: `1px solid ${dshThemeColor.border}` };
|
|
1504
|
+
const magpieRequestsHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, flex: 'none' };
|
|
1505
|
+
const magpieRequestsTitleStyle = { fontSize: uiFontSize(15), lineHeight: '20px' };
|
|
1506
|
+
const magpieRequestsCloseStyle = { flex: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, padding: 0, border: 0, borderRadius: '50%', background: 'transparent', color: dshThemeColor.labelSecondary, fontSize: uiFontSize(18), lineHeight: 1, cursor: 'pointer' };
|
|
1507
|
+
const magpieRequestsBodyStyle = { flex: '1 1 auto', minHeight: 0, overflowY: 'auto', overscrollBehavior: 'contain' };
|
|
1508
|
+
const magpieRequestsRetryStyle = { padding: '5px 12px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 999, background: dshThemeColor.menuBackground, color: dshThemeColor.labelSecondary, fontFamily: 'inherit', fontSize: uiFontSize(11), lineHeight: '15px', cursor: 'pointer' };
|
|
1160
1509
|
const sub2apiIdentityStyle = { display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };
|
|
1161
1510
|
const sub2apiLogoStyle = { display: 'block', borderRadius: 4, objectFit: 'contain' };
|
|
1162
1511
|
const deepseekBalanceIdentityStyle = { display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };
|