Fix : usage convert
This commit is contained in:
1 parent
7881db81ec
commit
e6e44ac364
10 files changed
+974
-16
No files matched your search
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Format ISO date string to countdown format
|
||||
* @param {string|Date} date - ISO date string or Date object
|
||||
* @returns {string} Formatted countdown (e.g., "5d 12h", "2h 30m", "15m") or "-"
|
||||
*/
|
||||
export function formatResetTime(date) {
|
||||
if (!date) return "-";
|
||||
|
||||
try {
|
||||
const resetDate = typeof date === "string" ? new Date(date) : date;
|
||||
const now = new Date();
|
||||
const diffMs = resetDate - now;
|
||||
|
||||
if (diffMs <= 0) return "-";
|
||||
|
||||
const totalMinutes = Math.floor(diffMs / (1000 * 60));
|
||||
const totalHours = Math.floor(totalMinutes / 60);
|
||||
const totalDays = Math.floor(totalHours / 24);
|
||||
|
||||
const days = totalDays;
|
||||
const hours = totalHours % 24;
|
||||
const minutes = totalMinutes % 60;
|
||||
|
||||
if (days > 0) {
|
||||
return `${days}d ${hours}h`;
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
}
|
||||
|
||||
return `${minutes}m`;
|
||||
} catch (error) {
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Tailwind color class based on percentage
|
||||
* @param {number} percentage - Remaining percentage (0-100)
|
||||
* @returns {string} Color name: "green" | "yellow" | "red" | "gray"
|
||||
*/
|
||||
export function getStatusColor(percentage) {
|
||||
if (percentage === 0 || percentage === null || percentage === undefined) {
|
||||
return "gray";
|
||||
}
|
||||
|
||||
if (percentage > 70) return "green";
|
||||
if (percentage >= 30) return "yellow";
|
||||
return "red";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status emoji based on percentage
|
||||
* @param {number} percentage - Remaining percentage (0-100)
|
||||
* @returns {string} Emoji: "🟢" | "🟡" | "🔴" | "⚫"
|
||||
*/
|
||||
export function getStatusEmoji(percentage) {
|
||||
if (percentage === 0 || percentage === null || percentage === undefined) {
|
||||
return "⚫";
|
||||
}
|
||||
|
||||
if (percentage > 70) return "🟢";
|
||||
if (percentage >= 30) return "🟡";
|
||||
return "🔴";
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate remaining percentage
|
||||
* @param {number} used - Used amount
|
||||
* @param {number} total - Total amount
|
||||
* @returns {number} Remaining percentage (0-100)
|
||||
*/
|
||||
export function calculatePercentage(used, total) {
|
||||
if (!total || total === 0) return 0;
|
||||
if (!used || used < 0) return 100;
|
||||
if (used >= total) return 0;
|
||||
|
||||
return Math.round(((total - used) / total) * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse provider-specific quota structures into normalized array
|
||||
* @param {string} provider - Provider name (github, antigravity, codex, kiro, claude)
|
||||
* @param {Object} data - Raw quota data from provider
|
||||
* @returns {Array<Object>} Normalized quota objects with { name, used, total, resetAt }
|
||||
*/
|
||||
export function parseQuotaData(provider, data) {
|
||||
if (!data || typeof data !== "object") return [];
|
||||
|
||||
const normalizedQuotas = [];
|
||||
|
||||
try {
|
||||
switch (provider.toLowerCase()) {
|
||||
case "github":
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([name, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "antigravity":
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([modelName, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name: modelName,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "codex":
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([quotaType, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name: quotaType,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "kiro":
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([quotaType, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name: quotaType,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "claude":
|
||||
if (data.message) {
|
||||
// Handle error message case
|
||||
normalizedQuotas.push({
|
||||
name: "error",
|
||||
used: 0,
|
||||
total: 0,
|
||||
resetAt: null,
|
||||
message: data.message,
|
||||
});
|
||||
} else if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([name, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Generic fallback for unknown providers
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([name, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error parsing quota data for ${provider}:`, error);
|
||||
return [];
|
||||
}
|
||||
|
||||
return normalizedQuotas;
|
||||
}
|
||||
Reference in new issue
Block a user