Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Updated NextJS to version 15. [#477](https://github.com/sourcebot-dev/sourcebot/pull/477)

## [4.6.4] - 2025-08-11

### Added
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@
"dotenv-cli": "^8.0.0",
"npm-run-all": "^4.1.5"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"resolutions": {
"prettier": "3.5.3"
}
}
2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@types/micromatch": "^4.0.9",
"@types/node": "^22.7.5",
"cross-env": "^7.0.3",
"json-schema-to-typescript": "^15.0.2",
"json-schema-to-typescript": "^15.0.4",
"tsc-watch": "^6.2.0",
"tsx": "^4.19.1",
"typescript": "^5.6.2",
Expand Down
1 change: 1 addition & 0 deletions packages/web/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# shadcn components
src/components/
next-env.d.ts
2 changes: 2 additions & 0 deletions packages/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const nextConfig = {
},
]
},

turbopack: {}
};

export default withSentryConfig(nextConfig, {
Expand Down
32 changes: 19 additions & 13 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "next dev --turbopack",
"build": "cross-env SKIP_ENV_VALIDATION=1 next build",
"start": "next start",
"lint": "cross-env SKIP_ENV_VALIDATION=1 next lint",
"lint": "cross-env SKIP_ENV_VALIDATION=1 eslint .",
"test": "vitest",
"dev:emails": "email dev --dir ./src/emails",
"stripe:listen": "stripe listen --forward-to http://localhost:3000/api/stripe"
Expand Down Expand Up @@ -146,7 +146,7 @@
"langfuse-vercel": "^3.38.4",
"lucide-react": "^0.517.0",
"micromatch": "^4.0.8",
"next": "14.2.30",
"next": "15.5.0",
"next-auth": "^5.0.0-beta.25",
"next-navigation-guard": "^0.2.0",
"next-themes": "^0.3.0",
Expand All @@ -157,9 +157,9 @@
"posthog-js": "^1.161.5",
"pretty-bytes": "^6.1.1",
"psl": "^1.15.0",
"react": "^18",
"react": "19.1.1",
"react-device-detect": "^2.2.3",
"react-dom": "^18",
"react-dom": "19.1.1",
"react-hook-form": "^7.53.0",
"react-hotkeys-hook": "^4.5.1",
"react-icons": "^5.3.0",
Expand Down Expand Up @@ -187,21 +187,23 @@
"zod-to-json-schema": "^3.24.5"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tanstack/eslint-plugin-query": "^5.74.7",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.0",
"@types/micromatch": "^4.0.9",
"@types/node": "^20",
"@types/nodemailer": "^6.4.17",
"@types/psl": "^1.1.3",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0",
"@types/react": "19.1.10",
"@types/react-dom": "19.1.7",
"@typescript-eslint/eslint-plugin": "^8.40.0",
"@typescript-eslint/parser": "^8.40.0",
"cross-env": "^7.0.3",
"eslint": "^8",
"eslint-config-next": "14.2.6",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-config-next": "15.5.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"jsdom": "^25.0.1",
"npm-run-all": "^4.1.5",
"postcss": "^8",
Expand All @@ -211,5 +213,9 @@
"typescript": "^5",
"vite-tsconfig-paths": "^5.1.3",
"vitest": "^2.1.5"
},
"resolutions": {
"@types/react": "19.1.10",
"@types/react-dom": "19.1.7"
}
}
6 changes: 3 additions & 3 deletions packages/web/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export const withTenancyModeEnforcement = async<T>(mode: TenancyMode, fn: () =>

////// Actions ///////

export const createOrg = (name: string, domain: string): Promise<{ id: number } | ServiceError> => sew(() =>
export const createOrg = async (name: string, domain: string): Promise<{ id: number } | ServiceError> => sew(() =>
withTenancyModeEnforcement('multi', () =>
withAuth(async (userId) => {
const org = await prisma.org.create({
Expand Down Expand Up @@ -293,7 +293,7 @@ export const completeOnboarding = async (domain: string): Promise<{ success: boo
})
));

export const getSecrets = (domain: string): Promise<{ createdAt: Date; key: string; }[] | ServiceError> => sew(() =>
export const getSecrets = async (domain: string): Promise<{ createdAt: Date; key: string; }[] | ServiceError> => sew(() =>
withAuth((userId) =>
withOrgMembership(userId, domain, async ({ org }) => {
const secrets = await prisma.secret.findMany({
Expand Down Expand Up @@ -1990,7 +1990,7 @@ export const rejectAccountRequest = async (requestId: string, domain: string) =>
));

export const dismissMobileUnsupportedSplashScreen = async () => sew(async () => {
await cookies().set(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, 'true');
await (await cookies()).set(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, 'true');
return true;
});

Expand Down
8 changes: 7 additions & 1 deletion packages/web/src/app/[domain]/agents/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ const agents = [
},
];

export default function AgentsPage({ params: { domain } }: { params: { domain: string } }) {
export default async function AgentsPage(props: { params: Promise<{ domain: string }> }) {
const params = await props.params;

const {
domain
} = params;

return (
<div className="flex flex-col items-center overflow-hidden min-h-screen">
<NavigationMenu domain={domain} />
Expand Down
13 changes: 10 additions & 3 deletions packages/web/src/app/[domain]/browse/[...path]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ import { Loader2 } from "lucide-react";
import { TreePreviewPanel } from "./components/treePreviewPanel";

interface BrowsePageProps {
params: {
params: Promise<{
path: string[];
domain: string;
};
}>;
}

export default async function BrowsePage({ params: { path: _rawPath, domain } }: BrowsePageProps) {
export default async function BrowsePage(props: BrowsePageProps) {
const params = await props.params;

const {
path: _rawPath,
domain
} = params;

const rawPath = decodeURIComponent(_rawPath.join('/'));
const { repoName, revisionName, path, pathType } = getBrowseParamsFromPathParam(rawPath);

Expand Down
7 changes: 4 additions & 3 deletions packages/web/src/app/[domain]/chat/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { ChatSidePanel } from '../components/chatSidePanel';
import { ResizablePanelGroup } from '@/components/ui/resizable';

interface PageProps {
params: {
params: Promise<{
domain: string;
id: string;
};
}>;
}

export default async function Page({ params }: PageProps) {
export default async function Page(props: PageProps) {
const params = await props.params;
const languageModels = await getConfiguredLanguageModelsInfo();
const repos = await getRepos(params.domain);
const searchContexts = await getSearchContexts(params.domain);
Expand Down
7 changes: 4 additions & 3 deletions packages/web/src/app/[domain]/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import { auth } from "@/auth";
import { AnimatedResizableHandle } from "@/components/ui/animatedResizableHandle";

interface PageProps {
params: {
params: Promise<{
domain: string;
};
}>;
}

export default async function Page({ params }: PageProps) {
export default async function Page(props: PageProps) {
const params = await props.params;
const languageModels = await getConfiguredLanguageModelsInfo();
const repos = await getRepos(params.domain);
const searchContexts = await getSearchContexts(params.domain);
Expand Down
55 changes: 30 additions & 25 deletions packages/web/src/app/[domain]/components/navigationMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,43 +57,48 @@ export const NavigationMenu = async ({
<NavigationMenuBase>
<NavigationMenuList>
<NavigationMenuItem>
<Link href={`/${domain}`} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Search
</NavigationMenuLink>
</Link>
<NavigationMenuLink
href={`/${domain}`}
className={navigationMenuTriggerStyle()}
>
Search
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<Link href={`/${domain}/repos`} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Repositories
</NavigationMenuLink>
</Link>
<NavigationMenuLink
href={`/${domain}/repos`}
className={navigationMenuTriggerStyle()}
>
Repositories
</NavigationMenuLink>
</NavigationMenuItem>
{isAuthenticated && (
<>
{env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === undefined && (
<NavigationMenuItem>
<Link href={`/${domain}/agents`} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Agents
</NavigationMenuLink>
</Link>
<NavigationMenuLink
href={`/${domain}/agents`}
className={navigationMenuTriggerStyle()}
>
Agents
</NavigationMenuLink>
</NavigationMenuItem>
)}
<NavigationMenuItem>
<Link href={`/${domain}/connections`} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Connections
</NavigationMenuLink>
</Link>
<NavigationMenuLink
href={`/${domain}/connections`}
className={navigationMenuTriggerStyle()}
>
Connections
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<Link href={`/${domain}/settings`} legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Settings
</NavigationMenuLink>
</Link>
<NavigationMenuLink
href={`/${domain}/settings`}
className={navigationMenuTriggerStyle()}
>
Settings
</NavigationMenuLink>
</NavigationMenuItem>
</>
)}
Expand Down
12 changes: 7 additions & 5 deletions packages/web/src/app/[domain]/connections/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ import { CodeHostType } from "@/lib/utils"
import { env } from "@/env.mjs"

interface ConnectionManagementPageProps {
params: {
params: Promise<{
domain: string
id: string
},
searchParams: {
}>,
searchParams: Promise<{
tab: string
}
}>
}

export default async function ConnectionManagementPage({ params, searchParams }: ConnectionManagementPageProps) {
export default async function ConnectionManagementPage(props: ConnectionManagementPageProps) {
const searchParams = await props.searchParams;
const params = await props.params;
const connection = await getConnectionByDomain(Number(params.id), params.domain);
if (!connection) {
return <NotFound className="flex w-full h-full items-center justify-center" message="Connection not found" />
Expand Down
23 changes: 17 additions & 6 deletions packages/web/src/app/[domain]/connections/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ import { auth } from "@/auth";
import { NavigationMenu } from "../components/navigationMenu";
import { redirect } from "next/navigation";

export default async function Layout({
children,
params: { domain },
}: Readonly<{
interface LayoutProps {
children: React.ReactNode;
params: { domain: string };
}>) {
params: Promise<{ domain: string }>;
}

export default async function Layout(
props: LayoutProps
) {
const params = await props.params;

const {
domain
} = params;

const {
children
} = props;

const session = await auth();
if (!session) {
return redirect(`/${domain}`);
Expand Down
9 changes: 4 additions & 5 deletions packages/web/src/app/[domain]/connections/new/[type]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import {
BitbucketCloudConnectionCreationForm,
BitbucketDataCenterConnectionCreationForm
} from "@/app/[domain]/components/connectionCreationForms";
import { useCallback } from "react";
import { useCallback, use } from "react";
import { useDomain } from "@/hooks/useDomain";

export default function NewConnectionPage({
params
}: { params: { type: string } }) {
export default function NewConnectionPage(props: { params: Promise<{ type: string }> }) {
const params = use(props.params);
const { type } = params;
const router = useRouter();
const domain = useDomain();
Expand Down Expand Up @@ -46,7 +45,7 @@ export default function NewConnectionPage({
if (type === 'bitbucket-server') {
return <BitbucketDataCenterConnectionCreationForm onCreated={onCreated} />;
}


router.push(`/${domain}/connections`);
}
10 changes: 8 additions & 2 deletions packages/web/src/app/[domain]/connections/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@ import { notFound, ServiceErrorException } from "@/lib/serviceError";
import { OrgRole } from "@sourcebot/db";
import { env } from "@/env.mjs";

export default async function ConnectionsPage({ params: { domain } }: { params: { domain: string } }) {
export default async function ConnectionsPage(props: { params: Promise<{ domain: string }> }) {
const params = await props.params;

const {
domain
} = params;

const connections = await getConnections(domain);
if (isServiceError(connections)) {
throw new ServiceErrorException(connections);
}

const membership = await getOrgMembership(domain);
if (isServiceError(membership)) {
return notFound();
throw new ServiceErrorException(notFound());
}

return (
Expand Down
Loading