mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
chore(release): v3.3.10 — merge Analytics and SQLite fixes (#849)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
9227964cb6
commit
6f9fec658f
@@ -295,51 +295,15 @@ export default function ComboHealthTab() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [retrying, setRetrying] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
|
||||
async function fetchComboHealth() {
|
||||
setLoading(true);
|
||||
const fetchData = useCallback(
|
||||
async (controller: AbortController, isRetry = false) => {
|
||||
if (isRetry) {
|
||||
setRetrying(true);
|
||||
} else {
|
||||
setLoading(true);
|
||||
}
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/usage/combo-health?range=${range}`, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch combo health data");
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ComboHealthResponse;
|
||||
setData(result);
|
||||
} catch (fetchError) {
|
||||
if ((fetchError as Error).name === "AbortError") {
|
||||
return;
|
||||
}
|
||||
|
||||
setError(fetchError instanceof Error ? fetchError.message : "Unknown error");
|
||||
setData(null);
|
||||
} finally {
|
||||
if (!controller.signal.aborted) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchComboHealth();
|
||||
|
||||
return () => controller.abort();
|
||||
}, [range]);
|
||||
|
||||
const combos = data?.combos ?? [];
|
||||
|
||||
const handleRetry = useCallback(() => {
|
||||
setRetrying(true);
|
||||
setError(null);
|
||||
const controller = new AbortController();
|
||||
|
||||
async function retryFetch() {
|
||||
try {
|
||||
const response = await fetch(`/api/usage/combo-health?range=${range}`, {
|
||||
signal: controller.signal,
|
||||
@@ -357,18 +321,29 @@ export default function ComboHealthTab() {
|
||||
return;
|
||||
}
|
||||
setError(fetchError instanceof Error ? fetchError.message : "Unknown error");
|
||||
if (!isRetry) setData(null);
|
||||
} finally {
|
||||
if (!controller.signal.aborted) {
|
||||
setLoading(false);
|
||||
setRetrying(false);
|
||||
if (isRetry) setRetrying(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retryFetch();
|
||||
},
|
||||
[range]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
fetchData(controller, false);
|
||||
return () => controller.abort();
|
||||
}, [range]);
|
||||
}, [fetchData]);
|
||||
|
||||
const combos = data?.combos ?? [];
|
||||
|
||||
const handleRetry = useCallback(() => {
|
||||
const controller = new AbortController();
|
||||
fetchData(controller, true);
|
||||
}, [fetchData]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- 012_quota_snapshots.sql
|
||||
-- 013_quota_snapshots.sql
|
||||
-- Quota snapshots for subscription utilization tracking.
|
||||
-- Stores periodic snapshots of quota state for historical analysis and time-series queries.
|
||||
|
||||
@@ -87,7 +87,11 @@ export function getAggregatedSnapshots(opts: {
|
||||
params.push(opts.until);
|
||||
}
|
||||
|
||||
const bucketSeconds = opts.bucketMinutes * 60;
|
||||
const bucketSeconds = Number(opts.bucketMinutes) * 60;
|
||||
if (!Number.isFinite(bucketSeconds) || bucketSeconds <= 0) {
|
||||
throw new Error("Invalid bucket size");
|
||||
}
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
datetime((strftime('%s', created_at) / ${bucketSeconds}) * ${bucketSeconds}, 'unixepoch') as bucket,
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function TimeRangeSelector({ value, onChange }: TimeRangeSelector
|
||||
return (
|
||||
<div
|
||||
role="tablist"
|
||||
aria-label="시간 범위 선택"
|
||||
aria-label="Select time range"
|
||||
className="inline-flex items-center gap-1 rounded-lg bg-black/5 p-1 dark:bg-white/5"
|
||||
>
|
||||
{OPTIONS.map((option) => {
|
||||
|
||||
Reference in New Issue
Block a user