mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-11 20:05:25 +00:00
fix(web): Fix /settings/connections throwing a error when there is a git connection present (#588)
This commit is contained in:
parent
4899c9fbc7
commit
581a5a0bd8
27 changed files with 175 additions and 127 deletions
|
|
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- [ask sb] Fixed issue where reasoning tokens would appear in `text` content for openai compatible models. [#582](https://github.com/sourcebot-dev/sourcebot/pull/582)
|
- [ask sb] Fixed issue where reasoning tokens would appear in `text` content for openai compatible models. [#582](https://github.com/sourcebot-dev/sourcebot/pull/582)
|
||||||
- Fixed issue with GitHub app token tracking and refreshing. [#583](https://github.com/sourcebot-dev/sourcebot/pull/583)
|
- Fixed issue with GitHub app token tracking and refreshing. [#583](https://github.com/sourcebot-dev/sourcebot/pull/583)
|
||||||
- Fixed "The account is already associated with another user" errors with GitLab oauth provider. [#584](https://github.com/sourcebot-dev/sourcebot/pull/584)
|
- Fixed "The account is already associated with another user" errors with GitLab oauth provider. [#584](https://github.com/sourcebot-dev/sourcebot/pull/584)
|
||||||
|
- Fixed error when viewing a generic git connection in `/settings/connections`. [#588](https://github.com/sourcebot-dev/sourcebot/pull/588)
|
||||||
|
|
||||||
## [4.8.1] - 2025-10-29
|
## [4.8.1] - 2025-10-29
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
import { env } from "./env.js";
|
import { env } from "./env.js";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
export const SINGLE_TENANT_ORG_ID = 1;
|
export const SINGLE_TENANT_ORG_ID = 1;
|
||||||
|
|
||||||
export const PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES = [
|
export const PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES: CodeHostType[] = [
|
||||||
'github',
|
'github',
|
||||||
'gitlab',
|
'gitlab',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { BitbucketRepository, getBitbucketReposFromConfig } from "./bitbucket.js
|
||||||
import { getAzureDevOpsReposFromConfig } from "./azuredevops.js";
|
import { getAzureDevOpsReposFromConfig } from "./azuredevops.js";
|
||||||
import { SchemaRestRepository as BitbucketServerRepository } from "@coderabbitai/bitbucket/server/openapi";
|
import { SchemaRestRepository as BitbucketServerRepository } from "@coderabbitai/bitbucket/server/openapi";
|
||||||
import { SchemaRepository as BitbucketCloudRepository } from "@coderabbitai/bitbucket/cloud/openapi";
|
import { SchemaRepository as BitbucketCloudRepository } from "@coderabbitai/bitbucket/cloud/openapi";
|
||||||
import { Prisma, PrismaClient } from '@sourcebot/db';
|
import { CodeHostType, Prisma, PrismaClient } from '@sourcebot/db';
|
||||||
import { WithRequired } from "./types.js"
|
import { WithRequired } from "./types.js"
|
||||||
import { marshalBool } from "./utils.js";
|
import { marshalBool } from "./utils.js";
|
||||||
import { createLogger } from '@sourcebot/logger';
|
import { createLogger } from '@sourcebot/logger';
|
||||||
|
|
@ -392,7 +392,7 @@ export const compileBitbucketConfig = async (
|
||||||
|
|
||||||
const repos = bitbucketRepos.map((repo) => {
|
const repos = bitbucketRepos.map((repo) => {
|
||||||
const isServer = config.deploymentType === 'server';
|
const isServer = config.deploymentType === 'server';
|
||||||
const codeHostType = isServer ? 'bitbucket-server' : 'bitbucket-cloud'; // zoekt expects bitbucket-server
|
const codeHostType: CodeHostType = isServer ? 'bitbucketServer' : 'bitbucketCloud';
|
||||||
const displayName = isServer ? (repo as BitbucketServerRepository).name! : (repo as BitbucketCloudRepository).full_name!;
|
const displayName = isServer ? (repo as BitbucketServerRepository).name! : (repo as BitbucketCloudRepository).full_name!;
|
||||||
const externalId = isServer ? (repo as BitbucketServerRepository).id!.toString() : (repo as BitbucketCloudRepository).uuid!;
|
const externalId = isServer ? (repo as BitbucketServerRepository).id!.toString() : (repo as BitbucketCloudRepository).uuid!;
|
||||||
const isPublic = isServer ? (repo as BitbucketServerRepository).public : (repo as BitbucketCloudRepository).is_private === false;
|
const isPublic = isServer ? (repo as BitbucketServerRepository).public : (repo as BitbucketCloudRepository).is_private === false;
|
||||||
|
|
@ -425,7 +425,8 @@ export const compileBitbucketConfig = async (
|
||||||
},
|
},
|
||||||
metadata: {
|
metadata: {
|
||||||
gitConfig: {
|
gitConfig: {
|
||||||
'zoekt.web-url-type': codeHostType,
|
// zoekt expects bitbucket-server and bitbucket-cloud
|
||||||
|
'zoekt.web-url-type': codeHostType === 'bitbucketServer' ? 'bitbucket-server' : 'bitbucket-cloud',
|
||||||
'zoekt.web-url': webUrl,
|
'zoekt.web-url': webUrl,
|
||||||
'zoekt.name': repoName,
|
'zoekt.name': repoName,
|
||||||
'zoekt.archived': marshalBool(isArchived),
|
'zoekt.archived': marshalBool(isArchived),
|
||||||
|
|
@ -507,7 +508,7 @@ export const compileGenericGitHostConfig_file = async (
|
||||||
const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, ''));
|
const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, ''));
|
||||||
|
|
||||||
const repo: RepoData = {
|
const repo: RepoData = {
|
||||||
external_codeHostType: 'generic-git-host',
|
external_codeHostType: 'genericGitHost',
|
||||||
external_codeHostUrl: remoteUrl.resource,
|
external_codeHostUrl: remoteUrl.resource,
|
||||||
external_id: remoteUrl.toString(),
|
external_id: remoteUrl.toString(),
|
||||||
cloneUrl: `file://${repoPath}`,
|
cloneUrl: `file://${repoPath}`,
|
||||||
|
|
@ -571,7 +572,7 @@ export const compileGenericGitHostConfig_url = async (
|
||||||
const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, ''));
|
const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, ''));
|
||||||
|
|
||||||
const repo: RepoData = {
|
const repo: RepoData = {
|
||||||
external_codeHostType: 'generic-git-host',
|
external_codeHostType: 'genericGitHost',
|
||||||
external_codeHostUrl: remoteUrl.origin,
|
external_codeHostUrl: remoteUrl.origin,
|
||||||
external_id: remoteUrl.toString(),
|
external_id: remoteUrl.toString(),
|
||||||
cloneUrl: remoteUrl.toString(),
|
cloneUrl: remoteUrl.toString(),
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ export const getRepoPath = (repo: Repo): { path: string, isReadOnly: boolean } =
|
||||||
// If we are dealing with a local repository, then use that as the path.
|
// If we are dealing with a local repository, then use that as the path.
|
||||||
// Mark as read-only since we aren't guaranteed to have write access to the local filesystem.
|
// Mark as read-only since we aren't guaranteed to have write access to the local filesystem.
|
||||||
const cloneUrl = new URL(repo.cloneUrl);
|
const cloneUrl = new URL(repo.cloneUrl);
|
||||||
if (repo.external_codeHostType === 'generic-git-host' && cloneUrl.protocol === 'file:') {
|
if (repo.external_codeHostType === 'genericGitHost' && cloneUrl.protocol === 'file:') {
|
||||||
return {
|
return {
|
||||||
path: cloneUrl.pathname,
|
path: cloneUrl.pathname,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
Migrates the `connectionType` column from text to a enum. The values in this field are known to
|
||||||
|
be one of the following: github, gitlab, gitea, gerrit, bitbucket, azuredevops, git.
|
||||||
|
|
||||||
|
This is occording to what we would expect to be in a valid config file for the schema version at commit 4899c9fbc755851af2ddcce99f4a4200f2faa4f6.
|
||||||
|
See: https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/schemas/src/v3/connection.type.ts#L3
|
||||||
|
*/
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ConnectionType" AS ENUM ('github', 'gitlab', 'gitea', 'gerrit', 'bitbucket', 'azuredevops', 'git');
|
||||||
|
|
||||||
|
-- AlterTable - Convert existing column to enum type without dropping data
|
||||||
|
ALTER TABLE "Connection"
|
||||||
|
ALTER COLUMN "connectionType" TYPE "ConnectionType"
|
||||||
|
USING "connectionType"::text::"ConnectionType";
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
Migrates the `external_codeHostType` column from text to a enum. The values in this field are known to
|
||||||
|
be one of the following: github, gitlab, gitea, gerrit, bitbucket-server, bitbucket-cloud, generic-git-host, azuredevops.
|
||||||
|
|
||||||
|
This is occording to what we would expect to be in the database written as of commit 4899c9fbc755851af2ddcce99f4a4200f2faa4f6.
|
||||||
|
See:
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L57
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L135
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L208
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L291
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L407
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L510
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L574
|
||||||
|
- https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L642
|
||||||
|
*/
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "CodeHostType" AS ENUM ('github', 'gitlab', 'gitea', 'gerrit', 'bitbucket-server', 'bitbucket-cloud', 'generic-git-host', 'azuredevops');
|
||||||
|
|
||||||
|
-- AlterTable - Convert existing column to enum type without dropping data
|
||||||
|
ALTER TABLE "Repo"
|
||||||
|
ALTER COLUMN "external_codeHostType" TYPE "CodeHostType"
|
||||||
|
USING "external_codeHostType"::text::"CodeHostType";
|
||||||
|
|
@ -29,6 +29,21 @@ enum ChatVisibility {
|
||||||
PUBLIC
|
PUBLIC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @note: The @map annotation is required to maintain backwards compatibility
|
||||||
|
/// with the existing database.
|
||||||
|
/// @note: In the generated client, these mapped values will be in pascalCase.
|
||||||
|
/// This behaviour will change in prisma v7. See: https://github.com/prisma/prisma/issues/8446#issuecomment-3356119713
|
||||||
|
enum CodeHostType {
|
||||||
|
github
|
||||||
|
gitlab
|
||||||
|
gitea
|
||||||
|
gerrit
|
||||||
|
bitbucketServer @map("bitbucket-server")
|
||||||
|
bitbucketCloud @map("bitbucket-cloud")
|
||||||
|
genericGitHost @map("generic-git-host")
|
||||||
|
azuredevops
|
||||||
|
}
|
||||||
|
|
||||||
model Repo {
|
model Repo {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String /// Full repo name, including the vcs hostname (ex. github.com/sourcebot-dev/sourcebot)
|
name String /// Full repo name, including the vcs hostname (ex. github.com/sourcebot-dev/sourcebot)
|
||||||
|
|
@ -53,7 +68,7 @@ model Repo {
|
||||||
indexedCommitHash String? /// The commit hash of the last indexed commit (on HEAD).
|
indexedCommitHash String? /// The commit hash of the last indexed commit (on HEAD).
|
||||||
|
|
||||||
external_id String /// The id of the repo in the external service
|
external_id String /// The id of the repo in the external service
|
||||||
external_codeHostType String /// The type of the external service (e.g., github, gitlab, etc.)
|
external_codeHostType CodeHostType /// The type of the external service (e.g., github, gitlab, etc.)
|
||||||
external_codeHostUrl String /// The base url of the external service (e.g., https://github.com)
|
external_codeHostUrl String /// The base url of the external service (e.g., https://github.com)
|
||||||
|
|
||||||
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||||
|
|
@ -125,6 +140,18 @@ model SearchContext {
|
||||||
@@unique([name, orgId])
|
@@unique([name, orgId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches the union of `type` fields in the schema.
|
||||||
|
/// @see: schemas/v3/connection.type.ts
|
||||||
|
enum ConnectionType {
|
||||||
|
github
|
||||||
|
gitlab
|
||||||
|
gitea
|
||||||
|
gerrit
|
||||||
|
bitbucket
|
||||||
|
azuredevops
|
||||||
|
git
|
||||||
|
}
|
||||||
|
|
||||||
model Connection {
|
model Connection {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String
|
name String
|
||||||
|
|
@ -135,7 +162,7 @@ model Connection {
|
||||||
repos RepoToConnection[]
|
repos RepoToConnection[]
|
||||||
|
|
||||||
// The type of connection (e.g., github, gitlab, etc.)
|
// The type of connection (e.g., github, gitlab, etc.)
|
||||||
connectionType String
|
connectionType ConnectionType
|
||||||
|
|
||||||
syncJobs ConnectionSyncJob[]
|
syncJobs ConnectionSyncJob[]
|
||||||
/// When the connection was last synced successfully.
|
/// When the connection was last synced successfully.
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export const CodePreviewPanel = async ({ path, repoName, revisionName }: CodePre
|
||||||
branchDisplayName={revisionName}
|
branchDisplayName={revisionName}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(fileWebUrl && codeHostInfo) && (
|
{fileWebUrl && (
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href={fileWebUrl}
|
href={fileWebUrl}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@ import { Badge } from "@/components/ui/badge";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { CardContent } from "@/components/ui/card";
|
import { CardContent } from "@/components/ui/card";
|
||||||
import { DemoExamples, DemoSearchExample, DemoSearchScope } from "@/types";
|
import { DemoExamples, DemoSearchExample, DemoSearchScope } from "@/types";
|
||||||
import { cn, CodeHostType, getCodeHostIcon } from "@/lib/utils";
|
import { cn, getCodeHostIcon } from "@/lib/utils";
|
||||||
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
import { SearchScopeInfoCard } from "@/features/chat/components/chatBox/searchScopeInfoCard";
|
import { SearchScopeInfoCard } from "@/features/chat/components/chatBox/searchScopeInfoCard";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
interface DemoCards {
|
interface DemoCards {
|
||||||
demoExamples: DemoExamples;
|
demoExamples: DemoExamples;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import { Separator } from "@/components/ui/separator";
|
||||||
import { Schema } from "ajv";
|
import { Schema } from "ajv";
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
import { CodeHostType } from "@/lib/utils";
|
|
||||||
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";
|
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
export type QuickActionFn<T> = (previous: T) => T;
|
export type QuickActionFn<T> = (previous: T) => T;
|
||||||
export type QuickAction<T> = {
|
export type QuickAction<T> = {
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
import { CodeHostType, isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import githubPatCreation from "@/public/github_pat_creation.png";
|
import githubPatCreation from "@/public/github_pat_creation.png";
|
||||||
import gitlabPatCreation from "@/public/gitlab_pat_creation.png";
|
import gitlabPatCreation from "@/public/gitlab_pat_creation.png";
|
||||||
import giteaPatCreation from "@/public/gitea_pat_creation.png";
|
import giteaPatCreation from "@/public/gitea_pat_creation.png";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { Eye, EyeOff, Loader2 } from "lucide-react";
|
import { Eye, EyeOff, Loader2 } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
@ -88,9 +89,9 @@ export const ImportSecretDialog = ({ open, onOpenChange, onSecretCreated, codeHo
|
||||||
return <GitHubPATCreationStep step={1} />;
|
return <GitHubPATCreationStep step={1} />;
|
||||||
case 'gitlab':
|
case 'gitlab':
|
||||||
return <GitLabPATCreationStep step={1} />;
|
return <GitLabPATCreationStep step={1} />;
|
||||||
case 'bitbucket-cloud':
|
case 'bitbucketCloud':
|
||||||
return <BitbucketCloudPATCreationStep step={1} />;
|
return <BitbucketCloudPATCreationStep step={1} />;
|
||||||
case 'bitbucket-server':
|
case 'bitbucketServer':
|
||||||
return <BitbucketServerPATCreationStep step={1} />;
|
return <BitbucketServerPATCreationStep step={1} />;
|
||||||
case 'gitea':
|
case 'gitea':
|
||||||
return <GiteaPATCreationStep step={1} />;
|
return <GiteaPATCreationStep step={1} />;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
|
||||||
import { RepositoryQuery } from "@/lib/types";
|
import { RepositoryQuery } from "@/lib/types";
|
||||||
import { getCodeHostInfoForRepo, getShortenedNumberDisplayString } from "@/lib/utils";
|
import { getCodeHostInfoForRepo, getShortenedNumberDisplayString } from "@/lib/utils";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { FileIcon, Loader2Icon, RefreshCwIcon } from "lucide-react";
|
import { Loader2Icon, RefreshCwIcon } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
@ -90,23 +90,14 @@ const RepoItem = ({ repo }: { repo: RepositoryQuery }) => {
|
||||||
webUrl: repo.webUrl,
|
webUrl: repo.webUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (info) {
|
|
||||||
return {
|
|
||||||
repoIcon: <Image
|
|
||||||
src={info.icon}
|
|
||||||
alt={info.codeHostName}
|
|
||||||
className={`w-4 h-4 ${info.iconClassName}`}
|
|
||||||
/>,
|
|
||||||
displayName: info.displayName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repoIcon: <FileIcon className="w-4 h-4" />,
|
repoIcon: <Image
|
||||||
displayName: repo.repoName,
|
src={info.icon}
|
||||||
|
alt={info.codeHostName}
|
||||||
|
className={`w-4 h-4 ${info.iconClassName}`}
|
||||||
|
/>,
|
||||||
|
displayName: info.displayName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}, [repo.repoName, repo.codeHostType, repo.repoDisplayName, repo.webUrl]);
|
}, [repo.repoName, repo.codeHostType, repo.repoDisplayName, repo.webUrl]);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { cn, getCodeHostInfoForRepo } from "@/lib/utils";
|
import { cn, getCodeHostInfoForRepo } from "@/lib/utils";
|
||||||
import { LaptopIcon } from "@radix-ui/react-icons";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { getBrowsePath } from "../browse/hooks/utils";
|
import { getBrowsePath } from "../browse/hooks/utils";
|
||||||
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
||||||
|
|
@ -17,6 +16,7 @@ import { VscodeFileIcon } from "@/app/components/vscodeFileIcon";
|
||||||
import { CopyIconButton } from "./copyIconButton";
|
import { CopyIconButton } from "./copyIconButton";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
interface FileHeaderProps {
|
interface FileHeaderProps {
|
||||||
path: string;
|
path: string;
|
||||||
|
|
@ -27,7 +27,7 @@ interface FileHeaderProps {
|
||||||
pathType?: 'blob' | 'tree';
|
pathType?: 'blob' | 'tree';
|
||||||
repo: {
|
repo: {
|
||||||
name: string;
|
name: string;
|
||||||
codeHostType: string;
|
codeHostType: CodeHostType;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
webUrl?: string;
|
webUrl?: string;
|
||||||
},
|
},
|
||||||
|
|
@ -202,17 +202,13 @@ export const PathHeader = ({
|
||||||
<div className="flex flex-row gap-2 items-center w-full overflow-hidden">
|
<div className="flex flex-row gap-2 items-center w-full overflow-hidden">
|
||||||
{isCodeHostIconVisible && (
|
{isCodeHostIconVisible && (
|
||||||
<>
|
<>
|
||||||
{info?.icon ? (
|
<a href={info.repoLink} target="_blank" rel="noopener noreferrer">
|
||||||
<a href={info.repoLink} target="_blank" rel="noopener noreferrer">
|
<Image
|
||||||
<Image
|
src={info.icon}
|
||||||
src={info.icon}
|
alt={info.codeHostName}
|
||||||
alt={info.codeHostName}
|
className={`w-4 h-4 ${info.iconClassName}`}
|
||||||
className={`w-4 h-4 ${info.iconClassName}`}
|
/>
|
||||||
/>
|
</a>
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<LaptopIcon className="w-4 h-4" />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import {
|
||||||
import { captureEvent } from "@/hooks/useCaptureEvent";
|
import { captureEvent } from "@/hooks/useCaptureEvent";
|
||||||
import { RepositoryQuery } from "@/lib/types";
|
import { RepositoryQuery } from "@/lib/types";
|
||||||
import { getCodeHostInfoForRepo } from "@/lib/utils";
|
import { getCodeHostInfoForRepo } from "@/lib/utils";
|
||||||
import { FileIcon } from "@radix-ui/react-icons";
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import Autoscroll from "embla-carousel-auto-scroll";
|
import Autoscroll from "embla-carousel-auto-scroll";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
@ -121,20 +120,13 @@ const RepositoryBadge = ({
|
||||||
webUrl: repo.webUrl,
|
webUrl: repo.webUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (info) {
|
|
||||||
return {
|
|
||||||
repoIcon: <Image
|
|
||||||
src={info.icon}
|
|
||||||
alt={info.codeHostName}
|
|
||||||
className={`w-4 h-4 ${info.iconClassName}`}
|
|
||||||
/>,
|
|
||||||
displayName: info.displayName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repoIcon: <FileIcon className="w-4 h-4" />,
|
repoIcon: <Image
|
||||||
displayName: repo.repoName,
|
src={info.icon}
|
||||||
|
alt={info.codeHostName}
|
||||||
|
className={`w-4 h-4 ${info.iconClassName}`}
|
||||||
|
/>,
|
||||||
|
displayName: info.displayName,
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
|
||||||
<h1 className="text-3xl font-semibold">{repo.displayName || repo.name}</h1>
|
<h1 className="text-3xl font-semibold">{repo.displayName || repo.name}</h1>
|
||||||
<p className="text-muted-foreground mt-2">{repo.name}</p>
|
<p className="text-muted-foreground mt-2">{repo.name}</p>
|
||||||
</div>
|
</div>
|
||||||
{(codeHostInfo && codeHostInfo.repoLink) && (
|
{codeHostInfo.repoLink && (
|
||||||
<Button variant="outline" asChild>
|
<Button variant="outline" asChild>
|
||||||
<Link href={codeHostInfo.repoLink} target="_blank" rel="noopener noreferrer" className="flex items-center">
|
<Link href={codeHostInfo.repoLink} target="_blank" rel="noopener noreferrer" className="flex items-center">
|
||||||
<Image
|
<Image
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,14 @@ import {
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
import { CodeHostType, getCodeHostBrowseAtBranchUrl } from "@/lib/utils"
|
import { getCodeHostBrowseAtBranchUrl } from "@/lib/utils"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
type RepoBranchesTableProps = {
|
type RepoBranchesTableProps = {
|
||||||
indexRevisions: string[];
|
indexRevisions: string[];
|
||||||
repoWebUrl: string | null;
|
repoWebUrl: string | null;
|
||||||
repoCodeHostType: string;
|
repoCodeHostType: CodeHostType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RepoBranchesTable = ({ indexRevisions, repoWebUrl, repoCodeHostType }: RepoBranchesTableProps) => {
|
export const RepoBranchesTable = ({ indexRevisions, repoWebUrl, repoCodeHostType }: RepoBranchesTableProps) => {
|
||||||
|
|
@ -39,7 +40,7 @@ export const RepoBranchesTable = ({ indexRevisions, repoWebUrl, repoCodeHostType
|
||||||
|
|
||||||
const branchUrl = getCodeHostBrowseAtBranchUrl({
|
const branchUrl = getCodeHostBrowseAtBranchUrl({
|
||||||
webUrl: repoWebUrl,
|
webUrl: repoWebUrl,
|
||||||
codeHostType: repoCodeHostType as CodeHostType,
|
codeHostType: repoCodeHostType,
|
||||||
branchName: refName,
|
branchName: refName,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { Input } from "@/components/ui/input"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
||||||
import { cn, CodeHostType, getCodeHostCommitUrl, getCodeHostIcon, getCodeHostInfoForRepo, getRepoImageSrc } from "@/lib/utils"
|
import { cn, getCodeHostCommitUrl, getCodeHostIcon, getCodeHostInfoForRepo, getRepoImageSrc } from "@/lib/utils"
|
||||||
import {
|
import {
|
||||||
type ColumnDef,
|
type ColumnDef,
|
||||||
type ColumnFiltersState,
|
type ColumnFiltersState,
|
||||||
|
|
@ -38,6 +38,7 @@ import { useToast } from "@/components/hooks/use-toast";
|
||||||
import { DisplayDate } from "../../components/DisplayDate"
|
import { DisplayDate } from "../../components/DisplayDate"
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
import { NotificationDot } from "../../components/notificationDot"
|
import { NotificationDot } from "../../components/notificationDot"
|
||||||
|
import { CodeHostType } from "@sourcebot/db"
|
||||||
|
|
||||||
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
// @see: https://v0.app/chat/repo-indexing-status-uhjdDim8OUS
|
||||||
|
|
||||||
|
|
@ -50,7 +51,7 @@ export type Repo = {
|
||||||
indexedAt: Date | null
|
indexedAt: Date | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
webUrl: string | null
|
webUrl: string | null
|
||||||
codeHostType: string
|
codeHostType: CodeHostType
|
||||||
imageUrl: string | null
|
imageUrl: string | null
|
||||||
indexedCommitHash: string | null
|
indexedCommitHash: string | null
|
||||||
latestJobStatus: "PENDING" | "IN_PROGRESS" | "COMPLETED" | "FAILED" | null
|
latestJobStatus: "PENDING" | "IN_PROGRESS" | "COMPLETED" | "FAILED" | null
|
||||||
|
|
@ -97,7 +98,7 @@ export const columns: ColumnDef<Repo>[] = [
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const repo = row.original;
|
const repo = row.original;
|
||||||
const codeHostIcon = getCodeHostIcon(repo.codeHostType as CodeHostType);
|
const codeHostIcon = getCodeHostIcon(repo.codeHostType);
|
||||||
const repoImageSrc = repo.imageUrl ? getRepoImageSrc(repo.imageUrl, repo.id) : undefined;
|
const repoImageSrc = repo.imageUrl ? getRepoImageSrc(repo.imageUrl, repo.id) : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -192,7 +193,7 @@ export const columns: ColumnDef<Repo>[] = [
|
||||||
|
|
||||||
const smallHash = hash.slice(0, 7);
|
const smallHash = hash.slice(0, 7);
|
||||||
const repo = row.original;
|
const repo = row.original;
|
||||||
const codeHostType = repo.codeHostType as CodeHostType;
|
const codeHostType = repo.codeHostType;
|
||||||
const webUrl = repo.webUrl;
|
const webUrl = repo.webUrl;
|
||||||
|
|
||||||
const commitUrl = getCodeHostCommitUrl({
|
const commitUrl = getCodeHostCommitUrl({
|
||||||
|
|
@ -252,7 +253,7 @@ export const columns: ColumnDef<Repo>[] = [
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
<Link href={`/${SINGLE_TENANT_ORG_DOMAIN}/repos/${repo.id}`}>View details</Link>
|
<Link href={`/${SINGLE_TENANT_ORG_DOMAIN}/repos/${repo.id}`}>View details</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
{(repo.webUrl && codeHostInfo) && (
|
{repo.webUrl && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem asChild>
|
<DropdownMenuItem asChild>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
||||||
import { env } from "@/env.mjs";
|
import { env } from "@/env.mjs";
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
|
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
|
||||||
import { notFound, ServiceErrorException } from "@/lib/serviceError";
|
import { notFound, ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { CodeHostType, isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import { withAuthV2 } from "@/withAuthV2";
|
import { withAuthV2 } from "@/withAuthV2";
|
||||||
import { AzureDevOpsConnectionConfig, BitbucketConnectionConfig, GenericGitHostConnectionConfig, GerritConnectionConfig, GiteaConnectionConfig, GithubConnectionConfig, GitlabConnectionConfig } from "@sourcebot/schemas/v3/index.type";
|
import { AzureDevOpsConnectionConfig, BitbucketConnectionConfig, GenericGitHostConnectionConfig, GerritConnectionConfig, GiteaConnectionConfig, GithubConnectionConfig, GitlabConnectionConfig } from "@sourcebot/schemas/v3/index.type";
|
||||||
import { getConfigSettings } from "@sourcebot/shared";
|
import { getConfigSettings } from "@sourcebot/shared";
|
||||||
|
|
@ -47,8 +47,9 @@ export default async function ConnectionDetailPage(props: ConnectionDetailPagePr
|
||||||
return undefined;
|
return undefined;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const codeHostUrl = (() => {
|
// Extracts the code host URL from the connection config.
|
||||||
const connectionType = connection.connectionType as CodeHostType;
|
const codeHostUrl: string = (() => {
|
||||||
|
const connectionType = connection.connectionType;
|
||||||
switch (connectionType) {
|
switch (connectionType) {
|
||||||
case 'github': {
|
case 'github': {
|
||||||
const config = connection.config as unknown as GithubConnectionConfig;
|
const config = connection.config as unknown as GithubConnectionConfig;
|
||||||
|
|
@ -66,19 +67,19 @@ export default async function ConnectionDetailPage(props: ConnectionDetailPagePr
|
||||||
const config = connection.config as unknown as GerritConnectionConfig;
|
const config = connection.config as unknown as GerritConnectionConfig;
|
||||||
return config.url;
|
return config.url;
|
||||||
}
|
}
|
||||||
case 'bitbucket-server': {
|
case 'bitbucket': {
|
||||||
const config = connection.config as unknown as BitbucketConnectionConfig;
|
const config = connection.config as unknown as BitbucketConnectionConfig;
|
||||||
return config.url!;
|
if (config.deploymentType === 'cloud') {
|
||||||
}
|
return config.url ?? 'https://bitbucket.org';
|
||||||
case 'bitbucket-cloud': {
|
} else {
|
||||||
const config = connection.config as unknown as BitbucketConnectionConfig;
|
return config.url!;
|
||||||
return config.url ?? 'https://bitbucket.org';
|
}
|
||||||
}
|
}
|
||||||
case 'azuredevops': {
|
case 'azuredevops': {
|
||||||
const config = connection.config as unknown as AzureDevOpsConnectionConfig;
|
const config = connection.config as unknown as AzureDevOpsConnectionConfig;
|
||||||
return config.url ?? 'https://dev.azure.com';
|
return config.url ?? 'https://dev.azure.com';
|
||||||
}
|
}
|
||||||
case 'generic-git-host': {
|
case 'git': {
|
||||||
const config = connection.config as unknown as GenericGitHostConnectionConfig;
|
const config = connection.config as unknown as GenericGitHostConnectionConfig;
|
||||||
return config.url;
|
return config.url;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
|
||||||
import { CodeHostType, getCodeHostIcon } from "@/lib/utils"
|
import { getCodeHostIcon } from "@/lib/utils"
|
||||||
|
import { ConnectionType } from "@sourcebot/db"
|
||||||
import {
|
import {
|
||||||
type ColumnDef,
|
type ColumnDef,
|
||||||
type ColumnFiltersState,
|
type ColumnFiltersState,
|
||||||
|
|
@ -35,7 +36,7 @@ export type Connection = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
syncedAt: Date | null
|
syncedAt: Date | null
|
||||||
codeHostType: CodeHostType
|
connectionType: ConnectionType
|
||||||
latestJobStatus: "PENDING" | "IN_PROGRESS" | "COMPLETED" | "FAILED" | null
|
latestJobStatus: "PENDING" | "IN_PROGRESS" | "COMPLETED" | "FAILED" | null
|
||||||
isFirstTimeSync: boolean
|
isFirstTimeSync: boolean
|
||||||
}
|
}
|
||||||
|
|
@ -80,13 +81,13 @@ export const columns: ColumnDef<Connection>[] = [
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const connection = row.original;
|
const connection = row.original;
|
||||||
const codeHostIcon = getCodeHostIcon(connection.codeHostType);
|
const codeHostIcon = getCodeHostIcon(connection.connectionType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row gap-2 items-center">
|
<div className="flex flex-row gap-2 items-center">
|
||||||
<Image
|
<Image
|
||||||
src={codeHostIcon.src}
|
src={codeHostIcon.src}
|
||||||
alt={`${connection.codeHostType} logo`}
|
alt={`${connection.connectionType} logo`}
|
||||||
className={codeHostIcon.className}
|
className={codeHostIcon.className}
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { sew } from "@/actions";
|
import { sew } from "@/actions";
|
||||||
import { ServiceErrorException } from "@/lib/serviceError";
|
import { ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { CodeHostType, isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import { withAuthV2 } from "@/withAuthV2";
|
import { withAuthV2 } from "@/withAuthV2";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ConnectionsTable } from "./components/connectionsTable";
|
import { ConnectionsTable } from "./components/connectionsTable";
|
||||||
|
|
@ -40,7 +40,7 @@ export default async function ConnectionsPage() {
|
||||||
<ConnectionsTable data={connections.map((connection) => ({
|
<ConnectionsTable data={connections.map((connection) => ({
|
||||||
id: connection.id,
|
id: connection.id,
|
||||||
name: connection.name,
|
name: connection.name,
|
||||||
codeHostType: connection.connectionType as CodeHostType,
|
connectionType: connection.connectionType,
|
||||||
syncedAt: connection.syncedAt,
|
syncedAt: connection.syncedAt,
|
||||||
latestJobStatus: connection.latestJobStatus,
|
latestJobStatus: connection.latestJobStatus,
|
||||||
isFirstTimeSync: connection.isFirstTimeSync,
|
isFirstTimeSync: connection.isFirstTimeSync,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
import { CodeHostIconButton } from "@/app/[domain]/components/codeHostIconButton";
|
import { CodeHostIconButton } from "@/app/[domain]/components/codeHostIconButton";
|
||||||
import { Card, CardTitle, CardDescription, CardHeader, CardContent } from "@/components/ui/card";
|
import { Card, CardTitle, CardDescription, CardHeader, CardContent } from "@/components/ui/card";
|
||||||
import { getCodeHostIcon } from "@/lib/utils";
|
import { getCodeHostIcon } from "@/lib/utils";
|
||||||
import { cn, CodeHostType } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { ImportSecretDialog } from "@/app/[domain]/components/importSecretDialog";
|
import { ImportSecretDialog } from "@/app/[domain]/components/importSecretDialog";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import { createCodeFoldingExtension } from "./codeFoldingExtension";
|
||||||
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
import { createAuditAction } from "@/ee/features/audit/actions";
|
import { createAuditAction } from "@/ee/features/audit/actions";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
const lineDecoration = Decoration.line({
|
const lineDecoration = Decoration.line({
|
||||||
attributes: { class: "cm-range-border-radius chat-lineHighlight" },
|
attributes: { class: "cm-range-border-radius chat-lineHighlight" },
|
||||||
|
|
@ -40,7 +41,7 @@ interface ReferencedFileSourceListItemProps {
|
||||||
language: string;
|
language: string;
|
||||||
revision: string;
|
revision: string;
|
||||||
repoName: string;
|
repoName: string;
|
||||||
repoCodeHostType: string;
|
repoCodeHostType: CodeHostType;
|
||||||
repoDisplayName?: string;
|
repoDisplayName?: string;
|
||||||
repoWebUrl?: string;
|
repoWebUrl?: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { cn, CodeHostType, getCodeHostIcon } from "@/lib/utils";
|
import { cn, getCodeHostIcon } from "@/lib/utils";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
import { LibraryBigIcon } from "lucide-react";
|
import { LibraryBigIcon } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { SearchScope } from "../types";
|
import { SearchScope } from "../types";
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ const getRepoPath = (repo: Repo): { path: string, isReadOnly: boolean } => {
|
||||||
// If we are dealing with a local repository, then use that as the path.
|
// If we are dealing with a local repository, then use that as the path.
|
||||||
// Mark as read-only since we aren't guaranteed to have write access to the local filesystem.
|
// Mark as read-only since we aren't guaranteed to have write access to the local filesystem.
|
||||||
const cloneUrl = new URL(repo.cloneUrl);
|
const cloneUrl = new URL(repo.cloneUrl);
|
||||||
if (repo.external_codeHostType === 'generic-git-host' && cloneUrl.protocol === 'file:') {
|
if (repo.external_codeHostType === 'genericGitHost' && cloneUrl.protocol === 'file:') {
|
||||||
return {
|
return {
|
||||||
path: cloneUrl.pathname,
|
path: cloneUrl.pathname,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// @NOTE : Please keep this file in sync with @sourcebot/mcp/src/schemas.ts
|
// @NOTE : Please keep this file in sync with @sourcebot/mcp/src/schemas.ts
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const locationSchema = z.object({
|
export const locationSchema = z.object({
|
||||||
|
|
@ -33,7 +34,7 @@ export const searchRequestSchema = z.object({
|
||||||
|
|
||||||
export const repositoryInfoSchema = z.object({
|
export const repositoryInfoSchema = z.object({
|
||||||
id: z.number(),
|
id: z.number(),
|
||||||
codeHostType: z.string(),
|
codeHostType: z.nativeEnum(CodeHostType),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
displayName: z.string().optional(),
|
displayName: z.string().optional(),
|
||||||
webUrl: z.string().optional(),
|
webUrl: z.string().optional(),
|
||||||
|
|
@ -153,7 +154,7 @@ export const fileSourceResponseSchema = z.object({
|
||||||
language: z.string(),
|
language: z.string(),
|
||||||
path: z.string(),
|
path: z.string(),
|
||||||
repository: z.string(),
|
repository: z.string(),
|
||||||
repositoryCodeHostType: z.string(),
|
repositoryCodeHostType: z.nativeEnum(CodeHostType),
|
||||||
repositoryDisplayName: z.string().optional(),
|
repositoryDisplayName: z.string().optional(),
|
||||||
repositoryWebUrl: z.string().optional(),
|
repositoryWebUrl: z.string().optional(),
|
||||||
branch: z.string().optional(),
|
branch: z.string().optional(),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { checkIfOrgDomainExists } from "@/actions";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { isServiceError } from "./utils";
|
import { isServiceError } from "./utils";
|
||||||
import { serviceErrorSchema } from "./serviceError";
|
import { serviceErrorSchema } from "./serviceError";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
export const secretCreateRequestSchema = z.object({
|
export const secretCreateRequestSchema = z.object({
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
|
|
@ -13,7 +14,7 @@ export const secreteDeleteRequestSchema = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const repositoryQuerySchema = z.object({
|
export const repositoryQuerySchema = z.object({
|
||||||
codeHostType: z.string(),
|
codeHostType: z.nativeEnum(CodeHostType),
|
||||||
repoId: z.number(),
|
repoId: z.number(),
|
||||||
repoName: z.string(),
|
repoName: z.string(),
|
||||||
repoDisplayName: z.string().optional(),
|
repoDisplayName: z.string().optional(),
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,10 @@ import { ServiceError } from "./serviceError";
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { ErrorCode } from "./errorCodes";
|
import { ErrorCode } from "./errorCodes";
|
||||||
import { NextRequest } from "next/server";
|
import { NextRequest } from "next/server";
|
||||||
import { Org } from "@sourcebot/db";
|
import { ConnectionType, Org } from "@sourcebot/db";
|
||||||
import { OrgMetadata, orgMetadataSchema } from "@/types";
|
import { OrgMetadata, orgMetadataSchema } from "@/types";
|
||||||
import { SINGLE_TENANT_ORG_DOMAIN } from "./constants";
|
import { SINGLE_TENANT_ORG_DOMAIN } from "./constants";
|
||||||
|
import { CodeHostType } from "@sourcebot/db";
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs))
|
||||||
|
|
@ -64,16 +65,6 @@ export const createPathWithQueryParams = (path: string, ...queryParams: [string,
|
||||||
return `${path}?${queryString}`;
|
return `${path}?${queryString}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeHostType =
|
|
||||||
"github" |
|
|
||||||
"gitlab" |
|
|
||||||
"gitea" |
|
|
||||||
"gerrit" |
|
|
||||||
"bitbucket-cloud" |
|
|
||||||
"bitbucket-server" |
|
|
||||||
"azuredevops" |
|
|
||||||
"generic-git-host";
|
|
||||||
|
|
||||||
export type AuthProviderType =
|
export type AuthProviderType =
|
||||||
"github" |
|
"github" |
|
||||||
"gitlab" |
|
"gitlab" |
|
||||||
|
|
@ -183,11 +174,11 @@ type CodeHostInfo = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCodeHostInfoForRepo = (repo: {
|
export const getCodeHostInfoForRepo = (repo: {
|
||||||
codeHostType: string,
|
codeHostType: CodeHostType,
|
||||||
name: string,
|
name: string,
|
||||||
displayName?: string,
|
displayName?: string,
|
||||||
webUrl?: string,
|
webUrl?: string,
|
||||||
}): CodeHostInfo | undefined => {
|
}): CodeHostInfo => {
|
||||||
const { codeHostType, name, displayName, webUrl } = repo;
|
const { codeHostType, name, displayName, webUrl } = repo;
|
||||||
|
|
||||||
switch (codeHostType) {
|
switch (codeHostType) {
|
||||||
|
|
@ -235,8 +226,7 @@ export const getCodeHostInfoForRepo = (repo: {
|
||||||
iconClassName: className,
|
iconClassName: className,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'gerrit':
|
case 'gerrit': {
|
||||||
case 'gitiles': {
|
|
||||||
const { src, className } = getCodeHostIcon('gerrit')!;
|
const { src, className } = getCodeHostIcon('gerrit')!;
|
||||||
return {
|
return {
|
||||||
type: "gerrit",
|
type: "gerrit",
|
||||||
|
|
@ -247,10 +237,10 @@ export const getCodeHostInfoForRepo = (repo: {
|
||||||
iconClassName: className,
|
iconClassName: className,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "bitbucket-server": {
|
case "bitbucketServer": {
|
||||||
const { src, className } = getCodeHostIcon('bitbucket-server')!;
|
const { src, className } = getCodeHostIcon('bitbucketServer')!;
|
||||||
return {
|
return {
|
||||||
type: "bitbucket-server",
|
type: "bitbucketServer",
|
||||||
displayName: displayName ?? name,
|
displayName: displayName ?? name,
|
||||||
codeHostName: "Bitbucket",
|
codeHostName: "Bitbucket",
|
||||||
repoLink: webUrl,
|
repoLink: webUrl,
|
||||||
|
|
@ -258,10 +248,10 @@ export const getCodeHostInfoForRepo = (repo: {
|
||||||
iconClassName: className,
|
iconClassName: className,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "bitbucket-cloud": {
|
case "bitbucketCloud": {
|
||||||
const { src, className } = getCodeHostIcon('bitbucket-cloud')!;
|
const { src, className } = getCodeHostIcon('bitbucketCloud')!;
|
||||||
return {
|
return {
|
||||||
type: "bitbucket-cloud",
|
type: "bitbucketCloud",
|
||||||
displayName: displayName ?? name,
|
displayName: displayName ?? name,
|
||||||
codeHostName: "Bitbucket",
|
codeHostName: "Bitbucket",
|
||||||
repoLink: webUrl,
|
repoLink: webUrl,
|
||||||
|
|
@ -269,10 +259,10 @@ export const getCodeHostInfoForRepo = (repo: {
|
||||||
iconClassName: className,
|
iconClassName: className,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "generic-git-host": {
|
case "genericGitHost": {
|
||||||
const { src, className } = getCodeHostIcon('generic-git-host')!;
|
const { src, className } = getCodeHostIcon('genericGitHost')!;
|
||||||
return {
|
return {
|
||||||
type: "generic-git-host",
|
type: "genericGitHost",
|
||||||
displayName: displayName ?? name,
|
displayName: displayName ?? name,
|
||||||
codeHostName: "Git Host",
|
codeHostName: "Git Host",
|
||||||
repoLink: webUrl,
|
repoLink: webUrl,
|
||||||
|
|
@ -283,7 +273,7 @@ export const getCodeHostInfoForRepo = (repo: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCodeHostIcon = (codeHostType: CodeHostType): { src: string, className?: string } => {
|
export const getCodeHostIcon = (codeHostType: CodeHostType | ConnectionType): { src: string, className?: string } => {
|
||||||
switch (codeHostType) {
|
switch (codeHostType) {
|
||||||
case "github":
|
case "github":
|
||||||
return {
|
return {
|
||||||
|
|
@ -302,8 +292,9 @@ export const getCodeHostIcon = (codeHostType: CodeHostType): { src: string, clas
|
||||||
return {
|
return {
|
||||||
src: gerritLogo,
|
src: gerritLogo,
|
||||||
}
|
}
|
||||||
case "bitbucket-cloud":
|
case "bitbucket":
|
||||||
case "bitbucket-server":
|
case "bitbucketCloud":
|
||||||
|
case "bitbucketServer":
|
||||||
return {
|
return {
|
||||||
src: bitbucketLogo,
|
src: bitbucketLogo,
|
||||||
}
|
}
|
||||||
|
|
@ -311,7 +302,8 @@ export const getCodeHostIcon = (codeHostType: CodeHostType): { src: string, clas
|
||||||
return {
|
return {
|
||||||
src: azuredevopsLogo,
|
src: azuredevopsLogo,
|
||||||
}
|
}
|
||||||
case "generic-git-host":
|
case "git":
|
||||||
|
case "genericGitHost":
|
||||||
return {
|
return {
|
||||||
src: gitLogo,
|
src: gitLogo,
|
||||||
}
|
}
|
||||||
|
|
@ -340,13 +332,13 @@ export const getCodeHostCommitUrl = ({
|
||||||
return `${webUrl}/commit/${commitHash}`;
|
return `${webUrl}/commit/${commitHash}`;
|
||||||
case 'azuredevops':
|
case 'azuredevops':
|
||||||
return `${webUrl}/commit/${commitHash}`;
|
return `${webUrl}/commit/${commitHash}`;
|
||||||
case 'bitbucket-cloud':
|
case 'bitbucketCloud':
|
||||||
return `${webUrl}/commits/${commitHash}`;
|
return `${webUrl}/commits/${commitHash}`;
|
||||||
case 'bitbucket-server':
|
case 'bitbucketServer':
|
||||||
return `${webUrl}/commits/${commitHash}`;
|
return `${webUrl}/commits/${commitHash}`;
|
||||||
case 'gerrit':
|
case 'gerrit':
|
||||||
return `${webUrl}/+/${commitHash}`;
|
return `${webUrl}/+/${commitHash}`;
|
||||||
case 'generic-git-host':
|
case 'genericGitHost':
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -373,13 +365,13 @@ export const getCodeHostBrowseAtBranchUrl = ({
|
||||||
return `${webUrl}/src/branch/${branchName}`;
|
return `${webUrl}/src/branch/${branchName}`;
|
||||||
case 'azuredevops':
|
case 'azuredevops':
|
||||||
return `${webUrl}?branch=${branchName}`;
|
return `${webUrl}?branch=${branchName}`;
|
||||||
case 'bitbucket-cloud':
|
case 'bitbucketCloud':
|
||||||
return `${webUrl}?at=${branchName}`;
|
return `${webUrl}?at=${branchName}`;
|
||||||
case 'bitbucket-server':
|
case 'bitbucketServer':
|
||||||
return `${webUrl}?at=${branchName}`;
|
return `${webUrl}?at=${branchName}`;
|
||||||
case 'gerrit':
|
case 'gerrit':
|
||||||
return `${webUrl}/+/${branchName}`;
|
return `${webUrl}/+/${branchName}`;
|
||||||
case 'generic-git-host':
|
case 'genericGitHost':
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,11 +381,11 @@ export const isAuthSupportedForCodeHost = (codeHostType: CodeHostType): boolean
|
||||||
case "github":
|
case "github":
|
||||||
case "gitlab":
|
case "gitlab":
|
||||||
case "gitea":
|
case "gitea":
|
||||||
case "bitbucket-cloud":
|
case "bitbucketCloud":
|
||||||
case "bitbucket-server":
|
case "bitbucketServer":
|
||||||
case "azuredevops":
|
case "azuredevops":
|
||||||
return true;
|
return true;
|
||||||
case "generic-git-host":
|
case "genericGitHost":
|
||||||
case "gerrit":
|
case "gerrit":
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue