fabro/apps/fabro-web/app/router.tsx
Bryan Helmkamp 1cdd78926e
Read Usage in the web app and rename the Billing tab to Usage
The run detail tab, route, query hook, and query key say usage. Every
read of input_tokens, output_tokens, total_tokens, reasoning_tokens,
cache_read_tokens, cache_write_tokens, and total_usd_micros moves to
usage.tokens and usage.cost, with lib/usage.ts replacing lib/billing.ts:
totalTokens sums the five buckets, and costSourceTag names a cost that
the provider reported or that was summed from differently sourced parts.
The Usage tab and the stage popover show that tag next to such a cost.

Test fixtures build a Usage through makeUsage; the failing set of the
web tests is unchanged from main (the same 13 environment failures).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 12:40:04 -06:00

182 lines
7.1 KiB
TypeScript

import { createElement } from "react";
import { type RouteObject, useParams } from "react-router";
import Root, { ErrorBoundary as RootErrorBoundary } from "./root";
import * as RedirectHome from "./routes/redirect-home";
import * as Setup from "./routes/setup";
import * as AuthLogin from "./routes/auth-login";
import * as Start from "./routes/start";
import * as ChatsLayout from "./routes/chats-layout";
import * as ChatsNew from "./routes/chats-new";
import * as ChatsDetail from "./routes/chats-detail";
import * as AskFabro from "./routes/ask-fabro";
import * as Automations from "./routes/automations";
import * as AutomationsNew from "./routes/automations-new";
import * as AutomationsEdit from "./routes/automations-edit";
import * as AutomationDetail from "./routes/automation-detail";
import * as Runs from "./routes/runs";
import * as RunDetail from "./routes/run-detail";
import * as RunOverview from "./routes/run-overview";
import * as RunStages from "./routes/run-stages";
import * as RunSettings from "./routes/run-settings";
import * as RunSource from "./routes/run-source";
import * as RunLogs from "./routes/run-logs";
import * as RunEvents from "./routes/run-events";
import * as RunArtifacts from "./routes/run-artifacts";
import * as RunChildren from "./routes/run-children";
import * as RunFiles from "./routes/run-files";
import * as RunSandbox from "./routes/run-sandbox";
import * as RunTerminal from "./routes/run-terminal";
import * as RunUsage from "./routes/run-usage";
import * as Insights from "./routes/insights";
import * as InsightsEditor from "./routes/insights-editor";
import * as InsightsNew from "./routes/insights-new";
import * as Settings from "./routes/settings";
import * as SettingsIndex from "./routes/settings-index";
import * as SettingsGeneral from "./routes/settings-general";
import * as SettingsIntegrations from "./routes/settings-integrations";
import * as SettingsModels from "./routes/settings-models";
import * as SettingsSandboxes from "./routes/settings-sandboxes";
import * as SettingsEnvironments from "./routes/settings-environments";
import * as SettingsEnvironmentsNew from "./routes/settings-environments-new";
import * as SettingsEnvironmentsEdit from "./routes/settings-environments-edit";
import * as SettingsMcps from "./routes/settings-mcps";
import * as SettingsMcpsNew from "./routes/settings-mcps-new";
import * as SettingsMcpsEdit from "./routes/settings-mcps-edit";
import * as SettingsSecrets from "./routes/settings-secrets";
import * as SettingsSecretsNew from "./routes/settings-secrets-new";
import * as SettingsVariables from "./routes/settings-variables";
import * as SettingsVariablesNew from "./routes/settings-variables-new";
import * as SettingsVariablesEdit from "./routes/settings-variables-edit";
import * as SettingsMonitoring from "./routes/settings-monitoring";
import * as SettingsSecurity from "./routes/settings-security";
import * as SettingsStorage from "./routes/settings-storage";
import * as SettingsLiveEvents from "./routes/settings-live-events";
import * as Profile from "./routes/profile";
import * as ProfileOverview from "./routes/profile-overview";
import * as ProfileSessions from "./routes/profile-sessions";
import AppShellModule from "./layouts/app-shell";
type RouteModule = {
default: React.ComponentType<any>;
handle?: RouteObject["handle"];
ErrorBoundary?: React.ComponentType<any>;
};
function withRouteModule(module: RouteModule) {
return function WrappedRouteComponent() {
const params = useParams();
return createElement(module.default, { params });
};
}
function route(
path: string,
module: RouteModule,
extra: Omit<RouteObject, "path" | "Component" | "index"> = {},
): RouteObject {
return {
path,
handle: module.handle,
Component: withRouteModule(module),
ErrorBoundary: module.ErrorBoundary,
...extra,
};
}
function indexRoute(module: RouteModule): RouteObject {
return {
index: true,
handle: module.handle,
Component: withRouteModule(module),
ErrorBoundary: module.ErrorBoundary,
};
}
export const routes: RouteObject[] = [
{
path: "/",
Component: Root,
ErrorBoundary: RootErrorBoundary,
children: [
indexRoute(RedirectHome),
route("setup", Setup),
route("login", AuthLogin),
route("runs/:id/terminal", RunTerminal),
{
Component: withRouteModule({
default: AppShellModule,
}),
children: [
route("start", Start),
route("chats", ChatsLayout, {
children: [
route("new", ChatsNew),
route(":chatId", ChatsDetail),
],
}),
route("ask-fabro", AskFabro),
route("automations", Automations),
route("automations/new", AutomationsNew),
route("automations/:id/edit", AutomationsEdit),
route("automations/:id", AutomationDetail),
// Backwards-compatible singular automation route used by older links.
route("automation/:id", AutomationDetail),
route("runs", Runs),
route("runs/:id", RunDetail, {
children: [
indexRoute(RunOverview),
route("stages", RunStages),
route("stages/:stageId", RunStages),
route("settings", RunSettings),
route("source", RunSource),
route("logs", RunLogs),
route("events", RunEvents),
route("artifacts", RunArtifacts),
route("files", RunFiles),
route("children", RunChildren),
route("sandbox", RunSandbox),
route("usage", RunUsage),
],
}),
route("insights", Insights, {
children: [
indexRoute(InsightsEditor),
route("new", InsightsNew),
],
}),
route("settings", Settings, {
children: [
indexRoute(SettingsIndex),
route("models", SettingsModels),
route("integrations", SettingsIntegrations),
route("sandboxes", SettingsSandboxes),
route("security", SettingsSecurity),
route("environments", SettingsEnvironments),
route("environments/new", SettingsEnvironmentsNew),
route("environments/:id/edit", SettingsEnvironmentsEdit),
route("mcps", SettingsMcps),
route("mcps/new", SettingsMcpsNew),
route("mcps/:id/edit", SettingsMcpsEdit),
route("variables", SettingsVariables),
route("variables/new", SettingsVariablesNew),
route("variables/:name/edit", SettingsVariablesEdit),
route("secrets", SettingsSecrets),
route("secrets/new", SettingsSecretsNew),
route("server", SettingsGeneral),
route("storage", SettingsStorage),
route("monitoring", SettingsMonitoring),
route("live-events", SettingsLiveEvents),
],
}),
route("profile", Profile, {
children: [
indexRoute(ProfileOverview),
route("sessions", ProfileSessions),
],
}),
],
},
],
},
];