mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-12 09:25:24 +02:00
feat(providers): add gitlab bitbucket and github providers
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
import {
|
||||
BitbucketIcon,
|
||||
GithubIcon,
|
||||
GitlabIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { api } from "@/utils/api";
|
||||
import { useUrl } from "@/utils/hooks/use-url";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { ExternalLink } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
const Schema = z.object({
|
||||
name: z.string().min(1, {
|
||||
message: "Name is required",
|
||||
}),
|
||||
username: z.string().min(1, {
|
||||
message: "Username is required",
|
||||
}),
|
||||
password: z.string().min(1, {
|
||||
message: "App Password is required",
|
||||
}),
|
||||
workspaceName: z.string().optional(),
|
||||
});
|
||||
|
||||
type Schema = z.infer<typeof Schema>;
|
||||
|
||||
export const AddBitbucketProvider = () => {
|
||||
const utils = api.useUtils();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const url = useUrl();
|
||||
const { mutateAsync, error, isError } =
|
||||
api.gitProvider.createBitbucketProvider.useMutation();
|
||||
const { data: auth } = api.auth.get.useQuery();
|
||||
const router = useRouter();
|
||||
const form = useForm<Schema>({
|
||||
defaultValues: {
|
||||
username: "",
|
||||
password: "",
|
||||
workspaceName: "",
|
||||
},
|
||||
resolver: zodResolver(Schema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.reset({
|
||||
username: "",
|
||||
password: "",
|
||||
workspaceName: "",
|
||||
});
|
||||
}, [form, isOpen]);
|
||||
|
||||
const onSubmit = async (data: Schema) => {
|
||||
await mutateAsync({
|
||||
bitbucketUsername: data.username,
|
||||
appPassword: data.password,
|
||||
bitbucketWorkspaceName: data.workspaceName || "",
|
||||
authId: auth?.id || "",
|
||||
name: data.name || "",
|
||||
})
|
||||
.then(async () => {
|
||||
await utils.gitProvider.getAll.invalidate();
|
||||
toast.success("Bitbucket configured successfully");
|
||||
setIsOpen(false);
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error configuring Bitbucket");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="flex items-center space-x-1 bg-blue-700 text-white hover:bg-blue-600"
|
||||
>
|
||||
<BitbucketIcon />
|
||||
<span>Bitbucket</span>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-2xl overflow-y-auto max-h-screen">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
Bitbucket Provider <BitbucketIcon className="size-5" />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||
<Form {...form}>
|
||||
<form
|
||||
id="hook-form-add-bitbucket"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="grid w-full gap-1"
|
||||
>
|
||||
<CardContent className="p-0">
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
To integrate your Bitbucket account, you need to create a new
|
||||
App Password in your Bitbucket settings. Follow these steps:
|
||||
</p>
|
||||
<ol className="list-decimal list-inside text-sm text-muted-foreground">
|
||||
<li className="flex flex-row gap-2 items-center">
|
||||
Create new App Password{" "}
|
||||
<Link
|
||||
href="https://bitbucket.org/account/settings/app-passwords/new"
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalLink className="w-fit text-primary size-4" />
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
When creating the App Password, ensure you grant the
|
||||
following permissions:
|
||||
<ul className="list-disc list-inside ml-4">
|
||||
<li>Account: Read</li>
|
||||
<li>Workspace membership: Read</li>
|
||||
<li>Projects: Read</li>
|
||||
<li>Repositories: Read</li>
|
||||
<li>Pull requests: Read</li>
|
||||
<li>Webhooks: Read and write</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
After creating, you'll receive an App Password. Copy it and
|
||||
paste it below along with your Bitbucket username.
|
||||
</li>
|
||||
</ol>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Random Name eg(my-personal-account)"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bitbucket Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Your Bitbucket username"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>App Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="ATBBPDYUC94nR96Nj7Cqpp4pfwKk03573DD2"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="workspaceName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Workspace Name (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="For organization accounts"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button isLoading={form.formState.isSubmitting}>
|
||||
Configure Bitbucket
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { api } from "@/utils/api";
|
||||
import { useUrl } from "@/utils/hooks/use-url";
|
||||
import { format } from "date-fns";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const AddGithubProvider = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const url = useUrl();
|
||||
const { data } = api.auth.get.useQuery();
|
||||
const [manifest, setManifest] = useState("");
|
||||
const [isOrganization, setIsOrganization] = useState(false);
|
||||
const [organizationName, setOrganization] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const url = document.location.origin;
|
||||
const manifest = JSON.stringify(
|
||||
{
|
||||
redirect_url: `${origin}/api/providers/github/redirect?authId=${data?.id}`,
|
||||
name: `Dokploy-${format(new Date(), "yyyy-MM-dd")}`,
|
||||
url: origin,
|
||||
hook_attributes: {
|
||||
url: `${url}/api/deploy/github`,
|
||||
},
|
||||
callback_urls: [`${origin}/api/providers/github/redirect`],
|
||||
public: false,
|
||||
request_oauth_on_install: true,
|
||||
default_permissions: {
|
||||
contents: "read",
|
||||
metadata: "read",
|
||||
emails: "read",
|
||||
pull_requests: "write",
|
||||
},
|
||||
default_events: ["pull_request", "push"],
|
||||
},
|
||||
null,
|
||||
4,
|
||||
);
|
||||
|
||||
setManifest(manifest);
|
||||
}, [data?.id]);
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="secondary" className="flex items-center space-x-1">
|
||||
<GithubIcon />
|
||||
<span>Github</span>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-2xl ">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
Github Provider <GithubIcon className="size-5" />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div id="hook-form-add-project" className="grid w-full gap-1">
|
||||
<CardContent className="p-0">
|
||||
<div className="flex flex-col ">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
To integrate your GitHub account with our services, you'll need
|
||||
to create and install a GitHub app. This process is
|
||||
straightforward and only takes a few minutes. Click the button
|
||||
below to get started.
|
||||
</p>
|
||||
<div className="mt-4 flex flex-col gap-4">
|
||||
<div className="flex flex-row gap-4">
|
||||
<span>Organization?</span>
|
||||
<Switch
|
||||
checked={isOrganization}
|
||||
onCheckedChange={(checked) => setIsOrganization(checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isOrganization && (
|
||||
<Input
|
||||
required
|
||||
placeholder="Organization name"
|
||||
onChange={(e) => setOrganization(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<form
|
||||
action={
|
||||
isOrganization
|
||||
? `https://github.com/organizations/${organizationName}/settings/apps/new?state=gh_init:${data?.id}`
|
||||
: `https://github.com/settings/apps/new?state=gh_init:${data?.id}`
|
||||
}
|
||||
method="post"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
name="manifest"
|
||||
id="manifest"
|
||||
defaultValue={manifest}
|
||||
className="invisible"
|
||||
/>
|
||||
<br />
|
||||
|
||||
<div className="flex w-full justify-end">
|
||||
<Button
|
||||
disabled={isOrganization && organizationName.length < 1}
|
||||
type="submit"
|
||||
className="self-end"
|
||||
>
|
||||
Create GitHub App
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</CardContent>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,250 @@
|
||||
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { api } from "@/utils/api";
|
||||
import { useUrl } from "@/utils/hooks/use-url";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { ExternalLink } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import { toast } from "sonner";
|
||||
|
||||
const Schema = z.object({
|
||||
name: z.string().min(1, {
|
||||
message: "Name is required",
|
||||
}),
|
||||
applicationId: z.string().min(1, {
|
||||
message: "Application ID is required",
|
||||
}),
|
||||
applicationSecret: z.string().min(1, {
|
||||
message: "Application Secret is required",
|
||||
}),
|
||||
|
||||
redirectUri: z.string().min(1, {
|
||||
message: "Redirect URI is required",
|
||||
}),
|
||||
groupName: z.string().optional(),
|
||||
});
|
||||
|
||||
type Schema = z.infer<typeof Schema>;
|
||||
|
||||
export const AddGitlabProvider = () => {
|
||||
const utils = api.useUtils();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const url = useUrl();
|
||||
const { data: auth } = api.auth.get.useQuery();
|
||||
const { mutateAsync, error, isError } =
|
||||
api.gitProvider.createGitlabProvider.useMutation();
|
||||
const webhookUrl = `${url}/api/providers/gitlab/callback`;
|
||||
|
||||
const form = useForm<Schema>({
|
||||
defaultValues: {
|
||||
applicationId: "",
|
||||
applicationSecret: "",
|
||||
groupName: "",
|
||||
redirectUri: webhookUrl,
|
||||
},
|
||||
resolver: zodResolver(Schema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.reset({
|
||||
applicationId: "",
|
||||
applicationSecret: "",
|
||||
groupName: "",
|
||||
redirectUri: webhookUrl,
|
||||
});
|
||||
}, [form, isOpen]);
|
||||
|
||||
const onSubmit = async (data: Schema) => {
|
||||
await mutateAsync({
|
||||
applicationId: data.applicationId || "",
|
||||
secret: data.applicationSecret || "",
|
||||
groupName: data.groupName || "",
|
||||
authId: auth?.id || "",
|
||||
name: data.name || "",
|
||||
redirectUri: data.redirectUri || "",
|
||||
})
|
||||
.then(async () => {
|
||||
await utils.gitProvider.getAll.invalidate();
|
||||
toast.success("GitLab created successfully");
|
||||
setIsOpen(false);
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error configuring GitLab");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="default"
|
||||
className="flex items-center space-x-1 bg-purple-700 text-white hover:bg-purple-600"
|
||||
>
|
||||
<GitlabIcon />
|
||||
<span>GitLab</span>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-2xl overflow-y-auto max-h-screen ">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
GitLab Provider <GitlabIcon className="size-5" />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||
<Form {...form}>
|
||||
<form
|
||||
id="hook-form-add-gitlab"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="grid w-full gap-1"
|
||||
>
|
||||
<CardContent className="p-0">
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
To integrate your GitLab account, you need to create a new
|
||||
application in your GitLab settings. Follow these steps:
|
||||
</p>
|
||||
<ol className="list-decimal list-inside text-sm text-muted-foreground">
|
||||
<li className="flex flex-row gap-2 items-center">
|
||||
Go to your GitLab profile settings{" "}
|
||||
<Link
|
||||
href="https://gitlab.com/-/profile/applications"
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalLink className="w-fit text-primary size-4" />
|
||||
</Link>
|
||||
</li>
|
||||
<li>Navigate to Applications</li>
|
||||
<li>
|
||||
Create a new application with the following details:
|
||||
<ul className="list-disc list-inside ml-4">
|
||||
<li>Name: Dokploy</li>
|
||||
<li>
|
||||
Redirect URI:{" "}
|
||||
<span className="text-primary">{webhookUrl}</span>{" "}
|
||||
</li>
|
||||
<li>Scopes: api, read_user, read_repository</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
After creating, you'll receive an Application ID and Secret,
|
||||
copy them and paste them below.
|
||||
</li>
|
||||
</ol>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Random Name eg(my-personal-account)"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="redirectUri"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Redirect URI</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
disabled
|
||||
placeholder="Random Name eg(my-personal-account)"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="applicationId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Application ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Application ID" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="applicationSecret"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Application Secret</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="Application Secret"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="groupName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Group Name (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="For organization/group access"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button isLoading={form.formState.isSubmitting}>
|
||||
Configure GitLab App
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { AddGitlabProvider } from "./add-gitlab-provider";
|
||||
import {
|
||||
BitbucketIcon,
|
||||
GithubIcon,
|
||||
GitlabIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { AddGithubProvider } from "./add-github-provider";
|
||||
import { AddBitbucketProvider } from "./add-bitbucket-provider";
|
||||
import { api } from "@/utils/api";
|
||||
import Link from "next/link";
|
||||
import { RemoveGitProvider } from "../github/remove-github-app";
|
||||
import { useUrl } from "@/utils/hooks/use-url";
|
||||
|
||||
export const ShowGitProviders = () => {
|
||||
const { data } = api.gitProvider.getAll.useQuery();
|
||||
|
||||
const url = useUrl();
|
||||
|
||||
const getGitlabUrl = (clientId: string, gitlabId: string) => {
|
||||
const redirectUri = `${url}/api/providers/gitlab/callback?gitlabId=${gitlabId}`;
|
||||
|
||||
const scope = "api read_user read_repository";
|
||||
|
||||
const authUrl = `https://gitlab.com/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
||||
|
||||
return authUrl;
|
||||
};
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-2xl font-bold">Git Providers</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Connect your Git Providers to use it for login.
|
||||
</p>
|
||||
</div>
|
||||
<Card className=" bg-transparent">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex gap-4 sm:flex-row flex-col w-full">
|
||||
<AddGithubProvider />
|
||||
<AddGitlabProvider />
|
||||
<AddBitbucketProvider />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{data?.map((gitProvider, index) => {
|
||||
const isGithub = gitProvider.providerType === "github";
|
||||
const isGitlab = gitProvider.providerType === "gitlab";
|
||||
const haveGithubRequirements =
|
||||
gitProvider.providerType === "github" &&
|
||||
gitProvider.githubProvider?.githubPrivateKey &&
|
||||
gitProvider.githubProvider?.githubAppId &&
|
||||
gitProvider.githubProvider?.githubInstallationId;
|
||||
|
||||
const haveGitlabRequirements =
|
||||
gitProvider.gitlabProvider?.accessToken &&
|
||||
gitProvider.gitlabProvider?.refreshToken;
|
||||
return (
|
||||
<div
|
||||
className="space-y-4"
|
||||
key={`${gitProvider.gitProviderId}-${index}`}
|
||||
>
|
||||
<Card className="flex sm:flex-row max-sm:gap-2 flex-col justify-between items-center p-4">
|
||||
<div className="flex items-center space-x-4 w-full">
|
||||
{gitProvider.providerType === "github" && (
|
||||
<GithubIcon className="w-6 h-6" />
|
||||
)}
|
||||
{gitProvider.providerType === "gitlab" && (
|
||||
<GitlabIcon className="w-6 h-6" />
|
||||
)}
|
||||
{gitProvider.providerType === "bitbucket" && (
|
||||
<BitbucketIcon className="w-6 h-6" />
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
{gitProvider.providerType === "github"
|
||||
? "GitHub"
|
||||
: gitProvider.providerType === "gitlab"
|
||||
? "GitLab"
|
||||
: "Bitbucket"}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{gitProvider.name}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex sm:gap-4 sm:flex-row flex-col">
|
||||
{!haveGithubRequirements && isGithub && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<Link
|
||||
href={`${gitProvider?.githubProvider?.githubAppName}/installations/new?state=gh_setup:${gitProvider?.githubProvider.githubProviderId}`}
|
||||
className={buttonVariants({ className: "w-fit" })}
|
||||
>
|
||||
Install Github App
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{haveGithubRequirements && isGithub && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<Link
|
||||
href={`${gitProvider?.githubProvider?.githubAppName}`}
|
||||
target="_blank"
|
||||
className={buttonVariants({
|
||||
className: "w-fit",
|
||||
variant: "secondary",
|
||||
})}
|
||||
>
|
||||
<span className="text-sm">Manage Github App</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!haveGitlabRequirements && isGitlab && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<Link
|
||||
href={getGitlabUrl(
|
||||
gitProvider.gitlabProvider?.applicationId || "",
|
||||
gitProvider.gitlabProvider?.gitlabProviderId || "",
|
||||
)}
|
||||
target="_blank"
|
||||
className={buttonVariants({
|
||||
className: "w-fit",
|
||||
variant: "secondary",
|
||||
})}
|
||||
>
|
||||
<span className="text-sm">Install Gitlab App</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<RemoveGitProvider
|
||||
gitProviderId={gitProvider.gitProviderId}
|
||||
gitProviderType={gitProvider.providerType}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user