flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

Observability gets its own page; tabs never overflow

Deployments had grown eight views, logs and errors among them, which are not deploying. It keeps what ships (Deployments, Environments, Releases, Feature flags); Observability is its own page in the menu (Logs, Errors, Uptime, Analytics), as Vercel has it. Soon tabs are marked with a dot instead of a pill, tab bars never show a scrollbar, and Soon pages under a project's tabs drop the breadcrumb the tabs already give.

syntaqxcommitted Parent3d8defbBrowse files
5 files+27−170/5 viewed
+4−0
11 import {
2+ Activity,
23 ArrowLeft,
34 GanttChart,
45 KanbanSquare,
496497 Deployments
497498 </SidebarLink>
498499 ) : null}
500+ <SidebarSoonLink to={`${base}/soon/logs`} also={soonPaths(base, "Observability")} icon={<Activity size={15} />} about="Logs, errors, uptime and analytics of the project's deployed apps.">
501+ Observability
502+ </SidebarSoonLink>
499503 <SidebarSoonLink to={`${base}/soon/security`} also={soonPaths(base, "Security")} icon={<ShieldCheck size={15} />} about="Findings, secret scanning, dependency updates and code scanning, each fixed by an agent.">
500504 Security
501505 </SidebarSoonLink>
+1−0
5252 key: "Deployments",
5353 tabs: [{ label: "Deployments", path: "deployments", members: true }, ...soon("Deployments")],
5454 },
55+ { key: "Observability", tabs: soon("Observability") },
5556 { key: "Security", tabs: soon("Security") },
5657 { key: "Insights", tabs: soon("Insights") },
5758 ];
+7−7
1515 * Where it lives: a project page whose tabs it joins, or the workspace,
1616 * for what spans projects (boards, the roadmap, packages, the fleet).
1717 */
18− section: "Code" | "Issues" | "Agents" | "Deployments" | "Security" | "Insights" | "Workspace";
18+ section: "Code" | "Issues" | "Agents" | "Deployments" | "Observability" | "Security" | "Insights" | "Workspace";
1919 /** One line, for the menu's tooltip and the page's lead. */
2020 summary: string;
2121 /** Why it matters, in two or three sentences. */
273273 // --- Observe ------------------------------------------------------------
274274 {
275275 key: "logs",
276− title: "Logs and metrics",
277− section: "Deployments",
276+ title: "Logs",
277+ section: "Observability",
278278 summary: "Requests, errors and CPU time of each deployment, and its logs.",
279279 why: "Every deployed app's logs and numbers, by deployment, so a regression points at the change that caused it.",
280280 plans: ["Live and searchable logs", "Requests, errors, latency and CPU by deployment", "Compare a preview with production"],
282282 },
283283 {
284284 key: "errors",
285− title: "Errors and incidents",
286− section: "Deployments",
285+ title: "Errors",
286+ section: "Observability",
287287 summary: "Errors from the running app, each becoming an issue an agent can take.",
288288 why: "An error in production should become a fix, not a dashboard. Each new error is grouped, explained, and turned into an issue with the context an agent needs.",
289289 plans: ["Errors grouped with stack and request", "One click to an issue for an agent", "Incidents with a timeline and who was told"],
292292 {
293293 key: "uptime",
294294 title: "Uptime",
295− section: "Deployments",
295+ section: "Observability",
296296 summary: "Checks that the app answers, from around the world.",
297297 why: "Know the app is down before your users tell you, and who was told.",
298298 plans: ["Checks from many places", "Alerts by email and webhook", "A public status page"],
300300 {
301301 key: "analytics",
302302 title: "Web analytics",
303− section: "Deployments",
303+ section: "Observability",
304304 summary: "Who visits the deployed apps, without cookies.",
305305 why: "Visits, pages and referrers for each app, private by design, from Cloudflare's own analytics.",
306306 plans: ["Visits, pages, referrers and countries", "No cookies, no personal data", "Per deployment and per preview"],
+6−4
8484 const current = (tab: PageTab) =>
8585 [tab.path, ...(tab.also ?? [])].some((path) => rest === path || rest.startsWith(`${path}/`));
8686 return (
87− <nav aria-label="Views" className="-mb-px flex gap-1 overflow-x-auto">
87+ <nav aria-label="Views" className="-mb-px flex gap-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
8888 {tabs.map((tab) => (
8989 <NavLink
9090 key={tab.path}
100100 }`}
101101 >
102102 {tab.label}
103+ {/* Soon, said quietly: a dot, with the word for screen readers. */}
103104 {tab.soon && (
104− <span className="rounded-full px-1.5 py-px text-[0.625rem] font-medium tracking-wide text-muted uppercase ring-1 ring-line">
105− Soon
106− </span>
105+ <>
106+ <span aria-hidden="true" className="size-1.5 rounded-full bg-accent/70" />
107+ <span className="sr-only">(soon)</span>
108+ </>
107109 )}
108110 </NavLink>
109111 ))}
+9−6
3737 const inWorkspace = item.section === "Workspace";
3838 return (
3939 <div className="mx-auto max-w-3xl">
40− <p className="flex items-center gap-2 text-sm text-muted">
41− <span>{inWorkspace ? "Across projects" : item.section}</span>
42− <span className="text-line-strong">/</span>
43− <span className="text-fg">{item.title}</span>
44− </p>
45− <div className="mt-4 flex flex-wrap items-center gap-3">
40+ {/* A project's tabs already say where this is; the workspace's need saying. */}
41+ {inWorkspace && (
42+ <p className="mb-4 flex items-center gap-2 text-sm text-muted">
43+ <span>Across projects</span>
44+ <span className="text-line-strong">/</span>
45+ <span className="text-fg">{item.title}</span>
46+ </p>
47+ )}
48+ <div className="flex flex-wrap items-center gap-3">
4649 <h1 className="text-3xl font-semibold tracking-tight">{item.title}</h1>
4750 <span className="inline-flex items-center gap-1.5 rounded-full border border-accent/40 bg-accent/10 px-2.5 py-0.5 text-xs font-medium text-accent">
4851 <Sparkles size={12} />