fix(site): simplify prerelease css (#24514)

> 🤖 This PR was modified by Coder Agent on behalf of Jake Howell

Removes the bottom-line navbar effect in `<NavbarView />` and cleans up
prerelease CSS.

- Remove `relative` from `<NavbarView />` as it was redundant with the
`sticky` class.
- Refactor `getPrereleaseFlag` to simplify version classification.
- Clean up unused prerelease CSS from `index.css`.

<img width="920" height="83" alt="image"
src="https://github.com/user-attachments/assets/84e351e6-d7a2-4fe2-a331-27c651266256"
/>
This commit is contained in:
Jake Howell
2026-04-21 02:11:25 +10:00
committed by GitHub
parent 2f0d715e9f
commit 3b561dcea9
6 changed files with 127 additions and 147 deletions
-44
View File
@@ -156,50 +156,6 @@
}
}
@layer components {
/* Map each stripe variant to a color token so the
pseudo-element rules can stay DRY. */
.navbar-stripe-devel {
--stripe-color: var(--content-warning);
}
.navbar-stripe-rc {
--stripe-color: var(--border-sky);
}
/* Thin stripe bars at the top and bottom edges of the
navbar. Using pseudo-elements keeps the stripes out of
the content area so nav links stay readable. */
.navbar-stripe-devel::before,
.navbar-stripe-devel::after,
.navbar-stripe-rc::before,
.navbar-stripe-rc::after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 4px;
background: repeating-linear-gradient(
-45deg,
transparent,
transparent 4px,
hsl(var(--stripe-color) / 0.5) 4px,
hsl(var(--stripe-color) / 0.5) 8px
);
pointer-events: none;
}
.navbar-stripe-devel::before,
.navbar-stripe-rc::before {
top: 0;
}
.navbar-stripe-devel::after,
.navbar-stripe-rc::after {
bottom: 0;
}
}
@layer base {
* {
@apply border-border;
@@ -16,7 +16,7 @@ import type { ProxyContextValue } from "#/contexts/ProxyContext";
import { useEmbeddedMetadata } from "#/hooks/useEmbeddedMetadata";
import { useDashboard } from "#/modules/dashboard/useDashboard";
import { NotificationsInbox } from "#/modules/notifications/NotificationsInbox/NotificationsInbox";
import { isDevBuild, isRcBuild } from "#/utils/buildInfo";
import { getPrereleaseFlag } from "#/utils/buildInfo";
import { cn } from "#/utils/cn";
import { DeploymentDropdown } from "./DeploymentDropdown";
import { MobileMenu } from "./MobileMenu";
@@ -61,16 +61,27 @@ export const NavbarView: FC<NavbarViewProps> = ({
canCreateChat,
proxyContextValue,
}) => {
const isDev = buildInfo ? isDevBuild(buildInfo) : false;
const isRc = buildInfo ? isRcBuild(buildInfo) : false;
const isPreRelease = isDev || isRc;
const prerelease = getPrereleaseFlag(buildInfo);
return (
<div
className={cn(
"sticky top-0 bg-surface-primary z-40 border-0 border-b border-solid h-[72px] min-h-[72px] flex items-center leading-none px-6 relative",
isRc ? "navbar-stripe-rc" : isDev ? "navbar-stripe-devel" : undefined,
"sticky top-0 bg-surface-primary z-40 border-0 border-b border-solid h-[72px] min-h-[72px] flex items-center leading-none px-6",
prerelease &&
cn(
"[&:before]:content-[''] [&:before]:absolute [&:before]:left-0",
"[&:before]:right-0 [&:before]:h-1 [&:before]:top-0",
"[&:before]:bg-[repeating-linear-gradient(-45deg,_transparent,_transparent_4px,_hsl(var(--stripe-color)_/_0.5)_4px,_hsl(var(--stripe-color)_/_0.5)_8px)]",
),
)}
style={{
"--stripe-color":
prerelease === "rc"
? "var(--border-sky)"
: prerelease === "devel"
? "var(--content-warning)"
: undefined,
}}
>
<NavLink to="/workspaces">
{logo_url ? (
@@ -82,7 +93,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
<NavItems className="ml-4" user={user} canCreateChat={canCreateChat} />
{isPreRelease && buildInfo?.version && (
{prerelease && buildInfo?.version && (
<a
href={buildInfo.external_url}
target="_blank"
@@ -90,7 +101,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
className="absolute top-0 left-1/2 -translate-x-1/2 no-underline z-10"
>
<Badge
variant={isRc ? "info" : "warning"}
variant={prerelease === "rc" ? "info" : "warning"}
size="sm"
className="font-mono rounded-t-none border-t-0"
>
@@ -262,8 +273,9 @@ function idleTasksLabel(count: number) {
const AgentsNavItem: FC<{ canCreateChat: boolean }> = ({ canCreateChat }) => {
const { experiments, buildInfo } = useDashboard();
const prerelease = getPrereleaseFlag(buildInfo);
const experimentEnabled =
experiments.includes("agents") || isDevBuild(buildInfo);
experiments.includes("agents") || prerelease === "devel";
if (!experimentEnabled || !canCreateChat) {
return null;
@@ -7,7 +7,7 @@ import {
} from "#/components/Sidebar/Sidebar";
import { Stack } from "#/components/Stack/Stack";
import type { Permissions } from "#/modules/permissions";
import { isDevBuild } from "#/utils/buildInfo";
import { getPrereleaseFlag } from "#/utils/buildInfo";
interface DeploymentSidebarViewProps {
/** Site-wide permissions. */
@@ -54,7 +54,8 @@ export const DeploymentSidebarView: FC<DeploymentSidebarViewProps> = ({
</SidebarNavItem>
)}
{permissions.viewDeploymentConfig &&
(experiments.includes("oauth2") || isDevBuild(buildInfo)) && (
(experiments.includes("oauth2") ||
getPrereleaseFlag(buildInfo) === "devel") && (
<SidebarNavItem href="/deployment/oauth2-provider/apps">
OAuth2 Applications
</SidebarNavItem>
+3 -2
View File
@@ -18,7 +18,7 @@ import {
SidebarNavItem,
} from "#/components/Sidebar/Sidebar";
import { useDashboard } from "#/modules/dashboard/useDashboard";
import { isDevBuild } from "#/utils/buildInfo";
import { getPrereleaseFlag } from "#/utils/buildInfo";
interface SidebarProps {
user: User;
@@ -45,7 +45,8 @@ export const Sidebar: FC<SidebarProps> = ({ user }) => {
<SidebarNavItem href="external-auth" icon={GitIcon}>
External Authentication
</SidebarNavItem>
{(experiments.includes("oauth2") || isDevBuild(buildInfo)) && (
{(experiments.includes("oauth2") ||
getPrereleaseFlag(buildInfo) === "devel") && (
<SidebarNavItem href="oauth2-provider" icon={ShieldIcon}>
OAuth2 Applications
</SidebarNavItem>
+81 -72
View File
@@ -1,5 +1,5 @@
import type { BuildInfoResponse } from "#/api/typesGenerated";
import { isDevBuild, isRcBuild } from "./buildInfo";
import { getPrereleaseFlag } from "./buildInfo";
const baseBuildInfo: BuildInfoResponse = {
agent_api_version: "1.0",
@@ -13,88 +13,97 @@ const baseBuildInfo: BuildInfoResponse = {
telemetry: false,
};
describe("isDevBuild", () => {
it("returns true for -devel versions", () => {
describe("getPrereleaseFlag", () => {
it("returns devel for -devel versions", () => {
expect(
isDevBuild({ ...baseBuildInfo, version: "v2.16.0-devel+abc123" }),
).toBe(true);
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.16.0-devel+abc123",
}),
).toBe("devel");
});
it("returns true for bare -devel versions", () => {
expect(isDevBuild({ ...baseBuildInfo, version: "v2.32.0-devel" })).toBe(
true,
);
});
it("returns true for v0.0.0", () => {
expect(isDevBuild({ ...baseBuildInfo, version: "v0.0.0" })).toBe(true);
});
it("returns false for release versions", () => {
expect(isDevBuild({ ...baseBuildInfo, version: "v2.16.0" })).toBe(false);
});
it("returns false for RC versions", () => {
expect(isDevBuild({ ...baseBuildInfo, version: "v2.32.0-rc.1" })).toBe(
false,
);
});
it("returns true for combined rc+devel versions", () => {
it("returns devel for bare -devel versions", () => {
expect(
isDevBuild({
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-devel",
}),
).toBe("devel");
});
it("returns devel for v0.0.0", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v0.0.0",
}),
).toBe("devel");
});
it("returns undefined for release versions", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.16.0",
}),
).toBeUndefined();
});
it("returns rc for RC versions", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-rc.1",
}),
).toBe("rc");
});
it("returns devel when version contains both rc and -devel (devel wins)", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.33.0-rc.1-devel+727ec00f7",
}),
).toBe(true);
).toBe("devel");
});
it("returns false for empty version", () => {
expect(isDevBuild({ ...baseBuildInfo, version: "" })).toBe(false);
});
});
describe("isRcBuild", () => {
it("returns true for -rc.0 versions", () => {
expect(isRcBuild({ ...baseBuildInfo, version: "v2.32.0-rc.0" })).toBe(true);
});
it("returns true for -rc.1 with build metadata", () => {
it("returns undefined for empty version", () => {
expect(
isRcBuild({ ...baseBuildInfo, version: "v2.32.0-rc.1+abc123" }),
).toBe(true);
});
it("returns true for higher RC numbers", () => {
expect(isRcBuild({ ...baseBuildInfo, version: "v2.32.0-rc.12" })).toBe(
true,
);
});
it("returns false for release versions", () => {
expect(isRcBuild({ ...baseBuildInfo, version: "v2.16.0" })).toBe(false);
});
it("returns false for devel versions", () => {
expect(
isRcBuild({ ...baseBuildInfo, version: "v2.16.0-devel+abc123" }),
).toBe(false);
});
it("returns false for empty version", () => {
expect(isRcBuild({ ...baseBuildInfo, version: "" })).toBe(false);
});
it("returns false for versions with rc but no dot", () => {
expect(isRcBuild({ ...baseBuildInfo, version: "v2.32.0-rc" })).toBe(false);
});
it("returns true for combined rc+devel versions", () => {
expect(
isRcBuild({
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.33.0-rc.1-devel+727ec00f7",
version: "",
}),
).toBe(true);
).toBeUndefined();
});
it("returns rc for -rc.0 and build metadata", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-rc.0",
}),
).toBe("rc");
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-rc.1+abc123",
}),
).toBe("rc");
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-rc.12",
}),
).toBe("rc");
});
it("returns undefined when rc segment lacks a dot", () => {
expect(
getPrereleaseFlag({
...baseBuildInfo,
version: "v2.32.0-rc",
}),
).toBeUndefined();
});
});
+19 -18
View File
@@ -23,27 +23,28 @@ export const getStaticBuildInfo = () => {
return CACHED_BUILD_INFO;
};
// Check if the current build is a development build.
// Development builds have versions containing "-devel" or "v0.0.0".
// This matches the backend's buildinfo.IsDev() logic.
export const isDevBuild = (input: BuildInfoResponse): boolean => {
const version = input.version;
if (!version) {
return false;
type PrereleaseFlag = "devel" | "rc" | undefined;
/** Classifies the dashboard build version for dev vs RC styling and experiments. */
export const getPrereleaseFlag = (
input?: BuildInfoResponse,
): PrereleaseFlag => {
// If no input is provided, return undefined.
if (!input) {
return undefined;
}
const version = input.version;
// Check for dev version pattern (contains "-devel") or no version (v0.0.0)
return version.includes("-devel") || version === "v0.0.0";
};
// Check if the current build is a release candidate. Release
// candidates have versions containing "-rc." (e.g. v2.32.0-rc.0,
// v2.32.0-rc.1+abc123, v2.33.0-rc.1-devel+727ec00f7).
export const isRcBuild = (input: BuildInfoResponse): boolean => {
const version = input.version;
if (!version) {
return false;
if (version.includes("-devel") || version === "v0.0.0") {
return "devel";
}
return version.includes("-rc.");
// Check if the current build is a release candidate. Release
// candidates have versions containing "-rc." (e.g. v2.32.0-rc.0,
// v2.32.0-rc.1+abc123, v2.33.0-rc.1-devel+727ec00f7).
if (version.includes("-rc.")) {
return "rc";
}
};