@mars-sea/dsh-commandcode-provider 0.12.9 → 0.13.0
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/CHANGELOG.md +41 -0
- package/README.md +11 -9
- package/README.zh-CN.md +6 -5
- package/lib/client.js +1201 -87
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +81 -8
- package/lib/index.js +733 -124
- package/lib/index.js.map +1 -1
- package/package.json +38 -38
package/lib/client.js
CHANGED
|
@@ -2766,6 +2766,7 @@ window.__ModuleLoader__.load({
|
|
|
2766
2766
|
//#endregion
|
|
2767
2767
|
//#region src/client/locales.ts
|
|
2768
2768
|
const zh = {
|
|
2769
|
+
openAnalytics: "查看模型用量、成本与性能分析",
|
|
2769
2770
|
nav: "Command Code",
|
|
2770
2771
|
title: "Command Code",
|
|
2771
2772
|
intro: "账户操作立即生效;其余设置修改后点击底部「保存」。API 密钥仅保存在本机凭据服务中,不会回显。",
|
|
@@ -2872,7 +2873,7 @@ window.__ModuleLoader__.load({
|
|
|
2872
2873
|
usageNetworkError: "无法连接 Command Code 服务",
|
|
2873
2874
|
usageNetworkHint: "所有请求都没有到达服务端。请检查网络连接或 API 地址设置。",
|
|
2874
2875
|
usageInvalidResponse: "Command Code 响应无法读取",
|
|
2875
|
-
usageInvalidResponseHint: "
|
|
2876
|
+
usageInvalidResponseHint: "已收到响应,但正文读取或解析失败。下方详情可区分读取超时、中断与格式异常;可先点击刷新重试。",
|
|
2876
2877
|
usageUpdated: "更新于",
|
|
2877
2878
|
usagePeriodEnd: "账期截止",
|
|
2878
2879
|
usageActive: "当前使用",
|
|
@@ -2940,6 +2941,7 @@ window.__ModuleLoader__.load({
|
|
|
2940
2941
|
integrationsTitle: "集成与显示"
|
|
2941
2942
|
};
|
|
2942
2943
|
const en = {
|
|
2944
|
+
openAnalytics: "View model usage, cost and performance",
|
|
2943
2945
|
nav: "Command Code",
|
|
2944
2946
|
title: "Command Code",
|
|
2945
2947
|
intro: "Account actions apply immediately; other settings are written by Save at the bottom. The API key stays in the local credential service and is never echoed.",
|
|
@@ -3046,7 +3048,7 @@ window.__ModuleLoader__.load({
|
|
|
3046
3048
|
usageNetworkError: "Could not reach the Command Code service",
|
|
3047
3049
|
usageNetworkHint: "No request reached the server. Check your network connection or the API base setting.",
|
|
3048
3050
|
usageInvalidResponse: "Could not read the Command Code response",
|
|
3049
|
-
usageInvalidResponseHint: "
|
|
3051
|
+
usageInvalidResponseHint: "Responses arrived, but reading or parsing their bodies failed. Details below distinguish timeouts, interrupted reads, and invalid formats. Try Refresh again.",
|
|
3050
3052
|
usageUpdated: "Updated",
|
|
3051
3053
|
usagePeriodEnd: "Period ends",
|
|
3052
3054
|
usageActive: "Active",
|
|
@@ -3273,7 +3275,7 @@ window.__ModuleLoader__.load({
|
|
|
3273
3275
|
}
|
|
3274
3276
|
//#endregion
|
|
3275
3277
|
//#region package.json
|
|
3276
|
-
var version = "0.
|
|
3278
|
+
var version = "0.13.0";
|
|
3277
3279
|
var repository = {
|
|
3278
3280
|
"type": "git",
|
|
3279
3281
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -5232,6 +5234,12 @@ window.__ModuleLoader__.load({
|
|
|
5232
5234
|
className: "cc-intro",
|
|
5233
5235
|
children: t("intro")
|
|
5234
5236
|
}),
|
|
5237
|
+
props.openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5238
|
+
variant: "ghost",
|
|
5239
|
+
size: "sm",
|
|
5240
|
+
onClick: props.openAnalytics,
|
|
5241
|
+
children: t("openAnalytics")
|
|
5242
|
+
}) : null,
|
|
5235
5243
|
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5236
5244
|
className: "cc-readOnly",
|
|
5237
5245
|
role: "status",
|
|
@@ -5544,11 +5552,193 @@ window.__ModuleLoader__.load({
|
|
|
5544
5552
|
});
|
|
5545
5553
|
}
|
|
5546
5554
|
//#endregion
|
|
5555
|
+
//#region src/client/analytics-copy.ts
|
|
5556
|
+
/** 模型分析沿用宿主语言;每个数值有独立标签,缺失样本与试算前提必须可见。 */
|
|
5557
|
+
const ANALYTICS_COPY_ZH = {
|
|
5558
|
+
analyticsNav: "模型分析",
|
|
5559
|
+
quotaNav: "账号额度",
|
|
5560
|
+
analysisRecent: "最近会话",
|
|
5561
|
+
analysisRange: "指定时间",
|
|
5562
|
+
analysisLimit: "会话数量",
|
|
5563
|
+
analysisFrom: "开始日期",
|
|
5564
|
+
analysisTo: "结束日期",
|
|
5565
|
+
analysisApply: "读取统计",
|
|
5566
|
+
analysisLoading: "正在读取历史记录…",
|
|
5567
|
+
analysisUnavailable: "宿主未提供历史查询服务,无法统计关闭后的会话。",
|
|
5568
|
+
analysisEmpty: "所选范围内没有 Command Code 请求记录。",
|
|
5569
|
+
analysisInvalid: "请输入 1–100 个会话,或不超过 366 天的有效日期范围。",
|
|
5570
|
+
analysisScope: "统计范围",
|
|
5571
|
+
analysisScanned: "已读取会话",
|
|
5572
|
+
analysisMatched: "含请求会话",
|
|
5573
|
+
analysisUnreadable: "读取失败",
|
|
5574
|
+
analysisSkipped: "已跳过",
|
|
5575
|
+
analysisPartial: "结果不完整:历史超过读取上限,或部分记录不可读。金额只覆盖已读取且可计价的请求。",
|
|
5576
|
+
analysisCatalog: "模型目录暂不可用,历史统计仍可查看。",
|
|
5577
|
+
analysisUnpriced: "部分请求缺少用量或价格,金额与词元仅为已知小计。展开明细可查看样本覆盖。",
|
|
5578
|
+
analysisOverview: "用量总览",
|
|
5579
|
+
analysisSections: "分析内容",
|
|
5580
|
+
analysisHistory: "历史用量",
|
|
5581
|
+
analysisSimulation: "价格试算",
|
|
5582
|
+
analysisByModel: "按模型查看",
|
|
5583
|
+
analysisModelHint: "展开模型,查看词元、请求状态与样本。",
|
|
5584
|
+
analysisCost: "已知成本 · 美元",
|
|
5585
|
+
analysisRequests: "模型请求",
|
|
5586
|
+
analysisSessionCount: "会话数",
|
|
5587
|
+
analysisResponse: "平均响应",
|
|
5588
|
+
analysisFirstToken: "平均首词元",
|
|
5589
|
+
analysisSpeed: "输出速度",
|
|
5590
|
+
analysisSeconds: "秒",
|
|
5591
|
+
analysisSpeedUnit: "词元/秒",
|
|
5592
|
+
analysisPriced: "计价请求",
|
|
5593
|
+
analysisTimed: "响应样本",
|
|
5594
|
+
analysisFirstTokenSamples: "首词元样本",
|
|
5595
|
+
analysisDecodeSamples: "解码样本",
|
|
5596
|
+
analysisUsageSamples: "用量样本",
|
|
5597
|
+
analysisAverage: "每会话均摊",
|
|
5598
|
+
analysisMissing: "无数据",
|
|
5599
|
+
analysisDetails: "查看汇总明细",
|
|
5600
|
+
analysisTokens: "词元与缓存",
|
|
5601
|
+
analysisInput: "未缓存输入",
|
|
5602
|
+
analysisOutput: "输出",
|
|
5603
|
+
analysisCacheRead: "缓存读取",
|
|
5604
|
+
analysisCacheWrite: "缓存写入",
|
|
5605
|
+
analysisOutcome: "请求状态",
|
|
5606
|
+
analysisCompleted: "完成",
|
|
5607
|
+
analysisFailed: "失败",
|
|
5608
|
+
analysisRetries: "宿主重试",
|
|
5609
|
+
analysisCancelled: "取消",
|
|
5610
|
+
analysisUnknown: "未知状态",
|
|
5611
|
+
analysisSamples: "统计样本",
|
|
5612
|
+
analysisSessionCost: "会话与成本",
|
|
5613
|
+
analysisMonthly: "按该时间段折算 30 天",
|
|
5614
|
+
analysisMonthlyHint: "仅完整、全部计价且跨度至少一天的日期范围提供折算。",
|
|
5615
|
+
analysisRules: "统计口径与试算说明",
|
|
5616
|
+
analysisShortBasis: "按当前价格估算,非历史账单。缺失用量与耗时不会补零。",
|
|
5617
|
+
analysisBasis: "按当前价格快照重算;不是历史账单,不含订阅费和充值,词元用量不等于账号积分。仅有请求数量、没有任务边界;不计算任务质量或智能评分。旧记录缺失的用量和耗时不会补零。",
|
|
5618
|
+
analysisAssumption: "沿用原请求的词元与时段,对比不同模型的价格。换模型后的生成长度、缓存命中、重试和质量可能变化;不会调用模型或自动推荐。",
|
|
5619
|
+
analysisContext: "上下文词元",
|
|
5620
|
+
analysisCapabilities: "模型能力",
|
|
5621
|
+
analysisEfforts: "推理力度",
|
|
5622
|
+
analysisExcluded: "超出上下文",
|
|
5623
|
+
analysisUnknownPrice: "未知用量或价格",
|
|
5624
|
+
analysisSearch: "筛选试算模型",
|
|
5625
|
+
analysisSearchPlaceholder: "输入模型名称或标识",
|
|
5626
|
+
analysisNoMatches: "没有匹配的模型,请调整筛选条件。",
|
|
5627
|
+
analysisImages: "支持图片",
|
|
5628
|
+
analysisTextOnly: "仅文本",
|
|
5629
|
+
analysisNoEfforts: "未提供推理力度",
|
|
5630
|
+
analysisCoverageHint: "耗时从步骤或重试开始计至模型结算;包含前置处理,不含后续工具执行。首词元包含推理与工具参数。速度按有解码计时的输出词元总量计算。试算未校验图片及工具兼容性,也不代表账号已获授权。",
|
|
5631
|
+
effortNone: "关闭 (none)",
|
|
5632
|
+
effortLow: "低 (low)",
|
|
5633
|
+
effortMedium: "中 (medium)",
|
|
5634
|
+
effortHigh: "高 (high)",
|
|
5635
|
+
effortXhigh: "极高 (xhigh)",
|
|
5636
|
+
effortMax: "最高 (max)"
|
|
5637
|
+
};
|
|
5638
|
+
/** 按项目约定,错误、缺失与读取状态在各语言环境中统一为中文。 */
|
|
5639
|
+
const ANALYTICS_COPY_EN = {
|
|
5640
|
+
analyticsNav: "Model analysis",
|
|
5641
|
+
quotaNav: "Account quota",
|
|
5642
|
+
analysisRecent: "Recent sessions",
|
|
5643
|
+
analysisRange: "Date range",
|
|
5644
|
+
analysisLimit: "Session count",
|
|
5645
|
+
analysisFrom: "Start date",
|
|
5646
|
+
analysisTo: "End date",
|
|
5647
|
+
analysisApply: "Read statistics",
|
|
5648
|
+
analysisLoading: ANALYTICS_COPY_ZH.analysisLoading,
|
|
5649
|
+
analysisUnavailable: ANALYTICS_COPY_ZH.analysisUnavailable,
|
|
5650
|
+
analysisEmpty: ANALYTICS_COPY_ZH.analysisEmpty,
|
|
5651
|
+
analysisInvalid: ANALYTICS_COPY_ZH.analysisInvalid,
|
|
5652
|
+
analysisScope: "Scope",
|
|
5653
|
+
analysisScanned: "Sessions read",
|
|
5654
|
+
analysisMatched: "Sessions with requests",
|
|
5655
|
+
analysisUnreadable: "Read failures",
|
|
5656
|
+
analysisSkipped: "Skipped",
|
|
5657
|
+
analysisPartial: ANALYTICS_COPY_ZH.analysisPartial,
|
|
5658
|
+
analysisCatalog: ANALYTICS_COPY_ZH.analysisCatalog,
|
|
5659
|
+
analysisUnpriced: ANALYTICS_COPY_ZH.analysisUnpriced,
|
|
5660
|
+
analysisOverview: "Usage overview",
|
|
5661
|
+
analysisSections: "Analysis sections",
|
|
5662
|
+
analysisHistory: "Recorded usage",
|
|
5663
|
+
analysisSimulation: "Price simulation",
|
|
5664
|
+
analysisByModel: "Usage by model",
|
|
5665
|
+
analysisModelHint: "Expand a model for tokens, request outcomes and samples.",
|
|
5666
|
+
analysisCost: "Known cost · USD",
|
|
5667
|
+
analysisRequests: "Model requests",
|
|
5668
|
+
analysisSessionCount: "Sessions",
|
|
5669
|
+
analysisResponse: "Mean response",
|
|
5670
|
+
analysisFirstToken: "Mean first token",
|
|
5671
|
+
analysisSpeed: "Output speed",
|
|
5672
|
+
analysisSeconds: "s",
|
|
5673
|
+
analysisSpeedUnit: "tokens/s",
|
|
5674
|
+
analysisPriced: "Priced requests",
|
|
5675
|
+
analysisTimed: "Response samples",
|
|
5676
|
+
analysisFirstTokenSamples: "First-token samples",
|
|
5677
|
+
analysisDecodeSamples: "Decode samples",
|
|
5678
|
+
analysisUsageSamples: "Usage samples",
|
|
5679
|
+
analysisAverage: "Per session",
|
|
5680
|
+
analysisMissing: ANALYTICS_COPY_ZH.analysisMissing,
|
|
5681
|
+
analysisDetails: "View aggregate details",
|
|
5682
|
+
analysisTokens: "Tokens and cache",
|
|
5683
|
+
analysisInput: "Uncached input",
|
|
5684
|
+
analysisOutput: "Output",
|
|
5685
|
+
analysisCacheRead: "Cache read",
|
|
5686
|
+
analysisCacheWrite: "Cache write",
|
|
5687
|
+
analysisOutcome: "Request outcomes",
|
|
5688
|
+
analysisCompleted: "Completed",
|
|
5689
|
+
analysisFailed: "Failed",
|
|
5690
|
+
analysisRetries: "Host retries",
|
|
5691
|
+
analysisCancelled: "Cancelled",
|
|
5692
|
+
analysisUnknown: "Unknown outcome",
|
|
5693
|
+
analysisSamples: "Samples",
|
|
5694
|
+
analysisSessionCost: "Sessions and cost",
|
|
5695
|
+
analysisMonthly: "30-day extrapolation from this range",
|
|
5696
|
+
analysisMonthlyHint: "Requires a complete, fully priced date range spanning at least one day.",
|
|
5697
|
+
analysisRules: "Statistics and simulation notes",
|
|
5698
|
+
analysisShortBasis: "Estimated at current prices, not an invoice. Missing usage and timing stay unknown.",
|
|
5699
|
+
analysisBasis: "Repriced with the current snapshot; not an invoice. Excludes subscriptions and top-ups. Tokens are not account credits. Requests have no task boundaries; no task quality or intelligence scores. Missing usage and timing stay unknown.",
|
|
5700
|
+
analysisAssumption: "Compares model prices using original tokens and request times. Output length, cache hits, retries and quality may change with another model. Makes no model calls or automatic recommendations.",
|
|
5701
|
+
analysisContext: "Context tokens",
|
|
5702
|
+
analysisCapabilities: "Model capabilities",
|
|
5703
|
+
analysisEfforts: "Reasoning efforts",
|
|
5704
|
+
analysisExcluded: "Over context limit",
|
|
5705
|
+
analysisUnknownPrice: "Unknown usage or price",
|
|
5706
|
+
analysisSearch: "Filter simulation models",
|
|
5707
|
+
analysisSearchPlaceholder: "Model name or ID",
|
|
5708
|
+
analysisNoMatches: ANALYTICS_COPY_ZH.analysisNoMatches,
|
|
5709
|
+
analysisImages: "Images supported",
|
|
5710
|
+
analysisTextOnly: "Text only",
|
|
5711
|
+
analysisNoEfforts: "No reasoning efforts listed",
|
|
5712
|
+
analysisCoverageHint: "Response time runs from step/retry start to model settlement, includes preparation and excludes subsequent tools. First token includes reasoning and tool arguments. Speed uses output tokens with decode timing. Simulation does not validate image/tool compatibility or prove account entitlement.",
|
|
5713
|
+
effortNone: "None",
|
|
5714
|
+
effortLow: "Low",
|
|
5715
|
+
effortMedium: "Medium",
|
|
5716
|
+
effortHigh: "High",
|
|
5717
|
+
effortXhigh: "Extra high",
|
|
5718
|
+
effortMax: "Max"
|
|
5719
|
+
};
|
|
5720
|
+
//#endregion
|
|
5547
5721
|
//#region src/client/panel-copy.ts
|
|
5722
|
+
/**
|
|
5723
|
+
* Bilingual copy for the Command Code **plans & quota panel** (the sidebar
|
|
5724
|
+
* footer card and the center-column dashboard it opens).
|
|
5725
|
+
*
|
|
5726
|
+
* The panel follows the harness's active language: `PANEL_LOCALE_NS` is a
|
|
5727
|
+
* registered locale namespace (`ctx.locale.register`), both panel slot
|
|
5728
|
+
* registrations declare it, and the renderer hands the component a `t` seat
|
|
5729
|
+
* whose identity changes on a language switch (so a memoized panel re-renders).
|
|
5730
|
+
* {@link buildPanelView} takes that translator as an input and builds every
|
|
5731
|
+
* string through it, so the projection stays React-free and testable and no
|
|
5732
|
+
* component carries copy of its own. The settings page keeps its own
|
|
5733
|
+
* `settings.commandcode` namespace (see `./locales.ts`); the two never mix.
|
|
5734
|
+
*
|
|
5735
|
+
* @module dsh-commandcode-provider/client/panel-copy
|
|
5736
|
+
*/
|
|
5548
5737
|
/** The locale namespace both panel slots bind their `t` seat to. */
|
|
5549
5738
|
const PANEL_LOCALE_NS = "panel.commandcode";
|
|
5550
5739
|
/** The panel's Simplified Chinese string table (the key-set source of truth). */
|
|
5551
5740
|
const PANEL_COPY_ZH = {
|
|
5741
|
+
...ANALYTICS_COPY_ZH,
|
|
5552
5742
|
nav: "Command Code",
|
|
5553
5743
|
subtitle: "套餐、额度与配额窗口",
|
|
5554
5744
|
refresh: "刷新",
|
|
@@ -5598,11 +5788,12 @@ window.__ModuleLoader__.load({
|
|
|
5598
5788
|
errorNetwork: "无法连接 Command Code 服务",
|
|
5599
5789
|
errorNetworkHint: "所有请求都没有到达服务端。请检查网络连接或 API 地址设置。",
|
|
5600
5790
|
errorInvalidResponse: "Command Code 响应无法读取",
|
|
5601
|
-
errorInvalidResponseHint: "
|
|
5791
|
+
errorInvalidResponseHint: "已收到响应,但正文读取或解析失败。下方详情可区分读取超时、中断与格式异常;可先点击刷新重试。",
|
|
5602
5792
|
errorGeneric: "用量获取失败"
|
|
5603
5793
|
};
|
|
5604
5794
|
/** The panel's English string table (must mirror {@link PANEL_COPY_ZH}). */
|
|
5605
5795
|
const PANEL_COPY_EN = {
|
|
5796
|
+
...ANALYTICS_COPY_EN,
|
|
5606
5797
|
nav: "Command Code",
|
|
5607
5798
|
subtitle: "Plans, credits and quota windows",
|
|
5608
5799
|
refresh: "Refresh",
|
|
@@ -5652,7 +5843,7 @@ window.__ModuleLoader__.load({
|
|
|
5652
5843
|
errorNetwork: "Could not reach the Command Code service",
|
|
5653
5844
|
errorNetworkHint: "No request reached the server. Check your network connection or the API base setting.",
|
|
5654
5845
|
errorInvalidResponse: "Could not read the Command Code response",
|
|
5655
|
-
errorInvalidResponseHint: "
|
|
5846
|
+
errorInvalidResponseHint: "Responses arrived, but reading or parsing their bodies failed. Details below distinguish timeouts, interrupted reads, and invalid formats. Try Refresh again.",
|
|
5656
5847
|
errorGeneric: "Could not fetch account usage"
|
|
5657
5848
|
};
|
|
5658
5849
|
/** Every panel key, in the English table's declaration order. */
|
|
@@ -5668,7 +5859,7 @@ window.__ModuleLoader__.load({
|
|
|
5668
5859
|
//#endregion
|
|
5669
5860
|
//#region src/client/panel.ts
|
|
5670
5861
|
/** `$1.23`, and `$0.0123` only when the amount is too small for cents to show it. */
|
|
5671
|
-
function money(value) {
|
|
5862
|
+
function money$1(value) {
|
|
5672
5863
|
if (value === 0) return formatMoney(0);
|
|
5673
5864
|
return Math.abs(value) < .01 ? formatMoneyExact(value) : formatMoney(value);
|
|
5674
5865
|
}
|
|
@@ -5711,7 +5902,7 @@ window.__ModuleLoader__.load({
|
|
|
5711
5902
|
const capped = limit.cap > 0;
|
|
5712
5903
|
return {
|
|
5713
5904
|
label,
|
|
5714
|
-
value: capped ? `${money(limit.used)} / ${money(limit.cap)}` : money(limit.used),
|
|
5905
|
+
value: capped ? `${money$1(limit.used)} / ${money$1(limit.cap)}` : money$1(limit.used),
|
|
5715
5906
|
capped,
|
|
5716
5907
|
percent,
|
|
5717
5908
|
barPercent: barPercent(percent),
|
|
@@ -5747,11 +5938,11 @@ window.__ModuleLoader__.load({
|
|
|
5747
5938
|
const percent = known ? rawPercent(used, limitValue) : 0;
|
|
5748
5939
|
return {
|
|
5749
5940
|
known,
|
|
5750
|
-
limit: limitValue !== null ? money(limitValue) : UNREPORTED,
|
|
5751
|
-
used: known ? money(used) : UNREPORTED,
|
|
5752
|
-
remaining: remainingReported ? money(remaining) : UNREPORTED,
|
|
5753
|
-
purchased: credits !== void 0 && credits.purchasedReported !== false ? money(Math.max(0, credits.purchasedCredits)) : UNREPORTED,
|
|
5754
|
-
free: credits !== void 0 && credits.freeReported !== false ? money(Math.max(0, credits.freeCredits)) : UNREPORTED,
|
|
5941
|
+
limit: limitValue !== null ? money$1(limitValue) : UNREPORTED,
|
|
5942
|
+
used: known ? money$1(used) : UNREPORTED,
|
|
5943
|
+
remaining: remainingReported ? money$1(remaining) : UNREPORTED,
|
|
5944
|
+
purchased: credits !== void 0 && credits.purchasedReported !== false ? money$1(Math.max(0, credits.purchasedCredits)) : UNREPORTED,
|
|
5945
|
+
free: credits !== void 0 && credits.freeReported !== false ? money$1(Math.max(0, credits.freeCredits)) : UNREPORTED,
|
|
5755
5946
|
percent,
|
|
5756
5947
|
barPercent: barPercent(percent),
|
|
5757
5948
|
exhausted: known && remaining <= 0,
|
|
@@ -5881,11 +6072,11 @@ window.__ModuleLoader__.load({
|
|
|
5881
6072
|
percent: `${percent}%`,
|
|
5882
6073
|
barPercent: barPercent(percent),
|
|
5883
6074
|
warn: window.exceeded,
|
|
5884
|
-
detail: `${money(window.used)} / ${money(window.cap)}`
|
|
6075
|
+
detail: `${money$1(window.used)} / ${money$1(window.cap)}`
|
|
5885
6076
|
});
|
|
5886
6077
|
}
|
|
5887
6078
|
const totalCost = selectedEntry?.report.usage?.totalCost;
|
|
5888
|
-
const cost = totalCost === void 0 ? "" : money(totalCost);
|
|
6079
|
+
const cost = totalCost === void 0 ? "" : money$1(totalCost);
|
|
5889
6080
|
let status = "";
|
|
5890
6081
|
if (entries.length > 0 && !entries.some((entry) => entry.configured)) status = t("unconfigured");
|
|
5891
6082
|
else if (selectedView?.mark !== void 0 && selectedView.mark !== "active") status = t(selectedView.mark);
|
|
@@ -5975,6 +6166,690 @@ window.__ModuleLoader__.load({
|
|
|
5975
6166
|
};
|
|
5976
6167
|
}
|
|
5977
6168
|
//#endregion
|
|
6169
|
+
//#region src/analytics-wire.ts
|
|
6170
|
+
const g = makeBoundaryValidator("commandcode/analytics");
|
|
6171
|
+
const nonnegative = (s, k) => {
|
|
6172
|
+
const n = g.numberField(s, k, k);
|
|
6173
|
+
return n >= 0 ? n : g.reject(k);
|
|
6174
|
+
};
|
|
6175
|
+
const count$1 = (s, k) => {
|
|
6176
|
+
const n = nonnegative(s, k);
|
|
6177
|
+
return Number.isSafeInteger(n) ? n : g.reject(k);
|
|
6178
|
+
};
|
|
6179
|
+
function parseAnalyticsQuery(value) {
|
|
6180
|
+
const s = g.record(value, "query");
|
|
6181
|
+
if (s.mode === "recent") {
|
|
6182
|
+
const limit = count$1(s, "limit");
|
|
6183
|
+
if (limit < 1 || limit > 100) return g.reject("limit");
|
|
6184
|
+
return {
|
|
6185
|
+
mode: "recent",
|
|
6186
|
+
limit
|
|
6187
|
+
};
|
|
6188
|
+
}
|
|
6189
|
+
if (s.mode !== "range") return g.reject("mode");
|
|
6190
|
+
const from = count$1(s, "from"), to = count$1(s, "to");
|
|
6191
|
+
if (to <= from || to - from > 316224e5 || to > 864e13) return g.reject("range");
|
|
6192
|
+
return {
|
|
6193
|
+
mode: "range",
|
|
6194
|
+
from,
|
|
6195
|
+
to
|
|
6196
|
+
};
|
|
6197
|
+
}
|
|
6198
|
+
const counts = [
|
|
6199
|
+
"sessions",
|
|
6200
|
+
"requests",
|
|
6201
|
+
"completed",
|
|
6202
|
+
"failed",
|
|
6203
|
+
"cancelled",
|
|
6204
|
+
"unknown",
|
|
6205
|
+
"retries",
|
|
6206
|
+
"usageSamples",
|
|
6207
|
+
"pricedRequests",
|
|
6208
|
+
"latencySamples",
|
|
6209
|
+
"ttftSamples",
|
|
6210
|
+
"decodeSamples"
|
|
6211
|
+
];
|
|
6212
|
+
const quantities = [
|
|
6213
|
+
"cost",
|
|
6214
|
+
"latencyMs",
|
|
6215
|
+
"ttftMs",
|
|
6216
|
+
"decodeMs",
|
|
6217
|
+
"decodeTokens"
|
|
6218
|
+
];
|
|
6219
|
+
const tokenKeys = [
|
|
6220
|
+
"uncachedInputTokens",
|
|
6221
|
+
"outputTokens",
|
|
6222
|
+
"cacheReadTokens",
|
|
6223
|
+
"cacheWriteTokens"
|
|
6224
|
+
];
|
|
6225
|
+
function metrics(value) {
|
|
6226
|
+
const s = g.record(value, "metrics"), result = {};
|
|
6227
|
+
for (const k of counts) result[k] = count$1(s, k);
|
|
6228
|
+
for (const k of quantities) result[k] = nonnegative(s, k);
|
|
6229
|
+
const tokens = g.record(s.tokens, "tokens");
|
|
6230
|
+
result.tokens = Object.fromEntries(tokenKeys.map((k) => [k, nonnegative(tokens, k)]));
|
|
6231
|
+
if (result.completed + result.failed + result.cancelled + result.unknown !== result.requests || result.pricedRequests > result.usageSamples || result.usageSamples > result.requests || result.retries > result.requests || result.ttftSamples > result.requests || result.latencySamples > result.requests || result.decodeSamples > result.requests) return g.reject("coverage");
|
|
6232
|
+
return result;
|
|
6233
|
+
}
|
|
6234
|
+
const nullable = (s, k) => s[k] === null ? null : nonnegative(s, k);
|
|
6235
|
+
function parseAnalyticsReport(value) {
|
|
6236
|
+
const s = g.record(value, "report");
|
|
6237
|
+
if (s.status !== "ready" && s.status !== "unavailable") return g.reject("status");
|
|
6238
|
+
if (!Array.isArray(s.models) || !Array.isArray(s.scenarios) || s.models.length > 1e3 || s.scenarios.length > 1e3) return g.reject("models");
|
|
6239
|
+
return {
|
|
6240
|
+
generatedAt: count$1(s, "generatedAt"),
|
|
6241
|
+
pricingKey: count$1(s, "pricingKey"),
|
|
6242
|
+
query: parseAnalyticsQuery(s.query),
|
|
6243
|
+
status: s.status,
|
|
6244
|
+
scannedSessions: count$1(s, "scannedSessions"),
|
|
6245
|
+
matchedSessions: count$1(s, "matchedSessions"),
|
|
6246
|
+
unreadableSessions: count$1(s, "unreadableSessions"),
|
|
6247
|
+
skippedSessions: count$1(s, "skippedSessions"),
|
|
6248
|
+
truncated: g.booleanField(s, "truncated", "truncated"),
|
|
6249
|
+
catalogUnavailable: g.booleanField(s, "catalogUnavailable", "catalogUnavailable"),
|
|
6250
|
+
totals: metrics(s.totals),
|
|
6251
|
+
monthlyEstimate: nullable(s, "monthlyEstimate"),
|
|
6252
|
+
models: s.models.map((value) => {
|
|
6253
|
+
const m = g.record(value, "model");
|
|
6254
|
+
return {
|
|
6255
|
+
...metrics(m),
|
|
6256
|
+
id: g.stringField(m, "id", "id")
|
|
6257
|
+
};
|
|
6258
|
+
}),
|
|
6259
|
+
scenarios: s.scenarios.map((value) => {
|
|
6260
|
+
const m = g.record(value, "scenario");
|
|
6261
|
+
if (!Array.isArray(m.efforts) || !m.efforts.every((v) => typeof v === "string")) return g.reject("efforts");
|
|
6262
|
+
return {
|
|
6263
|
+
id: g.stringField(m, "id", "id"),
|
|
6264
|
+
name: g.stringField(m, "name", "name"),
|
|
6265
|
+
contextWindow: nullable(m, "contextWindow"),
|
|
6266
|
+
images: g.booleanField(m, "images", "images"),
|
|
6267
|
+
efforts: m.efforts,
|
|
6268
|
+
cost: nonnegative(m, "cost"),
|
|
6269
|
+
pricedRequests: count$1(m, "pricedRequests"),
|
|
6270
|
+
excludedRequests: count$1(m, "excludedRequests"),
|
|
6271
|
+
unknownRequests: count$1(m, "unknownRequests")
|
|
6272
|
+
};
|
|
6273
|
+
})
|
|
6274
|
+
};
|
|
6275
|
+
}
|
|
6276
|
+
const ANALYTICS_REMOTE_CONTRIBUTION = {
|
|
6277
|
+
package: REMOTE_PACKAGE,
|
|
6278
|
+
descriptors: [{
|
|
6279
|
+
...makeRemoteDescriptor("commandcode/analytics", "analytics", `${REMOTE_PACKAGE}#AnalyticsReport`, { parse: parseAnalyticsReport }),
|
|
6280
|
+
parameters: [{
|
|
6281
|
+
name: "query",
|
|
6282
|
+
wire: "query",
|
|
6283
|
+
source: "json",
|
|
6284
|
+
codec: makeStrictCodec(`${REMOTE_PACKAGE}#AnalyticsQuery`, { parse: parseAnalyticsQuery })
|
|
6285
|
+
}]
|
|
6286
|
+
}]
|
|
6287
|
+
};
|
|
6288
|
+
//#endregion
|
|
6289
|
+
//#region src/client/analytics-view.tsx
|
|
6290
|
+
/** 只展示数字快照;筛选提交后才查询,页签、展开与模型筛选不触发历史读取。 */
|
|
6291
|
+
function localDate(time) {
|
|
6292
|
+
const d = new Date(time);
|
|
6293
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
6294
|
+
}
|
|
6295
|
+
/** 日期按用户本地日历展开为半开区间;截止日包括当日全部时间,夏令时不固定加 24 小时。 */
|
|
6296
|
+
function dateRange(from, to) {
|
|
6297
|
+
const start = /* @__PURE__ */ new Date(`${from}T00:00:00`), end = /* @__PURE__ */ new Date(`${to}T00:00:00`);
|
|
6298
|
+
if (localDate(start.getTime()) !== from || localDate(end.getTime()) !== to) throw new TypeError("无效日期");
|
|
6299
|
+
end.setDate(end.getDate() + 1);
|
|
6300
|
+
return parseAnalyticsQuery({
|
|
6301
|
+
mode: "range",
|
|
6302
|
+
from: start.getTime(),
|
|
6303
|
+
to: end.getTime()
|
|
6304
|
+
});
|
|
6305
|
+
}
|
|
6306
|
+
const money = (n) => `$${n.toFixed(4)}`;
|
|
6307
|
+
const digits = (n) => n.toLocaleString();
|
|
6308
|
+
const meanSeconds = (ms, samples, text) => samples ? `${(ms / samples / 1e3).toFixed(2)} ${text("analysisSeconds")}` : text("analysisMissing");
|
|
6309
|
+
const speed = (m, text) => m.decodeSamples && m.decodeMs ? `${(m.decodeTokens * 1e3 / m.decodeMs).toFixed(1)} ${text("analysisSpeedUnit")}` : text("analysisMissing");
|
|
6310
|
+
function effortName(effort, text) {
|
|
6311
|
+
const keys = {
|
|
6312
|
+
none: "effortNone",
|
|
6313
|
+
low: "effortLow",
|
|
6314
|
+
medium: "effortMedium",
|
|
6315
|
+
high: "effortHigh",
|
|
6316
|
+
xhigh: "effortXhigh",
|
|
6317
|
+
max: "effortMax"
|
|
6318
|
+
};
|
|
6319
|
+
return keys[effort] ? text(keys[effort]) : effort;
|
|
6320
|
+
}
|
|
6321
|
+
function Chevron() {
|
|
6322
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
6323
|
+
className: "ccp-analysisChevron",
|
|
6324
|
+
width: "16",
|
|
6325
|
+
height: "16",
|
|
6326
|
+
viewBox: "0 0 24 24",
|
|
6327
|
+
fill: "none",
|
|
6328
|
+
stroke: "currentColor",
|
|
6329
|
+
strokeWidth: "1.6",
|
|
6330
|
+
strokeLinecap: "round",
|
|
6331
|
+
strokeLinejoin: "round",
|
|
6332
|
+
"aria-hidden": "true",
|
|
6333
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m9 5 7 7-7 7" })
|
|
6334
|
+
});
|
|
6335
|
+
}
|
|
6336
|
+
function Metric({ label, value, sub }) {
|
|
6337
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6338
|
+
className: "ccp-analysisMetric",
|
|
6339
|
+
children: [
|
|
6340
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6341
|
+
className: "ccp-analysisLabel",
|
|
6342
|
+
children: label
|
|
6343
|
+
}),
|
|
6344
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6345
|
+
className: "ccp-analysisValue",
|
|
6346
|
+
children: value
|
|
6347
|
+
}),
|
|
6348
|
+
sub ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6349
|
+
className: "ccp-analysisSub",
|
|
6350
|
+
children: sub
|
|
6351
|
+
}) : null
|
|
6352
|
+
]
|
|
6353
|
+
});
|
|
6354
|
+
}
|
|
6355
|
+
function DetailGroup({ title, values, text }) {
|
|
6356
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6357
|
+
className: "ccp-analysisDetailGroup",
|
|
6358
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
6359
|
+
className: "ccp-analysisDetailTitle",
|
|
6360
|
+
children: text(title)
|
|
6361
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dl", {
|
|
6362
|
+
className: "ccp-analysisFacts",
|
|
6363
|
+
children: values.map(([key, value]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6364
|
+
className: "ccp-analysisFact",
|
|
6365
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
6366
|
+
className: "ccp-analysisLabel",
|
|
6367
|
+
children: text(key)
|
|
6368
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
6369
|
+
className: "ccp-analysisFactValue",
|
|
6370
|
+
children: value
|
|
6371
|
+
})]
|
|
6372
|
+
}, key))
|
|
6373
|
+
})]
|
|
6374
|
+
});
|
|
6375
|
+
}
|
|
6376
|
+
/** 样本为零时词元仍为未知;汇总和单模型复用相同口径,展开只改变展示。 */
|
|
6377
|
+
function MetricsDetails({ m, text }) {
|
|
6378
|
+
const tokens = m.tokens, tokenValue = (n) => m.usageSamples ? digits(n) : text("analysisMissing");
|
|
6379
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6380
|
+
className: "ccp-analysisDetails",
|
|
6381
|
+
children: [
|
|
6382
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6383
|
+
title: "analysisTokens",
|
|
6384
|
+
text,
|
|
6385
|
+
values: [
|
|
6386
|
+
["analysisInput", tokenValue(tokens.uncachedInputTokens)],
|
|
6387
|
+
["analysisOutput", tokenValue(tokens.outputTokens)],
|
|
6388
|
+
["analysisCacheRead", tokenValue(tokens.cacheReadTokens)],
|
|
6389
|
+
["analysisCacheWrite", tokenValue(tokens.cacheWriteTokens)]
|
|
6390
|
+
]
|
|
6391
|
+
}),
|
|
6392
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6393
|
+
title: "analysisOutcome",
|
|
6394
|
+
text,
|
|
6395
|
+
values: [
|
|
6396
|
+
["analysisCompleted", digits(m.completed)],
|
|
6397
|
+
["analysisFailed", digits(m.failed)],
|
|
6398
|
+
["analysisRetries", digits(m.retries)],
|
|
6399
|
+
["analysisCancelled", digits(m.cancelled)],
|
|
6400
|
+
["analysisUnknown", digits(m.unknown)]
|
|
6401
|
+
]
|
|
6402
|
+
}),
|
|
6403
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6404
|
+
title: "analysisSamples",
|
|
6405
|
+
text,
|
|
6406
|
+
values: [
|
|
6407
|
+
["analysisUsageSamples", digits(m.usageSamples)],
|
|
6408
|
+
["analysisPriced", digits(m.pricedRequests)],
|
|
6409
|
+
["analysisTimed", digits(m.latencySamples)],
|
|
6410
|
+
["analysisFirstTokenSamples", digits(m.ttftSamples)],
|
|
6411
|
+
["analysisDecodeSamples", digits(m.decodeSamples)]
|
|
6412
|
+
]
|
|
6413
|
+
}),
|
|
6414
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6415
|
+
title: "analysisSessionCost",
|
|
6416
|
+
text,
|
|
6417
|
+
values: [
|
|
6418
|
+
["analysisSessionCount", digits(m.sessions)],
|
|
6419
|
+
["analysisRequests", digits(m.requests)],
|
|
6420
|
+
["analysisAverage", m.sessions && m.pricedRequests ? money(m.cost / m.sessions) : text("analysisMissing")],
|
|
6421
|
+
["analysisSpeed", speed(m, text)]
|
|
6422
|
+
]
|
|
6423
|
+
})
|
|
6424
|
+
]
|
|
6425
|
+
});
|
|
6426
|
+
}
|
|
6427
|
+
function ModelRow({ m, text }) {
|
|
6428
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6429
|
+
className: "ccp-analysisModelRow",
|
|
6430
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6431
|
+
className: "ccp-analysisModelSummary",
|
|
6432
|
+
children: [
|
|
6433
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6434
|
+
className: "ccp-analysisIdentity",
|
|
6435
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6436
|
+
className: "ccp-analysisModelName",
|
|
6437
|
+
children: m.id
|
|
6438
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6439
|
+
className: "ccp-analysisSub",
|
|
6440
|
+
children: [
|
|
6441
|
+
text("analysisRequests"),
|
|
6442
|
+
" ",
|
|
6443
|
+
digits(m.requests),
|
|
6444
|
+
" · ",
|
|
6445
|
+
text("analysisSessionCount"),
|
|
6446
|
+
" ",
|
|
6447
|
+
digits(m.sessions)
|
|
6448
|
+
]
|
|
6449
|
+
})]
|
|
6450
|
+
}),
|
|
6451
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6452
|
+
label: text("analysisCost"),
|
|
6453
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6454
|
+
sub: `${text("analysisPriced")} ${m.pricedRequests}/${m.requests}`
|
|
6455
|
+
}),
|
|
6456
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6457
|
+
label: text("analysisResponse"),
|
|
6458
|
+
value: meanSeconds(m.latencyMs, m.latencySamples, text)
|
|
6459
|
+
}),
|
|
6460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6461
|
+
label: text("analysisFirstToken"),
|
|
6462
|
+
value: meanSeconds(m.ttftMs, m.ttftSamples, text)
|
|
6463
|
+
}),
|
|
6464
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6465
|
+
label: text("analysisSpeed"),
|
|
6466
|
+
value: speed(m, text)
|
|
6467
|
+
}),
|
|
6468
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})
|
|
6469
|
+
]
|
|
6470
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MetricsDetails, {
|
|
6471
|
+
m,
|
|
6472
|
+
text
|
|
6473
|
+
})]
|
|
6474
|
+
});
|
|
6475
|
+
}
|
|
6476
|
+
function ScenarioRow({ m, text }) {
|
|
6477
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6478
|
+
className: "ccp-analysisModelRow",
|
|
6479
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6480
|
+
className: "ccp-analysisScenarioSummary",
|
|
6481
|
+
children: [
|
|
6482
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6483
|
+
className: "ccp-analysisIdentity",
|
|
6484
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6485
|
+
className: "ccp-analysisModelName",
|
|
6486
|
+
children: m.name
|
|
6487
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6488
|
+
className: "ccp-analysisSub",
|
|
6489
|
+
children: m.id
|
|
6490
|
+
})]
|
|
6491
|
+
}),
|
|
6492
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6493
|
+
label: text("analysisCost"),
|
|
6494
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6495
|
+
sub: `${text("analysisPriced")} ${m.pricedRequests}/${m.pricedRequests + m.excludedRequests + m.unknownRequests}`
|
|
6496
|
+
}),
|
|
6497
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6498
|
+
label: text("analysisContext"),
|
|
6499
|
+
value: m.contextWindow === null ? text("analysisMissing") : digits(m.contextWindow)
|
|
6500
|
+
}),
|
|
6501
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6502
|
+
className: "ccp-analysisCapability",
|
|
6503
|
+
children: text(m.images ? "analysisImages" : "analysisTextOnly")
|
|
6504
|
+
}),
|
|
6505
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})
|
|
6506
|
+
]
|
|
6507
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6508
|
+
className: "ccp-analysisDetails ccp-analysisScenarioDetails",
|
|
6509
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6510
|
+
title: "analysisSamples",
|
|
6511
|
+
text,
|
|
6512
|
+
values: [
|
|
6513
|
+
["analysisPriced", digits(m.pricedRequests)],
|
|
6514
|
+
["analysisExcluded", digits(m.excludedRequests)],
|
|
6515
|
+
["analysisUnknownPrice", digits(m.unknownRequests)]
|
|
6516
|
+
]
|
|
6517
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6518
|
+
title: "analysisCapabilities",
|
|
6519
|
+
text,
|
|
6520
|
+
values: [["analysisEfforts", m.efforts.length ? m.efforts.map((e) => effortName(e, text)).join(", ") : text("analysisNoEfforts")]]
|
|
6521
|
+
})]
|
|
6522
|
+
})]
|
|
6523
|
+
});
|
|
6524
|
+
}
|
|
6525
|
+
function AnalyticsView(props) {
|
|
6526
|
+
const { text } = props, state = props.useCommandCodeAnalytics((s) => s), report = state.report;
|
|
6527
|
+
const [mode, setMode] = (0, react.useState)(report?.query.mode ?? "recent");
|
|
6528
|
+
const [limit, setLimit] = (0, react.useState)(report?.query.mode === "recent" ? String(report.query.limit) : "20");
|
|
6529
|
+
const [from, setFrom] = (0, react.useState)(localDate(report?.query.mode === "range" ? report.query.from : Date.now() - 25056e5));
|
|
6530
|
+
const [to, setTo] = (0, react.useState)(localDate(report?.query.mode === "range" ? report.query.to - 1 : Date.now()));
|
|
6531
|
+
const [invalid, setInvalid] = (0, react.useState)(false), [filter, setFilter] = (0, react.useState)("");
|
|
6532
|
+
const [page, setPage] = (0, react.useState)("history"), id = (0, react.useId)();
|
|
6533
|
+
const refresh = props.refreshAnalytics;
|
|
6534
|
+
(0, react.useEffect)(() => {
|
|
6535
|
+
if (state.status === "idle") refresh();
|
|
6536
|
+
}, [state.status, refresh]);
|
|
6537
|
+
const busy = state.status === "loading";
|
|
6538
|
+
const apply = () => {
|
|
6539
|
+
try {
|
|
6540
|
+
const query = mode === "recent" ? parseAnalyticsQuery({
|
|
6541
|
+
mode,
|
|
6542
|
+
limit: Number(limit)
|
|
6543
|
+
}) : dateRange(from, to);
|
|
6544
|
+
setInvalid(false);
|
|
6545
|
+
refresh(query);
|
|
6546
|
+
} catch {
|
|
6547
|
+
setInvalid(true);
|
|
6548
|
+
}
|
|
6549
|
+
};
|
|
6550
|
+
const navigateTab = (event) => {
|
|
6551
|
+
if (![
|
|
6552
|
+
"ArrowLeft",
|
|
6553
|
+
"ArrowRight",
|
|
6554
|
+
"Home",
|
|
6555
|
+
"End"
|
|
6556
|
+
].includes(event.key)) return;
|
|
6557
|
+
event.preventDefault();
|
|
6558
|
+
const next = event.key === "Home" ? "history" : event.key === "End" ? "simulation" : page === "history" ? "simulation" : "history";
|
|
6559
|
+
setPage(next);
|
|
6560
|
+
event.currentTarget.querySelector(`[data-page="${next}"]`)?.focus();
|
|
6561
|
+
};
|
|
6562
|
+
const scenarios = report?.scenarios.filter((m) => `${m.id} ${m.name}`.toLowerCase().includes(filter.trim().toLowerCase())) ?? [];
|
|
6563
|
+
const m = report?.totals;
|
|
6564
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6565
|
+
className: "ccp-analysis",
|
|
6566
|
+
"aria-label": text("analyticsNav"),
|
|
6567
|
+
"aria-busy": busy,
|
|
6568
|
+
children: [
|
|
6569
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
6570
|
+
className: "ccp-analysisFilters",
|
|
6571
|
+
noValidate: true,
|
|
6572
|
+
onSubmit: (e) => {
|
|
6573
|
+
e.preventDefault();
|
|
6574
|
+
if (!busy) apply();
|
|
6575
|
+
},
|
|
6576
|
+
children: [
|
|
6577
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6578
|
+
className: "ccp-analysisField ccp-analysisScopeField",
|
|
6579
|
+
children: [text("analysisScope"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6580
|
+
className: "ccp-analysisSelectShell",
|
|
6581
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
6582
|
+
className: "ccp-analysisInput ccp-analysisSelect",
|
|
6583
|
+
value: mode,
|
|
6584
|
+
disabled: busy,
|
|
6585
|
+
onChange: (e) => setMode(e.target.value),
|
|
6586
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6587
|
+
value: "recent",
|
|
6588
|
+
children: text("analysisRecent")
|
|
6589
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6590
|
+
value: "range",
|
|
6591
|
+
children: text("analysisRange")
|
|
6592
|
+
})]
|
|
6593
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})]
|
|
6594
|
+
})]
|
|
6595
|
+
}),
|
|
6596
|
+
mode === "recent" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6597
|
+
className: "ccp-analysisField",
|
|
6598
|
+
children: [text("analysisLimit"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6599
|
+
className: "ccp-analysisInput",
|
|
6600
|
+
type: "number",
|
|
6601
|
+
min: "1",
|
|
6602
|
+
max: "100",
|
|
6603
|
+
required: true,
|
|
6604
|
+
value: limit,
|
|
6605
|
+
disabled: busy,
|
|
6606
|
+
onChange: (e) => setLimit(e.target.value)
|
|
6607
|
+
})]
|
|
6608
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6609
|
+
className: "ccp-analysisField",
|
|
6610
|
+
children: [text("analysisFrom"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6611
|
+
className: "ccp-analysisInput",
|
|
6612
|
+
type: "date",
|
|
6613
|
+
required: true,
|
|
6614
|
+
value: from,
|
|
6615
|
+
disabled: busy,
|
|
6616
|
+
onChange: (e) => setFrom(e.target.value)
|
|
6617
|
+
})]
|
|
6618
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6619
|
+
className: "ccp-analysisField",
|
|
6620
|
+
children: [text("analysisTo"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6621
|
+
className: "ccp-analysisInput",
|
|
6622
|
+
type: "date",
|
|
6623
|
+
required: true,
|
|
6624
|
+
value: to,
|
|
6625
|
+
disabled: busy,
|
|
6626
|
+
onChange: (e) => setTo(e.target.value)
|
|
6627
|
+
})]
|
|
6628
|
+
})] }),
|
|
6629
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6630
|
+
className: "ccp-analysisApply",
|
|
6631
|
+
type: "submit",
|
|
6632
|
+
disabled: busy,
|
|
6633
|
+
children: text("analysisApply")
|
|
6634
|
+
})
|
|
6635
|
+
]
|
|
6636
|
+
}),
|
|
6637
|
+
invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6638
|
+
className: "ccp-analysisMessage ccp-analysisError",
|
|
6639
|
+
role: "alert",
|
|
6640
|
+
children: text("analysisInvalid")
|
|
6641
|
+
}) : null,
|
|
6642
|
+
busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6643
|
+
className: "ccp-analysisMessage",
|
|
6644
|
+
role: "status",
|
|
6645
|
+
children: text("analysisLoading")
|
|
6646
|
+
}) : null,
|
|
6647
|
+
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6648
|
+
className: "ccp-analysisMessage ccp-analysisError",
|
|
6649
|
+
role: "alert",
|
|
6650
|
+
children: state.error
|
|
6651
|
+
}) : null,
|
|
6652
|
+
report?.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6653
|
+
className: "ccp-analysisMessage",
|
|
6654
|
+
role: "status",
|
|
6655
|
+
children: text("analysisUnavailable")
|
|
6656
|
+
}) : null,
|
|
6657
|
+
report?.status === "ready" && m ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6658
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6659
|
+
className: "ccp-analysisScope",
|
|
6660
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
6661
|
+
text("analysisScope"),
|
|
6662
|
+
": ",
|
|
6663
|
+
report.query.mode === "recent" ? `${text("analysisRecent")} ${report.query.limit}` : `${localDate(report.query.from)} — ${localDate(report.query.to - 1)}`
|
|
6664
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
6665
|
+
text("analysisScanned"),
|
|
6666
|
+
" ",
|
|
6667
|
+
report.scannedSessions,
|
|
6668
|
+
" · ",
|
|
6669
|
+
text("analysisMatched"),
|
|
6670
|
+
" ",
|
|
6671
|
+
report.matchedSessions,
|
|
6672
|
+
" · ",
|
|
6673
|
+
text("analysisUnreadable"),
|
|
6674
|
+
" ",
|
|
6675
|
+
report.unreadableSessions,
|
|
6676
|
+
" · ",
|
|
6677
|
+
text("analysisSkipped"),
|
|
6678
|
+
" ",
|
|
6679
|
+
report.skippedSessions
|
|
6680
|
+
] })]
|
|
6681
|
+
}),
|
|
6682
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6683
|
+
className: "ccp-analysisOverview",
|
|
6684
|
+
role: "group",
|
|
6685
|
+
"aria-label": text("analysisOverview"),
|
|
6686
|
+
children: [
|
|
6687
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6688
|
+
label: text("analysisCost"),
|
|
6689
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6690
|
+
sub: `${text("analysisPriced")} ${m.pricedRequests}/${m.requests}`
|
|
6691
|
+
}),
|
|
6692
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6693
|
+
label: text("analysisRequests"),
|
|
6694
|
+
value: digits(m.requests),
|
|
6695
|
+
sub: `${text("analysisSessionCount")} ${digits(m.sessions)}`
|
|
6696
|
+
}),
|
|
6697
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6698
|
+
label: text("analysisResponse"),
|
|
6699
|
+
value: meanSeconds(m.latencyMs, m.latencySamples, text),
|
|
6700
|
+
sub: `${text("analysisTimed")} ${digits(m.latencySamples)}`
|
|
6701
|
+
}),
|
|
6702
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6703
|
+
label: text("analysisFirstToken"),
|
|
6704
|
+
value: meanSeconds(m.ttftMs, m.ttftSamples, text),
|
|
6705
|
+
sub: `${text("analysisFirstTokenSamples")} ${digits(m.ttftSamples)}`
|
|
6706
|
+
})
|
|
6707
|
+
]
|
|
6708
|
+
}),
|
|
6709
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6710
|
+
className: "ccp-analysisNote",
|
|
6711
|
+
children: text("analysisShortBasis")
|
|
6712
|
+
}),
|
|
6713
|
+
report.truncated || report.unreadableSessions > 0 || report.skippedSessions > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6714
|
+
className: "ccp-analysisMessage ccp-analysisWarning",
|
|
6715
|
+
role: "status",
|
|
6716
|
+
children: text("analysisPartial")
|
|
6717
|
+
}) : null,
|
|
6718
|
+
m.pricedRequests < m.requests ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6719
|
+
className: "ccp-analysisMessage ccp-analysisWarning",
|
|
6720
|
+
role: "status",
|
|
6721
|
+
children: text("analysisUnpriced")
|
|
6722
|
+
}) : null,
|
|
6723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6724
|
+
className: "ccp-analysisTabs",
|
|
6725
|
+
role: "tablist",
|
|
6726
|
+
"aria-label": text("analysisSections"),
|
|
6727
|
+
onKeyDown: navigateTab,
|
|
6728
|
+
children: ["history", "simulation"].map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6729
|
+
className: "ccp-analysisTab",
|
|
6730
|
+
id: `${id}-${tab}-tab`,
|
|
6731
|
+
"data-page": tab,
|
|
6732
|
+
type: "button",
|
|
6733
|
+
role: "tab",
|
|
6734
|
+
"aria-selected": page === tab,
|
|
6735
|
+
"aria-controls": `${id}-${tab}`,
|
|
6736
|
+
tabIndex: page === tab ? 0 : -1,
|
|
6737
|
+
onClick: () => setPage(tab),
|
|
6738
|
+
children: text(tab === "history" ? "analysisHistory" : "analysisSimulation")
|
|
6739
|
+
}, tab))
|
|
6740
|
+
}),
|
|
6741
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6742
|
+
className: "ccp-analysisPanel",
|
|
6743
|
+
id: `${id}-history`,
|
|
6744
|
+
role: "tabpanel",
|
|
6745
|
+
"aria-labelledby": `${id}-history-tab`,
|
|
6746
|
+
tabIndex: 0,
|
|
6747
|
+
hidden: page !== "history",
|
|
6748
|
+
children: [
|
|
6749
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6750
|
+
className: "ccp-analysisSectionHead",
|
|
6751
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
6752
|
+
className: "ccp-analysisHeading",
|
|
6753
|
+
children: text("analysisByModel")
|
|
6754
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6755
|
+
className: "ccp-analysisNote",
|
|
6756
|
+
children: text("analysisModelHint")
|
|
6757
|
+
})]
|
|
6758
|
+
}),
|
|
6759
|
+
m.requests === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6760
|
+
className: "ccp-analysisEmpty",
|
|
6761
|
+
children: text("analysisEmpty")
|
|
6762
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6763
|
+
className: "ccp-analysisModels",
|
|
6764
|
+
children: report.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
|
|
6765
|
+
m: model,
|
|
6766
|
+
text
|
|
6767
|
+
}, model.id))
|
|
6768
|
+
}),
|
|
6769
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6770
|
+
className: "ccp-analysisAggregate",
|
|
6771
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6772
|
+
className: "ccp-analysisDisclosure",
|
|
6773
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {}), text("analysisDetails")]
|
|
6774
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MetricsDetails, {
|
|
6775
|
+
m,
|
|
6776
|
+
text
|
|
6777
|
+
})]
|
|
6778
|
+
}),
|
|
6779
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6780
|
+
className: "ccp-analysisMonthly",
|
|
6781
|
+
children: [
|
|
6782
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisMonthly") }),
|
|
6783
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
6784
|
+
className: "ccp-analysisMonthlyValue",
|
|
6785
|
+
children: report.monthlyEstimate === null || report.truncated || report.unreadableSessions || report.skippedSessions ? text("analysisMissing") : money(report.monthlyEstimate)
|
|
6786
|
+
}),
|
|
6787
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6788
|
+
className: "ccp-analysisNote",
|
|
6789
|
+
children: text("analysisMonthlyHint")
|
|
6790
|
+
})
|
|
6791
|
+
]
|
|
6792
|
+
})
|
|
6793
|
+
]
|
|
6794
|
+
}),
|
|
6795
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6796
|
+
className: "ccp-analysisPanel",
|
|
6797
|
+
id: `${id}-simulation`,
|
|
6798
|
+
role: "tabpanel",
|
|
6799
|
+
"aria-labelledby": `${id}-simulation-tab`,
|
|
6800
|
+
tabIndex: 0,
|
|
6801
|
+
hidden: page !== "simulation",
|
|
6802
|
+
children: [
|
|
6803
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6804
|
+
className: "ccp-analysisAssumption",
|
|
6805
|
+
children: text("analysisAssumption")
|
|
6806
|
+
}),
|
|
6807
|
+
report.catalogUnavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6808
|
+
className: "ccp-analysisMessage ccp-analysisWarning",
|
|
6809
|
+
role: "status",
|
|
6810
|
+
children: text("analysisCatalog")
|
|
6811
|
+
}) : null,
|
|
6812
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6813
|
+
className: "ccp-analysisField ccp-analysisSearch",
|
|
6814
|
+
children: [text("analysisSearch"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6815
|
+
className: "ccp-analysisInput",
|
|
6816
|
+
type: "search",
|
|
6817
|
+
placeholder: text("analysisSearchPlaceholder"),
|
|
6818
|
+
value: filter,
|
|
6819
|
+
onChange: (e) => setFilter(e.target.value)
|
|
6820
|
+
})]
|
|
6821
|
+
}),
|
|
6822
|
+
m.requests === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6823
|
+
className: "ccp-analysisEmpty",
|
|
6824
|
+
children: text("analysisEmpty")
|
|
6825
|
+
}) : scenarios.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6826
|
+
className: "ccp-analysisModels",
|
|
6827
|
+
children: scenarios.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScenarioRow, {
|
|
6828
|
+
m: model,
|
|
6829
|
+
text
|
|
6830
|
+
}, model.id))
|
|
6831
|
+
}) : !report.catalogUnavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6832
|
+
className: "ccp-analysisEmpty",
|
|
6833
|
+
role: "status",
|
|
6834
|
+
children: text("analysisNoMatches")
|
|
6835
|
+
}) : null
|
|
6836
|
+
]
|
|
6837
|
+
}),
|
|
6838
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6839
|
+
className: "ccp-analysisRules",
|
|
6840
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6841
|
+
className: "ccp-analysisDisclosure",
|
|
6842
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {}), text("analysisRules")]
|
|
6843
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6844
|
+
className: "ccp-analysisRulesBody",
|
|
6845
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisBasis") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisCoverageHint") })]
|
|
6846
|
+
})]
|
|
6847
|
+
})
|
|
6848
|
+
] }) : null
|
|
6849
|
+
]
|
|
6850
|
+
});
|
|
6851
|
+
}
|
|
6852
|
+
//#endregion
|
|
5978
6853
|
//#region src/client/panel-view.tsx
|
|
5979
6854
|
/**
|
|
5980
6855
|
* React components for the Command Code plans & quota panel: the sidebar footer
|
|
@@ -6277,10 +7152,17 @@ window.__ModuleLoader__.load({
|
|
|
6277
7152
|
*/
|
|
6278
7153
|
function CommandCodePanel(props) {
|
|
6279
7154
|
const view = usePanelView(props);
|
|
7155
|
+
const [fallbackMode, setFallbackMode] = (0, react.useState)("quota");
|
|
7156
|
+
const mode = props.useCommandCodePanelMode?.((s) => s) ?? fallbackMode;
|
|
7157
|
+
const analyticsBusy = props.useCommandCodeAnalytics?.((s) => s.status === "loading") ?? false;
|
|
7158
|
+
const selectMode = (next) => {
|
|
7159
|
+
setFallbackMode(next);
|
|
7160
|
+
props.selectPanelMode?.(next);
|
|
7161
|
+
};
|
|
6280
7162
|
const text = (key) => view.text[key] ?? key;
|
|
6281
7163
|
const [selectedId, setSelectedId] = (0, react.useState)(void 0);
|
|
6282
7164
|
const startAutoRefresh = props.startAutoRefresh;
|
|
6283
|
-
(0, react.useEffect)(() => startAutoRefresh(), [startAutoRefresh]);
|
|
7165
|
+
(0, react.useEffect)(() => mode === "quota" ? startAutoRefresh() : void 0, [startAutoRefresh, mode]);
|
|
6284
7166
|
const accounts = view.accounts;
|
|
6285
7167
|
const selected = accounts.find((account) => account.id === selectedId) ?? view.selected ?? accounts[0];
|
|
6286
7168
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6288,7 +7170,7 @@ window.__ModuleLoader__.load({
|
|
|
6288
7170
|
role: "region",
|
|
6289
7171
|
"aria-label": text("nav"),
|
|
6290
7172
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6291
|
-
className:
|
|
7173
|
+
className: `ccp-mainInner${mode === "analysis" ? " ccp-mainInnerAnalysis" : ""}`,
|
|
6292
7174
|
children: [
|
|
6293
7175
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
6294
7176
|
className: "ccp-header",
|
|
@@ -6297,14 +7179,14 @@ window.__ModuleLoader__.load({
|
|
|
6297
7179
|
className: "ccp-headerText",
|
|
6298
7180
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
6299
7181
|
className: "ccp-title",
|
|
6300
|
-
children: text("nav")
|
|
6301
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7182
|
+
children: mode === "analysis" ? `Command Code · ${text("analyticsNav")}` : text("nav")
|
|
7183
|
+
}), mode === "quota" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6302
7184
|
className: "ccp-subtitle",
|
|
6303
7185
|
children: text("subtitle")
|
|
6304
|
-
})]
|
|
7186
|
+
}) : null]
|
|
6305
7187
|
}),
|
|
6306
7188
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "ccp-spacer" }),
|
|
6307
|
-
view.updatedAt !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7189
|
+
mode === "quota" && view.updatedAt !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6308
7190
|
className: "ccp-meta",
|
|
6309
7191
|
children: [
|
|
6310
7192
|
text("updated"),
|
|
@@ -6315,9 +7197,9 @@ window.__ModuleLoader__.load({
|
|
|
6315
7197
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6316
7198
|
variant: "ghost",
|
|
6317
7199
|
size: "sm",
|
|
6318
|
-
disabled: view.loading,
|
|
6319
|
-
onClick: () => props.refresh(),
|
|
6320
|
-
children: view.loading ? text("refreshing") : text("refresh")
|
|
7200
|
+
disabled: mode === "quota" ? view.loading : analyticsBusy,
|
|
7201
|
+
onClick: () => mode === "quota" ? props.refresh() : props.refreshAnalytics?.(),
|
|
7202
|
+
children: mode === "quota" && view.loading ? text("refreshing") : text("refresh")
|
|
6321
7203
|
}),
|
|
6322
7204
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6323
7205
|
variant: "ghost",
|
|
@@ -6326,75 +7208,108 @@ window.__ModuleLoader__.load({
|
|
|
6326
7208
|
"aria-label": text("close"),
|
|
6327
7209
|
title: text("closeHint"),
|
|
6328
7210
|
onClick: () => props.close(),
|
|
6329
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
7211
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
7212
|
+
width: "16",
|
|
7213
|
+
height: "16",
|
|
7214
|
+
viewBox: "0 0 24 24",
|
|
7215
|
+
fill: "none",
|
|
7216
|
+
stroke: "currentColor",
|
|
7217
|
+
strokeWidth: "1.6",
|
|
7218
|
+
strokeLinecap: "round",
|
|
6330
7219
|
"aria-hidden": "true",
|
|
6331
|
-
children: "
|
|
7220
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 6 12 12M18 6 6 18" })
|
|
6332
7221
|
})
|
|
6333
7222
|
})
|
|
6334
7223
|
]
|
|
6335
7224
|
}),
|
|
6336
|
-
|
|
6337
|
-
className: "ccp-notice",
|
|
6338
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6339
|
-
className: "ccp-noticeTitle",
|
|
6340
|
-
children: text("noKey")
|
|
6341
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6342
|
-
className: "ccp-noticeHint",
|
|
6343
|
-
children: text("noKeyHint")
|
|
6344
|
-
})]
|
|
6345
|
-
}) : null,
|
|
6346
|
-
view.failure !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6347
|
-
className: "ccp-notice ccp-noticeError",
|
|
6348
|
-
role: "alert",
|
|
6349
|
-
children: [
|
|
6350
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6351
|
-
className: "ccp-noticeTitle",
|
|
6352
|
-
children: text(view.failure.title)
|
|
6353
|
-
}),
|
|
6354
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6355
|
-
className: "ccp-noticeHint",
|
|
6356
|
-
children: text(view.failure.hint)
|
|
6357
|
-
}),
|
|
6358
|
-
view.failure.detail !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6359
|
-
className: "ccp-noticeDetail",
|
|
6360
|
-
children: view.failure.detail
|
|
6361
|
-
}) : null
|
|
6362
|
-
]
|
|
6363
|
-
}) : null,
|
|
6364
|
-
!view.noKey && view.failure === void 0 && accounts.length === 0 && view.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6365
|
-
className: "ccp-hint",
|
|
6366
|
-
children: text("loading")
|
|
6367
|
-
}) : null,
|
|
6368
|
-
view.staleError !== void 0 && view.staleError !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
6369
|
-
className: "ccp-hint",
|
|
6370
|
-
role: "status",
|
|
6371
|
-
children: [
|
|
6372
|
-
text("errorGeneric"),
|
|
6373
|
-
" — ",
|
|
6374
|
-
view.staleError
|
|
6375
|
-
]
|
|
6376
|
-
}) : null,
|
|
6377
|
-
accounts.length > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7225
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
6378
7226
|
className: "ccp-tabs",
|
|
6379
|
-
role: "tablist",
|
|
6380
7227
|
"aria-label": text("nav"),
|
|
6381
|
-
children:
|
|
7228
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7229
|
+
className: mode === "quota" ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
6382
7230
|
type: "button",
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
})
|
|
6394
|
-
|
|
7231
|
+
"aria-pressed": mode === "quota",
|
|
7232
|
+
onClick: () => selectMode("quota"),
|
|
7233
|
+
children: text("quotaNav")
|
|
7234
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7235
|
+
className: mode === "analysis" ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
7236
|
+
type: "button",
|
|
7237
|
+
"aria-pressed": mode === "analysis",
|
|
7238
|
+
onClick: () => selectMode("analysis"),
|
|
7239
|
+
children: text("analyticsNav")
|
|
7240
|
+
})]
|
|
7241
|
+
}),
|
|
7242
|
+
mode === "analysis" ? props.useCommandCodeAnalytics && props.refreshAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnalyticsView, {
|
|
7243
|
+
useCommandCodeAnalytics: props.useCommandCodeAnalytics,
|
|
7244
|
+
refreshAnalytics: props.refreshAnalytics,
|
|
7245
|
+
text
|
|
7246
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6395
7247
|
className: "ccp-hint",
|
|
6396
|
-
children: text(
|
|
6397
|
-
}) :
|
|
7248
|
+
children: text("analysisUnavailable")
|
|
7249
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7250
|
+
view.noKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7251
|
+
className: "ccp-notice",
|
|
7252
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7253
|
+
className: "ccp-noticeTitle",
|
|
7254
|
+
children: text("noKey")
|
|
7255
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7256
|
+
className: "ccp-noticeHint",
|
|
7257
|
+
children: text("noKeyHint")
|
|
7258
|
+
})]
|
|
7259
|
+
}) : null,
|
|
7260
|
+
view.failure !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7261
|
+
className: "ccp-notice ccp-noticeError",
|
|
7262
|
+
role: "alert",
|
|
7263
|
+
children: [
|
|
7264
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7265
|
+
className: "ccp-noticeTitle",
|
|
7266
|
+
children: text(view.failure.title)
|
|
7267
|
+
}),
|
|
7268
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7269
|
+
className: "ccp-noticeHint",
|
|
7270
|
+
children: text(view.failure.hint)
|
|
7271
|
+
}),
|
|
7272
|
+
view.failure.detail !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7273
|
+
className: "ccp-noticeDetail",
|
|
7274
|
+
children: view.failure.detail
|
|
7275
|
+
}) : null
|
|
7276
|
+
]
|
|
7277
|
+
}) : null,
|
|
7278
|
+
!view.noKey && view.failure === void 0 && accounts.length === 0 && view.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7279
|
+
className: "ccp-hint",
|
|
7280
|
+
children: text("loading")
|
|
7281
|
+
}) : null,
|
|
7282
|
+
view.staleError !== void 0 && view.staleError !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
7283
|
+
className: "ccp-hint",
|
|
7284
|
+
role: "status",
|
|
7285
|
+
children: [
|
|
7286
|
+
text("errorGeneric"),
|
|
7287
|
+
" — ",
|
|
7288
|
+
view.staleError
|
|
7289
|
+
]
|
|
7290
|
+
}) : null,
|
|
7291
|
+
accounts.length > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7292
|
+
className: "ccp-tabs",
|
|
7293
|
+
role: "tablist",
|
|
7294
|
+
"aria-label": text("nav"),
|
|
7295
|
+
children: accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7296
|
+
type: "button",
|
|
7297
|
+
role: "tab",
|
|
7298
|
+
"aria-selected": selected?.id === account.id,
|
|
7299
|
+
className: selected?.id === account.id ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
7300
|
+
onClick: () => setSelectedId(account.id),
|
|
7301
|
+
children: account.label
|
|
7302
|
+
}, account.id))
|
|
7303
|
+
}) : null,
|
|
7304
|
+
selected !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountCard, {
|
|
7305
|
+
account: selected,
|
|
7306
|
+
view
|
|
7307
|
+
}) : null,
|
|
7308
|
+
view.partial !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7309
|
+
className: "ccp-hint",
|
|
7310
|
+
children: text(view.partial)
|
|
7311
|
+
}) : null
|
|
7312
|
+
] })
|
|
6398
7313
|
]
|
|
6399
7314
|
})
|
|
6400
7315
|
});
|
|
@@ -7657,10 +8572,8 @@ window.__ModuleLoader__.load({
|
|
|
7657
8572
|
.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
7658
8573
|
.ccp-spacer{flex:1}
|
|
7659
8574
|
.ccp-meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5;font-variant-numeric:tabular-nums}
|
|
7660
|
-
/*
|
|
7661
|
-
glyph is enlarged and optically centred, so it reads as a dismiss control. */
|
|
8575
|
+
/* 关闭图标沿用原语义与按钮尺寸,线性 SVG 随宿主文字颜色变化。 */
|
|
7662
8576
|
.ccp-close{min-width:28px;justify-content:center;padding-left:0;padding-right:0}
|
|
7663
|
-
.ccp-close span{font-size:16px;line-height:1}
|
|
7664
8577
|
.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
7665
8578
|
|
|
7666
8579
|
.ccp-notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:12px 14px;flex-direction:column;gap:4px;display:flex}
|
|
@@ -7714,7 +8627,182 @@ window.__ModuleLoader__.load({
|
|
|
7714
8627
|
.ccp-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
7715
8628
|
|
|
7716
8629
|
@media (prefers-reduced-motion:reduce){.ccp-footFill,.ccp-barFill{transition:none}}
|
|
8630
|
+
/* 分析页使用独立宽度与私有选择器;数字总览和明细不影响原额度面板。 */
|
|
8631
|
+
.ccp-mainInnerAnalysis{max-width:1040px}
|
|
8632
|
+
.ccp-analysis{font-size:14px;line-height:1.6;min-width:0;color:var(--dsw-alias-label-primary)}
|
|
8633
|
+
.ccp-analysisFilters{display:flex;gap:12px;align-items:end;flex-wrap:wrap;margin:10px 0 18px}
|
|
8634
|
+
.ccp-analysisField{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary);min-width:0}
|
|
8635
|
+
.ccp-analysisFilters .ccp-analysisField{min-width:136px}
|
|
8636
|
+
.ccp-analysisFilters .ccp-analysisScopeField{flex:0 1 180px}
|
|
8637
|
+
/* 明确边框盒高度与行高,避免原生下拉、日期输入和按钮按各自外观计算尺寸。 */
|
|
8638
|
+
.ccp-analysisInput{box-sizing:border-box;width:100%;min-width:0;height:40px;padding:8px 11px;font:inherit;font-size:14px;line-height:20px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:7px}
|
|
8639
|
+
/* 原生选择行为保留;SVG 的位置与文字留白独立控制,点击箭头仍交给下拉框。 */
|
|
8640
|
+
.ccp-analysisSelectShell{position:relative;display:block;width:100%;min-width:0}
|
|
8641
|
+
.ccp-analysisSelect{appearance:none;-webkit-appearance:none;padding-inline-end:40px;text-overflow:ellipsis;cursor:pointer}
|
|
8642
|
+
.ccp-analysisSelectShell > .ccp-analysisChevron{position:absolute;inset-inline-end:12px;top:50%;transform:translateY(-50%) rotate(90deg);pointer-events:none}
|
|
8643
|
+
.ccp-analysisSelect:disabled + .ccp-analysisChevron{opacity:.65}
|
|
8644
|
+
.ccp-analysisInput::placeholder{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}
|
|
8645
|
+
.ccp-analysisApply{box-sizing:border-box;height:40px;font:inherit;font-size:14px;font-weight:500;line-height:20px;white-space:nowrap;padding:8px 18px;border:1px solid var(--dsw-alias-label-primary);border-radius:7px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);cursor:pointer}
|
|
8646
|
+
.ccp-analysisApply:disabled{opacity:.5;cursor:wait}
|
|
8647
|
+
.ccp-analysisInput:disabled{opacity:.65}
|
|
8648
|
+
.ccp-analysisInput:focus-visible,.ccp-analysisApply:focus-visible,.ccp-analysisTab:focus-visible,.ccp-analysisPanel:focus-visible,.ccp-analysisModelSummary:focus-visible,.ccp-analysisScenarioSummary:focus-visible,.ccp-analysisDisclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}
|
|
8649
|
+
/* 模型列表会裁切圆角,内收焦点框以保持第一行和最后一行也清晰可见。 */
|
|
8650
|
+
.ccp-analysisModelSummary:focus-visible,.ccp-analysisScenarioSummary:focus-visible,.ccp-analysisAggregate > .ccp-analysisDisclosure:focus-visible{outline-offset:-3px}
|
|
8651
|
+
.ccp-analysisScope{display:flex;justify-content:space-between;gap:6px 18px;flex-wrap:wrap;color:var(--dsw-alias-label-secondary);font-size:12px;margin-bottom:12px}
|
|
8652
|
+
.ccp-analysisOverview{display:grid;grid-template-columns:1.25fr repeat(3,1fr);padding:22px 0;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2);font-variant-numeric:tabular-nums}
|
|
8653
|
+
.ccp-analysisMetric{display:flex;flex-direction:column;gap:4px;min-width:0}
|
|
8654
|
+
.ccp-analysisLabel{font-size:12px;color:var(--dsw-alias-label-secondary);font-weight:400}
|
|
8655
|
+
.ccp-analysisValue{font-size:16px;line-height:1.4;font-weight:500;overflow-wrap:anywhere}
|
|
8656
|
+
.ccp-analysisSub{display:block;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400;overflow-wrap:anywhere}
|
|
8657
|
+
.ccp-analysisOverview .ccp-analysisMetric{padding:0 24px;border-left:1px solid var(--dsw-alias-border-l2)}
|
|
8658
|
+
.ccp-analysisOverview .ccp-analysisMetric:first-child{padding-left:0;border-left:0}
|
|
8659
|
+
.ccp-analysisOverview .ccp-analysisMetric:last-child{padding-right:0}
|
|
8660
|
+
.ccp-analysisOverview .ccp-analysisValue{font-size:26px;font-weight:600;letter-spacing:-.025em;margin:3px 0}
|
|
8661
|
+
.ccp-analysisNote{font-size:12px;color:var(--dsw-alias-label-secondary);margin:8px 0 0}
|
|
8662
|
+
.ccp-analysisMessage{margin:10px 0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:var(--dsw-alias-bg-layer-2);font-size:14px}
|
|
8663
|
+
.ccp-analysisWarning{border-left:3px solid var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary))}
|
|
8664
|
+
.ccp-analysisError{border-left:3px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}
|
|
8665
|
+
.ccp-analysisTabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2);margin:24px 0 0}
|
|
8666
|
+
.ccp-analysisTab{position:relative;border:0;background:transparent;font:inherit;font-size:14px;color:var(--dsw-alias-label-secondary);padding:10px 0 12px;cursor:pointer}
|
|
8667
|
+
.ccp-analysisTab[aria-selected="true"]{color:var(--dsw-alias-label-primary);font-weight:600}
|
|
8668
|
+
.ccp-analysisTab[aria-selected="true"]:after{content:"";position:absolute;bottom:-1px;left:0;right:0;height:2px;background:var(--dsw-alias-brand-primary);border-radius:2px}
|
|
8669
|
+
.ccp-analysisPanel{padding-top:18px;min-width:0}
|
|
8670
|
+
.ccp-analysisPanel[hidden]{display:none}
|
|
8671
|
+
.ccp-analysisSectionHead{display:flex;align-items:baseline;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:12px}
|
|
8672
|
+
.ccp-analysisHeading{font-size:14px;font-weight:600;margin:0}
|
|
8673
|
+
.ccp-analysisSectionHead .ccp-analysisNote{margin:0}
|
|
8674
|
+
.ccp-analysisModels{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;overflow:hidden}
|
|
8675
|
+
.ccp-analysisModelRow{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
8676
|
+
.ccp-analysisModelRow:first-child{border-top:0}
|
|
8677
|
+
.ccp-analysisModelSummary,.ccp-analysisScenarioSummary{position:relative;display:grid;grid-template-columns:minmax(180px,1.65fr) repeat(4,minmax(90px,1fr)) 16px;gap:16px;align-items:center;padding:18px 16px;cursor:pointer;list-style:none;font-variant-numeric:tabular-nums}
|
|
8678
|
+
.ccp-analysisScenarioSummary{grid-template-columns:minmax(180px,1.65fr) repeat(2,minmax(90px,1fr)) minmax(90px,.8fr) 16px}
|
|
8679
|
+
.ccp-analysisModelSummary::-webkit-details-marker,.ccp-analysisScenarioSummary::-webkit-details-marker,.ccp-analysisDisclosure::-webkit-details-marker{display:none}
|
|
8680
|
+
.ccp-analysisModelSummary:hover,.ccp-analysisScenarioSummary:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}
|
|
8681
|
+
.ccp-analysisIdentity{display:flex;flex-direction:column;gap:5px;min-width:0}
|
|
8682
|
+
.ccp-analysisModelName{font-size:14px;font-weight:600;overflow-wrap:anywhere}
|
|
8683
|
+
.ccp-analysisChevron{flex:none;color:var(--dsw-alias-label-secondary)}
|
|
8684
|
+
.ccp-analysisModelRow[open] > .ccp-analysisModelSummary > .ccp-analysisChevron,.ccp-analysisModelRow[open] > .ccp-analysisScenarioSummary > .ccp-analysisChevron,.ccp-analysisAggregate[open] > .ccp-analysisDisclosure > .ccp-analysisChevron,.ccp-analysisRules[open] > .ccp-analysisDisclosure > .ccp-analysisChevron{transform:rotate(90deg)}
|
|
8685
|
+
.ccp-analysisDetails{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:24px;padding:18px 16px 22px;background:var(--dsw-alias-bg-layer-2);border-top:1px solid var(--dsw-alias-border-l2)}
|
|
8686
|
+
.ccp-analysisDetailTitle{font-size:12px;font-weight:600;margin:0 0 10px}
|
|
8687
|
+
.ccp-analysisFacts{margin:0;display:flex;flex-direction:column;gap:8px}
|
|
8688
|
+
.ccp-analysisFact{display:flex;align-items:baseline;justify-content:space-between;gap:12px;min-width:0}
|
|
8689
|
+
.ccp-analysisFactValue{font-size:14px;margin:0;text-align:right;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;min-width:0}
|
|
8690
|
+
.ccp-analysisFact .ccp-analysisLabel{flex-shrink:0}
|
|
8691
|
+
.ccp-analysisAggregate{margin-top:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden}
|
|
8692
|
+
.ccp-analysisDisclosure{display:flex;gap:8px;align-items:center;cursor:pointer;list-style:none;font-size:12px;color:var(--dsw-alias-label-secondary);padding:11px 14px}
|
|
8693
|
+
.ccp-analysisMonthly{margin:16px 0 0;display:flex;flex-wrap:wrap;gap:4px 12px;align-items:baseline;font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
8694
|
+
.ccp-analysisMonthlyValue{font-size:14px;font-weight:500;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums}
|
|
8695
|
+
.ccp-analysisMonthly .ccp-analysisNote{width:100%;margin:0}
|
|
8696
|
+
.ccp-analysisAssumption{font-size:14px;line-height:1.6;color:var(--dsw-alias-label-secondary);margin:0 0 16px}
|
|
8697
|
+
.ccp-analysisSearch{max-width:360px;margin-bottom:16px}
|
|
8698
|
+
.ccp-analysisCapability{font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
8699
|
+
.ccp-analysisScenarioDetails{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}
|
|
8700
|
+
.ccp-analysisScenarioDetails .ccp-analysisFactValue{max-width:75%}
|
|
8701
|
+
.ccp-analysisEmpty{font-size:14px;color:var(--dsw-alias-label-secondary);text-align:center;padding:32px 16px;margin:0;border:1px dashed var(--dsw-alias-border-l2);border-radius:8px}
|
|
8702
|
+
.ccp-analysisRules{margin-top:22px;border-top:1px solid var(--dsw-alias-border-l2)}
|
|
8703
|
+
.ccp-analysisRules .ccp-analysisDisclosure{padding:14px 0}
|
|
8704
|
+
.ccp-analysisRulesBody{color:var(--dsw-alias-label-secondary);font-size:14px;padding-bottom:4px}
|
|
8705
|
+
.ccp-analysisRulesBody p{margin:0 0 12px}
|
|
8706
|
+
@media (max-width:860px){
|
|
8707
|
+
.ccp-analysisOverview .ccp-analysisMetric{padding:0 16px}
|
|
8708
|
+
.ccp-analysisOverview .ccp-analysisValue{font-size:22px}
|
|
8709
|
+
.ccp-analysisModelSummary{grid-template-columns:repeat(4,minmax(0,1fr)) 16px;gap:12px 16px}
|
|
8710
|
+
.ccp-analysisScenarioSummary{grid-template-columns:repeat(3,minmax(0,1fr)) 16px;gap:12px 16px}
|
|
8711
|
+
.ccp-analysisModelSummary > .ccp-analysisIdentity,.ccp-analysisScenarioSummary > .ccp-analysisIdentity{grid-column:1/-2}
|
|
8712
|
+
.ccp-analysisModelSummary > .ccp-analysisChevron{grid-column:5;grid-row:1}
|
|
8713
|
+
.ccp-analysisScenarioSummary > .ccp-analysisChevron{grid-column:4;grid-row:1}
|
|
8714
|
+
.ccp-analysisDetails{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
8715
|
+
}
|
|
8716
|
+
@media (max-width:640px){
|
|
8717
|
+
.ccp-mainInnerAnalysis{padding:20px 16px 32px}
|
|
8718
|
+
.ccp-analysisFilters{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
|
|
8719
|
+
.ccp-analysisFilters .ccp-analysisField{min-width:0}
|
|
8720
|
+
.ccp-analysisApply{grid-column:1/-1}
|
|
8721
|
+
.ccp-analysisOverview{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 0;padding:20px 0}
|
|
8722
|
+
.ccp-analysisOverview .ccp-analysisMetric{padding:0 12px}
|
|
8723
|
+
.ccp-analysisOverview .ccp-analysisMetric:nth-child(odd){border-left:0;padding-left:0}
|
|
8724
|
+
.ccp-analysisOverview .ccp-analysisValue{font-size:22px}
|
|
8725
|
+
.ccp-analysisModelSummary,.ccp-analysisScenarioSummary{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;padding:16px}
|
|
8726
|
+
.ccp-analysisModelSummary > .ccp-analysisIdentity,.ccp-analysisScenarioSummary > .ccp-analysisIdentity{grid-column:1/-1;padding-right:24px}
|
|
8727
|
+
.ccp-analysisModelSummary > .ccp-analysisChevron,.ccp-analysisScenarioSummary > .ccp-analysisChevron{position:absolute;top:19px;right:16px;grid-column:auto;grid-row:auto}
|
|
8728
|
+
.ccp-analysisDetails{gap:20px;grid-template-columns:1fr}
|
|
8729
|
+
.ccp-analysisFactValue{max-width:65%}
|
|
8730
|
+
.ccp-analysisSearch{max-width:none}
|
|
8731
|
+
}
|
|
7717
8732
|
`;
|
|
8733
|
+
//#endregion
|
|
8734
|
+
//#region src/client/analytics.ts
|
|
8735
|
+
/** 手动读取历史,旧宿主可降级;查询切换和卸载后不接受过期结果。 */
|
|
8736
|
+
var AnalyticsController = class {
|
|
8737
|
+
remote;
|
|
8738
|
+
current = { status: "idle" };
|
|
8739
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8740
|
+
generation = 0;
|
|
8741
|
+
disposed = false;
|
|
8742
|
+
query = {
|
|
8743
|
+
mode: "recent",
|
|
8744
|
+
limit: 20
|
|
8745
|
+
};
|
|
8746
|
+
constructor(remote) {
|
|
8747
|
+
this.remote = remote;
|
|
8748
|
+
}
|
|
8749
|
+
state() {
|
|
8750
|
+
return this.current;
|
|
8751
|
+
}
|
|
8752
|
+
subscribe(listener) {
|
|
8753
|
+
this.listeners.add(listener);
|
|
8754
|
+
return () => {
|
|
8755
|
+
this.listeners.delete(listener);
|
|
8756
|
+
};
|
|
8757
|
+
}
|
|
8758
|
+
dispose() {
|
|
8759
|
+
this.disposed = true;
|
|
8760
|
+
this.generation++;
|
|
8761
|
+
this.listeners.clear();
|
|
8762
|
+
}
|
|
8763
|
+
reload() {
|
|
8764
|
+
this.generation++;
|
|
8765
|
+
this.set({ status: "idle" });
|
|
8766
|
+
}
|
|
8767
|
+
refresh(query = this.query) {
|
|
8768
|
+
if (this.disposed) return;
|
|
8769
|
+
const requested = parseAnalyticsQuery(query);
|
|
8770
|
+
this.query = requested;
|
|
8771
|
+
const generation = ++this.generation;
|
|
8772
|
+
this.set({ status: "loading" });
|
|
8773
|
+
const call = this.remote.analytics;
|
|
8774
|
+
if (!call) {
|
|
8775
|
+
this.set({
|
|
8776
|
+
status: "error",
|
|
8777
|
+
error: "宿主不支持模型分析,请更新插件"
|
|
8778
|
+
});
|
|
8779
|
+
return;
|
|
8780
|
+
}
|
|
8781
|
+
Promise.resolve().then(() => call(requested)).then((result) => {
|
|
8782
|
+
if (this.disposed || generation !== this.generation) return;
|
|
8783
|
+
if (!result.ok) {
|
|
8784
|
+
this.set({
|
|
8785
|
+
status: "error",
|
|
8786
|
+
error: result.error.message === "宿主不支持模型分析,请更新插件" ? result.error.message : "模型分析读取失败,请稍后刷新或检查宿主日志"
|
|
8787
|
+
});
|
|
8788
|
+
return;
|
|
8789
|
+
}
|
|
8790
|
+
this.set({
|
|
8791
|
+
status: "ready",
|
|
8792
|
+
report: parseAnalyticsReport(result.value)
|
|
8793
|
+
});
|
|
8794
|
+
}).catch(() => {
|
|
8795
|
+
if (!this.disposed && generation === this.generation) this.set({
|
|
8796
|
+
status: "error",
|
|
8797
|
+
error: "模型分析读取失败,请稍后刷新或检查宿主日志"
|
|
8798
|
+
});
|
|
8799
|
+
});
|
|
8800
|
+
}
|
|
8801
|
+
set(state) {
|
|
8802
|
+
this.current = state;
|
|
8803
|
+
for (const listener of this.listeners) listener();
|
|
8804
|
+
}
|
|
8805
|
+
};
|
|
7718
8806
|
//#endregion
|
|
7719
8807
|
//#region src/client/index.ts
|
|
7720
8808
|
/** Install one stylesheet by id and return a disposer for its owning effect. */
|
|
@@ -7808,12 +8896,14 @@ window.__ModuleLoader__.load({
|
|
|
7808
8896
|
let usageMountError;
|
|
7809
8897
|
let pricesController;
|
|
7810
8898
|
let refreshUsage;
|
|
8899
|
+
let analyticsController;
|
|
7811
8900
|
const contribution = {
|
|
7812
8901
|
package: USAGE_REMOTE_CONTRIBUTION.package,
|
|
7813
8902
|
descriptors: [
|
|
7814
8903
|
...USAGE_REMOTE_CONTRIBUTION.descriptors,
|
|
7815
8904
|
...MODELS_REMOTE_CONTRIBUTION.descriptors,
|
|
7816
8905
|
...PRICES_REMOTE_CONTRIBUTION.descriptors,
|
|
8906
|
+
...ANALYTICS_REMOTE_CONTRIBUTION.descriptors,
|
|
7817
8907
|
...LOGIN_REMOTE_CONTRIBUTION.descriptors,
|
|
7818
8908
|
...ENROLLMENT_REMOTE_CONTRIBUTION.descriptors
|
|
7819
8909
|
]
|
|
@@ -7831,9 +8921,11 @@ window.__ModuleLoader__.load({
|
|
|
7831
8921
|
usageNamespace = namespaceCtx.remote.commandcode;
|
|
7832
8922
|
controller.refreshCatalog();
|
|
7833
8923
|
pricesController?.reload();
|
|
8924
|
+
analyticsController?.reload();
|
|
7834
8925
|
refreshUsage?.();
|
|
7835
8926
|
namespaceCtx.effect(() => () => {
|
|
7836
8927
|
usageNamespace = void 0;
|
|
8928
|
+
analyticsController?.reload();
|
|
7837
8929
|
}, "dsh-commandcode-provider: usage namespace");
|
|
7838
8930
|
});
|
|
7839
8931
|
}, (error) => {
|
|
@@ -7889,6 +8981,22 @@ window.__ModuleLoader__.load({
|
|
|
7889
8981
|
ctx.effect(() => () => pricesController?.dispose(), "dsh-commandcode-provider: price table");
|
|
7890
8982
|
const pricesStore = createSnapshotStore(pricesController.state());
|
|
7891
8983
|
pricesController.subscribe(() => pricesStore.set(pricesController.state()));
|
|
8984
|
+
analyticsController = new AnalyticsController({ analytics: async (query) => {
|
|
8985
|
+
const namespace = usageNamespace;
|
|
8986
|
+
if (typeof namespace?.analytics !== "function") return {
|
|
8987
|
+
ok: false,
|
|
8988
|
+
error: { message: "宿主不支持模型分析,请更新插件" }
|
|
8989
|
+
};
|
|
8990
|
+
return namespace.analytics(query);
|
|
8991
|
+
} });
|
|
8992
|
+
const analyticsStore = createSnapshotStore(analyticsController.state());
|
|
8993
|
+
analyticsController.subscribe(() => analyticsStore.set(analyticsController.state()));
|
|
8994
|
+
ctx.effect(() => () => analyticsController?.dispose(), "commandcode analytics controller");
|
|
8995
|
+
const panelMode = createSnapshotStore("quota");
|
|
8996
|
+
const openAnalytics = () => {
|
|
8997
|
+
panelMode.set("analysis");
|
|
8998
|
+
ctx.get("layout")?.selectPanel(PANEL_ID);
|
|
8999
|
+
};
|
|
7892
9000
|
const loginRemote = {
|
|
7893
9001
|
loginBegin: async (targetRef) => {
|
|
7894
9002
|
if (usageNamespace === void 0) return {
|
|
@@ -7952,6 +9060,7 @@ window.__ModuleLoader__.load({
|
|
|
7952
9060
|
discard: () => controller.discard(),
|
|
7953
9061
|
refreshCredentials: () => void controller.refreshCredentials(),
|
|
7954
9062
|
refreshUsage: () => void usageController.refresh(),
|
|
9063
|
+
...typeof ctx.get("layout")?.selectPanel === "function" ? { openAnalytics } : {},
|
|
7955
9064
|
beginLogin: (targetRef) => void loginController.begin(targetRef),
|
|
7956
9065
|
cancelLogin: () => void loginController.cancel(),
|
|
7957
9066
|
renameAccount: (ref, label) => controller.renameAccount(ref, label),
|
|
@@ -7997,14 +9106,19 @@ window.__ModuleLoader__.load({
|
|
|
7997
9106
|
const panelFace = () => ({
|
|
7998
9107
|
hooks: {
|
|
7999
9108
|
commandCodeUsage: usageStore,
|
|
8000
|
-
commandCodeSettings: store
|
|
9109
|
+
commandCodeSettings: store,
|
|
9110
|
+
commandCodeAnalytics: analyticsStore,
|
|
9111
|
+
commandCodePanelMode: panelMode
|
|
8001
9112
|
},
|
|
9113
|
+
selectPanelMode: (mode) => panelMode.set(mode),
|
|
9114
|
+
refreshAnalytics: (query) => analyticsController?.refresh(query),
|
|
8002
9115
|
refresh: () => {
|
|
8003
9116
|
pricesController?.ensure();
|
|
8004
9117
|
usageController.refresh();
|
|
8005
9118
|
},
|
|
8006
9119
|
startAutoRefresh: () => startPanelAutoRefresh(usageController, () => true),
|
|
8007
9120
|
open: () => {
|
|
9121
|
+
panelMode.set("quota");
|
|
8008
9122
|
ctx.get("layout")?.selectPanel(PANEL_ID);
|
|
8009
9123
|
},
|
|
8010
9124
|
close: () => {
|