mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-01 09:42:16 +00:00
Merge branch 'canary' into 319-ability-to-roll-back-service-depoyments
This commit is contained in:
@@ -247,7 +247,7 @@ export const UpdateVolume = ({
|
||||
control={form.control}
|
||||
name="content"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormItem className="max-w-full max-w-[45rem]">
|
||||
<FormLabel>Content</FormLabel>
|
||||
<FormControl>
|
||||
<FormControl>
|
||||
@@ -256,7 +256,7 @@ export const UpdateVolume = ({
|
||||
placeholder={`NODE_ENV=production
|
||||
PORT=3000
|
||||
`}
|
||||
className="h-96 font-mono"
|
||||
className="h-96 font-mono w-full"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -39,6 +39,7 @@ export type ValidationState = {
|
||||
error?: string;
|
||||
resolvedIp?: string;
|
||||
message?: string;
|
||||
cdnProvider?: string;
|
||||
};
|
||||
|
||||
export type ValidationStates = Record<string, ValidationState>;
|
||||
@@ -119,6 +120,7 @@ export const ShowDomains = ({ id, type }: Props) => {
|
||||
isValid: result.isValid,
|
||||
error: result.error,
|
||||
resolvedIp: result.resolvedIp,
|
||||
cdnProvider: result.cdnProvider,
|
||||
message: result.error && result.isValid ? result.error : undefined,
|
||||
},
|
||||
}));
|
||||
@@ -354,8 +356,9 @@ export const ShowDomains = ({ id, type }: Props) => {
|
||||
) : validationState?.isValid ? (
|
||||
<>
|
||||
<CheckCircle2 className="size-3 mr-1" />
|
||||
{validationState.message
|
||||
? "Behind Cloudflare"
|
||||
{validationState.message &&
|
||||
validationState.cdnProvider
|
||||
? `Behind ${validationState.cdnProvider}`
|
||||
: "DNS Valid"}
|
||||
</>
|
||||
) : validationState?.error ? (
|
||||
|
||||
@@ -49,7 +49,7 @@ export const ShowEnvironment = ({ applicationId }: Props) => {
|
||||
currentBuildArgs !== (data?.buildArgs || "");
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
if (data && !hasChanges) {
|
||||
form.reset({
|
||||
env: data.env || "",
|
||||
buildArgs: data.buildArgs || "",
|
||||
|
||||
@@ -16,9 +16,11 @@ import { api } from "@/utils/api";
|
||||
import { GitBranch, Loader2, UploadCloud } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { SaveBitbucketProvider } from "./save-bitbucket-provider";
|
||||
import { SaveDragNDrop } from "./save-drag-n-drop";
|
||||
import { SaveGitlabProvider } from "./save-gitlab-provider";
|
||||
import { UnauthorizedGitProvider } from "./unauthorized-git-provider";
|
||||
|
||||
type TabState =
|
||||
| "github"
|
||||
@@ -43,12 +45,31 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
|
||||
const { data: giteaProviders, isLoading: isLoadingGitea } =
|
||||
api.gitea.giteaProviders.useQuery();
|
||||
|
||||
const { data: application } = api.application.one.useQuery({ applicationId });
|
||||
const { data: application, refetch } = api.application.one.useQuery({
|
||||
applicationId,
|
||||
});
|
||||
const { mutateAsync: disconnectGitProvider } =
|
||||
api.application.disconnectGitProvider.useMutation();
|
||||
|
||||
const [tab, setSab] = useState<TabState>(application?.sourceType || "github");
|
||||
|
||||
const isLoading =
|
||||
isLoadingGithub || isLoadingGitlab || isLoadingBitbucket || isLoadingGitea;
|
||||
|
||||
const handleDisconnect = async () => {
|
||||
try {
|
||||
await disconnectGitProvider({ applicationId });
|
||||
toast.success("Repository disconnected successfully");
|
||||
await refetch();
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
`Failed to disconnect repository: ${
|
||||
error instanceof Error ? error.message : "Unknown error"
|
||||
}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Card className="group relative w-full bg-transparent">
|
||||
@@ -77,6 +98,38 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Check if user doesn't have access to the current git provider
|
||||
if (
|
||||
application &&
|
||||
!application.hasGitProviderAccess &&
|
||||
application.sourceType !== "docker" &&
|
||||
application.sourceType !== "drop"
|
||||
) {
|
||||
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={application}
|
||||
onDisconnect={handleDisconnect}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="group relative w-full bg-transparent">
|
||||
<CardHeader>
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
import {
|
||||
BitbucketIcon,
|
||||
GitIcon,
|
||||
GiteaIcon,
|
||||
GithubIcon,
|
||||
GitlabIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import type { RouterOutputs } from "@/utils/api";
|
||||
import { AlertCircle, GitBranch, Unlink } from "lucide-react";
|
||||
|
||||
interface Props {
|
||||
service:
|
||||
| RouterOutputs["application"]["one"]
|
||||
| RouterOutputs["compose"]["one"];
|
||||
onDisconnect: () => void;
|
||||
}
|
||||
|
||||
export const UnauthorizedGitProvider = ({ service, onDisconnect }: Props) => {
|
||||
const getProviderIcon = (sourceType: string) => {
|
||||
switch (sourceType) {
|
||||
case "github":
|
||||
return <GithubIcon className="size-5 text-muted-foreground" />;
|
||||
case "gitlab":
|
||||
return <GitlabIcon className="size-5 text-muted-foreground" />;
|
||||
case "bitbucket":
|
||||
return <BitbucketIcon className="size-5 text-muted-foreground" />;
|
||||
case "gitea":
|
||||
return <GiteaIcon className="size-5 text-muted-foreground" />;
|
||||
case "git":
|
||||
return <GitIcon className="size-5 text-muted-foreground" />;
|
||||
default:
|
||||
return <GitBranch className="size-5 text-muted-foreground" />;
|
||||
}
|
||||
};
|
||||
|
||||
const getRepositoryInfo = () => {
|
||||
switch (service.sourceType) {
|
||||
case "github":
|
||||
return {
|
||||
repo: service.repository,
|
||||
branch: service.branch,
|
||||
owner: service.owner,
|
||||
};
|
||||
case "gitlab":
|
||||
return {
|
||||
repo: service.gitlabRepository,
|
||||
branch: service.gitlabBranch,
|
||||
owner: service.gitlabOwner,
|
||||
};
|
||||
case "bitbucket":
|
||||
return {
|
||||
repo: service.bitbucketRepository,
|
||||
branch: service.bitbucketBranch,
|
||||
owner: service.bitbucketOwner,
|
||||
};
|
||||
case "gitea":
|
||||
return {
|
||||
repo: service.giteaRepository,
|
||||
branch: service.giteaBranch,
|
||||
owner: service.giteaOwner,
|
||||
};
|
||||
case "git":
|
||||
return {
|
||||
repo: service.customGitUrl,
|
||||
branch: service.customGitBranch,
|
||||
owner: null,
|
||||
};
|
||||
default:
|
||||
return { repo: null, branch: null, owner: null };
|
||||
}
|
||||
};
|
||||
|
||||
const { repo, branch, owner } = getRepositoryInfo();
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Alert>
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
This application is connected to a {service.sourceType} repository
|
||||
through a git provider that you don't have access to. You can see
|
||||
basic repository information below, but cannot modify the
|
||||
configuration.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Card className="border-dashed border-2 border-muted-foreground/20 bg-transparent">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
{getProviderIcon(service.sourceType)}
|
||||
<span className="capitalize text-sm font-medium">
|
||||
{service.sourceType} Repository
|
||||
</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{owner && (
|
||||
<div>
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
Owner:
|
||||
</span>
|
||||
<p className="text-sm">{owner}</p>
|
||||
</div>
|
||||
)}
|
||||
{repo && (
|
||||
<div>
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
Repository:
|
||||
</span>
|
||||
<p className="text-sm">{repo}</p>
|
||||
</div>
|
||||
)}
|
||||
{branch && (
|
||||
<div>
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
Branch:
|
||||
</span>
|
||||
<p className="text-sm">{branch}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="pt-4 border-t">
|
||||
<DialogAction
|
||||
title="Disconnect Repository"
|
||||
description="Are you sure you want to disconnect this repository?"
|
||||
type="default"
|
||||
onClick={async () => {
|
||||
onDisconnect();
|
||||
}}
|
||||
>
|
||||
<Button variant="secondary" className="w-full">
|
||||
<Unlink className="size-4 mr-2" />
|
||||
Disconnect Repository
|
||||
</Button>
|
||||
</DialogAction>
|
||||
<p className="text-xs text-muted-foreground mt-2">
|
||||
Disconnecting will allow you to configure a new repository with
|
||||
your own git providers.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user