Unified · Split
| @@ -105,4 +105,45 @@ it.layer(NodeServices.layer)("UsageService", (it) => { · 104 unmodified lines | |||
| 105 | ), | 105 | ), |
| 106 | ), | 106 | ), |
| 107 | ); | 107 | ); |
| 108 | |||
| 109 | it.effect("uses driver defaults when an enabled instance omits config", () => | ||
| 110 | Effect.gen(function* () { | ||
| 111 | const usage = yield* UsageService.UsageService; | ||
| 112 | const summary = yield* usage.readSummary(summaryInput); | ||
| 113 | |||
| 114 | expect(summary.sources.map((source) => source.fingerprint.provider)).toEqual(["codex"]); | ||
| 115 | }).pipe( | ||
| 116 | Effect.provide( | ||
| 117 | UsageService.layer.pipe( | ||
| 118 | Layer.provideMerge( | ||
| 119 | Layer.mergeAll( | ||
| 120 | ServerSettings.ServerSettingsService.layerTest({ | ||
| 121 | providerInstances: { | ||
| 122 | [ProviderInstanceId.make("claudeAgent")]: { | ||
| 123 | driver: ProviderDriverKind.make("claudeAgent"), | ||
| 124 | enabled: false, | ||
| 125 | config: {}, | ||
| 126 | }, | ||
| 127 | [ProviderInstanceId.make("codex")]: { | ||
| 128 | driver: ProviderDriverKind.make("codex"), | ||
| 129 | enabled: false, | ||
| 130 | config: {}, | ||
| 131 | }, | ||
| 132 | [ProviderInstanceId.make("codex-work")]: { | ||
| 133 | driver: ProviderDriverKind.make("codex"), | ||
| 134 | enabled: true, | ||
| 135 | }, | ||
| 136 | }, | ||
| 137 | }), | ||
| 138 | ServerConfig.layerTest(process.cwd(), { prefix: "t3-usage-test-" }), | ||
| 139 | Layer.succeed( | ||
| 140 | HttpClient.HttpClient, | ||
| 141 | HttpClient.make(() => Effect.die("unexpected usage pricing request")), | ||
| 142 | ), | ||
| 143 | ), | ||
| 144 | ), | ||
| 145 | ), | ||
| 146 | ), | ||
| 147 | ), | ||
| 148 | ); | ||
| 108 | }); | 149 | }); |
| @@ -234,7 +234,7 @@ export const make = Effect.gen(function* () { · 233 unmodified lines | |||
| 234 | settings, | 234 | settings, |
| 235 | ProviderDriverKind.make("claudeAgent"), | 235 | ProviderDriverKind.make("claudeAgent"), |
| 236 | )) { | 236 | )) { |
| 237 | const config = decodeClaudeSettings(instance.config); | 237 | const config = decodeClaudeSettings(instance.config ?? {}); |
| 238 | if (Option.isNone(config)) continue; | 238 | if (Option.isNone(config)) continue; |
| 239 | const claudeHome = yield* resolveClaudeHomePath(config.value); | 239 | const claudeHome = yield* resolveClaudeHomePath(config.value); |
| 240 | addDir("claude", yield* resolveClaudeTranscriptDir(claudeHome)); | 240 | addDir("claude", yield* resolveClaudeTranscriptDir(claudeHome)); |
| @@ -244,7 +244,7 @@ export const make = Effect.gen(function* () { · 3 unmodified lines | |||
| 244 | settings, | 244 | settings, |
| 245 | ProviderDriverKind.make("codex"), | 245 | ProviderDriverKind.make("codex"), |
| 246 | )) { | 246 | )) { |
| 247 | const config = decodeCodexSettings(instance.config); | 247 | const config = decodeCodexSettings(instance.config ?? {}); |
| 248 | if (Option.isNone(config)) continue; | 248 | if (Option.isNone(config)) continue; |
| 249 | const codexLayout = yield* resolveCodexHomeLayout(config.value); | 249 | const codexLayout = yield* resolveCodexHomeLayout(config.value); |
| 250 | addDir("codex", path.join(codexLayout.sharedHomePath, "sessions")); | 250 | addDir("codex", path.join(codexLayout.sharedHomePath, "sessions")); |
| @@ -62,6 +62,9 @@ export function UsagePage() { · 61 unmodified lines | |||
| 62 | } | 62 | } |
| 63 | return PROVIDER_ORDER.filter((provider) => enabled.has(provider)); | 63 | return PROVIDER_ORDER.filter((provider) => enabled.has(provider)); |
| 64 | }, [environments, merged.staleEnvironments]); | 64 | }, [environments, merged.staleEnvironments]); |
| 65 | const skeletonProviders = environments.some((environment) => environment.summary !== null) | ||
| 66 | ? providers | ||
| 67 | : PROVIDER_ORDER; | ||
| 65 | 68 | ||
| 66 | // Hold the content until every environment is terminal. Rendering merged | 69 | // Hold the content until every environment is terminal. Rendering merged |
| 67 | // totals while devices are still answering makes every number on the page | 70 | // totals while devices are still answering makes every number on the page |
| @@ -214,7 +217,7 @@ export function UsagePage() { · 146 unmodified lines | |||
| 214 | {settling ? ( | 217 | {settling ? ( |
| 215 | <> | 218 | <> |
| 216 | {environments.length > 1 ? <UsageDeviceStrip environments={environments} /> : null} | 219 | {environments.length > 1 ? <UsageDeviceStrip environments={environments} /> : null} |
| 217 | <UsageSkeleton /> | 220 | <UsageSkeleton providers={skeletonProviders} /> |
| 218 | </> | 221 | </> |
| 219 | ) : ( | 222 | ) : ( |
| 220 | <> | 223 | <> |
| @@ -588,7 +591,7 @@ function UsageDeviceStrip({ · 367 unmodified lines | |||
| 588 | * Static stand-in with the loaded page's shape. No shimmer; blocks fill in | 591 | * Static stand-in with the loaded page's shape. No shimmer; blocks fill in |
| 589 | * exactly once when the last device answers. | 592 | * exactly once when the last device answers. |
| 590 | */ | 593 | */ |
| 591 | function UsageSkeleton() { | 594 | function UsageSkeleton({ providers }: { readonly providers: readonly UsageProviderKind[] }) { |
| 592 | return ( | 595 | return ( |
| 593 | <> | 596 | <> |
| 594 | <section className="grid gap-6 lg:grid-cols-[minmax(0,16rem)_minmax(0,1fr)]"> | 597 | <section className="grid gap-6 lg:grid-cols-[minmax(0,16rem)_minmax(0,1fr)]"> |
| @@ -597,7 +600,7 @@ function UsageSkeleton() { · 2 unmodified lines | |||
| 597 | <div className="h-10 w-36 rounded-sm bg-muted" /> | 600 | <div className="h-10 w-36 rounded-sm bg-muted" /> |
| 598 | <div className="h-4 w-32 rounded-sm bg-muted" /> | 601 | <div className="h-4 w-32 rounded-sm bg-muted" /> |
| 599 | </div> | 602 | </div> |
| 600 | {PROVIDER_ORDER.map((provider) => ( | 603 | {providers.map((provider) => ( |
| 601 | <div key={provider} className="flex flex-col gap-1"> | 604 | <div key={provider} className="flex flex-col gap-1"> |
| 602 | <div className="flex min-h-5 items-center justify-between gap-4"> | 605 | <div className="flex min-h-5 items-center justify-between gap-4"> |
| 603 | <span className="flex items-center gap-2"> | 606 | <span className="flex items-center gap-2"> |