| |
| |
| |
| |
| |
|
|
|
|
| import { maskEmail } from "./maskEmail";
|
|
|
| |
| |
| |
| |
|
|
| export function formatTime(isoString: string | null | undefined) {
|
| try {
|
| if (!isoString) return "-";
|
| const d = new Date(isoString);
|
| return d.toLocaleTimeString("en-US", {
|
| hour12: false,
|
| hour: "2-digit",
|
| minute: "2-digit",
|
| second: "2-digit",
|
| });
|
| } catch {
|
| return "-";
|
| }
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function formatDuration(ms: number | null | undefined) {
|
| if (!ms) return "-";
|
| if (ms < 1000) return `${ms}ms`;
|
| return `${(ms / 1000).toFixed(1)}s`;
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function formatDateTime(iso: string | null | undefined) {
|
| try {
|
| if (!iso) return "-";
|
| const d = new Date(iso);
|
| return d.toLocaleDateString("pt-BR") + ", " + d.toLocaleTimeString("en-US", { hour12: false });
|
| } catch {
|
| return iso;
|
| }
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| export function maskSegment(value: string | null | undefined, start = 2, end = 2) {
|
| if (!value) return "";
|
| if (value.length <= start + end) return `${value.slice(0, 1)}***`;
|
| return `${value.slice(0, start)}***${value.slice(-end)}`;
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
| export function maskAccount(account: string | null | undefined, emailsVisible: boolean) {
|
| if (!account || account === "-") return "-";
|
| if (emailsVisible) return account;
|
| const atIdx = account.indexOf("@");
|
| if (atIdx > 3) {
|
| return maskEmail(account);
|
| }
|
| if (account.length > 8) {
|
| return account.slice(0, 5) + "***";
|
| }
|
| return account;
|
| }
|
|
|
| export function stableAccountSuffix(account: string | null | undefined): string {
|
| if (!account || account === "-") return "0000";
|
| let hash = 0x811c9dc5;
|
| for (let i = 0; i < account.length; i++) {
|
| hash ^= account.charCodeAt(i);
|
| hash = Math.imul(hash, 0x01000193) >>> 0;
|
| }
|
| return hash.toString(16).padStart(8, "0").slice(0, 4);
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
| export function formatApiKeyLabel(
|
| apiKeyName: string | null | undefined,
|
| apiKeyId: string | null | undefined
|
| ) {
|
| if (!apiKeyName && !apiKeyId) return "—";
|
| const displayName = apiKeyName || "key";
|
| if (!apiKeyId) return displayName;
|
| return `${displayName} (${maskSegment(apiKeyId, 4, 4)})`;
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function maskKey(key: string | null | undefined) {
|
| if (!key || key.length < 8) return "***";
|
| return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function fmtCompact(n: number | null | undefined) {
|
| if (n && n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1)}B`;
|
| if (n && n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
| if (n && n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
| return new Intl.NumberFormat().format(n || 0);
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function fmtFull(n: number | null | undefined) {
|
| return new Intl.NumberFormat().format(n || 0);
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
| export function formatCost(usd: number | null | undefined): string {
|
| const value = Number(usd || 0);
|
| if (!Number.isFinite(value) || value === 0) return "$0.00";
|
| if (value < 0.01) return `$${value.toFixed(6)}`;
|
| if (value < 1) return `$${value.toFixed(4)}`;
|
| return `$${value.toFixed(2)}`;
|
| }
|
|
|
| export const fmtCost = formatCost;
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export function formatCostAbbreviated(usd: number | null | undefined): string {
|
| const value = Number(usd || 0);
|
| if (!Number.isFinite(value) || value === 0) return "$0";
|
| const abs = Math.abs(value);
|
| if (abs < 0.01) {
|
| if (value < 0) {
|
| return `-$${Math.abs(value).toFixed(6)}`;
|
| }
|
| return `$${value.toFixed(6)}`;
|
| }
|
| let divisor: number, suffix: string;
|
| if (abs >= 1_000_000_000_000) {
|
| divisor = 1_000_000_000_000;
|
| suffix = "T";
|
| } else if (abs >= 1_000_000_000) {
|
| divisor = 1_000_000_000;
|
| suffix = "B";
|
| } else if (abs >= 1_000_000) {
|
| divisor = 1_000_000;
|
| suffix = "M";
|
| } else if (abs >= 1_000) {
|
| divisor = 1_000;
|
| suffix = "K";
|
| } else {
|
| if (value < 0) {
|
| return `-$${Math.abs(value).toFixed(2)}`;
|
| }
|
| return `$${value.toFixed(2)}`;
|
| }
|
| const abbreviated = abs / divisor;
|
| let formatted = abbreviated.toFixed(1);
|
| if (formatted.includes(".")) {
|
| formatted = formatted.replace(/\.?0+$/, "");
|
| }
|
| const sign = value < 0 ? "-" : "";
|
| return `${sign}$${formatted}${suffix}`;
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
| export function truncateUrl(url: string | null | undefined, max = 50) {
|
| if (!url) return "-";
|
| try {
|
| const parsed = new URL(url);
|
| const display = parsed.hostname + parsed.pathname;
|
| return display.length > max ? display.slice(0, max) + "…" : display;
|
| } catch {
|
| return url.length > max ? url.slice(0, max) + "…" : url;
|
| }
|
| }
|
|
|
| |
| |
| |
|
|
| export function safePercentage(value: unknown): number | undefined {
|
| return typeof value === "number" && isFinite(value) ? value : undefined;
|
| }
|
|
|