diff --git a/apps/web/src/page/onboarding/create-org.scene.test.ts b/apps/web/src/page/onboarding/create-org.scene.test.ts index b822569aff..4f09756d0f 100644 --- a/apps/web/src/page/onboarding/create-org.scene.test.ts +++ b/apps/web/src/page/onboarding/create-org.scene.test.ts @@ -37,7 +37,7 @@ const member: ClerkOrganization = { homeRegion: "us", isServedHere: true, isRegionOpen: false, - flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false, users: false }, + flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false }, } const view = (model: Model, h: HtmlBuilder): Html => createOrgView(h, model, "david@acme.dev", []) diff --git a/apps/web/src/page/onboarding/plan-gate.test.ts b/apps/web/src/page/onboarding/plan-gate.test.ts index df08046144..c21cf2e497 100644 --- a/apps/web/src/page/onboarding/plan-gate.test.ts +++ b/apps/web/src/page/onboarding/plan-gate.test.ts @@ -13,7 +13,7 @@ const organization: ClerkOrganization = { homeRegion: "us", isServedHere: true, isRegionOpen: false, - flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false, users: false }, + flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false }, } const customerWith = (status: string | null): CustomerSlot => ({ diff --git a/apps/web/src/page/onboarding/wrong-region.scene.test.ts b/apps/web/src/page/onboarding/wrong-region.scene.test.ts index 1a9e80e407..f985ee4554 100644 --- a/apps/web/src/page/onboarding/wrong-region.scene.test.ts +++ b/apps/web/src/page/onboarding/wrong-region.scene.test.ts @@ -15,7 +15,7 @@ const organization: ClerkOrganization = { homeRegion: "eu", isServedHere: false, isRegionOpen: false, - flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false, users: false }, + flags: { aiAutoTriage: false, releases: false, securityAudit: false, statusPages: false }, } const usOrganization: ClerkOrganization = { diff --git a/apps/web/src/platform/clerk.ts b/apps/web/src/platform/clerk.ts index e188c6d3c4..494877c1ce 100644 --- a/apps/web/src/platform/clerk.ts +++ b/apps/web/src/platform/clerk.ts @@ -217,7 +217,6 @@ export const ClerkOrganization = Schema.Struct({ releases: Schema.Boolean, securityAudit: Schema.Boolean, statusPages: Schema.Boolean, - users: Schema.Boolean, }), }) export type ClerkOrganization = typeof ClerkOrganization.Type diff --git a/apps/web/src/route/redirect.ts b/apps/web/src/route/redirect.ts index 813b9acb05..e21bd3f792 100644 --- a/apps/web/src/route/redirect.ts +++ b/apps/web/src/route/redirect.ts @@ -127,13 +127,12 @@ export const routeRedirect = (route: AppRoute): Option.Option => ) const isStatusPageRoute = AppRoute.isAnyOf(["StatusPages", "StatusPageNew", "StatusPage"]) -const isUsersRoute = AppRoute.isAnyOf(["Users", "UserDetail"]) /** A route an org outside its rollout cannot open goes home (`/status-pages` without `statusPages`). */ export const flaggedRouteRedirect = ( route: AppRoute, - flags: Pick, + flags: Pick, ): Option.Option => - (!flags.statusPages && isStatusPageRoute(route)) || (!flags.users && isUsersRoute(route)) + !flags.statusPages && isStatusPageRoute(route) ? redirect(AppRoute.Home({ search: {} }), true) : Option.none() diff --git a/apps/web/src/route/route.test.ts b/apps/web/src/route/route.test.ts index 4775655275..e9d860e27a 100644 --- a/apps/web/src/route/route.test.ts +++ b/apps/web/src/route/route.test.ts @@ -129,27 +129,12 @@ describe("routes", () => { test("an org outside the statusPages rollout is sent home from every status page route", () => { for (const path of ["/status-pages", "/status-pages/new", "/status-pages/stp_abc"]) { - expect(flaggedRouteRedirect(parse(path), { statusPages: false, users: true })).toEqual( + expect(flaggedRouteRedirect(parse(path), { statusPages: false })).toEqual( Option.some({ url: "/", isReplace: true }), ) - expect(flaggedRouteRedirect(parse(path), { statusPages: true, users: true })).toEqual( - Option.none(), - ) - } - expect(flaggedRouteRedirect(parse("/services"), { statusPages: false, users: false })).toEqual( - Option.none(), - ) - }) - - test("an org outside the users rollout is sent home from the users pages", () => { - for (const path of ["/users", "/users/user_42"]) { - expect(flaggedRouteRedirect(parse(path), { statusPages: true, users: false })).toEqual( - Option.some({ url: "/", isReplace: true }), - ) - expect(flaggedRouteRedirect(parse(path), { statusPages: true, users: true })).toEqual( - Option.none(), - ) + expect(flaggedRouteRedirect(parse(path), { statusPages: true })).toEqual(Option.none()) } + expect(flaggedRouteRedirect(parse("/services"), { statusPages: false })).toEqual(Option.none()) }) test("a literal sibling wins over a param route", () => { diff --git a/apps/web/src/shell/nav.test.ts b/apps/web/src/shell/nav.test.ts index 9b4a83fe54..06f48c47f4 100644 --- a/apps/web/src/shell/nav.test.ts +++ b/apps/web/src/shell/nav.test.ts @@ -5,7 +5,7 @@ import { Array as Arr, Option } from "effect" const infrastructure = Option.getOrUndefined( Arr.findFirst( Arr.flatMap( - navGroups({ releases: false, securityAudit: false, statusPages: false, users: false }), + navGroups({ releases: false, securityAudit: false, statusPages: false }), (group) => group.items, ), (item) => item.title === "Infrastructure", @@ -45,7 +45,7 @@ describe("isNavItemActive", () => { ) test("pages without a row of their own highlight their parent row", () => { - const off = { releases: false, securityAudit: false, statusPages: false, users: false } + const off = { releases: false, securityAudit: false, statusPages: false } expect(activeTitles("/anomalies", off)).toEqual(["Alerts"]) expect(activeTitles("/security/code/findings", off)).toEqual(["Code review"]) expect(activeTitles("/releases", off)).toEqual(["Services"]) @@ -53,7 +53,7 @@ describe("isNavItemActive", () => { }) test("a flagged page with its own row highlights only that row", () => { - const on = { releases: true, securityAudit: true, statusPages: true, users: true } + const on = { releases: true, securityAudit: true, statusPages: true } expect(activeTitles("/security", on)).toEqual(["Security"]) expect(activeTitles("/security/code/runs/run_1", on)).toEqual(["Security"]) expect(activeTitles("/releases", on)).toEqual(["Releases"]) @@ -66,17 +66,9 @@ describe("navGroups", () => { Arr.flatMap(navGroups(flags), (group) => Arr.map(group.items, (item) => item.title)) test("the Status pages row shows only for an org in the statusPages rollout", () => { - expect( - titles({ releases: false, securityAudit: false, statusPages: false, users: false }), - ).not.toContain("Status pages") - expect(titles({ releases: false, securityAudit: false, statusPages: true, users: false })).toContain( + expect(titles({ releases: false, securityAudit: false, statusPages: false })).not.toContain( "Status pages", ) - }) - - test("the Users row shows only for an org in the users rollout", () => { - const off = { releases: false, securityAudit: false, statusPages: false, users: false } - expect(titles(off)).not.toContain("Users") - expect(titles({ ...off, users: true })).toContain("Users") + expect(titles({ releases: false, securityAudit: false, statusPages: true })).toContain("Status pages") }) }) diff --git a/apps/web/src/shell/nav.ts b/apps/web/src/shell/nav.ts index 3be2a56a4a..22ded041ce 100644 --- a/apps/web/src/shell/nav.ts +++ b/apps/web/src/shell/nav.ts @@ -134,10 +134,9 @@ export type NavFlags = Readonly<{ releases: boolean securityAudit: boolean statusPages: boolean - users: boolean }> -/** `navGroups(flags)`; `releases`, `securityAudit`, `statusPages` and `users` gate a row each. */ +/** `navGroups(flags)`; `releases`, `securityAudit` and `statusPages` gate a row each. */ export const navGroups = (flags: NavFlags): ReadonlyArray => [ { id: "overview", items: [{ title: "Overview", href: "/", icon: "HouseIcon" }] }, { @@ -166,7 +165,7 @@ export const navGroups = (flags: NavFlags): ReadonlyArray => [ items: [ exploreItem, { title: "Web analytics", href: "/analytics", icon: "ChartBarHorizontalIcon" }, - ...(flags.users ? [{ title: "Users", href: "/users", icon: "UsersIcon" } as const] : []), + { title: "Users", href: "/users", icon: "UsersIcon" }, { title: "Dashboards", href: "/dashboards", icon: "GridSquareCirclePlusIcon" }, ], }, diff --git a/apps/web/src/shell/palette/entries.ts b/apps/web/src/shell/palette/entries.ts index 6c5601f3c8..e013dc0a90 100644 --- a/apps/web/src/shell/palette/entries.ts +++ b/apps/web/src/shell/palette/entries.ts @@ -66,7 +66,7 @@ const href = (url: string): Target => ({ _tag: "Href", href: url }) /** `paletteNavItems`: every section, its children and their views, deduplicated by title and href. */ const navigationEntries = (): ReadonlyArray => { const rows = Arr.flatMap( - navGroups({ releases: true, securityAudit: true, statusPages: true, users: true }), + navGroups({ releases: true, securityAudit: true, statusPages: true }), (group) => Arr.flatMap(group.items, (item) => [ { id: `nav:${item.title}`, title: item.title, href: item.href, icon: item.icon }, diff --git a/apps/web/src/shell/view-nav.ts b/apps/web/src/shell/view-nav.ts index 32068dcfaa..cd7ecc8b0b 100644 --- a/apps/web/src/shell/view-nav.ts +++ b/apps/web/src/shell/view-nav.ts @@ -44,7 +44,6 @@ export const shellNavGroups = (clerk: ShellClerk | null = null): ReadonlyArray { releases: false, securityAudit: false, statusPages: false, - users: false, }, }), memberships: [], diff --git a/packages/domain/src/organization-feature-flags.ts b/packages/domain/src/organization-feature-flags.ts index 88f0104a83..527375d17f 100644 --- a/packages/domain/src/organization-feature-flags.ts +++ b/packages/domain/src/organization-feature-flags.ts @@ -29,15 +29,12 @@ export const OrganizationFeatureFlags = Schema.Struct({ securityAudit: DisabledByDefaultFeatureFlag, /** Gates customer status pages: the nav row, the `/status-pages` routes, the API and MCP tools. */ statusPages: DisabledByDefaultFeatureFlag, - /** Gates the Users row under Analyze and the `/users` routes. */ - users: DisabledByDefaultFeatureFlag, }).pipe( Schema.encodeKeys({ aiAutoTriage: "aiautotriage", releases: "releases", securityAudit: "securityaudit", statusPages: "statuspages", - users: "users", }), ) @@ -51,7 +48,6 @@ export const DISABLED_ORGANIZATION_FEATURE_FLAGS: OrganizationFeatureFlags = { releases: false, securityAudit: false, statusPages: false, - users: false, } /** @@ -65,7 +61,6 @@ export const ENABLED_ORGANIZATION_FEATURE_FLAGS: OrganizationFeatureFlags = { releases: true, securityAudit: true, statusPages: true, - users: true, } /** Decode Clerk metadata, falling back to every rollout disabled for non-object input. */