Skip to content

Commit e5fe843

Browse files
authored
Merge pull request #53 from saagpatel/codex/refactor/wave5-6-settings-tab
refactor(components): decompose SettingsTab into per-section files + init hook
2 parents 9137eca + 1b00fb8 commit e5fe843

17 files changed

Lines changed: 2029 additions & 1190 deletions
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import type { ResponseQualityThresholds } from "../../features/analytics/qualityThresholds";
2+
import type { SearchApiEmbeddingModelStatus } from "../../types/settings";
3+
4+
export function formatBytes(bytes: number): string {
5+
if (bytes === 0) return "0 B";
6+
const k = 1024;
7+
const sizes = ["B", "KB", "MB", "GB"];
8+
const i = Math.floor(Math.log(bytes) / Math.log(k));
9+
return `${(bytes / k ** i).toFixed(1)} ${sizes[i]}`;
10+
}
11+
12+
export function formatSpeed(bps: number): string {
13+
if (bps === 0) return "";
14+
return `${formatBytes(bps)}/s`;
15+
}
16+
17+
export function formatVerificationStatus(
18+
status: string | null | undefined,
19+
): string {
20+
if (status === "verified") return "Verified";
21+
if (status === "unverified") return "Unverified";
22+
return "Unknown";
23+
}
24+
25+
export function getSearchApiEmbeddingBadge(
26+
status: SearchApiEmbeddingModelStatus | null,
27+
installError: string | null,
28+
): { label: string; className: string; detail: string } {
29+
if (installError) {
30+
return {
31+
label: "Unavailable",
32+
className: "error",
33+
detail: installError,
34+
};
35+
}
36+
37+
if (!status) {
38+
return {
39+
label: "Checking",
40+
className: "downloaded",
41+
detail:
42+
"Checking whether the managed search API embedding model is installed.",
43+
};
44+
}
45+
46+
if (!status.installed) {
47+
return {
48+
label: "Not Installed",
49+
className: "not-downloaded",
50+
detail:
51+
"Install this managed model to keep search-api embeddings explicit, pinned, and offline at runtime.",
52+
};
53+
}
54+
55+
if (!status.ready) {
56+
return {
57+
label: "Needs Repair",
58+
className: "error",
59+
detail:
60+
status.error ??
61+
"The managed search API embedding model is installed but not ready.",
62+
};
63+
}
64+
65+
return {
66+
label: "Ready",
67+
className: "loaded",
68+
detail: `Pinned revision ${status.revision}. Loaded from local disk only at runtime.`,
69+
};
70+
}
71+
72+
export function validateQualityThresholds(
73+
thresholds: ResponseQualityThresholds,
74+
): string | null {
75+
if (thresholds.editRatioWatch >= thresholds.editRatioAction) {
76+
return "Edit ratio watch threshold must be lower than action threshold.";
77+
}
78+
if (thresholds.timeToDraftWatchMs >= thresholds.timeToDraftActionMs) {
79+
return "Time-to-draft watch threshold must be lower than action threshold.";
80+
}
81+
if (thresholds.copyPerSaveWatch <= thresholds.copyPerSaveAction) {
82+
return "Copy-per-save watch threshold must be higher than action threshold.";
83+
}
84+
if (thresholds.editedSaveRateWatch >= thresholds.editedSaveRateAction) {
85+
return "Edited save rate watch threshold must be lower than action threshold.";
86+
}
87+
return null;
88+
}
89+
90+
export function formatAuditEvent(
91+
event: string | Record<string, string>,
92+
): string {
93+
if (typeof event === "string") return event;
94+
if (typeof event === "object" && event !== null) {
95+
const key = Object.keys(event)[0];
96+
return key ? `${key}: ${event[key]}` : JSON.stringify(event);
97+
}
98+
return String(event);
99+
}

0 commit comments

Comments
 (0)