Skip to content

Commit

A project's sidebar lists what is coming as rows of its own: Analytics, Firewall and Flags sit among Deployments, Observability and Security as faint rows with Soon, each leading to its page of what it will do, instead of hiding as tabs inside Insights, Security and Deployments. They show to members only, as the pages they will become are for the people running the project. Environments, Uptime, Delivery and Costs stay Soon tabs of the pages they belong to. A Soon page's breadcrumb names the feature rather than "Soon", and "Also coming" lists the other two in the sidebar's order. Checked: the site's typecheck and its 913 tests, and the real shell and Soon route rendered at 1440 and 390 px for a member and a visitor (each row current on its own page only, Soon pills aligned with the counts).

syntaqxcommitted Parentd6d966fBrowse files
3 files+46−240/3 viewed
+20−1
1−import { Activity, BarChart3, Building2, MessagesSquare, Bell, BookMarked, BookOpen, Bookmark, Blocks, Box, Check, ChevronDown, ChevronLeft, ChevronRight, CircleDot, GripVertical, CircleUserRound, Code2, Compass, CreditCard, Fingerprint, Gauge, GitBranch, GitPullRequest, Globe, History, Keyboard, KeyRound, Layers, LayoutDashboard, LayoutGrid, LifeBuoy, Lock, LogOut, Mail, MonitorCog, MonitorDown, Package, PlayCircle, Plug, Plus, Rocket, Search, ServerCog, Settings, Shapes, Shield, ShieldCheck, Scale, Smile, Sparkles, Star, House, Ticket, TrendingUp, UserPlus, UserRoundKey, Users, UsersRound, Webhook, X } from "lucide-react";
1+import { Activity, BarChart3, BrickWall, Building2, ChartLine, Flag, MessagesSquare, Bell, BookMarked, BookOpen, Bookmark, Blocks, Box, Check, ChevronDown, ChevronLeft, ChevronRight, CircleDot, GripVertical, CircleUserRound, Code2, Compass, CreditCard, Fingerprint, Gauge, GitBranch, GitPullRequest, Globe, History, Keyboard, KeyRound, Layers, LayoutDashboard, LayoutGrid, LifeBuoy, Lock, LogOut, Mail, MonitorCog, MonitorDown, Package, PlayCircle, Plug, Plus, Rocket, Search, ServerCog, Settings, Shapes, Shield, ShieldCheck, Scale, Smile, Sparkles, Star, House, Ticket, TrendingUp, UserPlus, UserRoundKey, Users, UsersRound, Webhook, X } from "lucide-react";
22 import { Fragment, type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
33 import { Link, useFetcher, useLocation, useNavigation, useRouteLoaderData, useSubmit } from "react-router";
44
740740 const INSIGHTS = roadmapItem("insights");
741741
742742 /**
743+ * A page a project will have that is a page of its own, not a tab: its own
744+ * faint row in the project's list, leading to what it will be.
745+ */
746+function ProjectSoonRow({ base, feature, icon }: { base: string; feature: string; icon: ReactNode }) {
747+ const item = roadmapItem(feature);
748+ if (!item) return null;
749+ return (
750+ <SidebarSoonLink to={`${base}/soon/${item.key}`} icon={icon} about={item.summary}>
751+ {item.title}
752+ </SidebarSoonLink>
753+ );
754+}
755+
756+/**
743757 * What the repository menu needs. Known from the address before the page's
744758 * data arrives, so the menu is right from the first frame; the counts fill
745759 * in once it does.
835849 Deployments
836850 </SidebarLink>
837851 ) : null}
852+ {repo.member && <ProjectSoonRow base={base} feature="analytics" icon={<ChartLine size={15} />} />}
838853 {shows.has("observability") && (
839854 <SidebarLink to={`${base}/observability`} also={soonPaths(base, "Observability")} icon={<Activity size={15} />}>
840855 Observability
841856 </SidebarLink>
842857 )}
858+ {repo.member && <ProjectSoonRow base={base} feature="firewall" icon={<BrickWall size={15} />} />}
859+ {repo.member && <ProjectSoonRow base={base} feature="flags" icon={<Flag size={15} />} />}
843860 {shows.has("security") ? (
844861 <SidebarLink to={`${base}/security`} also={soonPaths(base, "Security")} icon={<ShieldCheck size={15} />}>
845862 Security
16171634 if (third === "pull" && fourth) trail.push({ label: `Pull request #${fourth}`, short: `#${fourth}`, to: `${repo}/pull/${fourth}` });
16181635 else if (third === "issues" && fourth && fourth !== "new") trail.push({ label: `Issue #${fourth}`, short: `#${fourth}`, to: `${repo}/issues/${fourth}` });
16191636 else if (third === "commit" && fourth) trail.push({ label: fourth.slice(0, 7), to: `${repo}/commit/${fourth}`, mono: true });
1637+ // A Soon page names what is coming.
1638+ else if (third === "soon" && fourth && roadmapItem(fourth)) trail.push({ label: roadmapItem(fourth)!.title, to: `${repo}/soon/${fourth}` });
16201639 else if (third && SECTIONS[third]) {
16211640 trail.push({ label: SECTIONS[third]!, to: `${repo}/${third}` });
16221641 // A settings page names which one: Settings / Secrets and variables.
+25−22
1212 key: string;
1313 title: string;
1414 /**
15− * Where it lives: a project page whose tabs it joins, or the workspace,
16− * for what spans projects (Insights).
15+ * Where it lives: a project page whose tabs it joins, a page of its own
16+ * in the project's sidebar ("Project"), or the workspace, for what spans
17+ * projects (Insights).
1718 */
18− section: "Code" | "Issues" | "Deployments" | "Observability" | "Security" | "Insights" | "Workspace";
19+ section: "Code" | "Issues" | "Deployments" | "Observability" | "Security" | "Insights" | "Project" | "Workspace";
1920 /** One line, for the menu's tooltip and the page's lead. */
2021 summary: string;
2122 /** Why it matters, in two or three sentences. */
5960 ],
6061 today: { label: "Deployments", path: "deployments" },
6162 },
63+
64+ // --- Pages of their own in the project's sidebar ----------------------
65+ {
66+ key: "analytics",
67+ title: "Analytics",
68+ section: "Project",
69+ summary: "Who visits the deployed apps, without cookies.",
70+ why: "Visits, pages and referrers for each app, private by design, from Cloudflare's own analytics.",
71+ plans: ["Visits, pages, referrers and countries", "No cookies, no personal data", "Per deployment and per preview"],
72+ },
6273 {
74+ key: "firewall",
75+ title: "Firewall",
76+ section: "Project",
77+ summary: "Rules for who may reach the project's deployed apps.",
78+ why: "Deployed apps run on Cloudflare. Rate limits, bot protection and IP rules, per app and environment.",
79+ plans: ["Rate limits and bot protection", "IP and country rules", "Password-protected previews"],
80+ today: { label: "Deployments", path: "deployments" },
81+ },
82+ {
6383 key: "flags",
64− title: "Feature flags",
65− section: "Deployments",
84+ title: "Flags",
85+ section: "Project",
6686 summary: "Turn features on per environment or per user, without a deploy.",
6787 why: "Ship code dark and turn it on when ready, for some users first, at the edge, with no deploy.",
6888 plans: ["Flags read at the edge by deployed apps", "Rollouts by percentage, user or environment", "Reminders to clean up flags once fully on"],
7292 // --- Security -------------------------------------------------------------
7393 // The overview, secret scanning, code scanning, vulnerabilities and the
7494 // dependency graph are built: see routes/repo/security-*.tsx.
75− {
76− key: "firewall",
77− title: "Firewall",
78− section: "Security",
79− summary: "Rules for who may reach the project's deployed apps.",
80− why: "Deployed apps run on Cloudflare. Rate limits, bot protection and IP rules, per app and environment.",
81− plans: ["Rate limits and bot protection", "IP and country rules", "Password-protected previews"],
82− today: { label: "Deployments", path: "deployments" },
83− },
8495
8596 // --- Observe ------------------------------------------------------------
8697 {
90101 summary: "Checks that the app answers, from around the world.",
91102 why: "Know the app is down before your users tell you, and who was told.",
92103 plans: ["Checks from many places", "Alerts by email and webhook", "A public status page"],
93− },
94− {
95− key: "analytics",
96− title: "Web analytics",
97− section: "Insights",
98− summary: "Who visits the deployed apps, without cookies.",
99− why: "Visits, pages and referrers for each app, private by design, from Cloudflare's own analytics.",
100− plans: ["Visits, pages, referrers and countries", "No cookies, no personal data", "Per deployment and per preview"],
101104 },
102105
103106 // --- Insights -------------------------------------------------------------
+1−1
143143 {siblings.length > 0 && (
144144 <section className="mt-10">
145145 <h2 className="text-sm font-medium text-muted">
146− Also coming {inWorkspace ? "across projects" : `to ${item.section}`}
146+ Also coming {inWorkspace ? "across projects" : item.section === "Project" ? "to every project" : `to ${item.section}`}
147147 </h2>
148148 <ul className="mt-3 grid gap-3 sm:grid-cols-2">
149149 {siblings.map((other) => (