mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor(git-provider): update UnauthorizedGitProvider to use service prop and enhance access handling
- Changed the prop name from 'application' to 'service' in the UnauthorizedGitProvider component for clarity. - Updated the logic to check for unauthorized access to the git provider in the compose router, returning a new field 'hasGitProviderAccess'. - Implemented a disconnect functionality for git providers in the ShowProviderFormCompose component, providing user feedback on success or failure.
This commit is contained in:
@@ -122,7 +122,7 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<UnauthorizedGitProvider
|
<UnauthorizedGitProvider
|
||||||
application={application}
|
service={application}
|
||||||
onDisconnect={handleDisconnect}
|
onDisconnect={handleDisconnect}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -9,15 +9,17 @@ import { DialogAction } from "@/components/shared/dialog-action";
|
|||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import type { RouterOutputs } from "@/utils/api";
|
||||||
import { AlertCircle, GitBranch, Unlink } from "lucide-react";
|
import { AlertCircle, GitBranch, Unlink } from "lucide-react";
|
||||||
|
|
||||||
export const UnauthorizedGitProvider = ({
|
interface Props {
|
||||||
application,
|
service:
|
||||||
onDisconnect,
|
| RouterOutputs["application"]["one"]
|
||||||
}: {
|
| RouterOutputs["compose"]["one"];
|
||||||
application: any;
|
|
||||||
onDisconnect: () => void;
|
onDisconnect: () => void;
|
||||||
}) => {
|
}
|
||||||
|
|
||||||
|
export const UnauthorizedGitProvider = ({ service, onDisconnect }: Props) => {
|
||||||
const getProviderIcon = (sourceType: string) => {
|
const getProviderIcon = (sourceType: string) => {
|
||||||
switch (sourceType) {
|
switch (sourceType) {
|
||||||
case "github":
|
case "github":
|
||||||
@@ -36,35 +38,35 @@ export const UnauthorizedGitProvider = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getRepositoryInfo = () => {
|
const getRepositoryInfo = () => {
|
||||||
switch (application.sourceType) {
|
switch (service.sourceType) {
|
||||||
case "github":
|
case "github":
|
||||||
return {
|
return {
|
||||||
repo: application.repository,
|
repo: service.repository,
|
||||||
branch: application.branch,
|
branch: service.branch,
|
||||||
owner: application.owner,
|
owner: service.owner,
|
||||||
};
|
};
|
||||||
case "gitlab":
|
case "gitlab":
|
||||||
return {
|
return {
|
||||||
repo: application.gitlabRepository,
|
repo: service.gitlabRepository,
|
||||||
branch: application.gitlabBranch,
|
branch: service.gitlabBranch,
|
||||||
owner: application.gitlabOwner,
|
owner: service.gitlabOwner,
|
||||||
};
|
};
|
||||||
case "bitbucket":
|
case "bitbucket":
|
||||||
return {
|
return {
|
||||||
repo: application.bitbucketRepository,
|
repo: service.bitbucketRepository,
|
||||||
branch: application.bitbucketBranch,
|
branch: service.bitbucketBranch,
|
||||||
owner: application.bitbucketOwner,
|
owner: service.bitbucketOwner,
|
||||||
};
|
};
|
||||||
case "gitea":
|
case "gitea":
|
||||||
return {
|
return {
|
||||||
repo: application.giteaRepository,
|
repo: service.giteaRepository,
|
||||||
branch: application.giteaBranch,
|
branch: service.giteaBranch,
|
||||||
owner: application.giteaOwner,
|
owner: service.giteaOwner,
|
||||||
};
|
};
|
||||||
case "git":
|
case "git":
|
||||||
return {
|
return {
|
||||||
repo: application.customGitUrl,
|
repo: service.customGitUrl,
|
||||||
branch: application.customGitBranch,
|
branch: service.customGitBranch,
|
||||||
owner: null,
|
owner: null,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
@@ -79,7 +81,7 @@ export const UnauthorizedGitProvider = ({
|
|||||||
<Alert>
|
<Alert>
|
||||||
<AlertCircle className="h-4 w-4" />
|
<AlertCircle className="h-4 w-4" />
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
This application is connected to a {application.sourceType} repository
|
This application is connected to a {service.sourceType} repository
|
||||||
through a git provider that you don't have access to. You can see
|
through a git provider that you don't have access to. You can see
|
||||||
basic repository information below, but cannot modify the
|
basic repository information below, but cannot modify the
|
||||||
configuration.
|
configuration.
|
||||||
@@ -89,9 +91,9 @@ export const UnauthorizedGitProvider = ({
|
|||||||
<Card className="border-dashed border-2 border-muted-foreground/20 bg-transparent">
|
<Card className="border-dashed border-2 border-muted-foreground/20 bg-transparent">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2">
|
<CardTitle className="flex items-center gap-2">
|
||||||
{getProviderIcon(application.sourceType)}
|
{getProviderIcon(service.sourceType)}
|
||||||
<span className="capitalize text-sm font-medium">
|
<span className="capitalize text-sm font-medium">
|
||||||
{application.sourceType} Repository
|
{service.sourceType} Repository
|
||||||
</span>
|
</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import { SaveGitProviderCompose } from "./save-git-provider-compose";
|
|||||||
import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose";
|
import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose";
|
||||||
import { SaveGithubProviderCompose } from "./save-github-provider-compose";
|
import { SaveGithubProviderCompose } from "./save-github-provider-compose";
|
||||||
import { SaveGitlabProviderCompose } from "./save-gitlab-provider-compose";
|
import { SaveGitlabProviderCompose } from "./save-gitlab-provider-compose";
|
||||||
|
import { UnauthorizedGitProvider } from "@/components/dashboard/application/general/generic/unauthorized-git-provider";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
type TabState = "github" | "git" | "raw" | "gitlab" | "bitbucket" | "gitea";
|
type TabState = "github" | "git" | "raw" | "gitlab" | "bitbucket" | "gitea";
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -34,12 +36,29 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
|
|||||||
const { data: giteaProviders, isLoading: isLoadingGitea } =
|
const { data: giteaProviders, isLoading: isLoadingGitea } =
|
||||||
api.gitea.giteaProviders.useQuery();
|
api.gitea.giteaProviders.useQuery();
|
||||||
|
|
||||||
const { data: compose } = api.compose.one.useQuery({ composeId });
|
const { mutateAsync: disconnectGitProvider } =
|
||||||
|
api.compose.disconnectGitProvider.useMutation();
|
||||||
|
|
||||||
|
const { data: compose, refetch } = api.compose.one.useQuery({ composeId });
|
||||||
const [tab, setSab] = useState<TabState>(compose?.sourceType || "github");
|
const [tab, setSab] = useState<TabState>(compose?.sourceType || "github");
|
||||||
|
|
||||||
const isLoading =
|
const isLoading =
|
||||||
isLoadingGithub || isLoadingGitlab || isLoadingBitbucket || isLoadingGitea;
|
isLoadingGithub || isLoadingGitlab || isLoadingBitbucket || isLoadingGitea;
|
||||||
|
|
||||||
|
const handleDisconnect = async () => {
|
||||||
|
try {
|
||||||
|
await disconnectGitProvider({ composeId });
|
||||||
|
toast.success("Repository disconnected successfully");
|
||||||
|
await refetch();
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(
|
||||||
|
`Failed to disconnect repository: ${
|
||||||
|
error instanceof Error ? error.message : "Unknown error"
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<Card className="group relative w-full bg-transparent">
|
<Card className="group relative w-full bg-transparent">
|
||||||
@@ -68,6 +87,37 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if user doesn't have access to the current git provider
|
||||||
|
if (
|
||||||
|
compose &&
|
||||||
|
!compose.hasGitProviderAccess &&
|
||||||
|
compose.sourceType !== "raw"
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Card className="group relative w-full bg-transparent">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-start justify-between">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<span className="flex flex-col space-y-0.5">Provider</span>
|
||||||
|
<p className="flex items-center text-sm font-normal text-muted-foreground">
|
||||||
|
Repository connection through unauthorized provider
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="hidden space-y-1 text-sm font-normal md:block">
|
||||||
|
<GitBranch className="size-6 text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<UnauthorizedGitProvider
|
||||||
|
service={compose}
|
||||||
|
onDisconnect={handleDisconnect}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="group relative w-full bg-transparent">
|
<Card className="group relative w-full bg-transparent">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
deleteMount,
|
deleteMount,
|
||||||
findComposeById,
|
findComposeById,
|
||||||
findDomainsByComposeId,
|
findDomainsByComposeId,
|
||||||
|
findGitProviderById,
|
||||||
findProjectById,
|
findProjectById,
|
||||||
findServerById,
|
findServerById,
|
||||||
findUserById,
|
findUserById,
|
||||||
@@ -119,7 +120,45 @@ export const composeRouter = createTRPCRouter({
|
|||||||
message: "You are not authorized to access this compose",
|
message: "You are not authorized to access this compose",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return compose;
|
|
||||||
|
let hasGitProviderAccess = true;
|
||||||
|
let unauthorizedProvider: string | null = null;
|
||||||
|
|
||||||
|
const getGitProviderId = () => {
|
||||||
|
switch (compose.sourceType) {
|
||||||
|
case "github":
|
||||||
|
return compose.github?.gitProviderId;
|
||||||
|
case "gitlab":
|
||||||
|
return compose.gitlab?.gitProviderId;
|
||||||
|
case "bitbucket":
|
||||||
|
return compose.bitbucket?.gitProviderId;
|
||||||
|
case "gitea":
|
||||||
|
return compose.gitea?.gitProviderId;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const gitProviderId = getGitProviderId();
|
||||||
|
|
||||||
|
if (gitProviderId) {
|
||||||
|
try {
|
||||||
|
const gitProvider = await findGitProviderById(gitProviderId);
|
||||||
|
if (gitProvider.userId !== ctx.session.userId) {
|
||||||
|
hasGitProviderAccess = false;
|
||||||
|
unauthorizedProvider = compose.sourceType;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
hasGitProviderAccess = false;
|
||||||
|
unauthorizedProvider = compose.sourceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...compose,
|
||||||
|
hasGitProviderAccess,
|
||||||
|
unauthorizedProvider,
|
||||||
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
update: protectedProcedure
|
update: protectedProcedure
|
||||||
@@ -526,6 +565,61 @@ export const composeRouter = createTRPCRouter({
|
|||||||
const uniqueTags = _.uniq(allTags);
|
const uniqueTags = _.uniq(allTags);
|
||||||
return uniqueTags;
|
return uniqueTags;
|
||||||
}),
|
}),
|
||||||
|
disconnectGitProvider: protectedProcedure
|
||||||
|
.input(apiFindCompose)
|
||||||
|
.mutation(async ({ input, ctx }) => {
|
||||||
|
const compose = await findComposeById(input.composeId);
|
||||||
|
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "UNAUTHORIZED",
|
||||||
|
message: "You are not authorized to disconnect this git provider",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset all git provider related fields
|
||||||
|
await updateCompose(input.composeId, {
|
||||||
|
// GitHub fields
|
||||||
|
repository: null,
|
||||||
|
branch: null,
|
||||||
|
owner: null,
|
||||||
|
composePath: undefined,
|
||||||
|
githubId: null,
|
||||||
|
triggerType: "push",
|
||||||
|
|
||||||
|
// GitLab fields
|
||||||
|
gitlabRepository: null,
|
||||||
|
gitlabOwner: null,
|
||||||
|
gitlabBranch: null,
|
||||||
|
gitlabId: null,
|
||||||
|
gitlabProjectId: null,
|
||||||
|
gitlabPathNamespace: null,
|
||||||
|
|
||||||
|
// Bitbucket fields
|
||||||
|
bitbucketRepository: null,
|
||||||
|
bitbucketOwner: null,
|
||||||
|
bitbucketBranch: null,
|
||||||
|
bitbucketId: null,
|
||||||
|
|
||||||
|
// Gitea fields
|
||||||
|
giteaRepository: null,
|
||||||
|
giteaOwner: null,
|
||||||
|
giteaBranch: null,
|
||||||
|
giteaId: null,
|
||||||
|
|
||||||
|
// Custom Git fields
|
||||||
|
customGitBranch: null,
|
||||||
|
customGitUrl: null,
|
||||||
|
customGitSSHKeyId: null,
|
||||||
|
|
||||||
|
// Common fields
|
||||||
|
sourceType: "github", // Reset to default
|
||||||
|
composeStatus: "idle",
|
||||||
|
watchPaths: null,
|
||||||
|
enableSubmodules: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
|
||||||
move: protectedProcedure
|
move: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
|
|||||||
Reference in New Issue
Block a user