mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 12:25:22 +00:00
chore(web): Add count to members / requests / invites tabs in settings (#621)
Some checks failed
Update Roadmap Released / update (push) Has been cancelled
Publish to ghcr / build (linux/amd64, blacksmith-4vcpu-ubuntu-2404) (push) Has been cancelled
Publish to ghcr / build (linux/arm64, blacksmith-8vcpu-ubuntu-2204-arm) (push) Has been cancelled
Publish to ghcr / merge (push) Has been cancelled
Some checks failed
Update Roadmap Released / update (push) Has been cancelled
Publish to ghcr / build (linux/amd64, blacksmith-4vcpu-ubuntu-2404) (push) Has been cancelled
Publish to ghcr / build (linux/arm64, blacksmith-8vcpu-ubuntu-2204-arm) (push) Has been cancelled
Publish to ghcr / merge (push) Has been cancelled
This commit is contained in:
parent
831197980c
commit
97dd54d48f
4 changed files with 71 additions and 39 deletions
|
|
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added counts to members, requets, and invites tabs in the members settings. [#621](https://github.com/sourcebot-dev/sourcebot/pull/621)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed spurious infinite loads with explore panel, file tree, and file search command. [#617](https://github.com/sourcebot-dev/sourcebot/pull/617)
|
- Fixed spurious infinite loads with explore panel, file tree, and file search command. [#617](https://github.com/sourcebot-dev/sourcebot/pull/617)
|
||||||
- Wipe search context on init if entitlement no longer exists [#618](https://github.com/sourcebot-dev/sourcebot/pull/618)
|
- Wipe search context on init if entitlement no longer exists [#618](https://github.com/sourcebot-dev/sourcebot/pull/618)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConnectionStats, getRepos, getReposStats } from "@/actions";
|
import { getConnectionStats, getCurrentUserRole, getOrgAccountRequests, getRepos, getReposStats } from "@/actions";
|
||||||
import { SourcebotLogo } from "@/app/components/sourcebotLogo";
|
import { SourcebotLogo } from "@/app/components/sourcebotLogo";
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -10,7 +10,7 @@ import { env } from "@sourcebot/shared";
|
||||||
import { ServiceErrorException } from "@/lib/serviceError";
|
import { ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
|
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||||
import { RepoIndexingJobStatus, RepoIndexingJobType } from "@sourcebot/db";
|
import { OrgRole, RepoIndexingJobStatus, RepoIndexingJobType } from "@sourcebot/db";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { OrgSelector } from "../orgSelector";
|
import { OrgSelector } from "../orgSelector";
|
||||||
|
|
@ -39,11 +39,32 @@ export const NavigationMenu = async ({
|
||||||
throw new ServiceErrorException(repoStats);
|
throw new ServiceErrorException(repoStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
const connectionStats = isAuthenticated ? await getConnectionStats() : null;
|
const role = isAuthenticated ? await getCurrentUserRole(domain) : null;
|
||||||
if (isServiceError(connectionStats)) {
|
if (isServiceError(role)) {
|
||||||
throw new ServiceErrorException(connectionStats);
|
throw new ServiceErrorException(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stats = await (async () => {
|
||||||
|
if (!isAuthenticated || role !== OrgRole.OWNER) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const joinRequests = await getOrgAccountRequests(domain);
|
||||||
|
if (isServiceError(joinRequests)) {
|
||||||
|
throw new ServiceErrorException(joinRequests);
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectionStats = await getConnectionStats();
|
||||||
|
if (isServiceError(connectionStats)) {
|
||||||
|
throw new ServiceErrorException(connectionStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
numJoinRequests: joinRequests.length,
|
||||||
|
connectionStats,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
const sampleRepos = await getRepos({
|
const sampleRepos = await getRepos({
|
||||||
where: {
|
where: {
|
||||||
jobs: {
|
jobs: {
|
||||||
|
|
@ -100,9 +121,10 @@ export const NavigationMenu = async ({
|
||||||
numberOfRepos={numberOfRepos}
|
numberOfRepos={numberOfRepos}
|
||||||
isReposButtonNotificationDotVisible={numberOfReposWithFirstTimeIndexingJobsInProgress > 0}
|
isReposButtonNotificationDotVisible={numberOfReposWithFirstTimeIndexingJobsInProgress > 0}
|
||||||
isSettingsButtonNotificationDotVisible={
|
isSettingsButtonNotificationDotVisible={
|
||||||
connectionStats ?
|
stats ? (
|
||||||
connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0 :
|
stats.connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0 ||
|
||||||
false
|
stats.numJoinRequests > 0
|
||||||
|
) : false
|
||||||
}
|
}
|
||||||
isAuthenticated={isAuthenticated}
|
isAuthenticated={isAuthenticated}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export default async function SettingsLayout(
|
||||||
throw new ServiceErrorException(connectionStats);
|
throw new ServiceErrorException(connectionStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing");
|
const hasPermissionSyncingEntitlement = hasEntitlement("permission-syncing");
|
||||||
|
|
||||||
const sidebarNavItems: SidebarNavItem[] = [
|
const sidebarNavItems: SidebarNavItem[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -89,16 +89,8 @@ export default async function SettingsLayout(
|
||||||
}
|
}
|
||||||
] : []),
|
] : []),
|
||||||
...(userRoleInOrg === OrgRole.OWNER ? [{
|
...(userRoleInOrg === OrgRole.OWNER ? [{
|
||||||
title: (
|
title:"Members",
|
||||||
<div className="flex items-center gap-2">
|
isNotificationDotVisible: numJoinRequests !== undefined && numJoinRequests > 0,
|
||||||
Members
|
|
||||||
{numJoinRequests !== undefined && numJoinRequests > 0 && (
|
|
||||||
<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">
|
|
||||||
{numJoinRequests}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
href: `/${domain}/settings/members`,
|
href: `/${domain}/settings/members`,
|
||||||
}] : []),
|
}] : []),
|
||||||
...(userRoleInOrg === OrgRole.OWNER ? [
|
...(userRoleInOrg === OrgRole.OWNER ? [
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import { getSeats, SOURCEBOT_UNLIMITED_SEATS } from "@sourcebot/shared";
|
||||||
import { RequestsList } from "./components/requestsList";
|
import { RequestsList } from "./components/requestsList";
|
||||||
import { OrgRole } from "@prisma/client";
|
import { OrgRole } from "@prisma/client";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
import { NotificationDot } from "../../components/notificationDot";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
|
||||||
interface MembersSettingsPageProps {
|
interface MembersSettingsPageProps {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
|
|
@ -106,32 +108,45 @@ export default async function MembersSettingsPage(props: MembersSettingsPageProp
|
||||||
<TabSwitcher
|
<TabSwitcher
|
||||||
className="h-auto p-0 bg-transparent"
|
className="h-auto p-0 bg-transparent"
|
||||||
tabs={[
|
tabs={[
|
||||||
{ label: "Team Members", value: "members" },
|
|
||||||
...(userRoleInOrg === OrgRole.OWNER ? [
|
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
Pending Requests
|
Team Members
|
||||||
{requests.length > 0 && (
|
<Badge variant="secondary" className="px-1.5 relative">
|
||||||
<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">
|
{members.length}
|
||||||
{requests.length}
|
</Badge>
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
value: "requests"
|
value: "members"
|
||||||
},
|
},
|
||||||
{
|
...(userRoleInOrg === OrgRole.OWNER ? [
|
||||||
label: (
|
{
|
||||||
<div className="flex items-center gap-2">
|
label: (
|
||||||
Pending Invites
|
<div className="flex items-center gap-2">
|
||||||
{invites.length > 0 && (
|
{requests.length > 0 && (
|
||||||
<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">
|
<NotificationDot />
|
||||||
{invites.length}
|
)}
|
||||||
</span>
|
Pending Requests
|
||||||
)}
|
{requests.length > 0 && (
|
||||||
</div>
|
<Badge variant="secondary" className="px-1.5 relative">
|
||||||
),
|
{requests.length}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
value: "requests"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
Pending Invites
|
||||||
|
{invites.length > 0 && (
|
||||||
|
<Badge variant="secondary" className="px-1.5 relative">
|
||||||
|
{invites.length}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
value: "invites"
|
value: "invites"
|
||||||
},
|
},
|
||||||
] : []),
|
] : []),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue