Skip to content

Commit 97dd54d

Browse files
chore(web): Add count to members / requests / invites tabs in settings (#621)
1 parent 8311979 commit 97dd54d

File tree

4 files changed

+71
-39
lines changed

4 files changed

+71
-39
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Added counts to members, requets, and invites tabs in the members settings. [#621](https://github.com/sourcebot-dev/sourcebot/pull/621)
12+
1013
### Fixed
1114
- Fixed spurious infinite loads with explore panel, file tree, and file search command. [#617](https://github.com/sourcebot-dev/sourcebot/pull/617)
1215
- Wipe search context on init if entitlement no longer exists [#618](https://github.com/sourcebot-dev/sourcebot/pull/618)

packages/web/src/app/[domain]/components/navigationMenu/index.tsx

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getConnectionStats, getRepos, getReposStats } from "@/actions";
1+
import { getConnectionStats, getCurrentUserRole, getOrgAccountRequests, getRepos, getReposStats } from "@/actions";
22
import { SourcebotLogo } from "@/app/components/sourcebotLogo";
33
import { auth } from "@/auth";
44
import { Button } from "@/components/ui/button";
@@ -10,7 +10,7 @@ import { env } from "@sourcebot/shared";
1010
import { ServiceErrorException } from "@/lib/serviceError";
1111
import { isServiceError } from "@/lib/utils";
1212
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
13-
import { RepoIndexingJobStatus, RepoIndexingJobType } from "@sourcebot/db";
13+
import { OrgRole, RepoIndexingJobStatus, RepoIndexingJobType } from "@sourcebot/db";
1414
import Link from "next/link";
1515
import { redirect } from "next/navigation";
1616
import { OrgSelector } from "../orgSelector";
@@ -39,11 +39,32 @@ export const NavigationMenu = async ({
3939
throw new ServiceErrorException(repoStats);
4040
}
4141

42-
const connectionStats = isAuthenticated ? await getConnectionStats() : null;
43-
if (isServiceError(connectionStats)) {
44-
throw new ServiceErrorException(connectionStats);
42+
const role = isAuthenticated ? await getCurrentUserRole(domain) : null;
43+
if (isServiceError(role)) {
44+
throw new ServiceErrorException(role);
4545
}
4646

47+
const stats = await (async () => {
48+
if (!isAuthenticated || role !== OrgRole.OWNER) {
49+
return null;
50+
}
51+
52+
const joinRequests = await getOrgAccountRequests(domain);
53+
if (isServiceError(joinRequests)) {
54+
throw new ServiceErrorException(joinRequests);
55+
}
56+
57+
const connectionStats = await getConnectionStats();
58+
if (isServiceError(connectionStats)) {
59+
throw new ServiceErrorException(connectionStats);
60+
}
61+
62+
return {
63+
numJoinRequests: joinRequests.length,
64+
connectionStats,
65+
};
66+
})();
67+
4768
const sampleRepos = await getRepos({
4869
where: {
4970
jobs: {
@@ -100,9 +121,10 @@ export const NavigationMenu = async ({
100121
numberOfRepos={numberOfRepos}
101122
isReposButtonNotificationDotVisible={numberOfReposWithFirstTimeIndexingJobsInProgress > 0}
102123
isSettingsButtonNotificationDotVisible={
103-
connectionStats ?
104-
connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0 :
105-
false
124+
stats ? (
125+
stats.connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0 ||
126+
stats.numJoinRequests > 0
127+
) : false
106128
}
107129
isAuthenticated={isAuthenticated}
108130
/>

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export default async function SettingsLayout(
6969
throw new ServiceErrorException(connectionStats);
7070
}
7171

72-
const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing");
72+
const hasPermissionSyncingEntitlement = hasEntitlement("permission-syncing");
7373

7474
const sidebarNavItems: SidebarNavItem[] = [
7575
{
@@ -89,16 +89,8 @@ export default async function SettingsLayout(
8989
}
9090
] : []),
9191
...(userRoleInOrg === OrgRole.OWNER ? [{
92-
title: (
93-
<div className="flex items-center gap-2">
94-
Members
95-
{numJoinRequests !== undefined && numJoinRequests > 0 && (
96-
<span className="inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-medium text-primary-foreground">
97-
{numJoinRequests}
98-
</span>
99-
)}
100-
</div>
101-
),
92+
title:"Members",
93+
isNotificationDotVisible: numJoinRequests !== undefined && numJoinRequests > 0,
10294
href: `/${domain}/settings/members`,
10395
}] : []),
10496
...(userRoleInOrg === OrgRole.OWNER ? [

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

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { getSeats, SOURCEBOT_UNLIMITED_SEATS } from "@sourcebot/shared";
1313
import { RequestsList } from "./components/requestsList";
1414
import { OrgRole } from "@prisma/client";
1515
import { redirect } from "next/navigation";
16+
import { NotificationDot } from "../../components/notificationDot";
17+
import { Badge } from "@/components/ui/badge";
1618

1719
interface MembersSettingsPageProps {
1820
params: Promise<{
@@ -106,32 +108,45 @@ export default async function MembersSettingsPage(props: MembersSettingsPageProp
106108
<TabSwitcher
107109
className="h-auto p-0 bg-transparent"
108110
tabs={[
109-
{ label: "Team Members", value: "members" },
110-
...(userRoleInOrg === OrgRole.OWNER ? [
111111
{
112112
label: (
113113
<div className="flex items-center gap-2">
114-
Pending Requests
115-
{requests.length > 0 && (
116-
<span className="inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-medium text-primary-foreground">
117-
{requests.length}
118-
</span>
119-
)}
114+
Team Members
115+
<Badge variant="secondary" className="px-1.5 relative">
116+
{members.length}
117+
</Badge>
120118
</div>
121119
),
122-
value: "requests"
120+
value: "members"
123121
},
124-
{
125-
label: (
126-
<div className="flex items-center gap-2">
127-
Pending Invites
128-
{invites.length > 0 && (
129-
<span className="inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-medium text-primary-foreground">
130-
{invites.length}
131-
</span>
132-
)}
133-
</div>
134-
),
122+
...(userRoleInOrg === OrgRole.OWNER ? [
123+
{
124+
label: (
125+
<div className="flex items-center gap-2">
126+
{requests.length > 0 && (
127+
<NotificationDot />
128+
)}
129+
Pending Requests
130+
{requests.length > 0 && (
131+
<Badge variant="secondary" className="px-1.5 relative">
132+
{requests.length}
133+
</Badge>
134+
)}
135+
</div>
136+
),
137+
value: "requests"
138+
},
139+
{
140+
label: (
141+
<div className="flex items-center gap-2">
142+
Pending Invites
143+
{invites.length > 0 && (
144+
<Badge variant="secondary" className="px-1.5 relative">
145+
{invites.length}
146+
</Badge>
147+
)}
148+
</div>
149+
),
135150
value: "invites"
136151
},
137152
] : []),

0 commit comments

Comments
 (0)