mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 12:25:22 +00:00
chore(web): Upgrade to NextJS 15 (#477)
This commit is contained in:
parent
b36de3412d
commit
d9fa221d72
45 changed files with 1346 additions and 741 deletions
|
|
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated NextJS to version 15. [#477](https://github.com/sourcebot-dev/sourcebot/pull/477)
|
||||||
|
|
||||||
## [4.6.4] - 2025-08-11
|
## [4.6.4] - 2025-08-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -24,5 +24,8 @@
|
||||||
"dotenv-cli": "^8.0.0",
|
"dotenv-cli": "^8.0.0",
|
||||||
"npm-run-all": "^4.1.5"
|
"npm-run-all": "^4.1.5"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.7.0"
|
"packageManager": "yarn@4.7.0",
|
||||||
|
"resolutions": {
|
||||||
|
"prettier": "3.5.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"json-schema-to-typescript": "^15.0.2",
|
"json-schema-to-typescript": "^15.0.4",
|
||||||
"tsc-watch": "^6.2.0",
|
"tsc-watch": "^6.2.0",
|
||||||
"tsx": "^4.19.1",
|
"tsx": "^4.19.1",
|
||||||
"typescript": "^5.6.2",
|
"typescript": "^5.6.2",
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
# shadcn components
|
# shadcn components
|
||||||
src/components/
|
src/components/
|
||||||
|
next-env.d.ts
|
||||||
|
|
@ -38,6 +38,8 @@ const nextConfig = {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
turbopack: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withSentryConfig(nextConfig, {
|
export default withSentryConfig(nextConfig, {
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev --turbopack",
|
||||||
"build": "cross-env SKIP_ENV_VALIDATION=1 next build",
|
"build": "cross-env SKIP_ENV_VALIDATION=1 next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "cross-env SKIP_ENV_VALIDATION=1 next lint",
|
"lint": "cross-env SKIP_ENV_VALIDATION=1 eslint .",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"dev:emails": "email dev --dir ./src/emails",
|
"dev:emails": "email dev --dir ./src/emails",
|
||||||
"stripe:listen": "stripe listen --forward-to http://localhost:3000/api/stripe"
|
"stripe:listen": "stripe listen --forward-to http://localhost:3000/api/stripe"
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
"langfuse-vercel": "^3.38.4",
|
"langfuse-vercel": "^3.38.4",
|
||||||
"lucide-react": "^0.517.0",
|
"lucide-react": "^0.517.0",
|
||||||
"micromatch": "^4.0.8",
|
"micromatch": "^4.0.8",
|
||||||
"next": "14.2.30",
|
"next": "15.5.0",
|
||||||
"next-auth": "^5.0.0-beta.25",
|
"next-auth": "^5.0.0-beta.25",
|
||||||
"next-navigation-guard": "^0.2.0",
|
"next-navigation-guard": "^0.2.0",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
|
|
@ -157,9 +157,9 @@
|
||||||
"posthog-js": "^1.161.5",
|
"posthog-js": "^1.161.5",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"psl": "^1.15.0",
|
"psl": "^1.15.0",
|
||||||
"react": "^18",
|
"react": "19.1.1",
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^18",
|
"react-dom": "19.1.1",
|
||||||
"react-hook-form": "^7.53.0",
|
"react-hook-form": "^7.53.0",
|
||||||
"react-hotkeys-hook": "^4.5.1",
|
"react-hotkeys-hook": "^4.5.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
|
|
@ -187,21 +187,23 @@
|
||||||
"zod-to-json-schema": "^3.24.5"
|
"zod-to-json-schema": "^3.24.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3",
|
||||||
"@tanstack/eslint-plugin-query": "^5.74.7",
|
"@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/micromatch": "^4.0.9",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/psl": "^1.1.3",
|
"@types/psl": "^1.1.3",
|
||||||
"@types/react": "^18",
|
"@types/react": "19.1.10",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "19.1.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
||||||
"@typescript-eslint/parser": "^8.3.0",
|
"@typescript-eslint/parser": "^8.40.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.6",
|
"eslint-config-next": "15.5.0",
|
||||||
"eslint-plugin-react": "^7.35.0",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
|
@ -211,5 +213,9 @@
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
"vite-tsconfig-paths": "^5.1.3",
|
"vite-tsconfig-paths": "^5.1.3",
|
||||||
"vitest": "^2.1.5"
|
"vitest": "^2.1.5"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@types/react": "19.1.10",
|
||||||
|
"@types/react-dom": "19.1.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ export const withTenancyModeEnforcement = async<T>(mode: TenancyMode, fn: () =>
|
||||||
|
|
||||||
////// Actions ///////
|
////// 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', () =>
|
withTenancyModeEnforcement('multi', () =>
|
||||||
withAuth(async (userId) => {
|
withAuth(async (userId) => {
|
||||||
const org = await prisma.org.create({
|
const org = await prisma.org.create({
|
||||||
|
|
@ -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) =>
|
withAuth((userId) =>
|
||||||
withOrgMembership(userId, domain, async ({ org }) => {
|
withOrgMembership(userId, domain, async ({ org }) => {
|
||||||
const secrets = await prisma.secret.findMany({
|
const secrets = await prisma.secret.findMany({
|
||||||
|
|
@ -1990,7 +1990,7 @@ export const rejectAccountRequest = async (requestId: string, domain: string) =>
|
||||||
));
|
));
|
||||||
|
|
||||||
export const dismissMobileUnsupportedSplashScreen = async () => sew(async () => {
|
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;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
return (
|
||||||
<div className="flex flex-col items-center overflow-hidden min-h-screen">
|
<div className="flex flex-col items-center overflow-hidden min-h-screen">
|
||||||
<NavigationMenu domain={domain} />
|
<NavigationMenu domain={domain} />
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,20 @@ import { Loader2 } from "lucide-react";
|
||||||
import { TreePreviewPanel } from "./components/treePreviewPanel";
|
import { TreePreviewPanel } from "./components/treePreviewPanel";
|
||||||
|
|
||||||
interface BrowsePageProps {
|
interface BrowsePageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
path: string[];
|
path: string[];
|
||||||
domain: 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 rawPath = decodeURIComponent(_rawPath.join('/'));
|
||||||
const { repoName, revisionName, path, pathType } = getBrowseParamsFromPathParam(rawPath);
|
const { repoName, revisionName, path, pathType } = getBrowseParamsFromPathParam(rawPath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@ import { ChatSidePanel } from '../components/chatSidePanel';
|
||||||
import { ResizablePanelGroup } from '@/components/ui/resizable';
|
import { ResizablePanelGroup } from '@/components/ui/resizable';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
domain: string;
|
||||||
id: 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 languageModels = await getConfiguredLanguageModelsInfo();
|
||||||
const repos = await getRepos(params.domain);
|
const repos = await getRepos(params.domain);
|
||||||
const searchContexts = await getSearchContexts(params.domain);
|
const searchContexts = await getSearchContexts(params.domain);
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ import { auth } from "@/auth";
|
||||||
import { AnimatedResizableHandle } from "@/components/ui/animatedResizableHandle";
|
import { AnimatedResizableHandle } from "@/components/ui/animatedResizableHandle";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
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 languageModels = await getConfiguredLanguageModelsInfo();
|
||||||
const repos = await getRepos(params.domain);
|
const repos = await getRepos(params.domain);
|
||||||
const searchContexts = await getSearchContexts(params.domain);
|
const searchContexts = await getSearchContexts(params.domain);
|
||||||
|
|
|
||||||
|
|
@ -57,43 +57,48 @@ export const NavigationMenu = async ({
|
||||||
<NavigationMenuBase>
|
<NavigationMenuBase>
|
||||||
<NavigationMenuList>
|
<NavigationMenuList>
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<Link href={`/${domain}`} legacyBehavior passHref>
|
<NavigationMenuLink
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
href={`/${domain}`}
|
||||||
Search
|
className={navigationMenuTriggerStyle()}
|
||||||
</NavigationMenuLink>
|
>
|
||||||
</Link>
|
Search
|
||||||
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<Link href={`/${domain}/repos`} legacyBehavior passHref>
|
<NavigationMenuLink
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
href={`/${domain}/repos`}
|
||||||
Repositories
|
className={navigationMenuTriggerStyle()}
|
||||||
</NavigationMenuLink>
|
>
|
||||||
</Link>
|
Repositories
|
||||||
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
{isAuthenticated && (
|
{isAuthenticated && (
|
||||||
<>
|
<>
|
||||||
{env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === undefined && (
|
{env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === undefined && (
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<Link href={`/${domain}/agents`} legacyBehavior passHref>
|
<NavigationMenuLink
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
href={`/${domain}/agents`}
|
||||||
Agents
|
className={navigationMenuTriggerStyle()}
|
||||||
</NavigationMenuLink>
|
>
|
||||||
</Link>
|
Agents
|
||||||
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
)}
|
)}
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<Link href={`/${domain}/connections`} legacyBehavior passHref>
|
<NavigationMenuLink
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
href={`/${domain}/connections`}
|
||||||
Connections
|
className={navigationMenuTriggerStyle()}
|
||||||
</NavigationMenuLink>
|
>
|
||||||
</Link>
|
Connections
|
||||||
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<Link href={`/${domain}/settings`} legacyBehavior passHref>
|
<NavigationMenuLink
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
|
href={`/${domain}/settings`}
|
||||||
Settings
|
className={navigationMenuTriggerStyle()}
|
||||||
</NavigationMenuLink>
|
>
|
||||||
</Link>
|
Settings
|
||||||
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,18 @@ import { CodeHostType } from "@/lib/utils"
|
||||||
import { env } from "@/env.mjs"
|
import { env } from "@/env.mjs"
|
||||||
|
|
||||||
interface ConnectionManagementPageProps {
|
interface ConnectionManagementPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string
|
domain: string
|
||||||
id: string
|
id: string
|
||||||
},
|
}>,
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
tab: string
|
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);
|
const connection = await getConnectionByDomain(Number(params.id), params.domain);
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
return <NotFound className="flex w-full h-full items-center justify-center" message="Connection not found" />
|
return <NotFound className="flex w-full h-full items-center justify-center" message="Connection not found" />
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,24 @@ import { auth } from "@/auth";
|
||||||
import { NavigationMenu } from "../components/navigationMenu";
|
import { NavigationMenu } from "../components/navigationMenu";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default async function Layout({
|
interface LayoutProps {
|
||||||
children,
|
|
||||||
params: { domain },
|
|
||||||
}: Readonly<{
|
|
||||||
children: React.ReactNode;
|
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();
|
const session = await auth();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return redirect(`/${domain}`);
|
return redirect(`/${domain}`);
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,11 @@ import {
|
||||||
BitbucketCloudConnectionCreationForm,
|
BitbucketCloudConnectionCreationForm,
|
||||||
BitbucketDataCenterConnectionCreationForm
|
BitbucketDataCenterConnectionCreationForm
|
||||||
} from "@/app/[domain]/components/connectionCreationForms";
|
} from "@/app/[domain]/components/connectionCreationForms";
|
||||||
import { useCallback } from "react";
|
import { useCallback, use } from "react";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
|
|
||||||
export default function NewConnectionPage({
|
export default function NewConnectionPage(props: { params: Promise<{ type: string }> }) {
|
||||||
params
|
const params = use(props.params);
|
||||||
}: { params: { type: string } }) {
|
|
||||||
const { type } = params;
|
const { type } = params;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const domain = useDomain();
|
const domain = useDomain();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@ import { notFound, ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { OrgRole } from "@sourcebot/db";
|
import { OrgRole } from "@sourcebot/db";
|
||||||
import { env } from "@/env.mjs";
|
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);
|
const connections = await getConnections(domain);
|
||||||
if (isServiceError(connections)) {
|
if (isServiceError(connections)) {
|
||||||
throw new ServiceErrorException(connections);
|
throw new ServiceErrorException(connections);
|
||||||
|
|
@ -15,7 +21,7 @@ export default async function ConnectionsPage({ params: { domain } }: { params:
|
||||||
|
|
||||||
const membership = await getOrgMembership(domain);
|
const membership = await getOrgMembership(domain);
|
||||||
if (isServiceError(membership)) {
|
if (isServiceError(membership)) {
|
||||||
return notFound();
|
throw new ServiceErrorException(notFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,20 @@ import { GitHubStarToast } from "./components/githubStarToast";
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
children: React.ReactNode,
|
children: React.ReactNode,
|
||||||
params: { domain: string }
|
params: Promise<{ domain: string }>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout(props: LayoutProps) {
|
||||||
children,
|
const params = await props.params;
|
||||||
params: { domain },
|
|
||||||
}: LayoutProps) {
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
children
|
||||||
|
} = props;
|
||||||
|
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
|
|
||||||
if (!org) {
|
if (!org) {
|
||||||
|
|
@ -39,7 +46,18 @@ export default async function Layout({
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
const anonymousAccessEnabled = hasEntitlement("anonymous-access") && await getAnonymousAccessStatus(domain);
|
const anonymousAccessEnabled = await (async () => {
|
||||||
|
if (!hasEntitlement("anonymous-access")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = await getAnonymousAccessStatus(domain);
|
||||||
|
if (isServiceError(status)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
})();
|
||||||
|
|
||||||
// If the user is authenticated, we must check if they're a member of the org
|
// If the user is authenticated, we must check if they're a member of the org
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,13 @@ import { env } from "@/env.mjs";
|
||||||
import { loadJsonFile } from "@sourcebot/shared";
|
import { loadJsonFile } from "@sourcebot/shared";
|
||||||
import { DemoExamples, demoExamplesSchema } from "@/types";
|
import { DemoExamples, demoExamplesSchema } from "@/types";
|
||||||
|
|
||||||
export default async function Home({ params: { domain } }: { params: { domain: string } }) {
|
export default async function Home(props: { params: Promise<{ domain: string }> }) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
if (!org) {
|
if (!org) {
|
||||||
return <PageNotFound />
|
return <PageNotFound />
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,22 @@
|
||||||
import { NavigationMenu } from "../components/navigationMenu";
|
import { NavigationMenu } from "../components/navigationMenu";
|
||||||
|
|
||||||
export default function Layout({
|
interface LayoutProps {
|
||||||
children,
|
|
||||||
params: { domain },
|
|
||||||
}: Readonly<{
|
|
||||||
children: React.ReactNode;
|
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;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,13 @@ import { PageNotFound } from "../components/pageNotFound";
|
||||||
import { Header } from "../components/header";
|
import { Header } from "../components/header";
|
||||||
import { env } from "@/env.mjs";
|
import { env } from "@/env.mjs";
|
||||||
|
|
||||||
export default async function ReposPage({ params: { domain } }: { params: { domain: string } }) {
|
export default async function ReposPage(props: { params: Promise<{ domain: string }> }) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
if (!org) {
|
if (!org) {
|
||||||
return <PageNotFound />
|
return <PageNotFound />
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,18 @@ import { ErrorCode } from "@/lib/errorCodes";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
|
|
||||||
interface GeneralSettingsPageProps {
|
interface GeneralSettingsPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function GeneralSettingsPage({ params: { domain } }: GeneralSettingsPageProps) {
|
export default async function GeneralSettingsPage(props: GeneralSettingsPageProps) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const currentUserRole = await getCurrentUserRole(domain)
|
const currentUserRole = await getCurrentUserRole(domain)
|
||||||
if (isServiceError(currentUserRole)) {
|
if (isServiceError(currentUserRole)) {
|
||||||
throw new ServiceErrorException(currentUserRole);
|
throw new ServiceErrorException(currentUserRole);
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,18 @@ import { OrgRole } from "@sourcebot/db";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
interface AccessPageProps {
|
interface AccessPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function AccessPage({ params: { domain } }: AccessPageProps) {
|
export default async function AccessPage(props: AccessPageProps) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new Error("Organization not found");
|
throw new Error("Organization not found");
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,18 @@ export const metadata: Metadata = {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BillingPageProps {
|
interface BillingPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string
|
domain: string
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function BillingPage({
|
export default async function BillingPage(props: BillingPageProps) {
|
||||||
params: { domain },
|
const params = await props.params;
|
||||||
}: BillingPageProps) {
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
if (!IS_BILLING_ENABLED) {
|
if (!IS_BILLING_ENABLED) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,28 @@ import { getOrgFromDomain } from "@/data/org";
|
||||||
import { OrgRole } from "@prisma/client";
|
import { OrgRole } from "@prisma/client";
|
||||||
import { env } from "@/env.mjs";
|
import { env } from "@/env.mjs";
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
params: Promise<{ domain: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function SettingsLayout({
|
export default async function SettingsLayout(
|
||||||
children,
|
props: LayoutProps
|
||||||
params: { domain },
|
) {
|
||||||
}: Readonly<{
|
const params = await props.params;
|
||||||
children: React.ReactNode;
|
|
||||||
params: { domain: string };
|
const {
|
||||||
}>) {
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
children
|
||||||
|
} = props;
|
||||||
|
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return redirect(`/${domain}`);
|
return redirect(`/${domain}`);
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,18 @@ import { notFound, ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { env } from "@/env.mjs";
|
import { env } from "@/env.mjs";
|
||||||
|
|
||||||
interface LicensePageProps {
|
interface LicensePageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function LicensePage({ params: { domain } }: LicensePageProps) {
|
export default async function LicensePage(props: LicensePageProps) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined) {
|
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,27 @@ import { OrgRole } from "@prisma/client";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
interface MembersSettingsPageProps {
|
interface MembersSettingsPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string
|
domain: string
|
||||||
},
|
}>,
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
tab?: string
|
tab?: string
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function MembersSettingsPage({ params: { domain }, searchParams: { tab } }: MembersSettingsPageProps) {
|
export default async function MembersSettingsPage(props: MembersSettingsPageProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
|
|
||||||
|
const {
|
||||||
|
tab
|
||||||
|
} = searchParams;
|
||||||
|
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new Error("Organization not found");
|
throw new Error("Organization not found");
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,18 @@ import { ImportSecretCard } from "./components/importSecretCard";
|
||||||
import { ServiceErrorException } from "@/lib/serviceError";
|
import { ServiceErrorException } from "@/lib/serviceError";
|
||||||
|
|
||||||
interface SecretsPageProps {
|
interface SecretsPageProps {
|
||||||
params: {
|
params: Promise<{
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function SecretsPage({ params: { domain } }: SecretsPageProps) {
|
export default async function SecretsPage(props: SecretsPageProps) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
const secrets = await getSecrets(domain);
|
const secrets = await getSecrets(domain);
|
||||||
if (isServiceError(secrets)) {
|
if (isServiceError(secrets)) {
|
||||||
throw new ServiceErrorException(secrets);
|
throw new ServiceErrorException(secrets);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,13 @@ import { env } from "@/env.mjs";
|
||||||
import { IS_BILLING_ENABLED } from "@/ee/features/billing/stripe";
|
import { IS_BILLING_ENABLED } from "@/ee/features/billing/stripe";
|
||||||
import { getSubscriptionInfo } from "@/ee/features/billing/actions";
|
import { getSubscriptionInfo } from "@/ee/features/billing/actions";
|
||||||
|
|
||||||
export default async function Upgrade({ params: { domain } }: { params: { domain: string } }) {
|
export default async function Upgrade(props: { params: Promise<{ domain: string }> }) {
|
||||||
|
const params = await props.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
domain
|
||||||
|
} = params;
|
||||||
|
|
||||||
if (!IS_BILLING_ENABLED) {
|
if (!IS_BILLING_ENABLED) {
|
||||||
redirect(`/${domain}`);
|
redirect(`/${domain}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const logger = createLogger('stripe-webhook');
|
||||||
|
|
||||||
export async function POST(req: NextRequest) {
|
export async function POST(req: NextRequest) {
|
||||||
const body = await req.text();
|
const body = await req.text();
|
||||||
const signature = headers().get('stripe-signature');
|
const signature = (await headers()).get('stripe-signature');
|
||||||
|
|
||||||
if (!signature) {
|
if (!signature) {
|
||||||
return new Response('No signature', { status: 400 });
|
return new Response('No signature', { status: 400 });
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ import { NextRequest } from "next/server";
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
{ params }: { params: { domain: string; repoId: string } }
|
props: { params: Promise<{ domain: string; repoId: string }> }
|
||||||
) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
const { domain, repoId } = params;
|
const { domain, repoId } = params;
|
||||||
const repoIdNum = parseInt(repoId);
|
const repoIdNum = parseInt(repoId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export async function OrganizationAccessSettings() {
|
||||||
const metadata = getOrgMetadata(org);
|
const metadata = getOrgMetadata(org);
|
||||||
const anonymousAccessEnabled = metadata?.anonymousAccessEnabled ?? false;
|
const anonymousAccessEnabled = metadata?.anonymousAccessEnabled ?? false;
|
||||||
|
|
||||||
const headersList = headers();
|
const headersList = await headers();
|
||||||
const baseUrl = getBaseUrl(headersList);
|
const baseUrl = getBaseUrl(headersList);
|
||||||
const inviteLink = createInviteLink(baseUrl, org.inviteLinkId)
|
const inviteLink = createInviteLink(baseUrl, org.inviteLinkId)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
@import "./codemirror-styles.css";
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@import "./codemirror-styles.css";
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
html {
|
html {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { prisma } from "@/prisma";
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { ErrorCode } from "@/lib/errorCodes";
|
import { ErrorCode } from "@/lib/errorCodes";
|
||||||
|
|
||||||
export const joinOrganization = (orgId: number, inviteLinkId?: string) => sew(async () =>
|
export const joinOrganization = async (orgId: number, inviteLinkId?: string) => sew(async () =>
|
||||||
withAuth(async (userId) => {
|
withAuth(async (userId) => {
|
||||||
const org = await prisma.org.findUnique({
|
const org = await prisma.org.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,13 @@ import { getAuthProviders } from "@/lib/authProviders";
|
||||||
import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard";
|
import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard";
|
||||||
|
|
||||||
interface InvitePageProps {
|
interface InvitePageProps {
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
id?: string;
|
id?: string;
|
||||||
};
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function InvitePage({ searchParams }: InvitePageProps) {
|
export default async function InvitePage(props: InvitePageProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
||||||
if (!org || !org.isOnboarded) {
|
if (!org || !org.isOnboarded) {
|
||||||
return redirect("/onboard");
|
return redirect("/onboard");
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@ import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
|
||||||
const logger = createLogger('login-page');
|
const logger = createLogger('login-page');
|
||||||
|
|
||||||
interface LoginProps {
|
interface LoginProps {
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
callbackUrl?: string;
|
callbackUrl?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Login({ searchParams }: LoginProps) {
|
export default async function Login(props: LoginProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
logger.info("Login page loaded");
|
logger.info("Login page loaded");
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
|
import Link from "next/link"
|
||||||
|
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
@ -20,7 +21,7 @@ import { env } from "@/env.mjs";
|
||||||
import { GcpIapAuth } from "@/app/[domain]/components/gcpIapAuth";
|
import { GcpIapAuth } from "@/app/[domain]/components/gcpIapAuth";
|
||||||
|
|
||||||
interface OnboardingProps {
|
interface OnboardingProps {
|
||||||
searchParams?: { step?: string };
|
searchParams?: Promise<{ step?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnboardingStep {
|
interface OnboardingStep {
|
||||||
|
|
@ -38,7 +39,8 @@ interface ResourceCard {
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Onboarding({ searchParams }: OnboardingProps) {
|
export default async function Onboarding(props: OnboardingProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
const providers = getAuthProviders();
|
const providers = getAuthProviders();
|
||||||
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
|
|
@ -118,7 +120,7 @@ export default async function Onboarding({ searchParams }: OnboardingProps) {
|
||||||
component: (
|
component: (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<Button asChild className="w-full">
|
<Button asChild className="w-full">
|
||||||
<a href="/onboard?step=1">Get Started →</a>
|
<Link href="/onboard?step=1">Get Started →</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|
@ -170,7 +172,7 @@ export default async function Onboarding({ searchParams }: OnboardingProps) {
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<OrganizationAccessSettings />
|
<OrganizationAccessSettings />
|
||||||
<Button asChild className="w-full">
|
<Button asChild className="w-full">
|
||||||
<a href="/onboard?step=3">Continue →</a>
|
<Link href="/onboard?step=3">Continue →</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,13 @@ import { getOrgFromDomain } from '@/data/org';
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from '@/lib/constants';
|
import { SINGLE_TENANT_ORG_DOMAIN } from '@/lib/constants';
|
||||||
|
|
||||||
interface RedeemPageProps {
|
interface RedeemPageProps {
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
invite_id?: string;
|
invite_id?: string;
|
||||||
};
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function RedeemPage({ searchParams }: RedeemPageProps) {
|
export default async function RedeemPage(props: RedeemPageProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);
|
||||||
if (!org || !org.isOnboarded) {
|
if (!org || !org.isOnboarded) {
|
||||||
return redirect("/onboard");
|
return redirect("/onboard");
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@ import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
|
||||||
const logger = createLogger('signup-page');
|
const logger = createLogger('signup-page');
|
||||||
|
|
||||||
interface LoginProps {
|
interface LoginProps {
|
||||||
searchParams: {
|
searchParams: Promise<{
|
||||||
callbackUrl?: string;
|
callbackUrl?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Signup({ searchParams }: LoginProps) {
|
export default async function Signup(props: LoginProps) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (session) {
|
if (session) {
|
||||||
logger.info("Session found in signup page, redirecting to home");
|
logger.info("Session found in signup page, redirecting to home");
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,9 @@ export const ReferencedSourcesListView = ({
|
||||||
repoWebUrl={fileData.repositoryWebUrl}
|
repoWebUrl={fileData.repositoryWebUrl}
|
||||||
fileName={fileData.path}
|
fileName={fileData.path}
|
||||||
references={referencesInFile}
|
references={referencesInFile}
|
||||||
ref={(ref) => setEditorRef(fileId, ref)}
|
ref={ref => {
|
||||||
|
setEditorRef(fileId, ref);
|
||||||
|
}}
|
||||||
onSelectedReferenceChanged={onSelectedReferenceChanged}
|
onSelectedReferenceChanged={onSelectedReferenceChanged}
|
||||||
onHoveredReferenceChanged={onHoveredReferenceChanged}
|
onHoveredReferenceChanged={onHoveredReferenceChanged}
|
||||||
selectedReference={selectedReference}
|
selectedReference={selectedReference}
|
||||||
|
|
@ -280,6 +282,5 @@ export const ReferencedSourcesListView = ({
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect, test } from 'vitest'
|
import { expect, test } from 'vitest'
|
||||||
import { renderHook } from '@testing-library/react-hooks';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { useExtractReferences } from './useExtractReferences';
|
import { useExtractReferences } from './useExtractReferences';
|
||||||
import { getFileReferenceId } from './utils';
|
import { getFileReferenceId } from './utils';
|
||||||
import { TextUIPart } from 'ai';
|
import { TextUIPart } from 'ai';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect, test } from 'vitest'
|
import { expect, test } from 'vitest'
|
||||||
import { SBChatMessage } from './types';
|
import { SBChatMessage } from './types';
|
||||||
import { useMessagePairs } from './useMessagePairs';
|
import { useMessagePairs } from './useMessagePairs';
|
||||||
import { renderHook } from '@testing-library/react-hooks';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
|
||||||
test('useMessagePairs pairs user and assistant messages', () => {
|
test('useMessagePairs pairs user and assistant messages', () => {
|
||||||
const userMessage: SBChatMessage = {
|
const userMessage: SBChatMessage = {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export const FileTreeItemComponent = ({
|
||||||
isCollapsed?: boolean,
|
isCollapsed?: boolean,
|
||||||
isCollapseChevronVisible?: boolean,
|
isCollapseChevronVisible?: boolean,
|
||||||
onClick: () => void,
|
onClick: () => void,
|
||||||
parentRef: React.RefObject<HTMLDivElement>,
|
parentRef: React.RefObject<HTMLDivElement | null>,
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,164 +1,164 @@
|
||||||
import type { Config } from "tailwindcss"
|
import type { Config } from "tailwindcss"
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
darkMode: ["class"],
|
darkMode: ["class"],
|
||||||
content: [
|
content: [
|
||||||
'./pages/**/*.{ts,tsx}',
|
'./pages/**/*.{ts,tsx}',
|
||||||
'./components/**/*.{ts,tsx}',
|
'./components/**/*.{ts,tsx}',
|
||||||
'./app/**/*.{ts,tsx}',
|
'./app/**/*.{ts,tsx}',
|
||||||
'./src/**/*.{ts,tsx}',
|
'./src/**/*.{ts,tsx}',
|
||||||
],
|
],
|
||||||
prefix: "",
|
prefix: "",
|
||||||
theme: {
|
theme: {
|
||||||
container: {
|
container: {
|
||||||
center: true,
|
center: true,
|
||||||
padding: '2rem',
|
padding: '2rem',
|
||||||
screens: {
|
screens: {
|
||||||
'2xl': '1400px'
|
'2xl': '1400px'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
border: 'var(--border)',
|
border: 'var(--border)',
|
||||||
input: 'var(--input)',
|
input: 'var(--input)',
|
||||||
ring: 'var(--ring)',
|
ring: 'var(--ring)',
|
||||||
background: 'var(--background)',
|
background: 'var(--background)',
|
||||||
backgroundSecondary: 'var(--background-secondary)',
|
backgroundSecondary: 'var(--background-secondary)',
|
||||||
foreground: 'var(--foreground)',
|
foreground: 'var(--foreground)',
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: 'var(--primary)',
|
DEFAULT: 'var(--primary)',
|
||||||
foreground: 'var(--primary-foreground)'
|
foreground: 'var(--primary-foreground)'
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
DEFAULT: 'var(--secondary)',
|
DEFAULT: 'var(--secondary)',
|
||||||
foreground: 'var(--secondary-foreground)'
|
foreground: 'var(--secondary-foreground)'
|
||||||
},
|
},
|
||||||
destructive: {
|
destructive: {
|
||||||
DEFAULT: 'var(--destructive)',
|
DEFAULT: 'var(--destructive)',
|
||||||
foreground: 'var(--destructive-foreground)'
|
foreground: 'var(--destructive-foreground)'
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
DEFAULT: 'var(--muted)',
|
DEFAULT: 'var(--muted)',
|
||||||
foreground: 'var(--muted-foreground)',
|
foreground: 'var(--muted-foreground)',
|
||||||
accent: 'var(--muted-accent)'
|
accent: 'var(--muted-accent)'
|
||||||
},
|
},
|
||||||
accent: {
|
accent: {
|
||||||
DEFAULT: 'var(--accent)',
|
DEFAULT: 'var(--accent)',
|
||||||
foreground: 'var(--accent-foreground)'
|
foreground: 'var(--accent-foreground)'
|
||||||
},
|
},
|
||||||
popover: {
|
popover: {
|
||||||
DEFAULT: 'var(--popover)',
|
DEFAULT: 'var(--popover)',
|
||||||
foreground: 'var(--popover-foreground)'
|
foreground: 'var(--popover-foreground)'
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
DEFAULT: 'var(--card)',
|
DEFAULT: 'var(--card)',
|
||||||
foreground: 'var(--card-foreground)'
|
foreground: 'var(--card-foreground)'
|
||||||
},
|
},
|
||||||
highlight: 'var(--highlight)',
|
highlight: 'var(--highlight)',
|
||||||
link: 'var(--link)',
|
link: 'var(--link)',
|
||||||
sidebar: {
|
sidebar: {
|
||||||
DEFAULT: 'var(--sidebar-background)',
|
DEFAULT: 'var(--sidebar-background)',
|
||||||
foreground: 'var(--sidebar-foreground)',
|
foreground: 'var(--sidebar-foreground)',
|
||||||
primary: 'var(--sidebar-primary)',
|
primary: 'var(--sidebar-primary)',
|
||||||
'primary-foreground': 'var(--sidebar-primary-foreground)',
|
'primary-foreground': 'var(--sidebar-primary-foreground)',
|
||||||
accent: 'var(--sidebar-accent)',
|
accent: 'var(--sidebar-accent)',
|
||||||
'accent-foreground': 'var(--sidebar-accent-foreground)',
|
'accent-foreground': 'var(--sidebar-accent-foreground)',
|
||||||
border: 'var(--sidebar-border)',
|
border: 'var(--sidebar-border)',
|
||||||
ring: 'var(--sidebar-ring)'
|
ring: 'var(--sidebar-ring)'
|
||||||
},
|
},
|
||||||
warning: 'var(--warning)',
|
warning: 'var(--warning)',
|
||||||
editor: {
|
editor: {
|
||||||
background: 'var(--editor-background)',
|
background: 'var(--editor-background)',
|
||||||
foreground: 'var(--editor-foreground)',
|
foreground: 'var(--editor-foreground)',
|
||||||
caret: 'var(--editor-caret)',
|
caret: 'var(--editor-caret)',
|
||||||
selection: 'var(--editor-selection)',
|
selection: 'var(--editor-selection)',
|
||||||
selectionMatch: 'var(--editor-selection-match)',
|
selectionMatch: 'var(--editor-selection-match)',
|
||||||
gutterBackground: 'var(--editor-gutter-background)',
|
gutterBackground: 'var(--editor-gutter-background)',
|
||||||
gutterForeground: 'var(--editor-gutter-foreground)',
|
gutterForeground: 'var(--editor-gutter-foreground)',
|
||||||
gutterBorder: 'var(--editor-gutter-border)',
|
gutterBorder: 'var(--editor-gutter-border)',
|
||||||
gutterActiveForeground: 'var(--editor-gutter-active-foreground)',
|
gutterActiveForeground: 'var(--editor-gutter-active-foreground)',
|
||||||
lineHighlight: 'var(--editor-line-highlight)',
|
lineHighlight: 'var(--editor-line-highlight)',
|
||||||
tag: {
|
tag: {
|
||||||
keyword: 'var(--editor-tag-keyword)',
|
keyword: 'var(--editor-tag-keyword)',
|
||||||
name: 'var(--editor-tag-name)',
|
name: 'var(--editor-tag-name)',
|
||||||
function: 'var(--editor-tag-function)',
|
function: 'var(--editor-tag-function)',
|
||||||
label: 'var(--editor-tag-label)',
|
label: 'var(--editor-tag-label)',
|
||||||
constant: 'var(--editor-tag-constant)',
|
constant: 'var(--editor-tag-constant)',
|
||||||
definition: 'var(--editor-tag-definition)',
|
definition: 'var(--editor-tag-definition)',
|
||||||
brace: 'var(--editor-tag-brace)',
|
brace: 'var(--editor-tag-brace)',
|
||||||
type: 'var(--editor-tag-type)',
|
type: 'var(--editor-tag-type)',
|
||||||
operator: 'var(--editor-tag-operator)',
|
operator: 'var(--editor-tag-operator)',
|
||||||
tag: 'var(--editor-tag-tag)',
|
tag: 'var(--editor-tag-tag)',
|
||||||
'bracket-square': 'var(--editor-tag-bracket-square)',
|
'bracket-square': 'var(--editor-tag-bracket-square)',
|
||||||
'bracket-angle': 'var(--editor-tag-bracket-angle)',
|
'bracket-angle': 'var(--editor-tag-bracket-angle)',
|
||||||
attribute: 'var(--editor-tag-attribute)',
|
attribute: 'var(--editor-tag-attribute)',
|
||||||
string: 'var(--editor-tag-string)',
|
string: 'var(--editor-tag-string)',
|
||||||
link: 'var(--editor-tag-link)',
|
link: 'var(--editor-tag-link)',
|
||||||
meta: 'var(--editor-tag-meta)',
|
meta: 'var(--editor-tag-meta)',
|
||||||
comment: 'var(--editor-tag-comment)',
|
comment: 'var(--editor-tag-comment)',
|
||||||
emphasis: 'var(--editor-tag-emphasis)',
|
emphasis: 'var(--editor-tag-emphasis)',
|
||||||
heading: 'var(--editor-tag-heading)',
|
heading: 'var(--editor-tag-heading)',
|
||||||
atom: 'var(--editor-tag-atom)',
|
atom: 'var(--editor-tag-atom)',
|
||||||
processing: 'var(--editor-tag-processing)',
|
processing: 'var(--editor-tag-processing)',
|
||||||
separator: 'var(--editor-tag-separator)',
|
separator: 'var(--editor-tag-separator)',
|
||||||
invalid: 'var(--editor-tag-invalid)',
|
invalid: 'var(--editor-tag-invalid)',
|
||||||
quote: 'var(--editor-tag-quote)',
|
quote: 'var(--editor-tag-quote)',
|
||||||
'annotation-special': 'var(--editor-tag-annotation-special)',
|
'annotation-special': 'var(--editor-tag-annotation-special)',
|
||||||
number: 'var(--editor-tag-number)',
|
number: 'var(--editor-tag-number)',
|
||||||
regexp: 'var(--editor-tag-regexp)',
|
regexp: 'var(--editor-tag-regexp)',
|
||||||
'variable-local': 'var(--editor-tag-variable-local)'
|
'variable-local': 'var(--editor-tag-variable-local)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
reference: 'var(--chat-reference)',
|
reference: 'var(--chat-reference)',
|
||||||
'reference-hover': 'var(--chat-reference-hover)',
|
'reference-hover': 'var(--chat-reference-hover)',
|
||||||
'reference-selected': 'var(--chat-reference-selected)',
|
'reference-selected': 'var(--chat-reference-selected)',
|
||||||
'reference-selected-border': 'var(--chat-reference-selected-border)'
|
'reference-selected-border': 'var(--chat-reference-selected-border)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
editor: 'var(--editor-font-size)'
|
editor: 'var(--editor-font-size)'
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
editor: 'var(--editor-font-family)'
|
editor: 'var(--editor-font-family)'
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
lg: 'var(--radius)',
|
lg: 'var(--radius)',
|
||||||
md: 'calc(var(--radius) - 2px)',
|
md: 'calc(var(--radius) - 2px)',
|
||||||
sm: 'calc(var(--radius) - 4px)'
|
sm: 'calc(var(--radius) - 4px)'
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
'accordion-down': {
|
'accordion-down': {
|
||||||
from: {
|
from: {
|
||||||
height: '0'
|
height: '0'
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
height: 'var(--radix-accordion-content-height)'
|
height: 'var(--radix-accordion-content-height)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'accordion-up': {
|
'accordion-up': {
|
||||||
from: {
|
from: {
|
||||||
height: 'var(--radix-accordion-content-height)'
|
height: 'var(--radix-accordion-content-height)'
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
height: '0'
|
height: '0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||||
'spin-slow': 'spin 1.5s linear infinite',
|
'spin-slow': 'spin 1.5s linear infinite',
|
||||||
'bounce-slow': 'bounce 1.5s linear infinite'
|
'bounce-slow': 'bounce 1.5s linear infinite'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
require("tailwindcss-animate"),
|
require("tailwindcss-animate"),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
require('@tailwindcss/typography'),
|
require('@tailwindcss/typography'),
|
||||||
],
|
],
|
||||||
} satisfies Config
|
} satisfies Config
|
||||||
|
|
||||||
export default config
|
export default config
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
@ -18,10 +22,23 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"],
|
"@/*": [
|
||||||
"@/public/*": ["./public/*"]
|
"./src/*"
|
||||||
}
|
],
|
||||||
|
"@/public/*": [
|
||||||
|
"./public/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"target": "ES2017"
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/env.mjs"],
|
"include": [
|
||||||
"exclude": ["node_modules"]
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
"src/env.mjs"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue