From 90a433e761cf4ec199d58194d2051f5b258c45dd Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Thu, 9 Jul 2026 23:31:17 +1000 Subject: [PATCH 1/5] Remove dead helper code --- web/actions/migrations.ts | 11 ----- web/components/ui/canvas-wrapper.tsx | 29 ------------ web/lib/agent/expected-state.ts | 9 ---- web/lib/api-auth.ts | 4 -- web/lib/deployment-status.ts | 6 --- web/lib/inngest/functions/rollout-utils.ts | 18 ------- web/lib/members.ts | 8 ---- web/tests/members.test.ts | 8 ---- web/tests/rollout-utils.test.ts | 55 ---------------------- 9 files changed, 148 deletions(-) delete mode 100644 web/tests/rollout-utils.test.ts diff --git a/web/actions/migrations.ts b/web/actions/migrations.ts index 226839a9..56ec46d0 100644 --- a/web/actions/migrations.ts +++ b/web/actions/migrations.ts @@ -7,17 +7,6 @@ import { services } from "@/db/schema"; import { requireDeveloperRole } from "@/lib/auth"; import { inngest } from "@/lib/inngest/client"; import { inngestEvents } from "@/lib/inngest/events"; -import { startMigrationInternal } from "@/lib/migrations"; - -export async function startMigration( - serviceId: string, - targetServerId: string, -) { - await requireDeveloperRole(); - await startMigrationInternal(serviceId, targetServerId); - revalidatePath(`/dashboard/projects`); - return { success: true }; -} export async function cancelMigration(serviceId: string) { await requireDeveloperRole(); diff --git a/web/components/ui/canvas-wrapper.tsx b/web/components/ui/canvas-wrapper.tsx index 439e7556..7ed0baee 100644 --- a/web/components/ui/canvas-wrapper.tsx +++ b/web/components/ui/canvas-wrapper.tsx @@ -102,35 +102,6 @@ export function getStatusColorFromDeployments( return defaultColors; } -export type HealthColors = { - dot: string; - text: string; -}; - -const healthColorMap: Record = { - healthy: { - dot: "bg-emerald-500", - text: "text-emerald-600 dark:text-emerald-400", - }, - starting: { - dot: "bg-amber-500", - text: "text-amber-600 dark:text-amber-400", - }, - unhealthy: { - dot: "bg-rose-500", - text: "text-rose-600 dark:text-rose-400", - }, -}; - -const defaultHealthColors: HealthColors = { - dot: "bg-slate-400", - text: "text-slate-500", -}; - -export function getHealthColor(healthStatus: string): HealthColors { - return healthColorMap[healthStatus] || defaultHealthColors; -} - interface CanvasWrapperProps { children?: React.ReactNode; height?: string; diff --git a/web/lib/agent/expected-state.ts b/web/lib/agent/expected-state.ts index 74c6f4a5..cb13d987 100644 --- a/web/lib/agent/expected-state.ts +++ b/web/lib/agent/expected-state.ts @@ -264,15 +264,6 @@ async function fetchDeploymentPorts(deploymentIds: string[]) { .where(inArray(deploymentPorts.deploymentId, deploymentIds)); } -async function fetchServicePorts(serviceIds: string[]) { - if (serviceIds.length === 0) return []; - - return db - .select() - .from(servicePorts) - .where(inArray(servicePorts.serviceId, serviceIds)); -} - export function buildExpectedContainersFromRows({ deployments: deploymentRows, services: serviceRows, diff --git a/web/lib/api-auth.ts b/web/lib/api-auth.ts index 0ba7413d..a411461a 100644 --- a/web/lib/api-auth.ts +++ b/web/lib/api-auth.ts @@ -111,7 +111,3 @@ export async function requireRequestRole( export async function requireRequestDeveloperRole(request: Request) { return requireRequestRole(request, ["admin", "developer"]); } - -export async function requireRequestAdminRole(request: Request) { - return requireRequestRole(request, ["admin"]); -} diff --git a/web/lib/deployment-status.ts b/web/lib/deployment-status.ts index ed4619ad..efbbfb97 100644 --- a/web/lib/deployment-status.ts +++ b/web/lib/deployment-status.ts @@ -63,12 +63,6 @@ export function isTrafficActive(trafficState: TrafficState): boolean { return trafficState === "active"; } -export function isDeploymentExpected( - deployment: Pick, -): boolean { - return isRuntimeExpected(deployment.runtimeDesiredState); -} - export function isDeploymentRoutable( deployment: Pick, ): boolean { diff --git a/web/lib/inngest/functions/rollout-utils.ts b/web/lib/inngest/functions/rollout-utils.ts index f78c3857..30f4432c 100644 --- a/web/lib/inngest/functions/rollout-utils.ts +++ b/web/lib/inngest/functions/rollout-utils.ts @@ -4,24 +4,6 @@ import { deployments, rollouts } from "@/db/schema"; import { markDeploymentFailedRemoved } from "@/lib/deployment-status"; import { sendDeploymentFailureAlert } from "@/lib/email"; -export function shouldRollBackDeploymentState(deployment: { - trafficState: string; - runtimeDesiredState: string; -}) { - void deployment.trafficState; - return deployment.runtimeDesiredState !== "removed"; -} - -export function shouldRestoreDrainingDeployment(deployment: { - trafficState: string; - runtimeDesiredState: string; -}) { - return ( - deployment.trafficState === "draining" && - deployment.runtimeDesiredState !== "removed" - ); -} - export async function restoreDrainingDeploymentsForRollback(serviceId: string) { await db .update(deployments) diff --git a/web/lib/members.ts b/web/lib/members.ts index 9612d322..a05b59b6 100644 --- a/web/lib/members.ts +++ b/web/lib/members.ts @@ -4,7 +4,6 @@ import { db } from "@/db"; import { user } from "@/db/schema"; import type { InvitableMemberRole, MemberRole } from "@/db/types"; -export const MEMBER_ROLES = ["admin", "developer", "reader"] as const; export const INVITABLE_MEMBER_ROLES = ["developer", "reader"] as const; export const ADMIN_NOT_CONFIGURED_MESSAGE = "No admin user is configured. Run `pnpm admin:create ` from the web app to create the first admin."; @@ -20,13 +19,6 @@ export class AdminNotConfiguredError extends Error { } } -export function isMemberRole(value: unknown): value is MemberRole { - return ( - typeof value === "string" && - MEMBER_ROLES.includes(value as (typeof MEMBER_ROLES)[number]) - ); -} - export function isInvitableMemberRole( value: unknown, ): value is InvitableMemberRole { diff --git a/web/tests/members.test.ts b/web/tests/members.test.ts index df6062dd..0d71856e 100644 --- a/web/tests/members.test.ts +++ b/web/tests/members.test.ts @@ -3,17 +3,9 @@ import { createInviteToken, hashInviteToken, isInvitableMemberRole, - isMemberRole, } from "@/lib/members"; describe("member roles", () => { - it("validates supported roles", () => { - expect(isMemberRole("admin")).toBe(true); - expect(isMemberRole("developer")).toBe(true); - expect(isMemberRole("reader")).toBe(true); - expect(isMemberRole("owner")).toBe(false); - }); - it("validates invitable roles", () => { expect(isInvitableMemberRole("developer")).toBe(true); expect(isInvitableMemberRole("reader")).toBe(true); diff --git a/web/tests/rollout-utils.test.ts b/web/tests/rollout-utils.test.ts deleted file mode 100644 index 7dc9bb7e..00000000 --- a/web/tests/rollout-utils.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; - -vi.mock("@/db", () => ({ db: {} })); -vi.mock("@/lib/email", () => ({ - sendDeploymentFailureAlert: vi.fn(), -})); - -import { - shouldRestoreDrainingDeployment, - shouldRollBackDeploymentState, -} from "@/lib/inngest/functions/rollout-utils"; - -describe("rollout failure helpers", () => { - it("cleans up live rollout deployments even after DNS promotion", () => { - expect( - shouldRollBackDeploymentState({ - trafficState: "candidate", - runtimeDesiredState: "running", - }), - ).toBe(true); - expect( - shouldRollBackDeploymentState({ - trafficState: "active", - runtimeDesiredState: "running", - }), - ).toBe(true); - expect( - shouldRollBackDeploymentState({ - trafficState: "candidate", - runtimeDesiredState: "removed", - }), - ).toBe(false); - }); - - it("restores draining deployments by traffic intent only", () => { - expect( - shouldRestoreDrainingDeployment({ - trafficState: "draining", - runtimeDesiredState: "running", - }), - ).toBe(true); - expect( - shouldRestoreDrainingDeployment({ - trafficState: "draining", - runtimeDesiredState: "stopped", - }), - ).toBe(true); - expect( - shouldRestoreDrainingDeployment({ - trafficState: "draining", - runtimeDesiredState: "removed", - }), - ).toBe(false); - }); -}); From 5afc15a330d364919f4a3f728a87f94bf1df24fa Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Thu, 9 Jul 2026 23:37:22 +1000 Subject: [PATCH 2/5] Inline low-use display helpers --- .../metrics/metrics-history-charts.tsx | 30 ++++------ .../details/service-details-overview.tsx | 59 ++++++------------- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/web/components/metrics/metrics-history-charts.tsx b/web/components/metrics/metrics-history-charts.tsx index 837f8028..88572662 100644 --- a/web/components/metrics/metrics-history-charts.tsx +++ b/web/components/metrics/metrics-history-charts.tsx @@ -97,6 +97,11 @@ const CHARTS: ChartConfig[] = [ }, ]; +const CHART_THRESHOLDS = [ + { value: 70, color: "#f59e0b" }, + { value: 90, color: "#f43f5e" }, +]; + const SERVER_COLORS = [ "#10b981", "#0ea5e9", @@ -284,7 +289,7 @@ function MetricChartCard({ iconType="plainline" wrapperStyle={{ paddingBottom: 12 }} /> - {thresholdsForChart().map((threshold) => ( + {CHART_THRESHOLDS.map((threshold) => ( new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(), ); } - -function thresholdsForChart() { - return [ - { value: 70, color: "#f59e0b" }, - { value: 90, color: "#f43f5e" }, - ]; -} - function formatTooltipValue(item: TooltipPayload) { const value = Number(item.value); if (!Number.isFinite(value)) return "-"; - if (isBytesSeries(String(item.dataKey))) return formatBytes(value); + const dataKey = String(item.dataKey); + if ( + dataKey.startsWith("memoryUsedBytes:") || + dataKey.startsWith("diskUsedBytes:") + ) { + return formatBytes(value); + } return `${value.toFixed(1)}%`; } @@ -463,13 +466,6 @@ function getServerColor(index: number) { return SERVER_COLORS[index % SERVER_COLORS.length]; } -function isBytesSeries(dataKey: string) { - return ( - dataKey.startsWith("memoryUsedBytes:") || - dataKey.startsWith("diskUsedBytes:") - ); -} - function formatShortTime(value: string) { return new Intl.DateTimeFormat(undefined, { month: "short", diff --git a/web/components/service/details/service-details-overview.tsx b/web/components/service/details/service-details-overview.tsx index 3931e2da..dfc6e740 100644 --- a/web/components/service/details/service-details-overview.tsx +++ b/web/components/service/details/service-details-overview.tsx @@ -223,6 +223,10 @@ function ServiceMetricsPanel({ () => buildServiceMetricSummaryItems(chartMode, stats, chartRows, hasMetricData), [chartMode, stats, chartRows, hasMetricData], ); + const todayLabel = new Intl.DateTimeFormat(undefined, { + day: "numeric", + month: "short", + }).format(new Date()); return (
@@ -247,7 +251,7 @@ function ServiceMetricsPanel({ )}
-

{formatToday()}

+

{todayLabel}

total + server.configured, 0, ); -} - -function formatInstanceSummary(overview: OverviewData): string { - const configured = getConfiguredReplicaCount(overview); const serverCount = overview.serverSummaries.length; if (configured === 0) { @@ -953,18 +945,16 @@ function getPrimaryEndpoint(endpoints: EndpointItem[]): EndpointItem { function formatPortSummary(ports: Service["ports"]): string { if (ports.length === 0) return "No Ports"; - if (ports.length === 1) return formatPortLabel(ports[0]); + if (ports.length === 1) { + const port = ports[0]; + const protocol = (port.protocol || "http").toUpperCase(); + const external = port.externalPort ? ` -> :${port.externalPort}` : ""; + return `${protocol} :${port.port}${external}`; + } return formatCount(ports.length, "port"); } -function formatPortLabel(port: Service["ports"][number]): string { - const protocol = (port.protocol || "http").toUpperCase(); - const external = port.externalPort ? ` -> :${port.externalPort}` : ""; - - return `${protocol} :${port.port}${external}`; -} - function formatCount(count: number, singular: string): string { const label = singular .split(" ") @@ -1227,7 +1217,7 @@ function formatAxisTick(value: number, mode: ServiceChartMode): string { if (mode === "latency") return formatDurationMs(value); if (mode === "traffic") return formatBytes(value); if (mode === "resources") return `${formatRateTick(value)}%`; - return formatRequestTick(value); + return formatCompactNumber(value); } function formatRateTick(value: number): string { @@ -1243,10 +1233,6 @@ function getYAxisMargin(mode: ServiceChartMode): number { return -20; } -function formatRequestTick(value: number): string { - return formatCompactNumber(value); -} - function formatRequestCount(value: number): string { if (!Number.isFinite(value)) return "-"; @@ -1293,10 +1279,3 @@ function formatTooltipDate(value: string): string { minute: "2-digit", }).format(new Date(value)); } - -function formatToday(): string { - return new Intl.DateTimeFormat(undefined, { - day: "numeric", - month: "short", - }).format(new Date()); -} From c4cebe61463621a3a097924e2ee3eca901cc9257 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Fri, 10 Jul 2026 07:48:47 +1000 Subject: [PATCH 3/5] Inline one-off UI display helpers --- .../auth/device-authorization-page.tsx | 6 +- .../github/github-repo-selector.tsx | 8 +- web/components/settings/api-key-settings.tsx | 148 +++++++++--------- web/components/settings/global-settings.tsx | 18 +-- 4 files changed, 87 insertions(+), 93 deletions(-) diff --git a/web/components/auth/device-authorization-page.tsx b/web/components/auth/device-authorization-page.tsx index ee7f1a9b..552cc614 100644 --- a/web/components/auth/device-authorization-page.tsx +++ b/web/components/auth/device-authorization-page.tsx @@ -15,10 +15,6 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { authClient } from "@/lib/auth-client"; -function normalizeUserCode(value: string) { - return value.trim().replace(/-/g, "").toUpperCase(); -} - export function DeviceAuthorizationPage() { const router = useRouter(); const searchParams = useSearchParams(); @@ -36,7 +32,7 @@ export function DeviceAuthorizationPage() { const verifyCode = useCallback( async (code: string) => { - const formatted = normalizeUserCode(code); + const formatted = code.trim().replace(/-/g, "").toUpperCase(); if (!formatted) { setError("Enter the device code to continue"); return; diff --git a/web/components/github/github-repo-selector.tsx b/web/components/github/github-repo-selector.tsx index 04179728..5ad14e4d 100644 --- a/web/components/github/github-repo-selector.tsx +++ b/web/components/github/github-repo-selector.tsx @@ -26,11 +26,6 @@ const fetcher = (url: string) => fetch(url).then((res) => res.json()); const EMPTY_REPOS: GitHubRepo[] = []; -function getValidGitHubRepoName(url: string) { - const match = url.match(/^https:\/\/github\.com\/([^/]+\/[^/]+)\/?$/); - return match ? match[1] : null; -} - export function GitHubRepoSelector({ value, onChange, @@ -61,7 +56,8 @@ export function GitHubRepoSelector({ }, [repos, search]); const publicRepoFromSearch = useMemo(() => { - const repoName = getValidGitHubRepoName(search); + const match = search.match(/^https:\/\/github\.com\/([^/]+\/[^/]+)\/?$/); + const repoName = match ? match[1] : null; if (!repoName) return null; const alreadyInList = repos.some( (r) => r.fullName.toLowerCase() === repoName.toLowerCase(), diff --git a/web/components/settings/api-key-settings.tsx b/web/components/settings/api-key-settings.tsx index 36206cd2..b80a4f4d 100644 --- a/web/components/settings/api-key-settings.tsx +++ b/web/components/settings/api-key-settings.tsx @@ -87,19 +87,6 @@ function formatDate(value: string | Date | null) { return dateTimeFormatter.format(date); } -function describeSource(apiKey: ApiKeyRecord) { - const source = apiKey.metadata?.creationSource; - if (source === "techulus-cli") return "CLI"; - if (source === "dashboard") return "Dashboard"; - return "Manual"; -} - -function getKeyPreview(apiKey: ApiKeyRecord) { - if (apiKey.start) return `${apiKey.start}••••`; - if (apiKey.prefix) return `${apiKey.prefix}••••`; - return "Hidden"; -} - export function ApiKeySettings() { const [apiKeys, setApiKeys] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -227,68 +214,85 @@ export function ApiKeySettings() { ) : (
- {sortedApiKeys.map((apiKey, index) => ( -
0 ? "border-t" : "" - }`} - > -
-
-

- {apiKey.name ?? "Untitled key"} + {sortedApiKeys.map((apiKey, index) => { + const creationSource = apiKey.metadata?.creationSource; + const sourceLabel = + creationSource === "techulus-cli" + ? "CLI" + : creationSource === "dashboard" + ? "Dashboard" + : "Manual"; + const keyPreview = apiKey.start + ? `${apiKey.start}••••` + : apiKey.prefix + ? `${apiKey.prefix}••••` + : "Hidden"; + + return ( +

0 ? "border-t" : "" + }`} + > +
+
+

+ {apiKey.name ?? "Untitled key"} +

+ + {apiKey.enabled ? "Active" : "Disabled"} + + {sourceLabel} +
+

+ {keyPreview}

- - {apiKey.enabled ? "Active" : "Disabled"} - - {describeSource(apiKey)}
-

- {getKeyPreview(apiKey)} -

-
-
-

Created

-

{formatDate(apiKey.createdAt)}

-
-
-

Last used

-

{formatDate(apiKey.lastRequest)}

+
+

Created

+

{formatDate(apiKey.createdAt)}

+
+
+

Last used

+

{formatDate(apiKey.lastRequest)}

+
+ + } + > + + Revoke + + + + + Revoke {apiKey.name ?? "this API key"}? + + + Any script or CLI using this key will stop working + immediately. This cannot be undone. + + + + Cancel + void handleRevoke(apiKey)} + disabled={revokingId === apiKey.id} + > + {revokingId === apiKey.id + ? "Revoking..." + : "Revoke"} + + + +
- - } - > - - Revoke - - - - - Revoke {apiKey.name ?? "this API key"}? - - - Any script or CLI using this key will stop working - immediately. This cannot be undone. - - - - Cancel - void handleRevoke(apiKey)} - disabled={revokingId === apiKey.id} - > - {revokingId === apiKey.id ? "Revoking..." : "Revoke"} - - - - -
- ))} + ); + })}
)}
diff --git a/web/components/settings/global-settings.tsx b/web/components/settings/global-settings.tsx index 189ef3ce..e5cb40c5 100644 --- a/web/components/settings/global-settings.tsx +++ b/web/components/settings/global-settings.tsx @@ -100,13 +100,6 @@ const dateTimeFormatter = new Intl.DateTimeFormat(undefined, { const CONTROL_PLANE_UPGRADE_DOCS_URL = "https://docs.techulus.com/installation#manual-upgrades"; -function formatCheckedAt(value: string | null | undefined) { - if (!value) return "Never"; - const date = new Date(value); - if (Number.isNaN(date.getTime())) return "Unknown"; - return dateTimeFormatter.format(date); -} - export function GlobalSettings({ servers, membersData, @@ -310,6 +303,13 @@ export function GlobalSettings({ const updateState = initialSettings.controlPlaneUpdateState; const upgradeState = initialSettings.controlPlaneUpgradeState; const displayVersion = updateState?.currentVersion ?? appVersion ?? "dev"; + const checkedAtLabel = (() => { + if (!updateState?.checkedAt) return "Never"; + const date = new Date(updateState.checkedAt); + return Number.isNaN(date.getTime()) + ? "Unknown" + : dateTimeFormatter.format(date); + })(); const upgradeRunning = upgradeState?.status === "running"; return ( @@ -582,9 +582,7 @@ export function GlobalSettings({

Last checked

-

- {formatCheckedAt(updateState?.checkedAt)} -

+

{checkedAtLabel}

From a622398090a75c90e9483e2b36f84c719f1f8642 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Fri, 10 Jul 2026 07:52:37 +1000 Subject: [PATCH 4/5] Simplify checked-at label formatting --- web/components/settings/global-settings.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/components/settings/global-settings.tsx b/web/components/settings/global-settings.tsx index e5cb40c5..889adb09 100644 --- a/web/components/settings/global-settings.tsx +++ b/web/components/settings/global-settings.tsx @@ -303,13 +303,13 @@ export function GlobalSettings({ const updateState = initialSettings.controlPlaneUpdateState; const upgradeState = initialSettings.controlPlaneUpgradeState; const displayVersion = updateState?.currentVersion ?? appVersion ?? "dev"; - const checkedAtLabel = (() => { - if (!updateState?.checkedAt) return "Never"; - const date = new Date(updateState.checkedAt); - return Number.isNaN(date.getTime()) + let checkedAtLabel = "Never"; + if (updateState?.checkedAt) { + const checkedAt = new Date(updateState.checkedAt); + checkedAtLabel = Number.isNaN(checkedAt.getTime()) ? "Unknown" - : dateTimeFormatter.format(date); - })(); + : dateTimeFormatter.format(checkedAt); + } const upgradeRunning = upgradeState?.status === "running"; return ( From 28e7b34e11cee439787af469ad5f88b58fbc510a Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Fri, 10 Jul 2026 07:57:43 +1000 Subject: [PATCH 5/5] Use const checked-at label formatting --- web/components/settings/global-settings.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/components/settings/global-settings.tsx b/web/components/settings/global-settings.tsx index 889adb09..7f994059 100644 --- a/web/components/settings/global-settings.tsx +++ b/web/components/settings/global-settings.tsx @@ -303,13 +303,14 @@ export function GlobalSettings({ const updateState = initialSettings.controlPlaneUpdateState; const upgradeState = initialSettings.controlPlaneUpgradeState; const displayVersion = updateState?.currentVersion ?? appVersion ?? "dev"; - let checkedAtLabel = "Never"; - if (updateState?.checkedAt) { - const checkedAt = new Date(updateState.checkedAt); - checkedAtLabel = Number.isNaN(checkedAt.getTime()) + const checkedAt = updateState?.checkedAt + ? new Date(updateState.checkedAt) + : null; + const checkedAtLabel = !checkedAt + ? "Never" + : Number.isNaN(checkedAt.getTime()) ? "Unknown" : dateTimeFormatter.format(checkedAt); - } const upgradeRunning = upgradeState?.status === "running"; return (