feat: v0.5.2 - daily trend refactor + provider/model two-level drill-down
- Dashboard: 用量趋势卡片改为外层 tab 容器(下划线 tab),移除卡片标题与内部 pill 切换器 - 用量趋势: 新增 供应商模型用量趋势 tab,与 模型用量趋势 并列 - 供应商 tab 弹窗: 每日用量详情改为两级(供应商 → 模型)分组 - 后端: DailyRow 新增 by_provider_model 嵌套聚合 - 前端: DailyBars 通用化(dimension/colorMap),DailyDetailModal 按 tab 维度渲染 - i18n: 新增 providerDistribution(中/英) - 版本: 0.5.1 → 0.5.2(tauri.conf / Cargo.toml / package.json / README)
This commit is contained in:
1 parent
3dd1fd93fe
commit
a1fdc6c93d
16 files changed
+1190
-506
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export interface UpdateInfo {
|
||||
@@ -10,7 +10,10 @@ export interface UpdateInfo {
|
||||
}
|
||||
|
||||
const THROTTLE_KEY = "kimi-switch-last-update-check";
|
||||
const THROTTLE_MS = 24 * 60 * 60 * 1000; // 24 hours
|
||||
// Both the throttle window and the periodic re-check run on an 8h cadence:
|
||||
// long-running sessions still pick up new releases without a restart, and the
|
||||
// actual backend call is still gated so short windows don't double-fire.
|
||||
const CHECK_INTERVAL_MS = 8 * 60 * 60 * 1000; // 8 hours
|
||||
|
||||
export function useUpdateCheck() {
|
||||
const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);
|
||||
@@ -26,7 +29,7 @@ export function useUpdateCheck() {
|
||||
|
||||
const doCheck = useCallback(async (force: boolean) => {
|
||||
if (!force) {
|
||||
if (lastChecked && Date.now() - lastChecked < THROTTLE_MS) return;
|
||||
if (lastChecked && Date.now() - lastChecked < CHECK_INTERVAL_MS) return;
|
||||
}
|
||||
setChecking(true);
|
||||
try {
|
||||
@@ -40,16 +43,26 @@ export function useUpdateCheck() {
|
||||
// ignore
|
||||
}
|
||||
} catch {
|
||||
// silently fail — user can retry from Settings
|
||||
// silently fail — network errors, parse errors, etc. should not nag
|
||||
// the user. They can still trigger a manual check from Settings.
|
||||
} finally {
|
||||
setChecking(false);
|
||||
}
|
||||
}, [lastChecked]);
|
||||
|
||||
// On mount: throttled auto-check
|
||||
// Keep a ref to the latest doCheck so the periodic interval doesn't need
|
||||
// to be reset on every lastChecked change.
|
||||
const doCheckRef = useRef(doCheck);
|
||||
useEffect(() => {
|
||||
doCheck(false);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
doCheckRef.current = doCheck;
|
||||
}, [doCheck]);
|
||||
|
||||
// On mount: throttled auto-check + periodic re-check while the window
|
||||
// stays open. Errors are silent (handled inside doCheck).
|
||||
useEffect(() => {
|
||||
doCheckRef.current(false);
|
||||
const interval = setInterval(() => doCheckRef.current(false), CHECK_INTERVAL_MS);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const checkNow = useCallback(() => doCheck(true), [doCheck]);
|
||||
|
||||
Reference in new issue
Block a user