Commit

Fixes from the page sweep

- Deployments no longer show the paid-plan pitch to a workspace on the g1t plan or comped: it looked for a 'deployments' feature billing no longer has. - Usage shows a comped workspace as comped, not $0.00 of credit to add to. - Mission control's screen-reader table no longer widens the page. - The landing page's fact cards keep their top edge: a border, above the hero's fade.

syntaqxcommitted Parentd51c0c2Browse files
4 files+72−500/4 viewed
+4−3
269269 <div aria-hidden="true" className="h-16 bg-gradient-to-b from-transparent to-bg" />
270270 </section>
271271
272− {/* Facts, each one true today. */}
273− <section className="mx-auto max-w-6xl px-4">
274− <dl className="grid gap-px overflow-hidden rounded-2xl bg-line ring-1 ring-line sm:grid-cols-2 lg:grid-cols-4">
272+ {/* Facts, each one true today. Above the hero's fade, with a border of
273+ its own: a ring is a shadow, and the fade drew over its top edge. */}
274+ <section className="relative z-10 mx-auto max-w-6xl px-4">
275+ <dl className="grid gap-px overflow-hidden rounded-2xl border border-line bg-line sm:grid-cols-2 lg:grid-cols-4">
275276 {FACTS.map(([figure, about]) => (
276277 <div key={figure} className="bg-bg px-6 py-6">
277278 <dt className="font-mono text-2xl font-medium tracking-tight text-fg">{figure}</dt>
+23−20
526526 <span className="size-2 rounded-sm bg-info" /> People
527527 </span>
528528 </div>
529− <table className="sr-only">
530− <caption>Changes landed each day</caption>
531− <thead>
532− <tr>
533− <th>Day</th>
534− <th>Agents, on their own</th>
535− <th>Agents, merged by a person</th>
536− <th>People</th>
537− </tr>
538− </thead>
539− <tbody>
540− {week.days.map((day) => (
541− <tr key={day.key}>
542− <td>{day.key}</td>
543− <td>{day.agents}</td>
544− <td>{day.assisted}</td>
545− <td>{day.people}</td>
529+ {/* A table does not shrink to sr-only's 1px; its wrapper does. */}
530+ <div className="sr-only">
531+ <table>
532+ <caption>Changes landed each day</caption>
533+ <thead>
534+ <tr>
535+ <th>Day</th>
536+ <th>Agents, on their own</th>
537+ <th>Agents, merged by a person</th>
538+ <th>People</th>
546539 </tr>
547− ))}
548− </tbody>
549− </table>
540+ </thead>
541+ <tbody>
542+ {week.days.map((day) => (
543+ <tr key={day.key}>
544+ <td>{day.key}</td>
545+ <td>{day.agents}</td>
546+ <td>{day.assisted}</td>
547+ <td>{day.people}</td>
548+ </tr>
549+ ))}
550+ </tbody>
551+ </table>
552+ </div>
550553 </div>
551554 );
552555 }
+7−3
3434 ]);
3535 // Set not to deploy, in General settings: turning them on waits for that to change.
3636 const notDeploying = project?.ok ? project.value.deploys === "no" : false;
37− // Someone outside the workspace does not see its plans; the page works without.
38− const plan = features.ok ? (features.value.find((state) => state.plan.feature === "deployments") ?? null) : null;
37+ // Deployments come with the g1t plan. Someone outside the workspace does
38+ // not see its plans; the page works without, and the deployments service
39+ // refuses a deploy the plan does not cover.
40+ const plan = features.ok
41+ ? (features.value.find((state) => state.plan.feature === "plan" || state.plan.feature === "deployments") ?? null)
42+ : null;
3943 return { can: access.can, settings: unwrap(settings), ...unwrap(list), plan, computeNote, notDeploying };
4044 }
4145
106110 {!actionData && <ComputeNote note={loaderData.computeNote} />}
107111 </div>
108112
109− {!plan?.on ? (
113+ {plan != null && !plan.on && !plan.included && live.length === 0 ? (
110114 <PlanNeeded plan={plan} owner={params.owner} />
111115 ) : !settings.enabled ? (
112116 <section className="mt-2 rounded-xl border border-accent/30 bg-accent/5 p-6">
+38−24
44 import { MICROS_PER_DOLLAR, type UsageSlice } from "@g1t/contracts";
55
66 import type { Route } from "./+types/usage";
7−import { foldTasks, usageTask } from "../../lib/billing";
7+import { foldTasks, planStatus, usageTask } from "../../lib/billing";
88 import { page } from "../../lib/meta";
99 import { ButtonLink } from "../../components/ui";
1010 import { billing } from "../../lib/services.server";
3838 const asked = new URL(request.url).searchParams.get("period");
3939 const period: Period = asked && asked in PERIODS ? (asked as Period) : "month";
4040 const since = start(period);
41− const [usage, account] = await Promise.all([
41+ const [usage, account, features, entitlements] = await Promise.all([
4242 billing.usage(params.owner, viewer, since.toISOString()),
4343 billing.account(params.owner, viewer),
44+ billing.features(params.owner, viewer).catch(() => null),
45+ billing.entitlements(params.owner).catch(() => null),
4446 ]);
45− return { period, since: since.toISOString(), usage: unwrap(usage), account: unwrap(account) };
47+ const plan = features?.ok ? (features.value.find((state) => state.plan.feature === "plan") ?? null) : null;
48+ // A comped workspace is charged nothing, so it has no credit to run down.
49+ const comped = planStatus(plan, entitlements).kind === "comped";
50+ return { period, since: since.toISOString(), usage: unwrap(usage), account: unwrap(account), comped };
4651 }
4752
4853 function dollars(micros: number, digits = 2): string {
180185 }
181186
182187 export default function UsagePage({ loaderData, params }: Route.ComponentProps) {
183− const { period, since, usage, account } = loaderData;
188+ const { period, since, usage, account, comped } = loaderData;
184189 const byTask = foldTasks(usage.byTask);
185190 const base = `/${params.owner}`;
186191 const days = Math.max(1, Math.ceil((Date.now() - new Date(since).getTime()) / 86_400_000));
232237 value={usage.runs ? dollars(total / usage.runs, 3) : "—"}
233238 note="Making a change, reviewing, revising…"
234239 />
235− <div className="rounded-2xl bg-surface p-5 ring-1 ring-line">
236− <p className="flex items-center justify-between text-sm text-muted">
237− Credit left
238− {!usage.free && (
239− <Link to={`${base}/-/billing`} className="text-xs text-accent hover:underline">
240− Add credit
241− </Link>
242− )}
243− </p>
244− <p className={`mt-2 text-3xl font-semibold tracking-tight tabular-nums ${account.balanceMicros <= 0 ? "text-warn" : ""}`}>
245− {dollars(account.balanceMicros)}
246− </p>
247− <p className="mt-1 text-xs text-faint">
248− {usage.free
249− ? "Not drawn down while g1t is free."
250− : runway == null
251− ? "Nothing spent in this period."
252− : `About ${runway} ${runway === 1 ? "day" : "days"} at this rate.`}
253− </p>
254− </div>
240+ {comped ? (
241+ // Nothing is charged to a comped workspace: no credit to run down.
242+ <div className="rounded-2xl bg-surface p-5 ring-1 ring-line">
243+ <p className="text-sm text-muted">Credit</p>
244+ <p className="mt-2 text-3xl font-semibold tracking-tight text-accent">Comped</p>
245+ <p className="mt-1 text-xs text-faint">Recorded at what it costs; nothing is charged to this workspace.</p>
246+ </div>
247+ ) : (
248+ <div className="rounded-2xl bg-surface p-5 ring-1 ring-line">
249+ <p className="flex items-center justify-between text-sm text-muted">
250+ Credit left
251+ {!usage.free && (
252+ <Link to={`${base}/-/billing`} className="text-xs text-accent hover:underline">
253+ Add credit
254+ </Link>
255+ )}
256+ </p>
257+ <p className={`mt-2 text-3xl font-semibold tracking-tight tabular-nums ${account.balanceMicros <= 0 ? "text-warn" : ""}`}>
258+ {dollars(account.balanceMicros)}
259+ </p>
260+ <p className="mt-1 text-xs text-faint">
261+ {usage.free
262+ ? "Not drawn down while g1t is free."
263+ : runway == null
264+ ? "Nothing spent in this period."
265+ : `About ${runway} ${runway === 1 ? "day" : "days"} at this rate.`}
266+ </p>
267+ </div>
268+ )}
255269 </div>
256270
257271 <section className="rounded-2xl bg-surface p-5 ring-1 ring-line">