Skip to content

Commit 8f82509

Browse files
move analytics and license pages into owner only visibility
1 parent 26e2b63 commit 8f82509

File tree

4 files changed

+79
-19
lines changed

4 files changed

+79
-19
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11-
- Added `GET /api/diff` endpoint for retrieving structured diffs between two git refs ([#1063](https://github.com/sourcebot-dev/sourcebot/pull/1063))
11+
- Added `GET /api/diff` endpoint for retrieving structured diffs between two git refs [#1063](https://github.com/sourcebot-dev/sourcebot/pull/1063)
1212

1313
### Fixed
14-
- Fixed `GET /api/mcp` hanging with zero bytes by returning `405 Method Not Allowed` per the MCP Streamable HTTP spec ([#1064](https://github.com/sourcebot-dev/sourcebot/pull/1064))
14+
- Fixed `GET /api/mcp` hanging with zero bytes by returning `405 Method Not Allowed` per the MCP Streamable HTTP spec [#1064](https://github.com/sourcebot-dev/sourcebot/pull/1064)
1515

1616
### Removed
1717
- Removed "general" settings page with options to change organization name and domain. [#1065](https://github.com/sourcebot-dev/sourcebot/pull/1065)
1818

19+
### Changed
20+
- Changed the analytics and license settings pages to only be viewable by organization owners. [#1065](https://github.com/sourcebot-dev/sourcebot/pull/1065)
21+
1922
## [4.16.3] - 2026-03-27
2023

2124
### Added
Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
1-
"use client"
2-
1+
import { getMe } from "@/actions";
2+
import { getOrgFromDomain } from "@/data/org";
33
import { AnalyticsContent } from "@/ee/features/analytics/analyticsContent";
44
import { AnalyticsEntitlementMessage } from "@/ee/features/analytics/analyticsEntitlementMessage";
5-
import { useHasEntitlement } from "@/features/entitlements/useHasEntitlement";
5+
import { ServiceErrorException } from "@/lib/serviceError";
6+
import { isServiceError } from "@/lib/utils";
7+
import { OrgRole } from "@sourcebot/db";
8+
import { hasEntitlement } from "@sourcebot/shared";
9+
import { redirect } from "next/navigation";
610

7-
export default function AnalyticsPage() {
8-
return <AnalyticsPageContent />;
11+
interface Props {
12+
params: Promise<{
13+
domain: string;
14+
}>
915
}
1016

11-
function AnalyticsPageContent() {
12-
const hasAnalyticsEntitlement = useHasEntitlement("analytics");
17+
export default async function AnalyticsPage(props: Props) {
18+
const params = await props.params;
19+
20+
const {
21+
domain
22+
} = params;
23+
24+
const org = await getOrgFromDomain(domain);
25+
if (!org) {
26+
throw new Error("Organization not found");
27+
}
28+
29+
const me = await getMe();
30+
if (isServiceError(me)) {
31+
throw new ServiceErrorException(me);
32+
}
33+
34+
const userRoleInOrg = me.memberships.find((membership) => membership.id === org.id)?.role;
35+
if (!userRoleInOrg) {
36+
throw new Error("User role not found");
37+
}
38+
39+
if (userRoleInOrg !== OrgRole.OWNER) {
40+
redirect(`/${domain}/settings`);
41+
}
42+
43+
const hasAnalyticsEntitlement = hasEntitlement("analytics");
1344

1445
if (!hasAnalyticsEntitlement) {
1546
return <AnalyticsEntitlementMessage />;
1647
}
1748

1849
return <AnalyticsContent />;
19-
}
50+
}

packages/web/src/app/[domain]/settings/layout.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,23 @@ export const getSidebarNavItems = async () =>
115115
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/apiKeys`,
116116
}
117117
] : []),
118-
{
119-
title: "Analytics",
120-
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/analytics`,
121-
},
118+
...(role === OrgRole.OWNER ? [
119+
{
120+
title: "Analytics",
121+
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/analytics`,
122+
},
123+
] : []),
122124
...(hasEntitlement("sso") ? [
123125
{
124126
title: "Linked Accounts",
125127
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/linked-accounts`,
126128
}
127129
] : []),
128-
{
129-
title: "License",
130-
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/license`,
131-
}
130+
...(role === OrgRole.OWNER ? [
131+
{
132+
title: "License",
133+
href: `/${SINGLE_TENANT_ORG_DOMAIN}/settings/license`,
134+
}
135+
] : []),
132136
]
133137
});

packages/web/src/app/[domain]/settings/license/page.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { getLicenseKey, getEntitlements, getPlan, SOURCEBOT_UNLIMITED_SEATS } from "@sourcebot/shared";
22
import { Button } from "@/components/ui/button";
33
import { Info, Mail } from "lucide-react";
4-
import { getOrgMembers } from "@/actions";
4+
import { getMe, getOrgMembers } from "@/actions";
55
import { isServiceError } from "@/lib/utils";
66
import { ServiceErrorException } from "@/lib/serviceError";
7+
import { getOrgFromDomain } from "@/data/org";
8+
import { OrgRole } from "@sourcebot/db";
9+
import { redirect } from "next/navigation";
710

811
interface LicensePageProps {
912
params: Promise<{
@@ -18,6 +21,25 @@ export default async function LicensePage(props: LicensePageProps) {
1821
domain
1922
} = params;
2023

24+
const org = await getOrgFromDomain(domain);
25+
if (!org) {
26+
throw new Error("Organization not found");
27+
}
28+
29+
const me = await getMe();
30+
if (isServiceError(me)) {
31+
throw new ServiceErrorException(me);
32+
}
33+
34+
const userRoleInOrg = me.memberships.find((membership) => membership.id === org.id)?.role;
35+
if (!userRoleInOrg) {
36+
throw new Error("User role not found");
37+
}
38+
39+
if (userRoleInOrg !== OrgRole.OWNER) {
40+
redirect(`/${domain}/settings`);
41+
}
42+
2143
const licenseKey = getLicenseKey();
2244
const entitlements = getEntitlements();
2345
const plan = getPlan();

0 commit comments

Comments
 (0)