@mars-sea/dsh-commandcode-provider 0.12.10 → 0.13.1
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 +28 -0
- package/README.md +10 -10
- package/README.zh-CN.md +5 -4
- package/lib/client.js +1354 -86
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +81 -8
- package/lib/index.js +690 -110
- package/lib/index.js.map +1 -1
- package/package.json +37 -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.1";
|
|
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,215 @@ 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
|
+
analysisIntro: "查看历史用量,比较模型成本与响应表现。",
|
|
5585
|
+
analysisModel: "模型",
|
|
5586
|
+
analysisCostShare: "已知成本 / 占比",
|
|
5587
|
+
analysisNoShare: "无占比",
|
|
5588
|
+
analysisShareHint: "占全部已知成本小计",
|
|
5589
|
+
analysisSimulationHeading: "相同工作量价格试算",
|
|
5590
|
+
analysisSimulationHint: "计价覆盖不同的金额不能直接比较。",
|
|
5591
|
+
analysisSimulationCost: "试算成本",
|
|
5592
|
+
analysisCoverage: "计价覆盖",
|
|
5593
|
+
analysisUsd: "美元",
|
|
5594
|
+
analysisTokenUnit: "词元",
|
|
5595
|
+
analysisCost: "已知成本 · 美元",
|
|
5596
|
+
analysisRequests: "模型请求",
|
|
5597
|
+
analysisSessionCount: "会话数",
|
|
5598
|
+
analysisResponse: "平均响应",
|
|
5599
|
+
analysisFirstToken: "平均首词元",
|
|
5600
|
+
analysisSpeed: "输出速度",
|
|
5601
|
+
analysisSeconds: "秒",
|
|
5602
|
+
analysisSpeedUnit: "词元/秒",
|
|
5603
|
+
analysisPriced: "计价请求",
|
|
5604
|
+
analysisTimed: "响应样本",
|
|
5605
|
+
analysisFirstTokenSamples: "首词元样本",
|
|
5606
|
+
analysisDecodeSamples: "解码样本",
|
|
5607
|
+
analysisUsageSamples: "用量样本",
|
|
5608
|
+
analysisAverage: "每会话均摊",
|
|
5609
|
+
analysisMissing: "无数据",
|
|
5610
|
+
analysisDetails: "查看汇总明细",
|
|
5611
|
+
analysisTokens: "词元与缓存",
|
|
5612
|
+
analysisInput: "未缓存输入",
|
|
5613
|
+
analysisOutput: "输出",
|
|
5614
|
+
analysisCacheRead: "缓存读取",
|
|
5615
|
+
analysisCacheWrite: "缓存写入",
|
|
5616
|
+
analysisOutcome: "请求状态",
|
|
5617
|
+
analysisCompleted: "完成",
|
|
5618
|
+
analysisFailed: "失败",
|
|
5619
|
+
analysisRetries: "宿主重试",
|
|
5620
|
+
analysisCancelled: "取消",
|
|
5621
|
+
analysisUnknown: "未知状态",
|
|
5622
|
+
analysisSamples: "统计样本",
|
|
5623
|
+
analysisSessionCost: "会话与成本",
|
|
5624
|
+
analysisMonthly: "按该时间段折算 30 天",
|
|
5625
|
+
analysisMonthlyHint: "仅完整、全部计价且跨度至少一天的日期范围提供折算。",
|
|
5626
|
+
analysisRules: "统计口径与试算说明",
|
|
5627
|
+
analysisShortBasis: "按当前价格估算,非历史账单。缺失用量与耗时不会补零。",
|
|
5628
|
+
analysisBasis: "按当前价格快照重算;不是历史账单,不含订阅费和充值,词元用量不等于账号积分。仅有请求数量、没有任务边界;不计算任务质量或智能评分。旧记录缺失的用量和耗时不会补零。",
|
|
5629
|
+
analysisAssumption: "沿用原请求的词元与时段,对比不同模型的价格。换模型后的生成长度、缓存命中、重试和质量可能变化;不会调用模型或自动推荐。",
|
|
5630
|
+
analysisContext: "上下文词元",
|
|
5631
|
+
analysisCapabilities: "模型能力",
|
|
5632
|
+
analysisEfforts: "推理力度",
|
|
5633
|
+
analysisExcluded: "超出上下文",
|
|
5634
|
+
analysisUnknownPrice: "未知用量或价格",
|
|
5635
|
+
analysisSearch: "筛选试算模型",
|
|
5636
|
+
analysisSearchPlaceholder: "输入模型名称或标识",
|
|
5637
|
+
analysisNoMatches: "没有匹配的模型,请调整筛选条件。",
|
|
5638
|
+
analysisImages: "支持图片",
|
|
5639
|
+
analysisTextOnly: "仅文本",
|
|
5640
|
+
analysisNoEfforts: "未提供推理力度",
|
|
5641
|
+
analysisCoverageHint: "耗时从步骤或重试开始计至模型结算;包含前置处理,不含后续工具执行。首词元包含推理与工具参数。速度按有解码计时的输出词元总量计算。试算未校验图片及工具兼容性,也不代表账号已获授权。",
|
|
5642
|
+
effortNone: "关闭 (none)",
|
|
5643
|
+
effortLow: "低 (low)",
|
|
5644
|
+
effortMedium: "中 (medium)",
|
|
5645
|
+
effortHigh: "高 (high)",
|
|
5646
|
+
effortXhigh: "极高 (xhigh)",
|
|
5647
|
+
effortMax: "最高 (max)"
|
|
5648
|
+
};
|
|
5649
|
+
/** 按项目约定,错误、缺失与读取状态在各语言环境中统一为中文。 */
|
|
5650
|
+
const ANALYTICS_COPY_EN = {
|
|
5651
|
+
analyticsNav: "Model analysis",
|
|
5652
|
+
quotaNav: "Account quota",
|
|
5653
|
+
analysisRecent: "Recent sessions",
|
|
5654
|
+
analysisRange: "Date range",
|
|
5655
|
+
analysisLimit: "Session count",
|
|
5656
|
+
analysisFrom: "Start date",
|
|
5657
|
+
analysisTo: "End date",
|
|
5658
|
+
analysisApply: "Read statistics",
|
|
5659
|
+
analysisLoading: ANALYTICS_COPY_ZH.analysisLoading,
|
|
5660
|
+
analysisUnavailable: ANALYTICS_COPY_ZH.analysisUnavailable,
|
|
5661
|
+
analysisEmpty: ANALYTICS_COPY_ZH.analysisEmpty,
|
|
5662
|
+
analysisInvalid: ANALYTICS_COPY_ZH.analysisInvalid,
|
|
5663
|
+
analysisScope: "Scope",
|
|
5664
|
+
analysisScanned: "Sessions read",
|
|
5665
|
+
analysisMatched: "Sessions with requests",
|
|
5666
|
+
analysisUnreadable: "Read failures",
|
|
5667
|
+
analysisSkipped: "Skipped",
|
|
5668
|
+
analysisPartial: ANALYTICS_COPY_ZH.analysisPartial,
|
|
5669
|
+
analysisCatalog: ANALYTICS_COPY_ZH.analysisCatalog,
|
|
5670
|
+
analysisUnpriced: ANALYTICS_COPY_ZH.analysisUnpriced,
|
|
5671
|
+
analysisOverview: "Usage overview",
|
|
5672
|
+
analysisSections: "Analysis sections",
|
|
5673
|
+
analysisHistory: "Recorded usage",
|
|
5674
|
+
analysisSimulation: "Price simulation",
|
|
5675
|
+
analysisByModel: "Model usage comparison",
|
|
5676
|
+
analysisModelHint: "Bars show each share of the known cost subtotal; expand for details.",
|
|
5677
|
+
analysisIntro: "Review recorded usage and compare model cost and response times.",
|
|
5678
|
+
analysisModel: "Model",
|
|
5679
|
+
analysisCostShare: "Known cost / share",
|
|
5680
|
+
analysisNoShare: ANALYTICS_COPY_ZH.analysisNoShare,
|
|
5681
|
+
analysisShareHint: "Share of the known cost subtotal",
|
|
5682
|
+
analysisSimulationHeading: "Price simulation for the same workload",
|
|
5683
|
+
analysisSimulationHint: "Amounts with different priced coverage are not directly comparable.",
|
|
5684
|
+
analysisSimulationCost: "Simulated cost",
|
|
5685
|
+
analysisCoverage: "Priced coverage",
|
|
5686
|
+
analysisUsd: "USD",
|
|
5687
|
+
analysisTokenUnit: "tokens",
|
|
5688
|
+
analysisCost: "Known cost · USD",
|
|
5689
|
+
analysisRequests: "Model requests",
|
|
5690
|
+
analysisSessionCount: "Sessions",
|
|
5691
|
+
analysisResponse: "Mean response",
|
|
5692
|
+
analysisFirstToken: "Mean first token",
|
|
5693
|
+
analysisSpeed: "Output speed",
|
|
5694
|
+
analysisSeconds: "s",
|
|
5695
|
+
analysisSpeedUnit: "tokens/s",
|
|
5696
|
+
analysisPriced: "Priced requests",
|
|
5697
|
+
analysisTimed: "Response samples",
|
|
5698
|
+
analysisFirstTokenSamples: "First-token samples",
|
|
5699
|
+
analysisDecodeSamples: "Decode samples",
|
|
5700
|
+
analysisUsageSamples: "Usage samples",
|
|
5701
|
+
analysisAverage: "Per session",
|
|
5702
|
+
analysisMissing: ANALYTICS_COPY_ZH.analysisMissing,
|
|
5703
|
+
analysisDetails: "View aggregate details",
|
|
5704
|
+
analysisTokens: "Tokens and cache",
|
|
5705
|
+
analysisInput: "Uncached input",
|
|
5706
|
+
analysisOutput: "Output",
|
|
5707
|
+
analysisCacheRead: "Cache read",
|
|
5708
|
+
analysisCacheWrite: "Cache write",
|
|
5709
|
+
analysisOutcome: "Request outcomes",
|
|
5710
|
+
analysisCompleted: "Completed",
|
|
5711
|
+
analysisFailed: "Failed",
|
|
5712
|
+
analysisRetries: "Host retries",
|
|
5713
|
+
analysisCancelled: "Cancelled",
|
|
5714
|
+
analysisUnknown: "Unknown outcome",
|
|
5715
|
+
analysisSamples: "Samples",
|
|
5716
|
+
analysisSessionCost: "Sessions and cost",
|
|
5717
|
+
analysisMonthly: "30-day extrapolation from this range",
|
|
5718
|
+
analysisMonthlyHint: "Requires a complete, fully priced date range spanning at least one day.",
|
|
5719
|
+
analysisRules: "Statistics and simulation notes",
|
|
5720
|
+
analysisShortBasis: "Estimated at current prices, not an invoice. Missing usage and timing stay unknown.",
|
|
5721
|
+
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.",
|
|
5722
|
+
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.",
|
|
5723
|
+
analysisContext: "Context tokens",
|
|
5724
|
+
analysisCapabilities: "Model capabilities",
|
|
5725
|
+
analysisEfforts: "Reasoning efforts",
|
|
5726
|
+
analysisExcluded: "Over context limit",
|
|
5727
|
+
analysisUnknownPrice: "Unknown usage or price",
|
|
5728
|
+
analysisSearch: "Filter simulation models",
|
|
5729
|
+
analysisSearchPlaceholder: "Model name or ID",
|
|
5730
|
+
analysisNoMatches: ANALYTICS_COPY_ZH.analysisNoMatches,
|
|
5731
|
+
analysisImages: "Images supported",
|
|
5732
|
+
analysisTextOnly: "Text only",
|
|
5733
|
+
analysisNoEfforts: "No reasoning efforts listed",
|
|
5734
|
+
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.",
|
|
5735
|
+
effortNone: "None",
|
|
5736
|
+
effortLow: "Low",
|
|
5737
|
+
effortMedium: "Medium",
|
|
5738
|
+
effortHigh: "High",
|
|
5739
|
+
effortXhigh: "Extra high",
|
|
5740
|
+
effortMax: "Max"
|
|
5741
|
+
};
|
|
5742
|
+
//#endregion
|
|
5547
5743
|
//#region src/client/panel-copy.ts
|
|
5744
|
+
/**
|
|
5745
|
+
* Bilingual copy for the Command Code **plans & quota panel** (the sidebar
|
|
5746
|
+
* footer card and the center-column dashboard it opens).
|
|
5747
|
+
*
|
|
5748
|
+
* The panel follows the harness's active language: `PANEL_LOCALE_NS` is a
|
|
5749
|
+
* registered locale namespace (`ctx.locale.register`), both panel slot
|
|
5750
|
+
* registrations declare it, and the renderer hands the component a `t` seat
|
|
5751
|
+
* whose identity changes on a language switch (so a memoized panel re-renders).
|
|
5752
|
+
* {@link buildPanelView} takes that translator as an input and builds every
|
|
5753
|
+
* string through it, so the projection stays React-free and testable and no
|
|
5754
|
+
* component carries copy of its own. The settings page keeps its own
|
|
5755
|
+
* `settings.commandcode` namespace (see `./locales.ts`); the two never mix.
|
|
5756
|
+
*
|
|
5757
|
+
* @module dsh-commandcode-provider/client/panel-copy
|
|
5758
|
+
*/
|
|
5548
5759
|
/** The locale namespace both panel slots bind their `t` seat to. */
|
|
5549
5760
|
const PANEL_LOCALE_NS = "panel.commandcode";
|
|
5550
5761
|
/** The panel's Simplified Chinese string table (the key-set source of truth). */
|
|
5551
5762
|
const PANEL_COPY_ZH = {
|
|
5763
|
+
...ANALYTICS_COPY_ZH,
|
|
5552
5764
|
nav: "Command Code",
|
|
5553
5765
|
subtitle: "套餐、额度与配额窗口",
|
|
5554
5766
|
refresh: "刷新",
|
|
@@ -5598,11 +5810,12 @@ window.__ModuleLoader__.load({
|
|
|
5598
5810
|
errorNetwork: "无法连接 Command Code 服务",
|
|
5599
5811
|
errorNetworkHint: "所有请求都没有到达服务端。请检查网络连接或 API 地址设置。",
|
|
5600
5812
|
errorInvalidResponse: "Command Code 响应无法读取",
|
|
5601
|
-
errorInvalidResponseHint: "
|
|
5813
|
+
errorInvalidResponseHint: "已收到响应,但正文读取或解析失败。下方详情可区分读取超时、中断与格式异常;可先点击刷新重试。",
|
|
5602
5814
|
errorGeneric: "用量获取失败"
|
|
5603
5815
|
};
|
|
5604
5816
|
/** The panel's English string table (must mirror {@link PANEL_COPY_ZH}). */
|
|
5605
5817
|
const PANEL_COPY_EN = {
|
|
5818
|
+
...ANALYTICS_COPY_EN,
|
|
5606
5819
|
nav: "Command Code",
|
|
5607
5820
|
subtitle: "Plans, credits and quota windows",
|
|
5608
5821
|
refresh: "Refresh",
|
|
@@ -5652,7 +5865,7 @@ window.__ModuleLoader__.load({
|
|
|
5652
5865
|
errorNetwork: "Could not reach the Command Code service",
|
|
5653
5866
|
errorNetworkHint: "No request reached the server. Check your network connection or the API base setting.",
|
|
5654
5867
|
errorInvalidResponse: "Could not read the Command Code response",
|
|
5655
|
-
errorInvalidResponseHint: "
|
|
5868
|
+
errorInvalidResponseHint: "Responses arrived, but reading or parsing their bodies failed. Details below distinguish timeouts, interrupted reads, and invalid formats. Try Refresh again.",
|
|
5656
5869
|
errorGeneric: "Could not fetch account usage"
|
|
5657
5870
|
};
|
|
5658
5871
|
/** Every panel key, in the English table's declaration order. */
|
|
@@ -5668,7 +5881,7 @@ window.__ModuleLoader__.load({
|
|
|
5668
5881
|
//#endregion
|
|
5669
5882
|
//#region src/client/panel.ts
|
|
5670
5883
|
/** `$1.23`, and `$0.0123` only when the amount is too small for cents to show it. */
|
|
5671
|
-
function money(value) {
|
|
5884
|
+
function money$1(value) {
|
|
5672
5885
|
if (value === 0) return formatMoney(0);
|
|
5673
5886
|
return Math.abs(value) < .01 ? formatMoneyExact(value) : formatMoney(value);
|
|
5674
5887
|
}
|
|
@@ -5711,7 +5924,7 @@ window.__ModuleLoader__.load({
|
|
|
5711
5924
|
const capped = limit.cap > 0;
|
|
5712
5925
|
return {
|
|
5713
5926
|
label,
|
|
5714
|
-
value: capped ? `${money(limit.used)} / ${money(limit.cap)}` : money(limit.used),
|
|
5927
|
+
value: capped ? `${money$1(limit.used)} / ${money$1(limit.cap)}` : money$1(limit.used),
|
|
5715
5928
|
capped,
|
|
5716
5929
|
percent,
|
|
5717
5930
|
barPercent: barPercent(percent),
|
|
@@ -5747,11 +5960,11 @@ window.__ModuleLoader__.load({
|
|
|
5747
5960
|
const percent = known ? rawPercent(used, limitValue) : 0;
|
|
5748
5961
|
return {
|
|
5749
5962
|
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,
|
|
5963
|
+
limit: limitValue !== null ? money$1(limitValue) : UNREPORTED,
|
|
5964
|
+
used: known ? money$1(used) : UNREPORTED,
|
|
5965
|
+
remaining: remainingReported ? money$1(remaining) : UNREPORTED,
|
|
5966
|
+
purchased: credits !== void 0 && credits.purchasedReported !== false ? money$1(Math.max(0, credits.purchasedCredits)) : UNREPORTED,
|
|
5967
|
+
free: credits !== void 0 && credits.freeReported !== false ? money$1(Math.max(0, credits.freeCredits)) : UNREPORTED,
|
|
5755
5968
|
percent,
|
|
5756
5969
|
barPercent: barPercent(percent),
|
|
5757
5970
|
exhausted: known && remaining <= 0,
|
|
@@ -5881,11 +6094,11 @@ window.__ModuleLoader__.load({
|
|
|
5881
6094
|
percent: `${percent}%`,
|
|
5882
6095
|
barPercent: barPercent(percent),
|
|
5883
6096
|
warn: window.exceeded,
|
|
5884
|
-
detail: `${money(window.used)} / ${money(window.cap)}`
|
|
6097
|
+
detail: `${money$1(window.used)} / ${money$1(window.cap)}`
|
|
5885
6098
|
});
|
|
5886
6099
|
}
|
|
5887
6100
|
const totalCost = selectedEntry?.report.usage?.totalCost;
|
|
5888
|
-
const cost = totalCost === void 0 ? "" : money(totalCost);
|
|
6101
|
+
const cost = totalCost === void 0 ? "" : money$1(totalCost);
|
|
5889
6102
|
let status = "";
|
|
5890
6103
|
if (entries.length > 0 && !entries.some((entry) => entry.configured)) status = t("unconfigured");
|
|
5891
6104
|
else if (selectedView?.mark !== void 0 && selectedView.mark !== "active") status = t(selectedView.mark);
|
|
@@ -5975,6 +6188,795 @@ window.__ModuleLoader__.load({
|
|
|
5975
6188
|
};
|
|
5976
6189
|
}
|
|
5977
6190
|
//#endregion
|
|
6191
|
+
//#region src/analytics-wire.ts
|
|
6192
|
+
const g = makeBoundaryValidator("commandcode/analytics");
|
|
6193
|
+
const nonnegative = (s, k) => {
|
|
6194
|
+
const n = g.numberField(s, k, k);
|
|
6195
|
+
return n >= 0 ? n : g.reject(k);
|
|
6196
|
+
};
|
|
6197
|
+
const count$1 = (s, k) => {
|
|
6198
|
+
const n = nonnegative(s, k);
|
|
6199
|
+
return Number.isSafeInteger(n) ? n : g.reject(k);
|
|
6200
|
+
};
|
|
6201
|
+
function parseAnalyticsQuery(value) {
|
|
6202
|
+
const s = g.record(value, "query");
|
|
6203
|
+
if (s.mode === "recent") {
|
|
6204
|
+
const limit = count$1(s, "limit");
|
|
6205
|
+
if (limit < 1 || limit > 100) return g.reject("limit");
|
|
6206
|
+
return {
|
|
6207
|
+
mode: "recent",
|
|
6208
|
+
limit
|
|
6209
|
+
};
|
|
6210
|
+
}
|
|
6211
|
+
if (s.mode !== "range") return g.reject("mode");
|
|
6212
|
+
const from = count$1(s, "from"), to = count$1(s, "to");
|
|
6213
|
+
if (to <= from || to - from > 316224e5 || to > 864e13) return g.reject("range");
|
|
6214
|
+
return {
|
|
6215
|
+
mode: "range",
|
|
6216
|
+
from,
|
|
6217
|
+
to
|
|
6218
|
+
};
|
|
6219
|
+
}
|
|
6220
|
+
const counts = [
|
|
6221
|
+
"sessions",
|
|
6222
|
+
"requests",
|
|
6223
|
+
"completed",
|
|
6224
|
+
"failed",
|
|
6225
|
+
"cancelled",
|
|
6226
|
+
"unknown",
|
|
6227
|
+
"retries",
|
|
6228
|
+
"usageSamples",
|
|
6229
|
+
"pricedRequests",
|
|
6230
|
+
"latencySamples",
|
|
6231
|
+
"ttftSamples",
|
|
6232
|
+
"decodeSamples"
|
|
6233
|
+
];
|
|
6234
|
+
const quantities = [
|
|
6235
|
+
"cost",
|
|
6236
|
+
"latencyMs",
|
|
6237
|
+
"ttftMs",
|
|
6238
|
+
"decodeMs",
|
|
6239
|
+
"decodeTokens"
|
|
6240
|
+
];
|
|
6241
|
+
const tokenKeys = [
|
|
6242
|
+
"uncachedInputTokens",
|
|
6243
|
+
"outputTokens",
|
|
6244
|
+
"cacheReadTokens",
|
|
6245
|
+
"cacheWriteTokens"
|
|
6246
|
+
];
|
|
6247
|
+
function metrics(value) {
|
|
6248
|
+
const s = g.record(value, "metrics"), result = {};
|
|
6249
|
+
for (const k of counts) result[k] = count$1(s, k);
|
|
6250
|
+
for (const k of quantities) result[k] = nonnegative(s, k);
|
|
6251
|
+
const tokens = g.record(s.tokens, "tokens");
|
|
6252
|
+
result.tokens = Object.fromEntries(tokenKeys.map((k) => [k, nonnegative(tokens, k)]));
|
|
6253
|
+
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");
|
|
6254
|
+
return result;
|
|
6255
|
+
}
|
|
6256
|
+
const nullable = (s, k) => s[k] === null ? null : nonnegative(s, k);
|
|
6257
|
+
function parseAnalyticsReport(value) {
|
|
6258
|
+
const s = g.record(value, "report");
|
|
6259
|
+
if (s.status !== "ready" && s.status !== "unavailable") return g.reject("status");
|
|
6260
|
+
if (!Array.isArray(s.models) || !Array.isArray(s.scenarios) || s.models.length > 1e3 || s.scenarios.length > 1e3) return g.reject("models");
|
|
6261
|
+
return {
|
|
6262
|
+
generatedAt: count$1(s, "generatedAt"),
|
|
6263
|
+
pricingKey: count$1(s, "pricingKey"),
|
|
6264
|
+
query: parseAnalyticsQuery(s.query),
|
|
6265
|
+
status: s.status,
|
|
6266
|
+
scannedSessions: count$1(s, "scannedSessions"),
|
|
6267
|
+
matchedSessions: count$1(s, "matchedSessions"),
|
|
6268
|
+
unreadableSessions: count$1(s, "unreadableSessions"),
|
|
6269
|
+
skippedSessions: count$1(s, "skippedSessions"),
|
|
6270
|
+
truncated: g.booleanField(s, "truncated", "truncated"),
|
|
6271
|
+
catalogUnavailable: g.booleanField(s, "catalogUnavailable", "catalogUnavailable"),
|
|
6272
|
+
totals: metrics(s.totals),
|
|
6273
|
+
monthlyEstimate: nullable(s, "monthlyEstimate"),
|
|
6274
|
+
models: s.models.map((value) => {
|
|
6275
|
+
const m = g.record(value, "model");
|
|
6276
|
+
return {
|
|
6277
|
+
...metrics(m),
|
|
6278
|
+
id: g.stringField(m, "id", "id")
|
|
6279
|
+
};
|
|
6280
|
+
}),
|
|
6281
|
+
scenarios: s.scenarios.map((value) => {
|
|
6282
|
+
const m = g.record(value, "scenario");
|
|
6283
|
+
if (!Array.isArray(m.efforts) || !m.efforts.every((v) => typeof v === "string")) return g.reject("efforts");
|
|
6284
|
+
return {
|
|
6285
|
+
id: g.stringField(m, "id", "id"),
|
|
6286
|
+
name: g.stringField(m, "name", "name"),
|
|
6287
|
+
contextWindow: nullable(m, "contextWindow"),
|
|
6288
|
+
images: g.booleanField(m, "images", "images"),
|
|
6289
|
+
efforts: m.efforts,
|
|
6290
|
+
cost: nonnegative(m, "cost"),
|
|
6291
|
+
pricedRequests: count$1(m, "pricedRequests"),
|
|
6292
|
+
excludedRequests: count$1(m, "excludedRequests"),
|
|
6293
|
+
unknownRequests: count$1(m, "unknownRequests")
|
|
6294
|
+
};
|
|
6295
|
+
})
|
|
6296
|
+
};
|
|
6297
|
+
}
|
|
6298
|
+
const ANALYTICS_REMOTE_CONTRIBUTION = {
|
|
6299
|
+
package: REMOTE_PACKAGE,
|
|
6300
|
+
descriptors: [{
|
|
6301
|
+
...makeRemoteDescriptor("commandcode/analytics", "analytics", `${REMOTE_PACKAGE}#AnalyticsReport`, { parse: parseAnalyticsReport }),
|
|
6302
|
+
parameters: [{
|
|
6303
|
+
name: "query",
|
|
6304
|
+
wire: "query",
|
|
6305
|
+
source: "json",
|
|
6306
|
+
codec: makeStrictCodec(`${REMOTE_PACKAGE}#AnalyticsQuery`, { parse: parseAnalyticsQuery })
|
|
6307
|
+
}]
|
|
6308
|
+
}]
|
|
6309
|
+
};
|
|
6310
|
+
//#endregion
|
|
6311
|
+
//#region src/client/analytics-view.tsx
|
|
6312
|
+
/** 只展示数字快照;筛选提交后才查询,页签、展开与模型筛选不触发历史读取。 */
|
|
6313
|
+
function localDate(time) {
|
|
6314
|
+
const d = new Date(time);
|
|
6315
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
6316
|
+
}
|
|
6317
|
+
/** 日期按用户本地日历展开为半开区间;截止日包括当日全部时间,夏令时不固定加 24 小时。 */
|
|
6318
|
+
function dateRange(from, to) {
|
|
6319
|
+
const start = /* @__PURE__ */ new Date(`${from}T00:00:00`), end = /* @__PURE__ */ new Date(`${to}T00:00:00`);
|
|
6320
|
+
if (localDate(start.getTime()) !== from || localDate(end.getTime()) !== to) throw new TypeError("无效日期");
|
|
6321
|
+
end.setDate(end.getDate() + 1);
|
|
6322
|
+
return parseAnalyticsQuery({
|
|
6323
|
+
mode: "range",
|
|
6324
|
+
from: start.getTime(),
|
|
6325
|
+
to: end.getTime()
|
|
6326
|
+
});
|
|
6327
|
+
}
|
|
6328
|
+
const money = (n) => `$${n.toFixed(4)}`;
|
|
6329
|
+
const digits = (n) => n.toLocaleString();
|
|
6330
|
+
const meanSeconds = (ms, samples, text) => samples ? `${(ms / samples / 1e3).toFixed(2)} ${text("analysisSeconds")}` : text("analysisMissing");
|
|
6331
|
+
const speed = (m, text) => m.decodeSamples && m.decodeMs ? `${(m.decodeTokens * 1e3 / m.decodeMs).toFixed(1)} ${text("analysisSpeedUnit")}` : text("analysisMissing");
|
|
6332
|
+
function effortName(effort, text) {
|
|
6333
|
+
const keys = {
|
|
6334
|
+
none: "effortNone",
|
|
6335
|
+
low: "effortLow",
|
|
6336
|
+
medium: "effortMedium",
|
|
6337
|
+
high: "effortHigh",
|
|
6338
|
+
xhigh: "effortXhigh",
|
|
6339
|
+
max: "effortMax"
|
|
6340
|
+
};
|
|
6341
|
+
return keys[effort] ? text(keys[effort]) : effort;
|
|
6342
|
+
}
|
|
6343
|
+
function Chevron() {
|
|
6344
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
6345
|
+
className: "ccp-analysisChevron",
|
|
6346
|
+
width: "16",
|
|
6347
|
+
height: "16",
|
|
6348
|
+
viewBox: "0 0 24 24",
|
|
6349
|
+
fill: "none",
|
|
6350
|
+
stroke: "currentColor",
|
|
6351
|
+
strokeWidth: "1.6",
|
|
6352
|
+
strokeLinecap: "round",
|
|
6353
|
+
strokeLinejoin: "round",
|
|
6354
|
+
"aria-hidden": "true",
|
|
6355
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m9 5 7 7-7 7" })
|
|
6356
|
+
});
|
|
6357
|
+
}
|
|
6358
|
+
function AnalysisIcon({ kind }) {
|
|
6359
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
6360
|
+
className: "ccp-analysisIcon",
|
|
6361
|
+
width: "16",
|
|
6362
|
+
height: "16",
|
|
6363
|
+
viewBox: "0 0 24 24",
|
|
6364
|
+
fill: "none",
|
|
6365
|
+
stroke: "currentColor",
|
|
6366
|
+
strokeWidth: "1.6",
|
|
6367
|
+
strokeLinecap: "round",
|
|
6368
|
+
strokeLinejoin: "round",
|
|
6369
|
+
"aria-hidden": "true",
|
|
6370
|
+
children: kind === "info" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
6371
|
+
cx: "12",
|
|
6372
|
+
cy: "12",
|
|
6373
|
+
r: "9"
|
|
6374
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 11v6M12 7h.01" })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
6375
|
+
cx: "10.5",
|
|
6376
|
+
cy: "10.5",
|
|
6377
|
+
r: "6.5"
|
|
6378
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m16 16 4.5 4.5" })] })
|
|
6379
|
+
});
|
|
6380
|
+
}
|
|
6381
|
+
function Metric({ label, value, sub, children }) {
|
|
6382
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6383
|
+
className: "ccp-analysisMetric",
|
|
6384
|
+
children: [
|
|
6385
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6386
|
+
className: "ccp-analysisLabel ccp-analysisMetricLabel",
|
|
6387
|
+
children: label
|
|
6388
|
+
}),
|
|
6389
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6390
|
+
className: "ccp-analysisValue",
|
|
6391
|
+
children: value
|
|
6392
|
+
}),
|
|
6393
|
+
sub ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6394
|
+
className: "ccp-analysisSub",
|
|
6395
|
+
children: sub
|
|
6396
|
+
}) : null,
|
|
6397
|
+
children
|
|
6398
|
+
]
|
|
6399
|
+
});
|
|
6400
|
+
}
|
|
6401
|
+
/** 只比较已知成本;没有计价样本或已知小计为零时,不制造百分比。 */
|
|
6402
|
+
function knownCostShare(m, totalCost) {
|
|
6403
|
+
return m.pricedRequests > 0 && totalCost > 0 ? m.cost / totalCost * 100 : null;
|
|
6404
|
+
}
|
|
6405
|
+
function CostShare({ m, totalCost, text }) {
|
|
6406
|
+
const share = knownCostShare(m, totalCost);
|
|
6407
|
+
if (share === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6408
|
+
className: "ccp-analysisSub",
|
|
6409
|
+
children: text("analysisNoShare")
|
|
6410
|
+
});
|
|
6411
|
+
const percentage = `${share.toFixed(1)}%`;
|
|
6412
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6413
|
+
className: "ccp-analysisShare",
|
|
6414
|
+
title: `${text("analysisShareHint")} ${percentage}`,
|
|
6415
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6416
|
+
className: "ccp-analysisShareTrack",
|
|
6417
|
+
"aria-hidden": "true",
|
|
6418
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6419
|
+
className: "ccp-analysisShareFill",
|
|
6420
|
+
style: { width: `${Math.min(100, Math.max(0, share))}%` }
|
|
6421
|
+
})
|
|
6422
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6423
|
+
className: "ccp-analysisShareValue",
|
|
6424
|
+
children: percentage
|
|
6425
|
+
})]
|
|
6426
|
+
});
|
|
6427
|
+
}
|
|
6428
|
+
function DetailGroup({ title, values, text }) {
|
|
6429
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6430
|
+
className: "ccp-analysisDetailGroup",
|
|
6431
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
6432
|
+
className: "ccp-analysisDetailTitle",
|
|
6433
|
+
children: text(title)
|
|
6434
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dl", {
|
|
6435
|
+
className: "ccp-analysisFacts",
|
|
6436
|
+
children: values.map(([key, value]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6437
|
+
className: "ccp-analysisFact",
|
|
6438
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
6439
|
+
className: "ccp-analysisLabel",
|
|
6440
|
+
children: text(key)
|
|
6441
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
6442
|
+
className: "ccp-analysisFactValue",
|
|
6443
|
+
children: value
|
|
6444
|
+
})]
|
|
6445
|
+
}, key))
|
|
6446
|
+
})]
|
|
6447
|
+
});
|
|
6448
|
+
}
|
|
6449
|
+
/** 样本为零时词元仍为未知;汇总和单模型复用相同口径,展开只改变展示。 */
|
|
6450
|
+
function MetricsDetails({ m, text }) {
|
|
6451
|
+
const tokens = m.tokens, tokenValue = (n) => m.usageSamples ? digits(n) : text("analysisMissing");
|
|
6452
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6453
|
+
className: "ccp-analysisDetails",
|
|
6454
|
+
children: [
|
|
6455
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6456
|
+
title: "analysisTokens",
|
|
6457
|
+
text,
|
|
6458
|
+
values: [
|
|
6459
|
+
["analysisInput", tokenValue(tokens.uncachedInputTokens)],
|
|
6460
|
+
["analysisOutput", tokenValue(tokens.outputTokens)],
|
|
6461
|
+
["analysisCacheRead", tokenValue(tokens.cacheReadTokens)],
|
|
6462
|
+
["analysisCacheWrite", tokenValue(tokens.cacheWriteTokens)]
|
|
6463
|
+
]
|
|
6464
|
+
}),
|
|
6465
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6466
|
+
title: "analysisOutcome",
|
|
6467
|
+
text,
|
|
6468
|
+
values: [
|
|
6469
|
+
["analysisCompleted", digits(m.completed)],
|
|
6470
|
+
["analysisFailed", digits(m.failed)],
|
|
6471
|
+
["analysisRetries", digits(m.retries)],
|
|
6472
|
+
["analysisCancelled", digits(m.cancelled)],
|
|
6473
|
+
["analysisUnknown", digits(m.unknown)]
|
|
6474
|
+
]
|
|
6475
|
+
}),
|
|
6476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6477
|
+
title: "analysisSamples",
|
|
6478
|
+
text,
|
|
6479
|
+
values: [
|
|
6480
|
+
["analysisUsageSamples", digits(m.usageSamples)],
|
|
6481
|
+
["analysisPriced", digits(m.pricedRequests)],
|
|
6482
|
+
["analysisTimed", digits(m.latencySamples)],
|
|
6483
|
+
["analysisFirstTokenSamples", digits(m.ttftSamples)],
|
|
6484
|
+
["analysisDecodeSamples", digits(m.decodeSamples)]
|
|
6485
|
+
]
|
|
6486
|
+
}),
|
|
6487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6488
|
+
title: "analysisSessionCost",
|
|
6489
|
+
text,
|
|
6490
|
+
values: [
|
|
6491
|
+
["analysisSessionCount", digits(m.sessions)],
|
|
6492
|
+
["analysisRequests", digits(m.requests)],
|
|
6493
|
+
["analysisAverage", m.sessions && m.pricedRequests ? money(m.cost / m.sessions) : text("analysisMissing")],
|
|
6494
|
+
["analysisSpeed", speed(m, text)]
|
|
6495
|
+
]
|
|
6496
|
+
})
|
|
6497
|
+
]
|
|
6498
|
+
});
|
|
6499
|
+
}
|
|
6500
|
+
function ModelRow({ m, name, totalCost, text }) {
|
|
6501
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6502
|
+
className: "ccp-analysisModelRow",
|
|
6503
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6504
|
+
className: "ccp-analysisModelSummary",
|
|
6505
|
+
children: [
|
|
6506
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6507
|
+
className: "ccp-analysisIdentity",
|
|
6508
|
+
children: [
|
|
6509
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6510
|
+
className: "ccp-analysisModelName",
|
|
6511
|
+
children: name || m.id
|
|
6512
|
+
}),
|
|
6513
|
+
name && name !== m.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6514
|
+
className: "ccp-analysisSub",
|
|
6515
|
+
children: m.id
|
|
6516
|
+
}) : null,
|
|
6517
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6518
|
+
className: "ccp-analysisSub ccp-analysisModelCount",
|
|
6519
|
+
children: [
|
|
6520
|
+
text("analysisRequests"),
|
|
6521
|
+
" ",
|
|
6522
|
+
digits(m.requests),
|
|
6523
|
+
" · ",
|
|
6524
|
+
text("analysisSessionCount"),
|
|
6525
|
+
" ",
|
|
6526
|
+
digits(m.sessions)
|
|
6527
|
+
]
|
|
6528
|
+
})
|
|
6529
|
+
]
|
|
6530
|
+
}),
|
|
6531
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6532
|
+
label: text("analysisCostShare"),
|
|
6533
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6534
|
+
sub: `${text("analysisPriced")} ${m.pricedRequests}/${m.requests}`,
|
|
6535
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CostShare, {
|
|
6536
|
+
m,
|
|
6537
|
+
totalCost,
|
|
6538
|
+
text
|
|
6539
|
+
})
|
|
6540
|
+
}),
|
|
6541
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6542
|
+
label: text("analysisResponse"),
|
|
6543
|
+
value: meanSeconds(m.latencyMs, m.latencySamples, text)
|
|
6544
|
+
}),
|
|
6545
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6546
|
+
label: text("analysisFirstToken"),
|
|
6547
|
+
value: meanSeconds(m.ttftMs, m.ttftSamples, text)
|
|
6548
|
+
}),
|
|
6549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6550
|
+
label: text("analysisSpeed"),
|
|
6551
|
+
value: speed(m, text)
|
|
6552
|
+
}),
|
|
6553
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})
|
|
6554
|
+
]
|
|
6555
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MetricsDetails, {
|
|
6556
|
+
m,
|
|
6557
|
+
text
|
|
6558
|
+
})]
|
|
6559
|
+
});
|
|
6560
|
+
}
|
|
6561
|
+
function ScenarioRow({ m, text }) {
|
|
6562
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6563
|
+
className: "ccp-analysisModelRow",
|
|
6564
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6565
|
+
className: "ccp-analysisScenarioSummary",
|
|
6566
|
+
children: [
|
|
6567
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6568
|
+
className: "ccp-analysisIdentity",
|
|
6569
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6570
|
+
className: "ccp-analysisModelName",
|
|
6571
|
+
children: m.name
|
|
6572
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6573
|
+
className: "ccp-analysisSub",
|
|
6574
|
+
children: m.id
|
|
6575
|
+
})]
|
|
6576
|
+
}),
|
|
6577
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6578
|
+
label: text("analysisSimulationCost"),
|
|
6579
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6580
|
+
sub: text("analysisUsd")
|
|
6581
|
+
}),
|
|
6582
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6583
|
+
label: text("analysisCoverage"),
|
|
6584
|
+
value: `${m.pricedRequests}/${m.pricedRequests + m.excludedRequests + m.unknownRequests}`,
|
|
6585
|
+
sub: `${text("analysisExcluded")} ${digits(m.excludedRequests)} · ${text("analysisUnknownPrice")} ${digits(m.unknownRequests)}`
|
|
6586
|
+
}),
|
|
6587
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6588
|
+
label: text("analysisCapabilities"),
|
|
6589
|
+
value: m.contextWindow === null ? text("analysisMissing") : `${digits(m.contextWindow)} ${text("analysisTokenUnit")}`,
|
|
6590
|
+
sub: text(m.images ? "analysisImages" : "analysisTextOnly")
|
|
6591
|
+
}),
|
|
6592
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})
|
|
6593
|
+
]
|
|
6594
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6595
|
+
className: "ccp-analysisDetails ccp-analysisScenarioDetails",
|
|
6596
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6597
|
+
title: "analysisSamples",
|
|
6598
|
+
text,
|
|
6599
|
+
values: [
|
|
6600
|
+
["analysisPriced", digits(m.pricedRequests)],
|
|
6601
|
+
["analysisExcluded", digits(m.excludedRequests)],
|
|
6602
|
+
["analysisUnknownPrice", digits(m.unknownRequests)]
|
|
6603
|
+
]
|
|
6604
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailGroup, {
|
|
6605
|
+
title: "analysisCapabilities",
|
|
6606
|
+
text,
|
|
6607
|
+
values: [["analysisEfforts", m.efforts.length ? m.efforts.map((e) => effortName(e, text)).join(", ") : text("analysisNoEfforts")]]
|
|
6608
|
+
})]
|
|
6609
|
+
})]
|
|
6610
|
+
});
|
|
6611
|
+
}
|
|
6612
|
+
function AnalyticsView(props) {
|
|
6613
|
+
const { text } = props, state = props.useCommandCodeAnalytics((s) => s), report = state.report;
|
|
6614
|
+
const [mode, setMode] = (0, react.useState)(report?.query.mode ?? "recent");
|
|
6615
|
+
const [limit, setLimit] = (0, react.useState)(report?.query.mode === "recent" ? String(report.query.limit) : "20");
|
|
6616
|
+
const [from, setFrom] = (0, react.useState)(localDate(report?.query.mode === "range" ? report.query.from : Date.now() - 25056e5));
|
|
6617
|
+
const [to, setTo] = (0, react.useState)(localDate(report?.query.mode === "range" ? report.query.to - 1 : Date.now()));
|
|
6618
|
+
const [invalid, setInvalid] = (0, react.useState)(false), [filter, setFilter] = (0, react.useState)("");
|
|
6619
|
+
const [page, setPage] = (0, react.useState)("history"), id = (0, react.useId)();
|
|
6620
|
+
const refresh = props.refreshAnalytics;
|
|
6621
|
+
(0, react.useEffect)(() => {
|
|
6622
|
+
if (state.status === "idle") refresh();
|
|
6623
|
+
}, [state.status, refresh]);
|
|
6624
|
+
const busy = state.status === "loading";
|
|
6625
|
+
const apply = () => {
|
|
6626
|
+
try {
|
|
6627
|
+
const query = mode === "recent" ? parseAnalyticsQuery({
|
|
6628
|
+
mode,
|
|
6629
|
+
limit: Number(limit)
|
|
6630
|
+
}) : dateRange(from, to);
|
|
6631
|
+
setInvalid(false);
|
|
6632
|
+
refresh(query);
|
|
6633
|
+
} catch {
|
|
6634
|
+
setInvalid(true);
|
|
6635
|
+
}
|
|
6636
|
+
};
|
|
6637
|
+
const navigateTab = (event) => {
|
|
6638
|
+
if (![
|
|
6639
|
+
"ArrowLeft",
|
|
6640
|
+
"ArrowRight",
|
|
6641
|
+
"Home",
|
|
6642
|
+
"End"
|
|
6643
|
+
].includes(event.key)) return;
|
|
6644
|
+
event.preventDefault();
|
|
6645
|
+
const next = event.key === "Home" ? "history" : event.key === "End" ? "simulation" : page === "history" ? "simulation" : "history";
|
|
6646
|
+
setPage(next);
|
|
6647
|
+
event.currentTarget.querySelector(`[data-page="${next}"]`)?.focus();
|
|
6648
|
+
};
|
|
6649
|
+
const scenarios = report?.scenarios.filter((m) => `${m.id} ${m.name}`.toLowerCase().includes(filter.trim().toLowerCase())) ?? [];
|
|
6650
|
+
const names = new Map(report?.scenarios.map((m) => [m.id, m.name]));
|
|
6651
|
+
const m = report?.totals;
|
|
6652
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6653
|
+
className: "ccp-analysis",
|
|
6654
|
+
"aria-label": text("analyticsNav"),
|
|
6655
|
+
"aria-busy": busy,
|
|
6656
|
+
children: [
|
|
6657
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
6658
|
+
className: "ccp-analysisFilters",
|
|
6659
|
+
"data-mode": mode,
|
|
6660
|
+
noValidate: true,
|
|
6661
|
+
onSubmit: (e) => {
|
|
6662
|
+
e.preventDefault();
|
|
6663
|
+
if (!busy) apply();
|
|
6664
|
+
},
|
|
6665
|
+
children: [
|
|
6666
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6667
|
+
className: "ccp-analysisField ccp-analysisScopeField",
|
|
6668
|
+
children: [text("analysisScope"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6669
|
+
className: "ccp-analysisSelectShell",
|
|
6670
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
6671
|
+
className: "ccp-analysisInput ccp-analysisSelect",
|
|
6672
|
+
value: mode,
|
|
6673
|
+
disabled: busy,
|
|
6674
|
+
onChange: (e) => setMode(e.target.value),
|
|
6675
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6676
|
+
value: "recent",
|
|
6677
|
+
children: text("analysisRecent")
|
|
6678
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6679
|
+
value: "range",
|
|
6680
|
+
children: text("analysisRange")
|
|
6681
|
+
})]
|
|
6682
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {})]
|
|
6683
|
+
})]
|
|
6684
|
+
}),
|
|
6685
|
+
mode === "recent" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6686
|
+
className: "ccp-analysisField",
|
|
6687
|
+
children: [text("analysisLimit"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6688
|
+
className: "ccp-analysisInput",
|
|
6689
|
+
type: "number",
|
|
6690
|
+
min: "1",
|
|
6691
|
+
max: "100",
|
|
6692
|
+
required: true,
|
|
6693
|
+
value: limit,
|
|
6694
|
+
disabled: busy,
|
|
6695
|
+
onChange: (e) => setLimit(e.target.value)
|
|
6696
|
+
})]
|
|
6697
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6698
|
+
className: "ccp-analysisField ccp-analysisDateField",
|
|
6699
|
+
children: [text("analysisFrom"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6700
|
+
className: "ccp-analysisInput",
|
|
6701
|
+
type: "date",
|
|
6702
|
+
required: true,
|
|
6703
|
+
value: from,
|
|
6704
|
+
disabled: busy,
|
|
6705
|
+
onChange: (e) => setFrom(e.target.value)
|
|
6706
|
+
})]
|
|
6707
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6708
|
+
className: "ccp-analysisField ccp-analysisDateField",
|
|
6709
|
+
children: [text("analysisTo"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6710
|
+
className: "ccp-analysisInput",
|
|
6711
|
+
type: "date",
|
|
6712
|
+
required: true,
|
|
6713
|
+
value: to,
|
|
6714
|
+
disabled: busy,
|
|
6715
|
+
onChange: (e) => setTo(e.target.value)
|
|
6716
|
+
})]
|
|
6717
|
+
})] }),
|
|
6718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6719
|
+
className: "ccp-analysisApply",
|
|
6720
|
+
type: "submit",
|
|
6721
|
+
disabled: busy,
|
|
6722
|
+
children: text("analysisApply")
|
|
6723
|
+
})
|
|
6724
|
+
]
|
|
6725
|
+
}),
|
|
6726
|
+
invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6727
|
+
className: "ccp-analysisMessage ccp-analysisError",
|
|
6728
|
+
role: "alert",
|
|
6729
|
+
children: text("analysisInvalid")
|
|
6730
|
+
}) : null,
|
|
6731
|
+
busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6732
|
+
className: "ccp-analysisMessage",
|
|
6733
|
+
role: "status",
|
|
6734
|
+
children: text("analysisLoading")
|
|
6735
|
+
}) : null,
|
|
6736
|
+
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6737
|
+
className: "ccp-analysisMessage ccp-analysisError",
|
|
6738
|
+
role: "alert",
|
|
6739
|
+
children: state.error
|
|
6740
|
+
}) : null,
|
|
6741
|
+
report?.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6742
|
+
className: "ccp-analysisMessage",
|
|
6743
|
+
role: "status",
|
|
6744
|
+
children: text("analysisUnavailable")
|
|
6745
|
+
}) : null,
|
|
6746
|
+
report?.status === "ready" && m ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6747
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6748
|
+
className: "ccp-analysisScope",
|
|
6749
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
6750
|
+
text("analysisScope"),
|
|
6751
|
+
": ",
|
|
6752
|
+
report.query.mode === "recent" ? `${text("analysisRecent")} ${report.query.limit}` : `${localDate(report.query.from)} — ${localDate(report.query.to - 1)}`
|
|
6753
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
6754
|
+
text("analysisScanned"),
|
|
6755
|
+
" ",
|
|
6756
|
+
report.scannedSessions,
|
|
6757
|
+
" · ",
|
|
6758
|
+
text("analysisMatched"),
|
|
6759
|
+
" ",
|
|
6760
|
+
report.matchedSessions,
|
|
6761
|
+
" · ",
|
|
6762
|
+
text("analysisUnreadable"),
|
|
6763
|
+
" ",
|
|
6764
|
+
report.unreadableSessions,
|
|
6765
|
+
" · ",
|
|
6766
|
+
text("analysisSkipped"),
|
|
6767
|
+
" ",
|
|
6768
|
+
report.skippedSessions
|
|
6769
|
+
] })]
|
|
6770
|
+
}),
|
|
6771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6772
|
+
className: "ccp-analysisOverview",
|
|
6773
|
+
role: "group",
|
|
6774
|
+
"aria-label": text("analysisOverview"),
|
|
6775
|
+
children: [
|
|
6776
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6777
|
+
label: text("analysisCost"),
|
|
6778
|
+
value: m.pricedRequests ? money(m.cost) : text("analysisMissing"),
|
|
6779
|
+
sub: `${text("analysisPriced")} ${m.pricedRequests}/${m.requests}`
|
|
6780
|
+
}),
|
|
6781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6782
|
+
label: text("analysisRequests"),
|
|
6783
|
+
value: digits(m.requests),
|
|
6784
|
+
sub: `${text("analysisSessionCount")} ${digits(m.sessions)}`
|
|
6785
|
+
}),
|
|
6786
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6787
|
+
label: text("analysisResponse"),
|
|
6788
|
+
value: meanSeconds(m.latencyMs, m.latencySamples, text),
|
|
6789
|
+
sub: `${text("analysisTimed")} ${digits(m.latencySamples)}`
|
|
6790
|
+
}),
|
|
6791
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Metric, {
|
|
6792
|
+
label: text("analysisFirstToken"),
|
|
6793
|
+
value: meanSeconds(m.ttftMs, m.ttftSamples, text),
|
|
6794
|
+
sub: `${text("analysisFirstTokenSamples")} ${digits(m.ttftSamples)}`
|
|
6795
|
+
})
|
|
6796
|
+
]
|
|
6797
|
+
}),
|
|
6798
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6799
|
+
className: "ccp-analysisNote",
|
|
6800
|
+
children: text("analysisShortBasis")
|
|
6801
|
+
}),
|
|
6802
|
+
report.truncated || report.unreadableSessions > 0 || report.skippedSessions > 0 || m.pricedRequests < m.requests ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6803
|
+
className: "ccp-analysisMessage ccp-analysisWarning",
|
|
6804
|
+
role: "status",
|
|
6805
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnalysisIcon, { kind: "info" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [report.truncated || report.unreadableSessions > 0 || report.skippedSessions > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisPartial") }) : null, m.pricedRequests < m.requests ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisUnpriced") }) : null] })]
|
|
6806
|
+
}) : null,
|
|
6807
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6808
|
+
className: "ccp-analysisTabs",
|
|
6809
|
+
role: "tablist",
|
|
6810
|
+
"aria-label": text("analysisSections"),
|
|
6811
|
+
onKeyDown: navigateTab,
|
|
6812
|
+
children: ["history", "simulation"].map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
6813
|
+
className: "ccp-analysisTab",
|
|
6814
|
+
id: `${id}-${tab}-tab`,
|
|
6815
|
+
"data-page": tab,
|
|
6816
|
+
type: "button",
|
|
6817
|
+
role: "tab",
|
|
6818
|
+
"aria-selected": page === tab,
|
|
6819
|
+
"aria-controls": `${id}-${tab}`,
|
|
6820
|
+
tabIndex: page === tab ? 0 : -1,
|
|
6821
|
+
onClick: () => setPage(tab),
|
|
6822
|
+
children: [text(tab === "history" ? "analysisHistory" : "analysisSimulation"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6823
|
+
className: "ccp-analysisTabCount",
|
|
6824
|
+
children: digits(tab === "history" ? report.models.length : report.scenarios.length)
|
|
6825
|
+
})]
|
|
6826
|
+
}, tab))
|
|
6827
|
+
}),
|
|
6828
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6829
|
+
className: "ccp-analysisPanel",
|
|
6830
|
+
id: `${id}-history`,
|
|
6831
|
+
role: "tabpanel",
|
|
6832
|
+
"aria-labelledby": `${id}-history-tab`,
|
|
6833
|
+
tabIndex: 0,
|
|
6834
|
+
hidden: page !== "history",
|
|
6835
|
+
children: [
|
|
6836
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6837
|
+
className: "ccp-analysisSectionHead",
|
|
6838
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
6839
|
+
className: "ccp-analysisHeading",
|
|
6840
|
+
children: text("analysisByModel")
|
|
6841
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6842
|
+
className: "ccp-analysisNote",
|
|
6843
|
+
children: text("analysisModelHint")
|
|
6844
|
+
})]
|
|
6845
|
+
}),
|
|
6846
|
+
m.requests === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6847
|
+
className: "ccp-analysisEmpty",
|
|
6848
|
+
children: text("analysisEmpty")
|
|
6849
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6850
|
+
className: "ccp-analysisModels",
|
|
6851
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6852
|
+
className: "ccp-analysisTableHead",
|
|
6853
|
+
"aria-hidden": "true",
|
|
6854
|
+
children: [
|
|
6855
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisModel") }),
|
|
6856
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisCostShare") }),
|
|
6857
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisResponse") }),
|
|
6858
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisFirstToken") }),
|
|
6859
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisSpeed") }),
|
|
6860
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})
|
|
6861
|
+
]
|
|
6862
|
+
}), report.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
|
|
6863
|
+
m: model,
|
|
6864
|
+
name: names.get(model.id),
|
|
6865
|
+
totalCost: m.cost,
|
|
6866
|
+
text
|
|
6867
|
+
}, model.id))]
|
|
6868
|
+
}),
|
|
6869
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6870
|
+
className: "ccp-analysisFooter",
|
|
6871
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6872
|
+
className: "ccp-analysisAggregate",
|
|
6873
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6874
|
+
className: "ccp-analysisDisclosure",
|
|
6875
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {}), text("analysisDetails")]
|
|
6876
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MetricsDetails, {
|
|
6877
|
+
m,
|
|
6878
|
+
text
|
|
6879
|
+
})]
|
|
6880
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6881
|
+
className: "ccp-analysisMonthly",
|
|
6882
|
+
children: [
|
|
6883
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisMonthly") }),
|
|
6884
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
6885
|
+
className: "ccp-analysisMonthlyValue",
|
|
6886
|
+
children: report.monthlyEstimate === null || report.truncated || report.unreadableSessions || report.skippedSessions ? text("analysisMissing") : money(report.monthlyEstimate)
|
|
6887
|
+
}),
|
|
6888
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6889
|
+
className: "ccp-analysisNote",
|
|
6890
|
+
children: text("analysisMonthlyHint")
|
|
6891
|
+
})
|
|
6892
|
+
]
|
|
6893
|
+
})]
|
|
6894
|
+
})
|
|
6895
|
+
]
|
|
6896
|
+
}),
|
|
6897
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6898
|
+
className: "ccp-analysisPanel",
|
|
6899
|
+
id: `${id}-simulation`,
|
|
6900
|
+
role: "tabpanel",
|
|
6901
|
+
"aria-labelledby": `${id}-simulation-tab`,
|
|
6902
|
+
tabIndex: 0,
|
|
6903
|
+
hidden: page !== "simulation",
|
|
6904
|
+
children: [
|
|
6905
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6906
|
+
className: "ccp-analysisAssumption",
|
|
6907
|
+
children: text("analysisAssumption")
|
|
6908
|
+
}),
|
|
6909
|
+
report.catalogUnavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6910
|
+
className: "ccp-analysisMessage ccp-analysisWarning",
|
|
6911
|
+
role: "status",
|
|
6912
|
+
children: text("analysisCatalog")
|
|
6913
|
+
}) : null,
|
|
6914
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6915
|
+
className: "ccp-analysisSectionHead",
|
|
6916
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
6917
|
+
className: "ccp-analysisHeading",
|
|
6918
|
+
children: text("analysisSimulationHeading")
|
|
6919
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6920
|
+
className: "ccp-analysisNote",
|
|
6921
|
+
children: text("analysisSimulationHint")
|
|
6922
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6923
|
+
className: "ccp-analysisField ccp-analysisSearch",
|
|
6924
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6925
|
+
className: "ccp-analysisSearchLabel",
|
|
6926
|
+
children: text("analysisSearch")
|
|
6927
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6928
|
+
className: "ccp-analysisSearchShell",
|
|
6929
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnalysisIcon, { kind: "search" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6930
|
+
className: "ccp-analysisInput",
|
|
6931
|
+
type: "search",
|
|
6932
|
+
placeholder: text("analysisSearchPlaceholder"),
|
|
6933
|
+
value: filter,
|
|
6934
|
+
onChange: (e) => setFilter(e.target.value)
|
|
6935
|
+
})]
|
|
6936
|
+
})]
|
|
6937
|
+
})]
|
|
6938
|
+
}),
|
|
6939
|
+
m.requests === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6940
|
+
className: "ccp-analysisEmpty",
|
|
6941
|
+
children: text("analysisEmpty")
|
|
6942
|
+
}) : scenarios.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6943
|
+
className: "ccp-analysisModels",
|
|
6944
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6945
|
+
className: "ccp-analysisTableHead ccp-analysisScenarioHead",
|
|
6946
|
+
"aria-hidden": "true",
|
|
6947
|
+
children: [
|
|
6948
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisModel") }),
|
|
6949
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisSimulationCost") }),
|
|
6950
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisCoverage") }),
|
|
6951
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text("analysisCapabilities") }),
|
|
6952
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})
|
|
6953
|
+
]
|
|
6954
|
+
}), scenarios.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScenarioRow, {
|
|
6955
|
+
m: model,
|
|
6956
|
+
text
|
|
6957
|
+
}, model.id))]
|
|
6958
|
+
}) : !report.catalogUnavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6959
|
+
className: "ccp-analysisEmpty",
|
|
6960
|
+
role: "status",
|
|
6961
|
+
children: text("analysisNoMatches")
|
|
6962
|
+
}) : null
|
|
6963
|
+
]
|
|
6964
|
+
}),
|
|
6965
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6966
|
+
className: "ccp-analysisRules",
|
|
6967
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
6968
|
+
className: "ccp-analysisDisclosure",
|
|
6969
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, {}), text("analysisRules")]
|
|
6970
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6971
|
+
className: "ccp-analysisRulesBody",
|
|
6972
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisBasis") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text("analysisCoverageHint") })]
|
|
6973
|
+
})]
|
|
6974
|
+
})
|
|
6975
|
+
] }) : null
|
|
6976
|
+
]
|
|
6977
|
+
});
|
|
6978
|
+
}
|
|
6979
|
+
//#endregion
|
|
5978
6980
|
//#region src/client/panel-view.tsx
|
|
5979
6981
|
/**
|
|
5980
6982
|
* React components for the Command Code plans & quota panel: the sidebar footer
|
|
@@ -6277,10 +7279,17 @@ window.__ModuleLoader__.load({
|
|
|
6277
7279
|
*/
|
|
6278
7280
|
function CommandCodePanel(props) {
|
|
6279
7281
|
const view = usePanelView(props);
|
|
7282
|
+
const [fallbackMode, setFallbackMode] = (0, react.useState)("quota");
|
|
7283
|
+
const mode = props.useCommandCodePanelMode?.((s) => s) ?? fallbackMode;
|
|
7284
|
+
const analyticsBusy = props.useCommandCodeAnalytics?.((s) => s.status === "loading") ?? false;
|
|
7285
|
+
const selectMode = (next) => {
|
|
7286
|
+
setFallbackMode(next);
|
|
7287
|
+
props.selectPanelMode?.(next);
|
|
7288
|
+
};
|
|
6280
7289
|
const text = (key) => view.text[key] ?? key;
|
|
6281
7290
|
const [selectedId, setSelectedId] = (0, react.useState)(void 0);
|
|
6282
7291
|
const startAutoRefresh = props.startAutoRefresh;
|
|
6283
|
-
(0, react.useEffect)(() => startAutoRefresh(), [startAutoRefresh]);
|
|
7292
|
+
(0, react.useEffect)(() => mode === "quota" ? startAutoRefresh() : void 0, [startAutoRefresh, mode]);
|
|
6284
7293
|
const accounts = view.accounts;
|
|
6285
7294
|
const selected = accounts.find((account) => account.id === selectedId) ?? view.selected ?? accounts[0];
|
|
6286
7295
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6288,7 +7297,7 @@ window.__ModuleLoader__.load({
|
|
|
6288
7297
|
role: "region",
|
|
6289
7298
|
"aria-label": text("nav"),
|
|
6290
7299
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6291
|
-
className:
|
|
7300
|
+
className: `ccp-mainInner${mode === "analysis" ? " ccp-mainInnerAnalysis" : ""}`,
|
|
6292
7301
|
children: [
|
|
6293
7302
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
6294
7303
|
className: "ccp-header",
|
|
@@ -6297,14 +7306,14 @@ window.__ModuleLoader__.load({
|
|
|
6297
7306
|
className: "ccp-headerText",
|
|
6298
7307
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
6299
7308
|
className: "ccp-title",
|
|
6300
|
-
children: text("nav")
|
|
7309
|
+
children: mode === "analysis" ? `Command Code · ${text("analyticsNav")}` : text("nav")
|
|
6301
7310
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6302
7311
|
className: "ccp-subtitle",
|
|
6303
|
-
children: text("subtitle")
|
|
7312
|
+
children: text(mode === "quota" ? "subtitle" : "analysisIntro")
|
|
6304
7313
|
})]
|
|
6305
7314
|
}),
|
|
6306
7315
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "ccp-spacer" }),
|
|
6307
|
-
view.updatedAt !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7316
|
+
mode === "quota" && view.updatedAt !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6308
7317
|
className: "ccp-meta",
|
|
6309
7318
|
children: [
|
|
6310
7319
|
text("updated"),
|
|
@@ -6315,9 +7324,9 @@ window.__ModuleLoader__.load({
|
|
|
6315
7324
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6316
7325
|
variant: "ghost",
|
|
6317
7326
|
size: "sm",
|
|
6318
|
-
disabled: view.loading,
|
|
6319
|
-
onClick: () => props.refresh(),
|
|
6320
|
-
children: view.loading ? text("refreshing") : text("refresh")
|
|
7327
|
+
disabled: mode === "quota" ? view.loading : analyticsBusy,
|
|
7328
|
+
onClick: () => mode === "quota" ? props.refresh() : props.refreshAnalytics?.(),
|
|
7329
|
+
children: mode === "quota" && view.loading ? text("refreshing") : text("refresh")
|
|
6321
7330
|
}),
|
|
6322
7331
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6323
7332
|
variant: "ghost",
|
|
@@ -6326,75 +7335,108 @@ window.__ModuleLoader__.load({
|
|
|
6326
7335
|
"aria-label": text("close"),
|
|
6327
7336
|
title: text("closeHint"),
|
|
6328
7337
|
onClick: () => props.close(),
|
|
6329
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
7338
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
7339
|
+
width: "16",
|
|
7340
|
+
height: "16",
|
|
7341
|
+
viewBox: "0 0 24 24",
|
|
7342
|
+
fill: "none",
|
|
7343
|
+
stroke: "currentColor",
|
|
7344
|
+
strokeWidth: "1.6",
|
|
7345
|
+
strokeLinecap: "round",
|
|
6330
7346
|
"aria-hidden": "true",
|
|
6331
|
-
children: "
|
|
7347
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 6 12 12M18 6 6 18" })
|
|
6332
7348
|
})
|
|
6333
7349
|
})
|
|
6334
7350
|
]
|
|
6335
7351
|
}),
|
|
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", {
|
|
7352
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
6378
7353
|
className: "ccp-tabs",
|
|
6379
|
-
role: "tablist",
|
|
6380
7354
|
"aria-label": text("nav"),
|
|
6381
|
-
children:
|
|
7355
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7356
|
+
className: mode === "quota" ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
6382
7357
|
type: "button",
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
})
|
|
6394
|
-
|
|
7358
|
+
"aria-pressed": mode === "quota",
|
|
7359
|
+
onClick: () => selectMode("quota"),
|
|
7360
|
+
children: text("quotaNav")
|
|
7361
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7362
|
+
className: mode === "analysis" ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
7363
|
+
type: "button",
|
|
7364
|
+
"aria-pressed": mode === "analysis",
|
|
7365
|
+
onClick: () => selectMode("analysis"),
|
|
7366
|
+
children: text("analyticsNav")
|
|
7367
|
+
})]
|
|
7368
|
+
}),
|
|
7369
|
+
mode === "analysis" ? props.useCommandCodeAnalytics && props.refreshAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnalyticsView, {
|
|
7370
|
+
useCommandCodeAnalytics: props.useCommandCodeAnalytics,
|
|
7371
|
+
refreshAnalytics: props.refreshAnalytics,
|
|
7372
|
+
text
|
|
7373
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6395
7374
|
className: "ccp-hint",
|
|
6396
|
-
children: text(
|
|
6397
|
-
}) :
|
|
7375
|
+
children: text("analysisUnavailable")
|
|
7376
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7377
|
+
view.noKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7378
|
+
className: "ccp-notice",
|
|
7379
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7380
|
+
className: "ccp-noticeTitle",
|
|
7381
|
+
children: text("noKey")
|
|
7382
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7383
|
+
className: "ccp-noticeHint",
|
|
7384
|
+
children: text("noKeyHint")
|
|
7385
|
+
})]
|
|
7386
|
+
}) : null,
|
|
7387
|
+
view.failure !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7388
|
+
className: "ccp-notice ccp-noticeError",
|
|
7389
|
+
role: "alert",
|
|
7390
|
+
children: [
|
|
7391
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7392
|
+
className: "ccp-noticeTitle",
|
|
7393
|
+
children: text(view.failure.title)
|
|
7394
|
+
}),
|
|
7395
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7396
|
+
className: "ccp-noticeHint",
|
|
7397
|
+
children: text(view.failure.hint)
|
|
7398
|
+
}),
|
|
7399
|
+
view.failure.detail !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7400
|
+
className: "ccp-noticeDetail",
|
|
7401
|
+
children: view.failure.detail
|
|
7402
|
+
}) : null
|
|
7403
|
+
]
|
|
7404
|
+
}) : null,
|
|
7405
|
+
!view.noKey && view.failure === void 0 && accounts.length === 0 && view.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7406
|
+
className: "ccp-hint",
|
|
7407
|
+
children: text("loading")
|
|
7408
|
+
}) : null,
|
|
7409
|
+
view.staleError !== void 0 && view.staleError !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
7410
|
+
className: "ccp-hint",
|
|
7411
|
+
role: "status",
|
|
7412
|
+
children: [
|
|
7413
|
+
text("errorGeneric"),
|
|
7414
|
+
" — ",
|
|
7415
|
+
view.staleError
|
|
7416
|
+
]
|
|
7417
|
+
}) : null,
|
|
7418
|
+
accounts.length > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7419
|
+
className: "ccp-tabs",
|
|
7420
|
+
role: "tablist",
|
|
7421
|
+
"aria-label": text("nav"),
|
|
7422
|
+
children: accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7423
|
+
type: "button",
|
|
7424
|
+
role: "tab",
|
|
7425
|
+
"aria-selected": selected?.id === account.id,
|
|
7426
|
+
className: selected?.id === account.id ? "ccp-tab ccp-tabActive" : "ccp-tab",
|
|
7427
|
+
onClick: () => setSelectedId(account.id),
|
|
7428
|
+
children: account.label
|
|
7429
|
+
}, account.id))
|
|
7430
|
+
}) : null,
|
|
7431
|
+
selected !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountCard, {
|
|
7432
|
+
account: selected,
|
|
7433
|
+
view
|
|
7434
|
+
}) : null,
|
|
7435
|
+
view.partial !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7436
|
+
className: "ccp-hint",
|
|
7437
|
+
children: text(view.partial)
|
|
7438
|
+
}) : null
|
|
7439
|
+
] })
|
|
6398
7440
|
]
|
|
6399
7441
|
})
|
|
6400
7442
|
});
|
|
@@ -7657,10 +8699,8 @@ window.__ModuleLoader__.load({
|
|
|
7657
8699
|
.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
7658
8700
|
.ccp-spacer{flex:1}
|
|
7659
8701
|
.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. */
|
|
8702
|
+
/* 关闭图标沿用原语义与按钮尺寸,线性 SVG 随宿主文字颜色变化。 */
|
|
7662
8703
|
.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
8704
|
.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
7665
8705
|
|
|
7666
8706
|
.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 +8754,209 @@ window.__ModuleLoader__.load({
|
|
|
7714
8754
|
.ccp-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
7715
8755
|
|
|
7716
8756
|
@media (prefers-reduced-motion:reduce){.ccp-footFill,.ccp-barFill{transition:none}}
|
|
8757
|
+
/* 分析页继承设置页和宿主控件的语义变量;独立选择器不影响账号额度页面。 */
|
|
8758
|
+
.ccp-mainInnerAnalysis{max-width:1040px;box-sizing:border-box}
|
|
8759
|
+
/* 宿主侧栏会缩窄中心面板,按实际可用宽度切换列数,而不是仅看浏览器宽度。 */
|
|
8760
|
+
.ccp-analysis{font-size:14px;line-height:22px;min-width:0;color:var(--dsw-alias-label-primary);container-type:inline-size;container-name:ccp-analysis}
|
|
8761
|
+
.ccp-analysisFilters{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin:8px 0 20px}
|
|
8762
|
+
.ccp-analysisField{display:flex;flex-direction:column;gap:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);min-width:0}
|
|
8763
|
+
.ccp-analysisFilters .ccp-analysisField{flex:0 1 158px}
|
|
8764
|
+
.ccp-analysisFilters .ccp-analysisScopeField{flex-basis:184px}
|
|
8765
|
+
.ccp-analysisFilters .ccp-analysisDateField{flex-basis:166px}
|
|
8766
|
+
/* 对齐原生选择器、日期输入与按钮的边框盒;保留独立箭头留白和点击区域。 */
|
|
8767
|
+
.ccp-analysisInput{box-sizing:border-box;width:100%;min-width:0;height:36px;padding:0 11px;font:inherit;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:.5px solid var(--dsw-alias-border-l4);border-radius:8px}
|
|
8768
|
+
.ccp-analysisSelectShell{position:relative;display:block;width:100%;min-width:0}
|
|
8769
|
+
.ccp-analysisSelect{appearance:none;-webkit-appearance:none;padding-inline-end:40px;text-overflow:ellipsis;cursor:pointer;border:0;border-radius:18px;background:var(--dsw-alias-bg-module-platform)}
|
|
8770
|
+
.ccp-analysisSelectShell > .ccp-analysisChevron{position:absolute;inset-inline-end:12px;top:50%;transform:translateY(-50%) rotate(90deg);pointer-events:none}
|
|
8771
|
+
.ccp-analysisSelect:disabled + .ccp-analysisChevron{opacity:.6}
|
|
8772
|
+
.ccp-analysisInput::placeholder{color:var(--dsw-alias-label-tertiary)}
|
|
8773
|
+
.ccp-analysisApply{box-sizing:border-box;flex:none;height:36px;font:inherit;font-size:14px;line-height:22px;white-space:nowrap;padding:0 20px;border:0;border-radius:var(--dsw-radius-md,18px);background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);cursor:pointer;margin-left:2px}
|
|
8774
|
+
.ccp-analysisApply:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}
|
|
8775
|
+
.ccp-analysisApply:disabled{opacity:.4;cursor:wait}
|
|
8776
|
+
.ccp-analysisInput:disabled{opacity:.6}
|
|
8777
|
+
.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}
|
|
8778
|
+
/* 模型列表会裁切圆角,内收焦点框以保持第一行和最后一行也清晰可见。 */
|
|
8779
|
+
.ccp-analysisModelSummary:focus-visible,.ccp-analysisScenarioSummary:focus-visible{outline-offset:-3px;border-radius:6px}
|
|
8780
|
+
.ccp-analysisScope{display:flex;justify-content:space-between;gap:8px 18px;flex-wrap:wrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin-bottom:12px}
|
|
8781
|
+
.ccp-analysisScope > span:first-child{color:var(--dsw-alias-label-primary);font-weight:500}
|
|
8782
|
+
.ccp-analysisOverview{display:grid;grid-template-columns:1.45fr repeat(3,1fr);gap:20px;padding:16px 18px;background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;font-variant-numeric:tabular-nums}
|
|
8783
|
+
.ccp-analysisMetric{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
8784
|
+
.ccp-analysisLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);font-weight:400}
|
|
8785
|
+
.ccp-analysisValue{font-size:14px;line-height:22px;font-weight:500;overflow-wrap:anywhere}
|
|
8786
|
+
.ccp-analysisSub{display:block;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;font-weight:400;overflow-wrap:anywhere}
|
|
8787
|
+
.ccp-analysisOverview .ccp-analysisMetric{gap:5px}
|
|
8788
|
+
.ccp-analysisOverview .ccp-analysisValue{font-size:20px;line-height:28px;font-weight:500}
|
|
8789
|
+
.ccp-analysisNote{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);margin:9px 0 0}
|
|
8790
|
+
.ccp-analysisMessage{margin:12px 0 0;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:12px;background:var(--dsw-alias-bg-layer-3);font-size:14px;line-height:22px}
|
|
8791
|
+
.ccp-analysisWarning{display:flex;align-items:flex-start;gap:8px}
|
|
8792
|
+
.ccp-analysisIcon{flex:none}
|
|
8793
|
+
.ccp-analysisWarning > .ccp-analysisIcon{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary));margin-top:3px}
|
|
8794
|
+
.ccp-analysisWarning p{margin:0}
|
|
8795
|
+
.ccp-analysisWarning p + p{margin-top:5px}
|
|
8796
|
+
.ccp-analysisError{color:var(--dsw-alias-state-error-primary)}
|
|
8797
|
+
/* 沿用宿主分段控件的轨道、浮层与胶囊尺寸,保留原有页签键盘语义。 */
|
|
8798
|
+
.ccp-analysisTabs{box-sizing:border-box;display:inline-grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:2px;padding:4px;border:0;border-radius:var(--dsw-radius-md,18px);background:var(--dsw-alias-interactive-bg-hover);margin:22px 0 0;max-width:100%}
|
|
8799
|
+
.ccp-analysisTab{height:28px;padding:0 16px;border:0;border-radius:var(--dsw-radius-sm,14px);background:transparent;font:inherit;font-size:13px;line-height:20px;font-weight:500;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer}
|
|
8800
|
+
.ccp-analysisTab:hover,.ccp-analysisTab[aria-selected="true"]{color:var(--dsw-alias-label-primary)}
|
|
8801
|
+
.ccp-analysisTab[aria-selected="true"]{background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-soft)}
|
|
8802
|
+
.ccp-analysisTabCount{display:inline-flex;justify-content:center;min-width:16px;padding:0 4px;margin-left:6px;border-radius:999px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
8803
|
+
.ccp-analysisPanel{padding-top:20px;min-width:0}
|
|
8804
|
+
.ccp-analysisPanel[hidden]{display:none}
|
|
8805
|
+
.ccp-analysisSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px}
|
|
8806
|
+
.ccp-analysisHeading{font-size:14px;line-height:22px;font-weight:500;margin:0}
|
|
8807
|
+
.ccp-analysisSectionHead .ccp-analysisNote{margin:0;max-width:56ch}
|
|
8808
|
+
.ccp-analysisModels{border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;overflow:hidden}
|
|
8809
|
+
.ccp-analysisModelRow + .ccp-analysisModelRow{border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
8810
|
+
.ccp-analysisTableHead,.ccp-analysisModelSummary,.ccp-analysisScenarioSummary{position:relative;display:grid;grid-template-columns:minmax(190px,2.1fr) minmax(150px,1.45fr) minmax(90px,.9fr) minmax(90px,.9fr) minmax(100px,1fr) 16px;gap:18px;align-items:center;padding:16px 18px;font-variant-numeric:tabular-nums}
|
|
8811
|
+
.ccp-analysisTableHead{padding-top:11px;padding-bottom:11px;background:var(--dsw-alias-interactive-bg-hover);border-bottom:.5px solid var(--dsw-alias-border-l2);font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
|
|
8812
|
+
.ccp-analysisTableHead > span:not(:first-child){text-align:right}
|
|
8813
|
+
.ccp-analysisScenarioHead,.ccp-analysisScenarioSummary{grid-template-columns:minmax(190px,2fr) minmax(118px,1.1fr) minmax(155px,1.35fr) minmax(142px,1.15fr) 16px}
|
|
8814
|
+
.ccp-analysisScenarioHead > span:nth-child(3),.ccp-analysisScenarioHead > span:nth-child(4){text-align:left}
|
|
8815
|
+
.ccp-analysisModelSummary,.ccp-analysisScenarioSummary{cursor:pointer;list-style:none;min-height:60px}
|
|
8816
|
+
.ccp-analysisModelSummary::-webkit-details-marker,.ccp-analysisScenarioSummary::-webkit-details-marker,.ccp-analysisDisclosure::-webkit-details-marker{display:none}
|
|
8817
|
+
.ccp-analysisModelSummary:hover,.ccp-analysisScenarioSummary:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
8818
|
+
.ccp-analysisIdentity{display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
8819
|
+
.ccp-analysisModelName{font-size:14px;line-height:22px;font-weight:500;overflow-wrap:anywhere}
|
|
8820
|
+
.ccp-analysisModelCount{margin-top:3px}
|
|
8821
|
+
.ccp-analysisModelSummary > .ccp-analysisMetric,.ccp-analysisScenarioSummary > .ccp-analysisMetric{align-items:flex-end}
|
|
8822
|
+
.ccp-analysisScenarioSummary > .ccp-analysisMetric:nth-child(3),.ccp-analysisScenarioSummary > .ccp-analysisMetric:nth-child(4){align-items:flex-start}
|
|
8823
|
+
/* 宽表使用集中表头,但保留每个指标的无障碍标签;窄面板恢复可见标签。 */
|
|
8824
|
+
.ccp-analysisModelSummary .ccp-analysisMetricLabel,.ccp-analysisScenarioSummary .ccp-analysisMetricLabel,.ccp-analysisSearchLabel{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
|
|
8825
|
+
.ccp-analysisShare{display:flex;align-items:center;gap:8px;width:100%;max-width:148px;margin-top:3px}
|
|
8826
|
+
.ccp-analysisShareTrack{display:block;flex:1;height:4px;overflow:hidden;background:var(--dsw-alias-bg-module-platform);border-radius:999px}
|
|
8827
|
+
.ccp-analysisShareFill{display:block;height:100%;background:var(--dsw-alias-label-secondary);border-radius:999px}
|
|
8828
|
+
.ccp-analysisShareValue{font-size:12px;line-height:18px;min-width:40px;text-align:right;color:var(--dsw-alias-label-tertiary)}
|
|
8829
|
+
.ccp-analysisChevron{flex:none;color:var(--dsw-alias-label-tertiary)}
|
|
8830
|
+
.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)}
|
|
8831
|
+
.ccp-analysisDetails{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:22px;padding:16px 18px;background:var(--dsw-alias-bg-module-platform);border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
8832
|
+
.ccp-analysisDetailTitle{font-size:12px;line-height:18px;font-weight:600;margin:0 0 11px}
|
|
8833
|
+
.ccp-analysisFacts{margin:0;display:flex;flex-direction:column;gap:8px}
|
|
8834
|
+
.ccp-analysisFact{display:flex;align-items:baseline;justify-content:space-between;gap:10px;min-width:0}
|
|
8835
|
+
.ccp-analysisFactValue{font-size:14px;line-height:22px;margin:0;text-align:right;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;min-width:0}
|
|
8836
|
+
.ccp-analysisFact .ccp-analysisLabel{flex-shrink:0}
|
|
8837
|
+
.ccp-analysisFooter{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-top:14px}
|
|
8838
|
+
.ccp-analysisAggregate{flex:1;min-width:210px}
|
|
8839
|
+
.ccp-analysisAggregate > .ccp-analysisDetails{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;margin-top:6px}
|
|
8840
|
+
.ccp-analysisDisclosure{display:flex;gap:7px;align-items:center;cursor:pointer;list-style:none;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);padding:7px 0}
|
|
8841
|
+
.ccp-analysisDisclosure > .ccp-analysisChevron{width:14px;height:14px}
|
|
8842
|
+
.ccp-analysisMonthly{flex:none;max-width:340px;display:flex;justify-content:flex-end;flex-wrap:wrap;gap:2px 8px;align-items:baseline;text-align:right;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);padding-top:5px}
|
|
8843
|
+
.ccp-analysisMonthlyValue{font-size:14px;line-height:22px;font-weight:500;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums}
|
|
8844
|
+
.ccp-analysisMonthly .ccp-analysisNote{width:100%;margin:0}
|
|
8845
|
+
.ccp-analysisAssumption{font-size:14px;line-height:22px;color:var(--dsw-alias-label-tertiary);margin:0 0 18px;max-width:76ch}
|
|
8846
|
+
.ccp-analysisSearch{flex:0 1 270px}
|
|
8847
|
+
.ccp-analysisSearchShell{position:relative;display:block}
|
|
8848
|
+
.ccp-analysisSearchShell > .ccp-analysisIcon{position:absolute;top:10px;left:11px;color:var(--dsw-alias-label-tertiary);pointer-events:none}
|
|
8849
|
+
.ccp-analysisSearch .ccp-analysisInput{padding-left:35px}
|
|
8850
|
+
.ccp-analysisScenarioDetails{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}
|
|
8851
|
+
.ccp-analysisScenarioDetails .ccp-analysisFactValue{max-width:70%}
|
|
8852
|
+
.ccp-analysisEmpty{font-size:14px;line-height:22px;color:var(--dsw-alias-label-tertiary);text-align:center;padding:34px 18px;margin:0;border:1px dashed var(--dsw-alias-border-l4);border-radius:8px}
|
|
8853
|
+
.ccp-analysisRules{margin-top:22px;border-top:.5px solid var(--dsw-alias-border-l2);padding-top:8px}
|
|
8854
|
+
.ccp-analysisRulesBody{display:grid;grid-template-columns:1fr 1fr;gap:24px;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px;margin-top:9px}
|
|
8855
|
+
.ccp-analysisRulesBody p{margin:0 0 10px}
|
|
8856
|
+
@container ccp-analysis (max-width:920px){
|
|
8857
|
+
.ccp-analysisTableHead{display:none}
|
|
8858
|
+
.ccp-analysisModelSummary{grid-template-columns:repeat(4,minmax(0,1fr)) 16px;gap:12px 18px}
|
|
8859
|
+
.ccp-analysisScenarioSummary{grid-template-columns:repeat(3,minmax(0,1fr)) 16px;gap:12px 18px}
|
|
8860
|
+
.ccp-analysisModelSummary > .ccp-analysisIdentity,.ccp-analysisScenarioSummary > .ccp-analysisIdentity{grid-column:1/-2}
|
|
8861
|
+
.ccp-analysisModelSummary > .ccp-analysisChevron{grid-column:5;grid-row:1;justify-self:end}
|
|
8862
|
+
.ccp-analysisScenarioSummary > .ccp-analysisChevron{grid-column:4;grid-row:1;justify-self:end}
|
|
8863
|
+
.ccp-analysisModelSummary > .ccp-analysisMetric,.ccp-analysisScenarioSummary > .ccp-analysisMetric{align-items:flex-start}
|
|
8864
|
+
.ccp-analysisModelSummary .ccp-analysisMetricLabel,.ccp-analysisScenarioSummary .ccp-analysisMetricLabel{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}
|
|
8865
|
+
.ccp-analysisDetails{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
8866
|
+
}
|
|
8867
|
+
@container ccp-analysis (max-width:588px){
|
|
8868
|
+
.ccp-analysisFilters{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
|
|
8869
|
+
.ccp-analysisFilters[data-mode="range"] .ccp-analysisScopeField{grid-column:1/-1}
|
|
8870
|
+
.ccp-analysisApply{grid-column:1/-1;margin:0;width:100%}
|
|
8871
|
+
.ccp-analysisOverview{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 18px;padding:16px}
|
|
8872
|
+
.ccp-analysisModelSummary,.ccp-analysisScenarioSummary{grid-template-columns:repeat(2,minmax(0,1fr));gap:15px 18px;padding:16px}
|
|
8873
|
+
.ccp-analysisModelSummary > .ccp-analysisIdentity,.ccp-analysisScenarioSummary > .ccp-analysisIdentity{grid-column:1/-1;padding-right:24px}
|
|
8874
|
+
.ccp-analysisModelSummary > .ccp-analysisChevron,.ccp-analysisScenarioSummary > .ccp-analysisChevron{position:absolute;top:18px;right:16px;grid-column:auto;grid-row:auto}
|
|
8875
|
+
.ccp-analysisDetails,.ccp-analysisScenarioDetails{gap:20px;grid-template-columns:1fr;padding:16px}
|
|
8876
|
+
.ccp-analysisAggregate{width:100%;min-width:0}
|
|
8877
|
+
.ccp-analysisMonthly{width:100%;max-width:none;justify-content:flex-start;text-align:left;padding-top:0}
|
|
8878
|
+
.ccp-analysisSectionHead{align-items:flex-start}
|
|
8879
|
+
.ccp-analysisSectionHead .ccp-analysisSearch{flex-basis:100%;width:100%;order:2}
|
|
8880
|
+
.ccp-analysisRulesBody{grid-template-columns:1fr;gap:12px}
|
|
8881
|
+
/* 英文页签带数量时允许换行,避免轨道或文字撑出宿主的窄面板。 */
|
|
8882
|
+
.ccp-analysisTabs{margin-top:18px;grid-auto-columns:minmax(0,1fr)}
|
|
8883
|
+
.ccp-analysisTab{height:auto;min-height:28px;padding:4px 8px;white-space:normal}
|
|
8884
|
+
}
|
|
8885
|
+
@media (max-width:640px){.ccp-mainInnerAnalysis{padding:20px 16px 32px}}
|
|
7717
8886
|
`;
|
|
8887
|
+
//#endregion
|
|
8888
|
+
//#region src/client/analytics.ts
|
|
8889
|
+
/** 手动读取历史,旧宿主可降级;查询切换和卸载后不接受过期结果。 */
|
|
8890
|
+
var AnalyticsController = class {
|
|
8891
|
+
remote;
|
|
8892
|
+
current = { status: "idle" };
|
|
8893
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8894
|
+
generation = 0;
|
|
8895
|
+
disposed = false;
|
|
8896
|
+
query = {
|
|
8897
|
+
mode: "recent",
|
|
8898
|
+
limit: 20
|
|
8899
|
+
};
|
|
8900
|
+
constructor(remote) {
|
|
8901
|
+
this.remote = remote;
|
|
8902
|
+
}
|
|
8903
|
+
state() {
|
|
8904
|
+
return this.current;
|
|
8905
|
+
}
|
|
8906
|
+
subscribe(listener) {
|
|
8907
|
+
this.listeners.add(listener);
|
|
8908
|
+
return () => {
|
|
8909
|
+
this.listeners.delete(listener);
|
|
8910
|
+
};
|
|
8911
|
+
}
|
|
8912
|
+
dispose() {
|
|
8913
|
+
this.disposed = true;
|
|
8914
|
+
this.generation++;
|
|
8915
|
+
this.listeners.clear();
|
|
8916
|
+
}
|
|
8917
|
+
reload() {
|
|
8918
|
+
this.generation++;
|
|
8919
|
+
this.set({ status: "idle" });
|
|
8920
|
+
}
|
|
8921
|
+
refresh(query = this.query) {
|
|
8922
|
+
if (this.disposed) return;
|
|
8923
|
+
const requested = parseAnalyticsQuery(query);
|
|
8924
|
+
this.query = requested;
|
|
8925
|
+
const generation = ++this.generation;
|
|
8926
|
+
this.set({ status: "loading" });
|
|
8927
|
+
const call = this.remote.analytics;
|
|
8928
|
+
if (!call) {
|
|
8929
|
+
this.set({
|
|
8930
|
+
status: "error",
|
|
8931
|
+
error: "宿主不支持模型分析,请更新插件"
|
|
8932
|
+
});
|
|
8933
|
+
return;
|
|
8934
|
+
}
|
|
8935
|
+
Promise.resolve().then(() => call(requested)).then((result) => {
|
|
8936
|
+
if (this.disposed || generation !== this.generation) return;
|
|
8937
|
+
if (!result.ok) {
|
|
8938
|
+
this.set({
|
|
8939
|
+
status: "error",
|
|
8940
|
+
error: result.error.message === "宿主不支持模型分析,请更新插件" ? result.error.message : "模型分析读取失败,请稍后刷新或检查宿主日志"
|
|
8941
|
+
});
|
|
8942
|
+
return;
|
|
8943
|
+
}
|
|
8944
|
+
this.set({
|
|
8945
|
+
status: "ready",
|
|
8946
|
+
report: parseAnalyticsReport(result.value)
|
|
8947
|
+
});
|
|
8948
|
+
}).catch(() => {
|
|
8949
|
+
if (!this.disposed && generation === this.generation) this.set({
|
|
8950
|
+
status: "error",
|
|
8951
|
+
error: "模型分析读取失败,请稍后刷新或检查宿主日志"
|
|
8952
|
+
});
|
|
8953
|
+
});
|
|
8954
|
+
}
|
|
8955
|
+
set(state) {
|
|
8956
|
+
this.current = state;
|
|
8957
|
+
for (const listener of this.listeners) listener();
|
|
8958
|
+
}
|
|
8959
|
+
};
|
|
7718
8960
|
//#endregion
|
|
7719
8961
|
//#region src/client/index.ts
|
|
7720
8962
|
/** Install one stylesheet by id and return a disposer for its owning effect. */
|
|
@@ -7808,12 +9050,14 @@ window.__ModuleLoader__.load({
|
|
|
7808
9050
|
let usageMountError;
|
|
7809
9051
|
let pricesController;
|
|
7810
9052
|
let refreshUsage;
|
|
9053
|
+
let analyticsController;
|
|
7811
9054
|
const contribution = {
|
|
7812
9055
|
package: USAGE_REMOTE_CONTRIBUTION.package,
|
|
7813
9056
|
descriptors: [
|
|
7814
9057
|
...USAGE_REMOTE_CONTRIBUTION.descriptors,
|
|
7815
9058
|
...MODELS_REMOTE_CONTRIBUTION.descriptors,
|
|
7816
9059
|
...PRICES_REMOTE_CONTRIBUTION.descriptors,
|
|
9060
|
+
...ANALYTICS_REMOTE_CONTRIBUTION.descriptors,
|
|
7817
9061
|
...LOGIN_REMOTE_CONTRIBUTION.descriptors,
|
|
7818
9062
|
...ENROLLMENT_REMOTE_CONTRIBUTION.descriptors
|
|
7819
9063
|
]
|
|
@@ -7831,9 +9075,11 @@ window.__ModuleLoader__.load({
|
|
|
7831
9075
|
usageNamespace = namespaceCtx.remote.commandcode;
|
|
7832
9076
|
controller.refreshCatalog();
|
|
7833
9077
|
pricesController?.reload();
|
|
9078
|
+
analyticsController?.reload();
|
|
7834
9079
|
refreshUsage?.();
|
|
7835
9080
|
namespaceCtx.effect(() => () => {
|
|
7836
9081
|
usageNamespace = void 0;
|
|
9082
|
+
analyticsController?.reload();
|
|
7837
9083
|
}, "dsh-commandcode-provider: usage namespace");
|
|
7838
9084
|
});
|
|
7839
9085
|
}, (error) => {
|
|
@@ -7889,6 +9135,22 @@ window.__ModuleLoader__.load({
|
|
|
7889
9135
|
ctx.effect(() => () => pricesController?.dispose(), "dsh-commandcode-provider: price table");
|
|
7890
9136
|
const pricesStore = createSnapshotStore(pricesController.state());
|
|
7891
9137
|
pricesController.subscribe(() => pricesStore.set(pricesController.state()));
|
|
9138
|
+
analyticsController = new AnalyticsController({ analytics: async (query) => {
|
|
9139
|
+
const namespace = usageNamespace;
|
|
9140
|
+
if (typeof namespace?.analytics !== "function") return {
|
|
9141
|
+
ok: false,
|
|
9142
|
+
error: { message: "宿主不支持模型分析,请更新插件" }
|
|
9143
|
+
};
|
|
9144
|
+
return namespace.analytics(query);
|
|
9145
|
+
} });
|
|
9146
|
+
const analyticsStore = createSnapshotStore(analyticsController.state());
|
|
9147
|
+
analyticsController.subscribe(() => analyticsStore.set(analyticsController.state()));
|
|
9148
|
+
ctx.effect(() => () => analyticsController?.dispose(), "commandcode analytics controller");
|
|
9149
|
+
const panelMode = createSnapshotStore("quota");
|
|
9150
|
+
const openAnalytics = () => {
|
|
9151
|
+
panelMode.set("analysis");
|
|
9152
|
+
ctx.get("layout")?.selectPanel(PANEL_ID);
|
|
9153
|
+
};
|
|
7892
9154
|
const loginRemote = {
|
|
7893
9155
|
loginBegin: async (targetRef) => {
|
|
7894
9156
|
if (usageNamespace === void 0) return {
|
|
@@ -7952,6 +9214,7 @@ window.__ModuleLoader__.load({
|
|
|
7952
9214
|
discard: () => controller.discard(),
|
|
7953
9215
|
refreshCredentials: () => void controller.refreshCredentials(),
|
|
7954
9216
|
refreshUsage: () => void usageController.refresh(),
|
|
9217
|
+
...typeof ctx.get("layout")?.selectPanel === "function" ? { openAnalytics } : {},
|
|
7955
9218
|
beginLogin: (targetRef) => void loginController.begin(targetRef),
|
|
7956
9219
|
cancelLogin: () => void loginController.cancel(),
|
|
7957
9220
|
renameAccount: (ref, label) => controller.renameAccount(ref, label),
|
|
@@ -7997,14 +9260,19 @@ window.__ModuleLoader__.load({
|
|
|
7997
9260
|
const panelFace = () => ({
|
|
7998
9261
|
hooks: {
|
|
7999
9262
|
commandCodeUsage: usageStore,
|
|
8000
|
-
commandCodeSettings: store
|
|
9263
|
+
commandCodeSettings: store,
|
|
9264
|
+
commandCodeAnalytics: analyticsStore,
|
|
9265
|
+
commandCodePanelMode: panelMode
|
|
8001
9266
|
},
|
|
9267
|
+
selectPanelMode: (mode) => panelMode.set(mode),
|
|
9268
|
+
refreshAnalytics: (query) => analyticsController?.refresh(query),
|
|
8002
9269
|
refresh: () => {
|
|
8003
9270
|
pricesController?.ensure();
|
|
8004
9271
|
usageController.refresh();
|
|
8005
9272
|
},
|
|
8006
9273
|
startAutoRefresh: () => startPanelAutoRefresh(usageController, () => true),
|
|
8007
9274
|
open: () => {
|
|
9275
|
+
panelMode.set("quota");
|
|
8008
9276
|
ctx.get("layout")?.selectPanel(PANEL_ID);
|
|
8009
9277
|
},
|
|
8010
9278
|
close: () => {
|