mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(gitea): add Gitea repository support
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import type { Schema } from "@dokploy/server/templates";
|
||||||
import type { CompleteTemplate } from "@dokploy/server/templates/processors";
|
import type { CompleteTemplate } from "@dokploy/server/templates/processors";
|
||||||
import { processTemplate } from "@dokploy/server/templates/processors";
|
import { processTemplate } from "@dokploy/server/templates/processors";
|
||||||
import type { Schema } from "@dokploy/server/templates";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
describe("processTemplate", () => {
|
describe("processTemplate", () => {
|
||||||
// Mock schema for testing
|
// Mock schema for testing
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { CodeEditor } from "@/components/shared/code-editor";
|
import { CodeEditor } from "@/components/shared/code-editor";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -32,7 +33,6 @@ import { useEffect, useState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
|
|
||||||
const ImportSchema = z.object({
|
const ImportSchema = z.object({
|
||||||
base64: z.string(),
|
base64: z.string(),
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { Form } from "@/components/ui/form";
|
|||||||
import { Secrets } from "@/components/ui/secrets";
|
import { Secrets } from "@/components/ui/secrets";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
const addEnvironmentSchema = z.object({
|
const addEnvironmentSchema = z.object({
|
||||||
env: z.string(),
|
env: z.string(),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -39,13 +41,11 @@ import { cn } from "@/lib/utils";
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const BitbucketProviderSchema = z.object({
|
const BitbucketProviderSchema = z.object({
|
||||||
buildPath: z.string().min(1, "Path is required").default("/"),
|
buildPath: z.string().min(1, "Path is required").default("/"),
|
||||||
|
|||||||
@@ -115,7 +115,11 @@ export const SaveDockerProvider = ({ applicationId }: Props) => {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Username</FormLabel>
|
<FormLabel>Username</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder="Username" autoComplete="username" {...field} />
|
<Input
|
||||||
|
placeholder="Username"
|
||||||
|
autoComplete="username"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@@ -130,7 +134,12 @@ export const SaveDockerProvider = ({ applicationId }: Props) => {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Password</FormLabel>
|
<FormLabel>Password</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder="Password" autoComplete="one-time-code" {...field} type="password" />
|
<Input
|
||||||
|
placeholder="Password"
|
||||||
|
autoComplete="one-time-code"
|
||||||
|
{...field}
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ import {
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
import { GitIcon } from "@/components/icons/data-tools-icons";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { GitIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
|
|
||||||
const GitProviderSchema = z.object({
|
const GitProviderSchema = z.object({
|
||||||
buildPath: z.string().min(1, "Path is required").default("/"),
|
buildPath: z.string().min(1, "Path is required").default("/"),
|
||||||
|
|||||||
@@ -235,7 +235,8 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
|||||||
? "Loading...."
|
? "Loading...."
|
||||||
: field.value.owner
|
: field.value.owner
|
||||||
? repositories?.find(
|
? repositories?.find(
|
||||||
(repo: GiteaRepository) => repo.name === field.value.repo,
|
(repo: GiteaRepository) =>
|
||||||
|
repo.name === field.value.repo,
|
||||||
)?.name
|
)?.name
|
||||||
: "Select repository"}
|
: "Select repository"}
|
||||||
|
|
||||||
@@ -327,7 +328,8 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
|||||||
? "Loading...."
|
? "Loading...."
|
||||||
: field.value
|
: field.value
|
||||||
? branches?.find(
|
? branches?.find(
|
||||||
(branch: GiteaBranch) => branch.name === field.value,
|
(branch: GiteaBranch) =>
|
||||||
|
branch.name === field.value,
|
||||||
)?.name
|
)?.name
|
||||||
: "Select branch"}
|
: "Select branch"}
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
@@ -411,4 +413,4 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
|||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -34,17 +36,15 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
|
|
||||||
const GithubProviderSchema = z.object({
|
const GithubProviderSchema = z.object({
|
||||||
buildPath: z.string().min(1, "Path is required").default("/"),
|
buildPath: z.string().min(1, "Path is required").default("/"),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -35,17 +37,15 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
|
|
||||||
const GitlabProviderSchema = z.object({
|
const GitlabProviderSchema = z.object({
|
||||||
buildPath: z.string().min(1, "Path is required").default("/"),
|
buildPath: z.string().min(1, "Path is required").default("/"),
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { SaveGitProvider } from "@/components/dashboard/application/general/gene
|
|||||||
import { SaveGiteaProvider } from "@/components/dashboard/application/general/generic/save-gitea-provider";
|
import { SaveGiteaProvider } from "@/components/dashboard/application/general/generic/save-gitea-provider";
|
||||||
import { SaveGithubProvider } from "@/components/dashboard/application/general/generic/save-github-provider";
|
import { SaveGithubProvider } from "@/components/dashboard/application/general/generic/save-github-provider";
|
||||||
import {
|
import {
|
||||||
BitbucketIcon,
|
BitbucketIcon,
|
||||||
DockerIcon,
|
DockerIcon,
|
||||||
GitIcon,
|
GitIcon,
|
||||||
GiteaIcon,
|
GiteaIcon,
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
GitlabIcon,
|
GitlabIcon,
|
||||||
} from "@/components/icons/data-tools-icons";
|
} from "@/components/icons/data-tools-icons";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
@@ -20,190 +20,197 @@ import { SaveBitbucketProvider } from "./save-bitbucket-provider";
|
|||||||
import { SaveDragNDrop } from "./save-drag-n-drop";
|
import { SaveDragNDrop } from "./save-drag-n-drop";
|
||||||
import { SaveGitlabProvider } from "./save-gitlab-provider";
|
import { SaveGitlabProvider } from "./save-gitlab-provider";
|
||||||
|
|
||||||
type TabState = "github" | "docker" | "git" | "drop" | "gitlab" | "bitbucket" | "gitea";
|
type TabState =
|
||||||
|
| "github"
|
||||||
|
| "docker"
|
||||||
|
| "git"
|
||||||
|
| "drop"
|
||||||
|
| "gitlab"
|
||||||
|
| "bitbucket"
|
||||||
|
| "gitea";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
applicationId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShowProviderForm = ({ applicationId }: Props) => {
|
export const ShowProviderForm = ({ applicationId }: Props) => {
|
||||||
const { data: githubProviders } = api.github.githubProviders.useQuery();
|
const { data: githubProviders } = api.github.githubProviders.useQuery();
|
||||||
const { data: gitlabProviders } = api.gitlab.gitlabProviders.useQuery();
|
const { data: gitlabProviders } = api.gitlab.gitlabProviders.useQuery();
|
||||||
const { data: bitbucketProviders } =
|
const { data: bitbucketProviders } =
|
||||||
api.bitbucket.bitbucketProviders.useQuery();
|
api.bitbucket.bitbucketProviders.useQuery();
|
||||||
const { data: giteaProviders } = api.gitea.giteaProviders.useQuery();
|
const { data: giteaProviders } = api.gitea.giteaProviders.useQuery();
|
||||||
|
|
||||||
const { data: application } = api.application.one.useQuery({ applicationId });
|
const { data: application } = api.application.one.useQuery({ applicationId });
|
||||||
const [tab, setSab] = useState<TabState>(application?.sourceType || "github");
|
const [tab, setSab] = useState<TabState>(application?.sourceType || "github");
|
||||||
return (
|
return (
|
||||||
<Card className="group relative w-full bg-transparent">
|
<Card className="group relative w-full bg-transparent">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-start justify-between">
|
<CardTitle className="flex items-start justify-between">
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<span className="flex flex-col space-y-0.5">Provider</span>
|
<span className="flex flex-col space-y-0.5">Provider</span>
|
||||||
<p className="flex items-center text-sm font-normal text-muted-foreground">
|
<p className="flex items-center text-sm font-normal text-muted-foreground">
|
||||||
Select the source of your code
|
Select the source of your code
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden space-y-1 text-sm font-normal md:block">
|
<div className="hidden space-y-1 text-sm font-normal md:block">
|
||||||
<GitBranch className="size-6 text-muted-foreground" />
|
<GitBranch className="size-6 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={tab}
|
value={tab}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
onValueChange={(e) => {
|
onValueChange={(e) => {
|
||||||
setSab(e as TabState);
|
setSab(e as TabState);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row items-center justify-between w-full gap-4">
|
<div className="flex flex-row items-center justify-between w-full gap-4">
|
||||||
<TabsList className="md:grid md:w-fit md:grid-cols-7 max-md:overflow-x-scroll justify-start bg-transparent overflow-y-hidden">
|
<TabsList className="md:grid md:w-fit md:grid-cols-7 max-md:overflow-x-scroll justify-start bg-transparent overflow-y-hidden">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="github"
|
value="github"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<GithubIcon className="size-4 text-current fill-current" />
|
<GithubIcon className="size-4 text-current fill-current" />
|
||||||
Github
|
Github
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="gitlab"
|
value="gitlab"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<GitlabIcon className="size-4 text-current fill-current" />
|
<GitlabIcon className="size-4 text-current fill-current" />
|
||||||
Gitlab
|
Gitlab
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="bitbucket"
|
value="bitbucket"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<BitbucketIcon className="size-4 text-current fill-current" />
|
<BitbucketIcon className="size-4 text-current fill-current" />
|
||||||
Bitbucket
|
Bitbucket
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="gitea"
|
value="gitea"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<GiteaIcon className="size-4 text-current fill-current" />
|
<GiteaIcon className="size-4 text-current fill-current" />
|
||||||
Gitea
|
Gitea
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="docker"
|
value="docker"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<DockerIcon className="size-5 text-current" />
|
<DockerIcon className="size-5 text-current" />
|
||||||
Docker
|
Docker
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="git"
|
value="git"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<GitIcon />
|
<GitIcon />
|
||||||
Git
|
Git
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="drop"
|
value="drop"
|
||||||
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
className="rounded-none border-b-2 gap-2 border-b-transparent data-[state=active]:border-b-2 data-[state=active]:border-b-border"
|
||||||
>
|
>
|
||||||
<UploadCloud className="size-5 text-current" />
|
<UploadCloud className="size-5 text-current" />
|
||||||
Drop
|
Drop
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TabsContent value="github" className="w-full p-2">
|
<TabsContent value="github" className="w-full p-2">
|
||||||
{githubProviders && githubProviders?.length > 0 ? (
|
{githubProviders && githubProviders?.length > 0 ? (
|
||||||
<SaveGithubProvider applicationId={applicationId} />
|
<SaveGithubProvider applicationId={applicationId} />
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
||||||
<GithubIcon className="size-8 text-muted-foreground" />
|
<GithubIcon className="size-8 text-muted-foreground" />
|
||||||
<span className="text-base text-muted-foreground">
|
<span className="text-base text-muted-foreground">
|
||||||
To deploy using GitHub, you need to configure your account
|
To deploy using GitHub, you need to configure your account
|
||||||
first. Please, go to{" "}
|
first. Please, go to{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/settings/git-providers"
|
href="/dashboard/settings/git-providers"
|
||||||
className="text-foreground"
|
className="text-foreground"
|
||||||
>
|
>
|
||||||
Settings
|
Settings
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
to do so.
|
to do so.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="gitlab" className="w-full p-2">
|
<TabsContent value="gitlab" className="w-full p-2">
|
||||||
{gitlabProviders && gitlabProviders?.length > 0 ? (
|
{gitlabProviders && gitlabProviders?.length > 0 ? (
|
||||||
<SaveGitlabProvider applicationId={applicationId} />
|
<SaveGitlabProvider applicationId={applicationId} />
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
||||||
<GitlabIcon className="size-8 text-muted-foreground" />
|
<GitlabIcon className="size-8 text-muted-foreground" />
|
||||||
<span className="text-base text-muted-foreground">
|
<span className="text-base text-muted-foreground">
|
||||||
To deploy using GitLab, you need to configure your account
|
To deploy using GitLab, you need to configure your account
|
||||||
first. Please, go to{" "}
|
first. Please, go to{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/settings/git-providers"
|
href="/dashboard/settings/git-providers"
|
||||||
className="text-foreground"
|
className="text-foreground"
|
||||||
>
|
>
|
||||||
Settings
|
Settings
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
to do so.
|
to do so.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="bitbucket" className="w-full p-2">
|
<TabsContent value="bitbucket" className="w-full p-2">
|
||||||
{bitbucketProviders && bitbucketProviders?.length > 0 ? (
|
{bitbucketProviders && bitbucketProviders?.length > 0 ? (
|
||||||
<SaveBitbucketProvider applicationId={applicationId} />
|
<SaveBitbucketProvider applicationId={applicationId} />
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
||||||
<BitbucketIcon className="size-8 text-muted-foreground" />
|
<BitbucketIcon className="size-8 text-muted-foreground" />
|
||||||
<span className="text-base text-muted-foreground">
|
<span className="text-base text-muted-foreground">
|
||||||
To deploy using Bitbucket, you need to configure your account
|
To deploy using Bitbucket, you need to configure your account
|
||||||
first. Please, go to{" "}
|
first. Please, go to{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/settings/git-providers"
|
href="/dashboard/settings/git-providers"
|
||||||
className="text-foreground"
|
className="text-foreground"
|
||||||
>
|
>
|
||||||
Settings
|
Settings
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
to do so.
|
to do so.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="gitea" className="w-full p-2">
|
<TabsContent value="gitea" className="w-full p-2">
|
||||||
{giteaProviders && giteaProviders?.length > 0 ? (
|
{giteaProviders && giteaProviders?.length > 0 ? (
|
||||||
<SaveGiteaProvider applicationId={applicationId} />
|
<SaveGiteaProvider applicationId={applicationId} />
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center">
|
||||||
<GiteaIcon className="size-8 text-muted-foreground" />
|
<GiteaIcon className="size-8 text-muted-foreground" />
|
||||||
<span className="text-base text-muted-foreground">
|
<span className="text-base text-muted-foreground">
|
||||||
To deploy using Gitea, you need to configure your account
|
To deploy using Gitea, you need to configure your account
|
||||||
first. Please, go to{" "}
|
first. Please, go to{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/settings/git-providers"
|
href="/dashboard/settings/git-providers"
|
||||||
className="text-foreground"
|
className="text-foreground"
|
||||||
>
|
>
|
||||||
Settings
|
Settings
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
to do so.
|
to do so.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="docker" className="w-full p-2">
|
<TabsContent value="docker" className="w-full p-2">
|
||||||
<SaveDockerProvider applicationId={applicationId} />
|
<SaveDockerProvider applicationId={applicationId} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="git" className="w-full p-2">
|
<TabsContent value="git" className="w-full p-2">
|
||||||
<SaveGitProvider applicationId={applicationId} />
|
<SaveGitProvider applicationId={applicationId} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="drop" className="w-full p-2">
|
<TabsContent value="drop" className="w-full p-2">
|
||||||
<SaveDragNDrop applicationId={applicationId} />
|
<SaveDragNDrop applicationId={applicationId} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import { Ban, CheckCircle2, Hammer, HelpCircle, Terminal } from "lucide-react";
|
import { Ban, CheckCircle2, Hammer, HelpCircle, Terminal } from "lucide-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -39,13 +41,11 @@ import { cn } from "@/lib/utils";
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const BitbucketProviderSchema = z.object({
|
const BitbucketProviderSchema = z.object({
|
||||||
composePath: z.string().min(1),
|
composePath: z.string().min(1),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { GitIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -27,13 +28,12 @@ import {
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { GitIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const GitProviderSchema = z.object({
|
const GitProviderSchema = z.object({
|
||||||
composePath: z.string().min(1),
|
composePath: z.string().min(1),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -39,12 +40,11 @@ import { cn } from "@/lib/utils";
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const GithubProviderSchema = z.object({
|
const GithubProviderSchema = z.object({
|
||||||
composePath: z.string().min(1),
|
composePath: z.string().min(1),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -39,13 +41,11 @@ import { cn } from "@/lib/utils";
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const GitlabProviderSchema = z.object({
|
const GitlabProviderSchema = z.object({
|
||||||
composePath: z.string().min(1),
|
composePath: z.string().min(1),
|
||||||
|
|||||||
@@ -147,7 +147,9 @@ export const IsolatedDeployment = ({ composeId }: Props) => {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="mt-4 flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
|
<FormItem className="mt-4 flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<FormLabel>Enable Isolated Deployment ({data?.appName})</FormLabel>
|
<FormLabel>
|
||||||
|
Enable Isolated Deployment ({data?.appName})
|
||||||
|
</FormLabel>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Enable isolated deployment to the compose file.
|
Enable isolated deployment to the compose file.
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
|
|||||||
@@ -286,16 +286,21 @@ export const AddBackup = ({ databaseId, databaseType, refetch }: Props) => {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Keep the latest</FormLabel>
|
<FormLabel>Keep the latest</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input type="number" placeholder={"keeps all the backups if left empty"} {...field} />
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder={"keeps all the backups if left empty"}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Optional. If provided, only keeps the latest N backups in the cloud.
|
Optional. If provided, only keeps the latest N backups
|
||||||
|
in the cloud.
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="enabled"
|
name="enabled"
|
||||||
|
|||||||
@@ -16,18 +16,20 @@ import {
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { DatabaseBackup, Play, Trash2 } from "lucide-react";
|
import { DatabaseBackup, Play, Trash2 } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import type { ServiceType } from "../../application/advanced/show-resources";
|
import type { ServiceType } from "../../application/advanced/show-resources";
|
||||||
import { AddBackup } from "./add-backup";
|
import { AddBackup } from "./add-backup";
|
||||||
import { UpdateBackup } from "./update-backup";
|
import { UpdateBackup } from "./update-backup";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string;
|
id: string;
|
||||||
type: Exclude<ServiceType, "application" | "redis">;
|
type: Exclude<ServiceType, "application" | "redis">;
|
||||||
}
|
}
|
||||||
export const ShowBackups = ({ id, type }: Props) => {
|
export const ShowBackups = ({ id, type }: Props) => {
|
||||||
const [activeManualBackup, setActiveManualBackup] = useState<string | undefined>();
|
const [activeManualBackup, setActiveManualBackup] = useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
const queryMap = {
|
const queryMap = {
|
||||||
postgres: () =>
|
postgres: () =>
|
||||||
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
||||||
@@ -142,7 +144,7 @@ export const ShowBackups = ({ id, type }: Props) => {
|
|||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<span className="font-medium">Keep Latest</span>
|
<span className="font-medium">Keep Latest</span>
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
{backup.keepLatestCount || 'All'}
|
{backup.keepLatestCount || "All"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -153,7 +155,10 @@ export const ShowBackups = ({ id, type }: Props) => {
|
|||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
isLoading={isManualBackup && activeManualBackup === backup.backupId}
|
isLoading={
|
||||||
|
isManualBackup &&
|
||||||
|
activeManualBackup === backup.backupId
|
||||||
|
}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setActiveManualBackup(backup.backupId);
|
setActiveManualBackup(backup.backupId);
|
||||||
await manualBackup({
|
await manualBackup({
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
|
|||||||
enabled: backup.enabled || false,
|
enabled: backup.enabled || false,
|
||||||
prefix: backup.prefix,
|
prefix: backup.prefix,
|
||||||
schedule: backup.schedule,
|
schedule: backup.schedule,
|
||||||
keepLatestCount: backup.keepLatestCount ? Number(backup.keepLatestCount) : undefined,
|
keepLatestCount: backup.keepLatestCount
|
||||||
|
? Number(backup.keepLatestCount)
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form, form.reset, backup]);
|
}, [form, form.reset, backup]);
|
||||||
@@ -274,10 +276,15 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Keep the latest</FormLabel>
|
<FormLabel>Keep the latest</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input type="number" placeholder={"keeps all the backups if left empty"} {...field} />
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder={"keeps all the backups if left empty"}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Optional. If provided, only keeps the latest N backups in the cloud.
|
Optional. If provided, only keeps the latest N backups
|
||||||
|
in the cloud.
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -20,11 +20,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const DockerProviderSchema = z.object({
|
const DockerProviderSchema = z.object({
|
||||||
externalPort: z.preprocess((a) => {
|
externalPort: z.preprocess((a) => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -20,11 +20,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const DockerProviderSchema = z.object({
|
const DockerProviderSchema = z.object({
|
||||||
externalPort: z.preprocess((a) => {
|
externalPort: z.preprocess((a) => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -20,11 +20,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const DockerProviderSchema = z.object({
|
const DockerProviderSchema = z.object({
|
||||||
externalPort: z.preprocess((a) => {
|
externalPort: z.preprocess((a) => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -20,11 +20,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const DockerProviderSchema = z.object({
|
const DockerProviderSchema = z.object({
|
||||||
externalPort: z.preprocess((a) => {
|
externalPort: z.preprocess((a) => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ import {
|
|||||||
SearchIcon,
|
SearchIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState, useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
const TEMPLATE_BASE_URL_KEY = "dokploy_template_base_url";
|
const TEMPLATE_BASE_URL_KEY = "dokploy_template_base_url";
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
const examples = [
|
const examples = [
|
||||||
"Make a personal blog",
|
"Make a personal blog",
|
||||||
|
|||||||
@@ -186,7 +186,9 @@ export const ShowProjects = () => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
||||||
>
|
>
|
||||||
<span className="truncate">{domain.host}</span>
|
<span className="truncate">
|
||||||
|
{domain.host}
|
||||||
|
</span>
|
||||||
<ExternalLinkIcon className="size-4 shrink-0" />
|
<ExternalLinkIcon className="size-4 shrink-0" />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -222,7 +224,9 @@ export const ShowProjects = () => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
||||||
>
|
>
|
||||||
<span className="truncate">{domain.host}</span>
|
<span className="truncate">
|
||||||
|
{domain.host}
|
||||||
|
</span>
|
||||||
<ExternalLinkIcon className="size-4 shrink-0" />
|
<ExternalLinkIcon className="size-4 shrink-0" />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -20,11 +20,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const DockerProviderSchema = z.object({
|
const DockerProviderSchema = z.object({
|
||||||
externalPort: z.preprocess((a) => {
|
externalPort: z.preprocess((a) => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
Ban,
|
Ban,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { api } from "@/utils/api";
|
|
||||||
import {
|
import {
|
||||||
type ChartConfig,
|
type ChartConfig,
|
||||||
ChartContainer,
|
ChartContainer,
|
||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
} from "@/components/ui/chart";
|
} from "@/components/ui/chart";
|
||||||
|
import { api } from "@/utils/api";
|
||||||
import {
|
import {
|
||||||
Area,
|
Area,
|
||||||
AreaChart,
|
AreaChart,
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ import {
|
|||||||
import { type RouterOutputs, api } from "@/utils/api";
|
import { type RouterOutputs, api } from "@/utils/api";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ArrowDownUp,
|
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
InfoIcon,
|
ArrowDownUp,
|
||||||
Calendar as CalendarIcon,
|
Calendar as CalendarIcon,
|
||||||
|
InfoIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState, useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { RequestDistributionChart } from "./request-distribution-chart";
|
import { RequestDistributionChart } from "./request-distribution-chart";
|
||||||
import { RequestsTable } from "./requests-table";
|
import { RequestsTable } from "./requests-table";
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
|
import { CodeEditor } from "@/components/shared/code-editor";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { api } from "@/utils/api";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
DialogDescription,
|
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@@ -17,22 +25,14 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { api } from "@/utils/api";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
FormDescription,
|
|
||||||
} from "@/components/ui/form";
|
|
||||||
import { Switch } from "@/components/ui/switch";
|
|
||||||
import copy from "copy-to-clipboard";
|
|
||||||
import { CodeEditor } from "@/components/shared/code-editor";
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
name: z.string().min(1, "Name is required"),
|
name: z.string().min(1, "Name is required"),
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { DialogAction } from "@/components/shared/dialog-action";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@@ -7,13 +9,11 @@ import {
|
|||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { ExternalLinkIcon, KeyIcon, Trash2, Clock, Tag } from "lucide-react";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
|
import { Clock, ExternalLinkIcon, KeyIcon, Tag, Trash2 } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { formatDistanceToNow } from "date-fns";
|
|
||||||
import { DialogAction } from "@/components/shared/dialog-action";
|
|
||||||
import { AddApiKey } from "./add-api-key";
|
import { AddApiKey } from "./add-api-key";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
|
|
||||||
export const ShowApiKeys = () => {
|
export const ShowApiKeys = () => {
|
||||||
const { data, refetch } = api.user.get.useQuery();
|
const { data, refetch } = api.user.get.useQuery();
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ import { api } from "@/utils/api";
|
|||||||
import {
|
import {
|
||||||
Boxes,
|
Boxes,
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
|
Loader2,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
Loader2,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { AddNode } from "./add-node";
|
import { AddNode } from "./add-node";
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const Schema = z.object({
|
|||||||
redirectUri: z.string().min(1, {
|
redirectUri: z.string().min(1, {
|
||||||
message: "Redirect URI is required",
|
message: "Redirect URI is required",
|
||||||
}),
|
}),
|
||||||
organizationName: z.string().optional(), // Added organizationName to the schema
|
organizationName: z.string().optional(), // Added organizationName to the schema
|
||||||
});
|
});
|
||||||
|
|
||||||
type Schema = z.infer<typeof Schema>;
|
type Schema = z.infer<typeof Schema>;
|
||||||
@@ -54,7 +54,6 @@ export const AddGiteaProvider = () => {
|
|||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const url = useUrl();
|
const url = useUrl();
|
||||||
const { data: auth } = api.user.get.useQuery();
|
|
||||||
const { mutateAsync, error, isError } = api.gitea.create.useMutation(); // Updated API call for Gitea
|
const { mutateAsync, error, isError } = api.gitea.create.useMutation(); // Updated API call for Gitea
|
||||||
const webhookUrl = `${url}/api/providers/gitea/callback`; // Updated webhook URL for Gitea
|
const webhookUrl = `${url}/api/providers/gitea/callback`; // Updated webhook URL for Gitea
|
||||||
|
|
||||||
@@ -149,12 +148,15 @@ export const AddGiteaProvider = () => {
|
|||||||
Redirect URI:{" "}
|
Redirect URI:{" "}
|
||||||
<span className="text-primary">{webhookUrl}</span>{" "}
|
<span className="text-primary">{webhookUrl}</span>{" "}
|
||||||
</li>
|
</li>
|
||||||
<li>Select Permissions - organization: read, user: read, repository: read/write</li>
|
<li>
|
||||||
|
Select Permissions - organization: read, user: read,
|
||||||
|
repository: read/write
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
After creating, you'll receive an ID and Secret,
|
After creating, you'll receive an ID and Secret, copy them
|
||||||
copy them and paste them below.
|
and paste them below.
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
@@ -1,280 +1,303 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { useUrl } from "@/utils/hooks/use-url";
|
import { useUrl } from "@/utils/hooks/use-url";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { PenBoxIcon } from "lucide-react";
|
import { PenBoxIcon } from "lucide-react";
|
||||||
import { useState, useEffect } from "react";
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
name: z.string().min(1, "Name is required"),
|
name: z.string().min(1, "Name is required"),
|
||||||
giteaUrl: z.string().min(1, "Gitea URL is required"),
|
giteaUrl: z.string().min(1, "Gitea URL is required"),
|
||||||
clientId: z.string().min(1, "Client ID is required"),
|
clientId: z.string().min(1, "Client ID is required"),
|
||||||
clientSecret: z.string().min(1, "Client Secret is required"),
|
clientSecret: z.string().min(1, "Client Secret is required"),
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
giteaId: string;
|
giteaId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditGiteaProvider = ({ giteaId }: Props) => {
|
export const EditGiteaProvider = ({ giteaId }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { data: gitea, isLoading, refetch } = api.gitea.one.useQuery({ giteaId });
|
const {
|
||||||
const { mutateAsync, isLoading: isUpdating } = api.gitea.update.useMutation();
|
data: gitea,
|
||||||
const { mutateAsync: testConnection, isLoading: isTesting } = api.gitea.testConnection.useMutation();
|
isLoading,
|
||||||
const url = useUrl();
|
refetch,
|
||||||
const utils = api.useUtils();
|
} = api.gitea.one.useQuery({ giteaId });
|
||||||
|
const { mutateAsync, isLoading: isUpdating } = api.gitea.update.useMutation();
|
||||||
|
const { mutateAsync: testConnection, isLoading: isTesting } =
|
||||||
|
api.gitea.testConnection.useMutation();
|
||||||
|
const url = useUrl();
|
||||||
|
const utils = api.useUtils();
|
||||||
|
|
||||||
// Handle OAuth redirect results
|
// Handle OAuth redirect results
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { connected, error } = router.query;
|
const { connected, error } = router.query;
|
||||||
|
|
||||||
// Only process if router is ready and query parameters exist
|
|
||||||
if (!router.isReady) return;
|
|
||||||
|
|
||||||
if (connected) {
|
// Only process if router is ready and query parameters exist
|
||||||
toast.success("Successfully connected to Gitea", {
|
if (!router.isReady) return;
|
||||||
description: "Your Gitea provider has been authorized.",
|
|
||||||
id: 'gitea-connection-success'
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
// Clear the query parameters to prevent re-triggering
|
|
||||||
router.replace({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: {}
|
|
||||||
}, undefined, { shallow: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
if (connected) {
|
||||||
toast.error("Gitea Connection Failed", {
|
toast.success("Successfully connected to Gitea", {
|
||||||
description: decodeURIComponent(error as string),
|
description: "Your Gitea provider has been authorized.",
|
||||||
id: 'gitea-connection-error'
|
id: "gitea-connection-success",
|
||||||
});
|
});
|
||||||
// Clear the query parameters to prevent re-triggering
|
refetch();
|
||||||
router.replace({
|
// Clear the query parameters to prevent re-triggering
|
||||||
pathname: router.pathname,
|
router.replace(
|
||||||
query: {}
|
{
|
||||||
}, undefined, { shallow: true });
|
pathname: router.pathname,
|
||||||
}
|
query: {},
|
||||||
}, [router.query, router.isReady, refetch]);
|
},
|
||||||
|
undefined,
|
||||||
|
{ shallow: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
if (error) {
|
||||||
resolver: zodResolver(formSchema),
|
toast.error("Gitea Connection Failed", {
|
||||||
defaultValues: {
|
description: decodeURIComponent(error as string),
|
||||||
name: "",
|
id: "gitea-connection-error",
|
||||||
giteaUrl: "https://gitea.com",
|
});
|
||||||
clientId: "",
|
// Clear the query parameters to prevent re-triggering
|
||||||
clientSecret: "",
|
router.replace(
|
||||||
},
|
{
|
||||||
});
|
pathname: router.pathname,
|
||||||
|
query: {},
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
{ shallow: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [router.query, router.isReady, refetch]);
|
||||||
|
|
||||||
// Update form values when data is loaded
|
const form = useForm<z.infer<typeof formSchema>>({
|
||||||
useEffect(() => {
|
resolver: zodResolver(formSchema),
|
||||||
if (gitea) {
|
defaultValues: {
|
||||||
form.reset({
|
name: "",
|
||||||
name: gitea.gitProvider?.name || "",
|
giteaUrl: "https://gitea.com",
|
||||||
giteaUrl: gitea.giteaUrl || "https://gitea.com",
|
clientId: "",
|
||||||
clientId: gitea.clientId || "",
|
clientSecret: "",
|
||||||
clientSecret: gitea.clientSecret || "",
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}, [gitea, form.reset]);
|
|
||||||
|
|
||||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
// Update form values when data is loaded
|
||||||
await mutateAsync({
|
useEffect(() => {
|
||||||
giteaId: giteaId,
|
if (gitea) {
|
||||||
gitProviderId: gitea?.gitProvider?.gitProviderId || "",
|
form.reset({
|
||||||
name: values.name,
|
name: gitea.gitProvider?.name || "",
|
||||||
giteaUrl: values.giteaUrl,
|
giteaUrl: gitea.giteaUrl || "https://gitea.com",
|
||||||
clientId: values.clientId,
|
clientId: gitea.clientId || "",
|
||||||
clientSecret: values.clientSecret,
|
clientSecret: gitea.clientSecret || "",
|
||||||
})
|
});
|
||||||
.then(async () => {
|
}
|
||||||
await utils.gitProvider.getAll.invalidate();
|
}, [gitea, form.reset]);
|
||||||
toast.success("Gitea provider updated successfully");
|
|
||||||
await refetch();
|
|
||||||
setOpen(false);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toast.error("Error updating Gitea provider");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTestConnection = async () => {
|
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||||
try {
|
await mutateAsync({
|
||||||
const result = await testConnection({ giteaId });
|
giteaId: giteaId,
|
||||||
toast.success("Gitea Connection Verified", {
|
gitProviderId: gitea?.gitProvider?.gitProviderId || "",
|
||||||
description: result
|
name: values.name,
|
||||||
});
|
giteaUrl: values.giteaUrl,
|
||||||
} catch (error: any) {
|
clientId: values.clientId,
|
||||||
const authUrl = error.authorizationUrl || getGiteaOAuthUrl();
|
clientSecret: values.clientSecret,
|
||||||
|
})
|
||||||
toast.error("Gitea Not Connected", {
|
.then(async () => {
|
||||||
description: error.message || "Please complete the OAuth authorization process.",
|
await utils.gitProvider.getAll.invalidate();
|
||||||
action: authUrl && authUrl !== "#" ? {
|
toast.success("Gitea provider updated successfully");
|
||||||
label: "Authorize Now",
|
await refetch();
|
||||||
onClick: () => window.open(authUrl, "_blank")
|
setOpen(false);
|
||||||
} : undefined,
|
})
|
||||||
});
|
.catch(() => {
|
||||||
}
|
toast.error("Error updating Gitea provider");
|
||||||
};
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Generate Gitea OAuth URL with state parameter
|
const handleTestConnection = async () => {
|
||||||
const getGiteaOAuthUrl = () => {
|
try {
|
||||||
const clientId = form.getValues().clientId;
|
const result = await testConnection({ giteaId });
|
||||||
const giteaUrl = form.getValues().giteaUrl;
|
toast.success("Gitea Connection Verified", {
|
||||||
|
description: result,
|
||||||
if (!clientId || !giteaUrl) {
|
});
|
||||||
toast.error("Configuration Incomplete", {
|
} catch (error: any) {
|
||||||
description: "Please fill in Client ID and Gitea URL first."
|
const authUrl = error.authorizationUrl || getGiteaOAuthUrl();
|
||||||
});
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectUri = `${url}/api/providers/gitea/callback`;
|
|
||||||
|
|
||||||
// Use the scopes from the gitea data (if available), else fallback to default scopes
|
|
||||||
const scopes = gitea?.scopes?.split(',').join(' ') || 'repo repo:status read:user read:org';
|
|
||||||
//const scopes = gitea?.scopes || 'repo,repo:status,read:user,read:org';
|
|
||||||
|
|
||||||
const state = giteaId;
|
|
||||||
|
|
||||||
return `${giteaUrl}/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scopes)}&state=${encodeURIComponent(state)}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Show loading state if data is being fetched
|
toast.error("Gitea Not Connected", {
|
||||||
if (isLoading) {
|
description:
|
||||||
return (
|
error.message || "Please complete the OAuth authorization process.",
|
||||||
<Button variant="ghost" size="icon" disabled>
|
action:
|
||||||
<PenBoxIcon className="h-4 w-4 text-muted-foreground" />
|
authUrl && authUrl !== "#"
|
||||||
</Button>
|
? {
|
||||||
);
|
label: "Authorize Now",
|
||||||
}
|
onClick: () => window.open(authUrl, "_blank"),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
// Generate Gitea OAuth URL with state parameter
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
const getGiteaOAuthUrl = () => {
|
||||||
<DialogTrigger asChild>
|
const clientId = form.getValues().clientId;
|
||||||
<Button variant="ghost" size="icon" className="group hover:bg-blue-500/10">
|
const giteaUrl = form.getValues().giteaUrl;
|
||||||
<PenBoxIcon className="size-3.5 text-primary group-hover:text-blue-500" />
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Edit Gitea Provider</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
Update your Gitea provider details.
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<Form {...form}>
|
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="name"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Name</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder="My Gitea" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="giteaUrl"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Gitea URL</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder="https://gitea.example.com" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="clientId"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Client ID</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder="Client ID" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="clientSecret"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Client Secret</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
placeholder="Client Secret"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="flex justify-end gap-2">
|
if (!clientId || !giteaUrl) {
|
||||||
<Button
|
toast.error("Configuration Incomplete", {
|
||||||
type="button"
|
description: "Please fill in Client ID and Gitea URL first.",
|
||||||
variant="outline"
|
});
|
||||||
onClick={handleTestConnection}
|
return "#";
|
||||||
isLoading={isTesting}
|
}
|
||||||
>
|
|
||||||
Test Connection
|
const redirectUri = `${url}/api/providers/gitea/callback`;
|
||||||
</Button>
|
|
||||||
|
// Use the scopes from the gitea data (if available), else fallback to default scopes
|
||||||
<Button
|
const scopes =
|
||||||
type="button"
|
gitea?.scopes?.split(",").join(" ") ||
|
||||||
variant="outline"
|
"repo repo:status read:user read:org";
|
||||||
onClick={() => {
|
//const scopes = gitea?.scopes || 'repo,repo:status,read:user,read:org';
|
||||||
const authUrl = getGiteaOAuthUrl();
|
|
||||||
if (authUrl !== "#") {
|
const state = giteaId;
|
||||||
window.open(authUrl, "_blank");
|
|
||||||
}
|
return `${giteaUrl}/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scopes)}&state=${encodeURIComponent(state)}`;
|
||||||
}}
|
};
|
||||||
>
|
|
||||||
Connect to Gitea
|
// Show loading state if data is being fetched
|
||||||
</Button>
|
if (isLoading) {
|
||||||
|
return (
|
||||||
<Button type="submit" isLoading={isUpdating}>
|
<Button variant="ghost" size="icon" disabled>
|
||||||
Save
|
<PenBoxIcon className="h-4 w-4 text-muted-foreground" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
);
|
||||||
</form>
|
}
|
||||||
</Form>
|
|
||||||
</DialogContent>
|
return (
|
||||||
</Dialog>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
);
|
<DialogTrigger asChild>
|
||||||
};
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="group hover:bg-blue-500/10"
|
||||||
|
>
|
||||||
|
<PenBoxIcon className="size-3.5 text-primary group-hover:text-blue-500" />
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Edit Gitea Provider</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Update your Gitea provider details.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="name"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="My Gitea" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="giteaUrl"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Gitea URL</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="https://gitea.example.com" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="clientId"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Client ID</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="Client ID" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="clientSecret"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Client Secret</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder="Client Secret"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleTestConnection}
|
||||||
|
isLoading={isTesting}
|
||||||
|
>
|
||||||
|
Test Connection
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => {
|
||||||
|
const authUrl = getGiteaOAuthUrl();
|
||||||
|
if (authUrl !== "#") {
|
||||||
|
window.open(authUrl, "_blank");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Connect to Gitea
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button type="submit" isLoading={isUpdating}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,273 +1,285 @@
|
|||||||
import {
|
import {
|
||||||
BitbucketIcon,
|
BitbucketIcon,
|
||||||
|
GiteaIcon,
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
GitlabIcon,
|
GitlabIcon,
|
||||||
GiteaIcon,
|
} from "@/components/icons/data-tools-icons";
|
||||||
} from "@/components/icons/data-tools-icons";
|
import { DialogAction } from "@/components/shared/dialog-action";
|
||||||
import { DialogAction } from "@/components/shared/dialog-action";
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
import { Button, buttonVariants } from "@/components/ui/button";
|
import {
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
Card,
|
||||||
import { api } from "@/utils/api";
|
CardContent,
|
||||||
import { useUrl } from "@/utils/hooks/use-url";
|
CardDescription,
|
||||||
import { formatDate } from "date-fns";
|
CardHeader,
|
||||||
import {
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import { api } from "@/utils/api";
|
||||||
|
import { useUrl } from "@/utils/hooks/use-url";
|
||||||
|
import { formatDate } from "date-fns";
|
||||||
|
import {
|
||||||
ExternalLinkIcon,
|
ExternalLinkIcon,
|
||||||
GitBranch,
|
GitBranch,
|
||||||
ImportIcon,
|
ImportIcon,
|
||||||
Loader2,
|
Loader2,
|
||||||
Trash2,
|
Trash2,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { AddBitbucketProvider } from "./bitbucket/add-bitbucket-provider";
|
import { AddBitbucketProvider } from "./bitbucket/add-bitbucket-provider";
|
||||||
import { EditBitbucketProvider } from "./bitbucket/edit-bitbucket-provider";
|
import { EditBitbucketProvider } from "./bitbucket/edit-bitbucket-provider";
|
||||||
import { AddGithubProvider } from "./github/add-github-provider";
|
import { AddGiteaProvider } from "./gitea/add-gitea-provider";
|
||||||
import { EditGithubProvider } from "./github/edit-github-provider";
|
import { EditGiteaProvider } from "./gitea/edit-gitea-provider";
|
||||||
import { AddGitlabProvider } from "./gitlab/add-gitlab-provider";
|
import { AddGithubProvider } from "./github/add-github-provider";
|
||||||
import { EditGitlabProvider } from "./gitlab/edit-gitlab-provider";
|
import { EditGithubProvider } from "./github/edit-github-provider";
|
||||||
import { AddGiteaProvider } from "./gitea/add-gitea-provider";
|
import { AddGitlabProvider } from "./gitlab/add-gitlab-provider";
|
||||||
import { EditGiteaProvider } from "./gitea/edit-gitea-provider";
|
import { EditGitlabProvider } from "./gitlab/edit-gitlab-provider";
|
||||||
|
|
||||||
export const ShowGitProviders = () => {
|
|
||||||
const { data, isLoading, refetch } = api.gitProvider.getAll.useQuery();
|
|
||||||
const { mutateAsync, isLoading: isRemoving } = api.gitProvider.remove.useMutation();
|
|
||||||
const url = useUrl();
|
|
||||||
|
|
||||||
const getGitlabUrl = (
|
|
||||||
clientId: string,
|
|
||||||
gitlabId: string,
|
|
||||||
gitlabUrl: string,
|
|
||||||
) => {
|
|
||||||
const redirectUri = `${url}/api/providers/gitlab/callback?gitlabId=${gitlabId}`;
|
|
||||||
const scope = "api read_user read_repository";
|
|
||||||
const authUrl = `${gitlabUrl}/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
|
||||||
return authUrl;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getGiteaUrl = (
|
|
||||||
clientId: string,
|
|
||||||
giteaId: string,
|
|
||||||
giteaUrl: string,
|
|
||||||
) => {
|
|
||||||
const redirectUri = `${url}/api/providers/gitea/callback?giteaId=${giteaId}`;
|
|
||||||
const scope = "repo";
|
|
||||||
const authUrl = `${giteaUrl}/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
|
||||||
return authUrl;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full">
|
|
||||||
<Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-5xl mx-auto">
|
|
||||||
<div className="rounded-xl bg-background shadow-md ">
|
|
||||||
<CardHeader className="">
|
|
||||||
<CardTitle className="text-xl flex flex-row gap-2">
|
|
||||||
<GitBranch className="size-6 text-muted-foreground self-center" />
|
|
||||||
Git Providers
|
|
||||||
</CardTitle>
|
|
||||||
<CardDescription>
|
|
||||||
Connect your Git provider for authentication.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-2 py-8 border-t">
|
|
||||||
{isLoading ? (
|
|
||||||
<div className="flex flex-row gap-2 items-center justify-center text-sm text-muted-foreground min-h-[25vh]">
|
|
||||||
<span>Loading...</span>
|
|
||||||
<Loader2 className="animate-spin size-4" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{data?.length === 0 ? (
|
|
||||||
<div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
|
|
||||||
<GitBranch className="size-8 self-center text-muted-foreground" />
|
|
||||||
<span className="text-base text-muted-foreground text-center">
|
|
||||||
Create your first Git Provider
|
|
||||||
</span>
|
|
||||||
<div>
|
|
||||||
<div className="flex items-center bg-sidebar p-1 w-full rounded-lg">
|
|
||||||
<div className="flex items-center gap-4 p-3.5 rounded-lg bg-background border w-full">
|
|
||||||
<AddGithubProvider />
|
|
||||||
<AddGitlabProvider />
|
|
||||||
<AddBitbucketProvider />
|
|
||||||
<AddGiteaProvider />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex flex-col gap-4 min-h-[25vh]">
|
|
||||||
<div className="flex flex-col gap-2 rounded-lg ">
|
|
||||||
<span className="text-base font-medium">
|
|
||||||
Available Providers
|
|
||||||
</span>
|
|
||||||
<div className="flex items-center bg-sidebar p-1 w-full rounded-lg">
|
|
||||||
<div className="flex items-center gap-4 p-3.5 rounded-lg bg-background border w-full">
|
|
||||||
<AddGithubProvider />
|
|
||||||
<AddGitlabProvider />
|
|
||||||
<AddBitbucketProvider />
|
|
||||||
<AddGiteaProvider />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-4 rounded-lg ">
|
|
||||||
{data?.map((gitProvider, _index) => {
|
|
||||||
const isGithub = gitProvider.providerType === "github";
|
|
||||||
const isGitlab = gitProvider.providerType === "gitlab";
|
|
||||||
const isBitbucket = gitProvider.providerType === "bitbucket";
|
|
||||||
const isGitea = gitProvider.providerType === "gitea";
|
|
||||||
|
|
||||||
const haveGithubRequirements = isGithub &&
|
|
||||||
gitProvider.github?.githubPrivateKey &&
|
|
||||||
gitProvider.github?.githubAppId &&
|
|
||||||
gitProvider.github?.githubInstallationId;
|
|
||||||
|
|
||||||
const haveGitlabRequirements = isGitlab &&
|
|
||||||
gitProvider.gitlab?.accessToken &&
|
|
||||||
gitProvider.gitlab?.refreshToken;
|
|
||||||
|
|
||||||
const haveGiteaRequirements = isGitea &&
|
|
||||||
gitProvider.gitea?.accessToken &&
|
|
||||||
gitProvider.gitea?.refreshToken;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={gitProvider.gitProviderId}
|
|
||||||
className="flex items-center justify-between bg-sidebar p-1 w-full rounded-lg"
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between p-3.5 rounded-lg bg-background border w-full">
|
|
||||||
<div className="flex flex-col items-center justify-between">
|
|
||||||
<div className="flex gap-2 flex-row items-center">
|
|
||||||
{isGithub && (
|
|
||||||
<GithubIcon className="size-5" />
|
|
||||||
)}
|
|
||||||
{isGitlab && (
|
|
||||||
<GitlabIcon className="size-5" />
|
|
||||||
)}
|
|
||||||
{isBitbucket && (
|
|
||||||
<BitbucketIcon className="size-5" />
|
|
||||||
)}
|
|
||||||
{isGitea && (
|
|
||||||
<GiteaIcon className="size-5" />
|
|
||||||
)}
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<span className="text-sm font-medium">
|
|
||||||
{gitProvider.name}
|
|
||||||
</span>
|
|
||||||
<span className="text-xs text-muted-foreground">
|
|
||||||
{formatDate(
|
|
||||||
gitProvider.createdAt,
|
|
||||||
"yyyy-MM-dd hh:mm:ss a"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-row gap-1">
|
|
||||||
{!haveGithubRequirements && isGithub && (
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Link
|
|
||||||
href={`${gitProvider?.github?.githubAppName}/installations/new?state=gh_setup:${gitProvider?.github.githubId}`}
|
|
||||||
className={buttonVariants({
|
|
||||||
size: "icon",
|
|
||||||
variant: "ghost",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<ImportIcon className="size-4 text-primary" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{haveGithubRequirements && isGithub && (
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Link
|
|
||||||
href={`${gitProvider?.github?.githubAppName}`}
|
|
||||||
target="_blank"
|
|
||||||
className={buttonVariants({
|
|
||||||
size: "icon",
|
|
||||||
variant: "ghost",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<ExternalLinkIcon className="size-4 text-primary" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!haveGitlabRequirements && isGitlab && (
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Link
|
|
||||||
href={getGitlabUrl(
|
|
||||||
gitProvider.gitlab?.applicationId || "",
|
|
||||||
gitProvider.gitlab?.gitlabId || "",
|
|
||||||
gitProvider.gitlab?.gitlabUrl,
|
|
||||||
)}
|
|
||||||
target="_blank"
|
|
||||||
className={buttonVariants({
|
|
||||||
size: "icon",
|
|
||||||
variant: "ghost",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<ImportIcon className="size-4 text-primary" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{isGithub && haveGithubRequirements && (
|
|
||||||
<EditGithubProvider githubId={gitProvider.github?.githubId} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isGitlab && (
|
|
||||||
<EditGitlabProvider gitlabId={gitProvider.gitlab?.gitlabId} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isBitbucket && (
|
|
||||||
<EditBitbucketProvider bitbucketId={gitProvider.bitbucket?.bitbucketId} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isGitea && (
|
export const ShowGitProviders = () => {
|
||||||
<EditGiteaProvider giteaId={gitProvider.gitea?.giteaId} />
|
const { data, isLoading, refetch } = api.gitProvider.getAll.useQuery();
|
||||||
)}
|
const { mutateAsync, isLoading: isRemoving } =
|
||||||
|
api.gitProvider.remove.useMutation();
|
||||||
<DialogAction
|
const url = useUrl();
|
||||||
title="Delete Git Provider"
|
|
||||||
description="Are you sure you want to delete this Git Provider?"
|
const getGitlabUrl = (
|
||||||
type="destructive"
|
clientId: string,
|
||||||
onClick={async () => {
|
gitlabId: string,
|
||||||
await mutateAsync({
|
gitlabUrl: string,
|
||||||
gitProviderId: gitProvider.gitProviderId,
|
) => {
|
||||||
})
|
const redirectUri = `${url}/api/providers/gitlab/callback?gitlabId=${gitlabId}`;
|
||||||
.then(() => {
|
const scope = "api read_user read_repository";
|
||||||
toast.success("Git Provider deleted successfully");
|
const authUrl = `${gitlabUrl}/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
||||||
refetch();
|
return authUrl;
|
||||||
})
|
};
|
||||||
.catch(() => {
|
|
||||||
toast.error("Error deleting Git Provider");
|
return (
|
||||||
});
|
<div className="w-full">
|
||||||
}}
|
<Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-5xl mx-auto">
|
||||||
>
|
<div className="rounded-xl bg-background shadow-md ">
|
||||||
<Button
|
<CardHeader className="">
|
||||||
variant="ghost"
|
<CardTitle className="text-xl flex flex-row gap-2">
|
||||||
size="icon"
|
<GitBranch className="size-6 text-muted-foreground self-center" />
|
||||||
className="group hover:bg-red-500/10"
|
Git Providers
|
||||||
isLoading={isRemoving}
|
</CardTitle>
|
||||||
>
|
<CardDescription>
|
||||||
<Trash2 className="size-4 text-primary group-hover:text-red-500" />
|
Connect your Git provider for authentication.
|
||||||
</Button>
|
</CardDescription>
|
||||||
</DialogAction>
|
</CardHeader>
|
||||||
</div>
|
<CardContent className="space-y-2 py-8 border-t">
|
||||||
</div>
|
{isLoading ? (
|
||||||
|
<div className="flex flex-row gap-2 items-center justify-center text-sm text-muted-foreground min-h-[25vh]">
|
||||||
|
<span>Loading...</span>
|
||||||
|
<Loader2 className="animate-spin size-4" />
|
||||||
</div>
|
</div>
|
||||||
);
|
) : (
|
||||||
})}
|
<>
|
||||||
</div>
|
{data?.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
|
||||||
<div className="flex flex-row gap-2 flex-wrap w-full justify-end mr-4">
|
<GitBranch className="size-8 self-center text-muted-foreground" />
|
||||||
{/* <AddCertificate /> */}
|
<span className="text-base text-muted-foreground text-center">
|
||||||
</div>
|
Create your first Git Provider
|
||||||
</div>
|
</span>
|
||||||
)}
|
<div>
|
||||||
</>
|
<div className="flex items-center bg-sidebar p-1 w-full rounded-lg">
|
||||||
)}
|
<div className="flex items-center gap-4 p-3.5 rounded-lg bg-background border w-full">
|
||||||
</CardContent>
|
<AddGithubProvider />
|
||||||
</div>
|
<AddGitlabProvider />
|
||||||
</Card>
|
<AddBitbucketProvider />
|
||||||
</div>
|
<AddGiteaProvider />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col gap-4 min-h-[25vh]">
|
||||||
|
<div className="flex flex-col gap-2 rounded-lg ">
|
||||||
|
<span className="text-base font-medium">
|
||||||
|
Available Providers
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center bg-sidebar p-1 w-full rounded-lg">
|
||||||
|
<div className="flex items-center gap-4 p-3.5 rounded-lg bg-background border w-full">
|
||||||
|
<AddGithubProvider />
|
||||||
|
<AddGitlabProvider />
|
||||||
|
<AddBitbucketProvider />
|
||||||
|
<AddGiteaProvider />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-4 rounded-lg ">
|
||||||
|
{data?.map((gitProvider, _index) => {
|
||||||
|
const isGithub = gitProvider.providerType === "github";
|
||||||
|
const isGitlab = gitProvider.providerType === "gitlab";
|
||||||
|
const isBitbucket =
|
||||||
|
gitProvider.providerType === "bitbucket";
|
||||||
|
const isGitea = gitProvider.providerType === "gitea";
|
||||||
|
|
||||||
|
const haveGithubRequirements =
|
||||||
|
isGithub &&
|
||||||
|
gitProvider.github?.githubPrivateKey &&
|
||||||
|
gitProvider.github?.githubAppId &&
|
||||||
|
gitProvider.github?.githubInstallationId;
|
||||||
|
|
||||||
|
const haveGitlabRequirements =
|
||||||
|
isGitlab &&
|
||||||
|
gitProvider.gitlab?.accessToken &&
|
||||||
|
gitProvider.gitlab?.refreshToken;
|
||||||
|
|
||||||
|
const haveGiteaRequirements =
|
||||||
|
isGitea &&
|
||||||
|
gitProvider.gitea?.accessToken &&
|
||||||
|
gitProvider.gitea?.refreshToken;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={gitProvider.gitProviderId}
|
||||||
|
className="flex items-center justify-between bg-sidebar p-1 w-full rounded-lg"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between p-3.5 rounded-lg bg-background border w-full">
|
||||||
|
<div className="flex flex-col items-center justify-between">
|
||||||
|
<div className="flex gap-2 flex-row items-center">
|
||||||
|
{isGithub && (
|
||||||
|
<GithubIcon className="size-5" />
|
||||||
|
)}
|
||||||
|
{isGitlab && (
|
||||||
|
<GitlabIcon className="size-5" />
|
||||||
|
)}
|
||||||
|
{isBitbucket && (
|
||||||
|
<BitbucketIcon className="size-5" />
|
||||||
|
)}
|
||||||
|
{isGitea && <GiteaIcon className="size-5" />}
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<span className="text-sm font-medium">
|
||||||
|
{gitProvider.name}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{formatDate(
|
||||||
|
gitProvider.createdAt,
|
||||||
|
"yyyy-MM-dd hh:mm:ss a",
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-1">
|
||||||
|
{!haveGithubRequirements && isGithub && (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<Link
|
||||||
|
href={`${gitProvider?.github?.githubAppName}/installations/new?state=gh_setup:${gitProvider?.github.githubId}`}
|
||||||
|
className={buttonVariants({
|
||||||
|
size: "icon",
|
||||||
|
variant: "ghost",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ImportIcon className="size-4 text-primary" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{haveGithubRequirements && isGithub && (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<Link
|
||||||
|
href={`${gitProvider?.github?.githubAppName}`}
|
||||||
|
target="_blank"
|
||||||
|
className={buttonVariants({
|
||||||
|
size: "icon",
|
||||||
|
variant: "ghost",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ExternalLinkIcon className="size-4 text-primary" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!haveGitlabRequirements && isGitlab && (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<Link
|
||||||
|
href={getGitlabUrl(
|
||||||
|
gitProvider.gitlab?.applicationId || "",
|
||||||
|
gitProvider.gitlab?.gitlabId || "",
|
||||||
|
gitProvider.gitlab?.gitlabUrl,
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
className={buttonVariants({
|
||||||
|
size: "icon",
|
||||||
|
variant: "ghost",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ImportIcon className="size-4 text-primary" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isGithub && haveGithubRequirements && (
|
||||||
|
<EditGithubProvider
|
||||||
|
githubId={gitProvider.github?.githubId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isGitlab && (
|
||||||
|
<EditGitlabProvider
|
||||||
|
gitlabId={gitProvider.gitlab?.gitlabId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isBitbucket && (
|
||||||
|
<EditBitbucketProvider
|
||||||
|
bitbucketId={
|
||||||
|
gitProvider.bitbucket?.bitbucketId
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isGitea && (
|
||||||
|
<EditGiteaProvider
|
||||||
|
giteaId={gitProvider.gitea?.giteaId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DialogAction
|
||||||
|
title="Delete Git Provider"
|
||||||
|
description="Are you sure you want to delete this Git Provider?"
|
||||||
|
type="destructive"
|
||||||
|
onClick={async () => {
|
||||||
|
await mutateAsync({
|
||||||
|
gitProviderId: gitProvider.gitProviderId,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
toast.success(
|
||||||
|
"Git Provider deleted successfully",
|
||||||
|
);
|
||||||
|
refetch();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error(
|
||||||
|
"Error deleting Git Provider",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="group hover:bg-red-500/10"
|
||||||
|
isLoading={isRemoving}
|
||||||
|
>
|
||||||
|
<Trash2 className="size-4 text-primary group-hover:text-red-500" />
|
||||||
|
</Button>
|
||||||
|
</DialogAction>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-2 flex-wrap w-full justify-end mr-4">
|
||||||
|
{/* <AddCertificate /> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { useTranslation } from "next-i18next";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { ShowNodesModal } from "../cluster/nodes/show-nodes-modal";
|
||||||
import { TerminalModal } from "../web-server/terminal-modal";
|
import { TerminalModal } from "../web-server/terminal-modal";
|
||||||
import { ShowServerActions } from "./actions/show-server-actions";
|
import { ShowServerActions } from "./actions/show-server-actions";
|
||||||
import { HandleServers } from "./handle-servers";
|
import { HandleServers } from "./handle-servers";
|
||||||
@@ -42,7 +43,6 @@ import { ShowMonitoringModal } from "./show-monitoring-modal";
|
|||||||
import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal";
|
import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal";
|
||||||
import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
||||||
import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription";
|
import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription";
|
||||||
import { ShowNodesModal } from "../cluster/nodes/show-nodes-modal";
|
|
||||||
|
|
||||||
export const ShowServers = () => {
|
export const ShowServers = () => {
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -22,7 +23,6 @@ import dynamic from "next/dynamic";
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { badgeStateColor } from "../../application/logs/show";
|
import { badgeStateColor } from "../../application/logs/show";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
|
|
||||||
export const DockerLogsId = dynamic(
|
export const DockerLogsId = dynamic(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
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 { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { DatabaseIcon, AlertTriangle } from "lucide-react";
|
import { AlertTriangle, DatabaseIcon } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
|
||||||
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
||||||
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
||||||
|
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
||||||
import { RebuildDatabase } from "./rebuild-database";
|
import { RebuildDatabase } from "./rebuild-database";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -241,34 +241,34 @@ export const BitbucketIcon = ({ className }: Props) => {
|
|||||||
export const GiteaIcon = ({ className }: Props) => {
|
export const GiteaIcon = ({ className }: Props) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
className={className}
|
className={className}
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="main_outline"
|
id="main_outline"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="18"
|
width="18"
|
||||||
height="18"
|
height="18"
|
||||||
viewBox="5.67 143.05 628.65 387.55"
|
viewBox="5.67 143.05 628.65 387.55"
|
||||||
enableBackground="new 0 0 640 640"
|
enableBackground="new 0 0 640 640"
|
||||||
>
|
>
|
||||||
<g>
|
|
||||||
<path
|
|
||||||
id="teabag"
|
|
||||||
style={{ fill: '#FFFFFF' }}
|
|
||||||
d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"
|
|
||||||
/>
|
|
||||||
<g>
|
|
||||||
<g>
|
<g>
|
||||||
<path
|
<path
|
||||||
style={{ fill: '#609926' }}
|
id="teabag"
|
||||||
d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"
|
style={{ fill: "#FFFFFF" }}
|
||||||
/>
|
d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"
|
||||||
<path
|
|
||||||
style={{ fill: '#609926' }}
|
|
||||||
d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8C343.2,346.5,335,363.3,326.8,380.1z"
|
|
||||||
/>
|
/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
style={{ fill: "#609926" }}
|
||||||
|
d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
style={{ fill: "#609926" }}
|
||||||
|
d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8C343.2,346.5,335,363.3,326.8,380.1z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import type { IUpdateData } from "@dokploy/server/index";
|
import type { IUpdateData } from "@dokploy/server/index";
|
||||||
|
import { Download } from "lucide-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import UpdateServer from "../dashboard/settings/web-server/update-server";
|
import UpdateServer from "../dashboard/settings/web-server/update-server";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Download } from "lucide-react";
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ export const BreadcrumbSidebar = ({ list }: Props) => {
|
|||||||
)}
|
)}
|
||||||
</BreadcrumbLink>
|
</BreadcrumbLink>
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
{_index + 1 < list.length && <BreadcrumbSeparator className="block" />}
|
{_index + 1 < list.length && (
|
||||||
|
<BreadcrumbSeparator className="block" />
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</BreadcrumbList>
|
</BreadcrumbList>
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ import { json } from "@codemirror/lang-json";
|
|||||||
import { yaml } from "@codemirror/lang-yaml";
|
import { yaml } from "@codemirror/lang-yaml";
|
||||||
import { StreamLanguage } from "@codemirror/language";
|
import { StreamLanguage } from "@codemirror/language";
|
||||||
|
|
||||||
|
import {
|
||||||
|
type Completion,
|
||||||
|
type CompletionContext,
|
||||||
|
type CompletionResult,
|
||||||
|
autocompletion,
|
||||||
|
} from "@codemirror/autocomplete";
|
||||||
import { properties } from "@codemirror/legacy-modes/mode/properties";
|
import { properties } from "@codemirror/legacy-modes/mode/properties";
|
||||||
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
||||||
import { EditorView } from "@codemirror/view";
|
import { EditorView } from "@codemirror/view";
|
||||||
import { githubDark, githubLight } from "@uiw/codemirror-theme-github";
|
import { githubDark, githubLight } from "@uiw/codemirror-theme-github";
|
||||||
import CodeMirror, { type ReactCodeMirrorProps } from "@uiw/react-codemirror";
|
import CodeMirror, { type ReactCodeMirrorProps } from "@uiw/react-codemirror";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import {
|
|
||||||
autocompletion,
|
|
||||||
type CompletionContext,
|
|
||||||
type CompletionResult,
|
|
||||||
type Completion,
|
|
||||||
} from "@codemirror/autocomplete";
|
|
||||||
|
|
||||||
// Docker Compose completion options
|
// Docker Compose completion options
|
||||||
const dockerComposeServices = [
|
const dockerComposeServices = [
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type * as React from "react";
|
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
import { DayPicker } from "react-day-picker";
|
import { DayPicker } from "react-day-picker";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||||
|
|
||||||
|
|||||||
157
apps/dokploy/drizzle/0076_tough_iron_patriot.sql
Normal file
157
apps/dokploy/drizzle/0076_tough_iron_patriot.sql
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumlabel = 'gitea' AND
|
||||||
|
enumtypid = (SELECT oid FROM pg_type WHERE typname = 'sourceType')) THEN
|
||||||
|
ALTER TYPE "public"."sourceType" ADD VALUE 'gitea' BEFORE 'drop';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumlabel = 'gitea' AND
|
||||||
|
enumtypid = (SELECT oid FROM pg_type WHERE typname = 'sourceTypeCompose')) THEN
|
||||||
|
ALTER TYPE "public"."sourceTypeCompose" ADD VALUE 'gitea' BEFORE 'raw';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumlabel = 'gitea' AND
|
||||||
|
enumtypid = (SELECT oid FROM pg_type WHERE typname = 'gitProviderType')) THEN
|
||||||
|
ALTER TYPE "public"."gitProviderType" ADD VALUE 'gitea';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'gitea') THEN
|
||||||
|
CREATE TABLE "gitea" (
|
||||||
|
"giteaId" text PRIMARY KEY NOT NULL,
|
||||||
|
"giteaUrl" text DEFAULT 'https://gitea.com' NOT NULL,
|
||||||
|
"redirect_uri" text,
|
||||||
|
"client_id" text,
|
||||||
|
"client_secret" text,
|
||||||
|
"gitProviderId" text NOT NULL,
|
||||||
|
"gitea_username" text,
|
||||||
|
"access_token" text,
|
||||||
|
"refresh_token" text,
|
||||||
|
"expires_at" integer,
|
||||||
|
"scopes" text DEFAULT 'repo,repo:status,read:user,read:org',
|
||||||
|
"last_authenticated_at" integer
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaProjectId') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaProjectId" integer;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaRepository') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaRepository" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaOwner') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaOwner" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaBranch') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaBranch" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaBuildPath') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaBuildPath" text DEFAULT '/';
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaPathNamespace') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaPathNamespace" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'application' AND column_name = 'giteaId') THEN
|
||||||
|
ALTER TABLE "application" ADD COLUMN "giteaId" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'compose' AND column_name = 'giteaRepository') THEN
|
||||||
|
ALTER TABLE "compose" ADD COLUMN "giteaRepository" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'compose' AND column_name = 'giteaOwner') THEN
|
||||||
|
ALTER TABLE "compose" ADD COLUMN "giteaOwner" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'compose' AND column_name = 'giteaBranch') THEN
|
||||||
|
ALTER TABLE "compose" ADD COLUMN "giteaBranch" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'compose' AND column_name = 'giteaId') THEN
|
||||||
|
ALTER TABLE "compose" ADD COLUMN "giteaId" text;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.table_constraints
|
||||||
|
WHERE constraint_name = 'gitea_gitProviderId_git_provider_gitProviderId_fk'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE "gitea" ADD CONSTRAINT "gitea_gitProviderId_git_provider_gitProviderId_fk"
|
||||||
|
FOREIGN KEY ("gitProviderId") REFERENCES "public"."git_provider"("gitProviderId")
|
||||||
|
ON DELETE cascade ON UPDATE no action;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.table_constraints
|
||||||
|
WHERE constraint_name = 'application_giteaId_gitea_giteaId_fk'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE "application" ADD CONSTRAINT "application_giteaId_gitea_giteaId_fk"
|
||||||
|
FOREIGN KEY ("giteaId") REFERENCES "public"."gitea"("giteaId")
|
||||||
|
ON DELETE set null ON UPDATE no action;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.table_constraints
|
||||||
|
WHERE constraint_name = 'compose_giteaId_gitea_giteaId_fk'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE "compose" ADD CONSTRAINT "compose_giteaId_gitea_giteaId_fk"
|
||||||
|
FOREIGN KEY ("giteaId") REFERENCES "public"."gitea"("giteaId")
|
||||||
|
ON DELETE set null ON UPDATE no action;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "27ba0f3d-859f-4233-a179-8aee11ad9179",
|
"id": "7c8508ba-01eb-487e-88cf-0abe10916904",
|
||||||
"prevId": "dd51ff04-a160-4d0d-b72f-4916493b740f",
|
"prevId": "f74127dc-3cda-4091-988f-97b60eb22427",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
@@ -179,6 +179,13 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "'github'"
|
"default": "'github'"
|
||||||
},
|
},
|
||||||
|
"cleanCache": {
|
||||||
|
"name": "cleanCache",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"name": "repository",
|
"name": "repository",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -247,6 +254,43 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaProjectId": {
|
||||||
|
"name": "giteaProjectId",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaRepository": {
|
||||||
|
"name": "giteaRepository",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaOwner": {
|
||||||
|
"name": "giteaOwner",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBranch": {
|
||||||
|
"name": "giteaBranch",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBuildPath": {
|
||||||
|
"name": "giteaBuildPath",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'/'"
|
||||||
|
},
|
||||||
|
"giteaPathNamespace": {
|
||||||
|
"name": "giteaPathNamespace",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"bitbucketRepository": {
|
"bitbucketRepository": {
|
||||||
"name": "bitbucketRepository",
|
"name": "bitbucketRepository",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -458,6 +502,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"bitbucketId": {
|
"bitbucketId": {
|
||||||
"name": "bitbucketId",
|
"name": "bitbucketId",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -538,6 +588,19 @@
|
|||||||
"onDelete": "set null",
|
"onDelete": "set null",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
},
|
},
|
||||||
|
"application_giteaId_gitea_giteaId_fk": {
|
||||||
|
"name": "application_giteaId_gitea_giteaId_fk",
|
||||||
|
"tableFrom": "application",
|
||||||
|
"tableTo": "gitea",
|
||||||
|
"columnsFrom": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
"application_bitbucketId_bitbucket_bitbucketId_fk": {
|
"application_bitbucketId_bitbucket_bitbucketId_fk": {
|
||||||
"name": "application_bitbucketId_bitbucket_bitbucketId_fk",
|
"name": "application_bitbucketId_bitbucket_bitbucketId_fk",
|
||||||
"tableFrom": "application",
|
"tableFrom": "application",
|
||||||
@@ -1703,6 +1766,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"keepLatestCount": {
|
||||||
|
"name": "keepLatestCount",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"databaseType": {
|
"databaseType": {
|
||||||
"name": "databaseType",
|
"name": "databaseType",
|
||||||
"type": "databaseType",
|
"type": "databaseType",
|
||||||
@@ -2908,6 +2977,24 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaRepository": {
|
||||||
|
"name": "giteaRepository",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaOwner": {
|
||||||
|
"name": "giteaOwner",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBranch": {
|
||||||
|
"name": "giteaBranch",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"customGitUrl": {
|
"customGitUrl": {
|
||||||
"name": "customGitUrl",
|
"name": "customGitUrl",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -3005,6 +3092,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"serverId": {
|
"serverId": {
|
||||||
"name": "serverId",
|
"name": "serverId",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -3079,6 +3172,19 @@
|
|||||||
"onDelete": "set null",
|
"onDelete": "set null",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
},
|
},
|
||||||
|
"compose_giteaId_gitea_giteaId_fk": {
|
||||||
|
"name": "compose_giteaId_gitea_giteaId_fk",
|
||||||
|
"tableFrom": "compose",
|
||||||
|
"tableTo": "gitea",
|
||||||
|
"columnsFrom": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
"compose_serverId_server_serverId_fk": {
|
"compose_serverId_server_serverId_fk": {
|
||||||
"name": "compose_serverId_server_serverId_fk",
|
"name": "compose_serverId_server_serverId_fk",
|
||||||
"tableFrom": "compose",
|
"tableFrom": "compose",
|
||||||
@@ -3937,6 +4043,107 @@
|
|||||||
"checkConstraints": {},
|
"checkConstraints": {},
|
||||||
"isRLSEnabled": false
|
"isRLSEnabled": false
|
||||||
},
|
},
|
||||||
|
"public.gitea": {
|
||||||
|
"name": "gitea",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"giteaUrl": {
|
||||||
|
"name": "giteaUrl",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'https://gitea.com'"
|
||||||
|
},
|
||||||
|
"redirect_uri": {
|
||||||
|
"name": "redirect_uri",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"client_id": {
|
||||||
|
"name": "client_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"client_secret": {
|
||||||
|
"name": "client_secret",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gitProviderId": {
|
||||||
|
"name": "gitProviderId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"gitea_username": {
|
||||||
|
"name": "gitea_username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"access_token": {
|
||||||
|
"name": "access_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"name": "refresh_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"scopes": {
|
||||||
|
"name": "scopes",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'repo,repo:status,read:user,read:org'"
|
||||||
|
},
|
||||||
|
"last_authenticated_at": {
|
||||||
|
"name": "last_authenticated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"gitea_gitProviderId_git_provider_gitProviderId_fk": {
|
||||||
|
"name": "gitea_gitProviderId_git_provider_gitProviderId_fk",
|
||||||
|
"tableFrom": "gitea",
|
||||||
|
"tableTo": "git_provider",
|
||||||
|
"columnsFrom": [
|
||||||
|
"gitProviderId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"gitProviderId"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
"public.server": {
|
"public.server": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
@@ -5001,6 +5208,7 @@
|
|||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket",
|
"bitbucket",
|
||||||
|
"gitea",
|
||||||
"drop"
|
"drop"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -5097,6 +5305,7 @@
|
|||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket",
|
"bitbucket",
|
||||||
|
"gitea",
|
||||||
"raw"
|
"raw"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -5125,7 +5334,8 @@
|
|||||||
"values": [
|
"values": [
|
||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket"
|
"bitbucket",
|
||||||
|
"gitea"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"public.serverStatus": {
|
"public.serverStatus": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "d4d95ab9-16bd-4583-949e-d6ae0a0bb7a0",
|
"id": "c8f3ee9b-66c6-4a23-a151-78e04363bdf9",
|
||||||
"prevId": "27ba0f3d-859f-4233-a179-8aee11ad9179",
|
"prevId": "f74127dc-3cda-4091-988f-97b60eb22427",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
@@ -179,6 +179,13 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "'github'"
|
"default": "'github'"
|
||||||
},
|
},
|
||||||
|
"cleanCache": {
|
||||||
|
"name": "cleanCache",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"name": "repository",
|
"name": "repository",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -247,6 +254,43 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaProjectId": {
|
||||||
|
"name": "giteaProjectId",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaRepository": {
|
||||||
|
"name": "giteaRepository",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaOwner": {
|
||||||
|
"name": "giteaOwner",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBranch": {
|
||||||
|
"name": "giteaBranch",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBuildPath": {
|
||||||
|
"name": "giteaBuildPath",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'/'"
|
||||||
|
},
|
||||||
|
"giteaPathNamespace": {
|
||||||
|
"name": "giteaPathNamespace",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"bitbucketRepository": {
|
"bitbucketRepository": {
|
||||||
"name": "bitbucketRepository",
|
"name": "bitbucketRepository",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -458,6 +502,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"bitbucketId": {
|
"bitbucketId": {
|
||||||
"name": "bitbucketId",
|
"name": "bitbucketId",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -538,6 +588,19 @@
|
|||||||
"onDelete": "set null",
|
"onDelete": "set null",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
},
|
},
|
||||||
|
"application_giteaId_gitea_giteaId_fk": {
|
||||||
|
"name": "application_giteaId_gitea_giteaId_fk",
|
||||||
|
"tableFrom": "application",
|
||||||
|
"tableTo": "gitea",
|
||||||
|
"columnsFrom": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
"application_bitbucketId_bitbucket_bitbucketId_fk": {
|
"application_bitbucketId_bitbucket_bitbucketId_fk": {
|
||||||
"name": "application_bitbucketId_bitbucket_bitbucketId_fk",
|
"name": "application_bitbucketId_bitbucket_bitbucketId_fk",
|
||||||
"tableFrom": "application",
|
"tableFrom": "application",
|
||||||
@@ -2914,6 +2977,24 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaRepository": {
|
||||||
|
"name": "giteaRepository",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaOwner": {
|
||||||
|
"name": "giteaOwner",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"giteaBranch": {
|
||||||
|
"name": "giteaBranch",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"customGitUrl": {
|
"customGitUrl": {
|
||||||
"name": "customGitUrl",
|
"name": "customGitUrl",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -3011,6 +3092,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
"serverId": {
|
"serverId": {
|
||||||
"name": "serverId",
|
"name": "serverId",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -3085,6 +3172,19 @@
|
|||||||
"onDelete": "set null",
|
"onDelete": "set null",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
},
|
},
|
||||||
|
"compose_giteaId_gitea_giteaId_fk": {
|
||||||
|
"name": "compose_giteaId_gitea_giteaId_fk",
|
||||||
|
"tableFrom": "compose",
|
||||||
|
"tableTo": "gitea",
|
||||||
|
"columnsFrom": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"giteaId"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
"compose_serverId_server_serverId_fk": {
|
"compose_serverId_server_serverId_fk": {
|
||||||
"name": "compose_serverId_server_serverId_fk",
|
"name": "compose_serverId_server_serverId_fk",
|
||||||
"tableFrom": "compose",
|
"tableFrom": "compose",
|
||||||
@@ -3943,6 +4043,107 @@
|
|||||||
"checkConstraints": {},
|
"checkConstraints": {},
|
||||||
"isRLSEnabled": false
|
"isRLSEnabled": false
|
||||||
},
|
},
|
||||||
|
"public.gitea": {
|
||||||
|
"name": "gitea",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"giteaId": {
|
||||||
|
"name": "giteaId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"giteaUrl": {
|
||||||
|
"name": "giteaUrl",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'https://gitea.com'"
|
||||||
|
},
|
||||||
|
"redirect_uri": {
|
||||||
|
"name": "redirect_uri",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"client_id": {
|
||||||
|
"name": "client_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"client_secret": {
|
||||||
|
"name": "client_secret",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gitProviderId": {
|
||||||
|
"name": "gitProviderId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"gitea_username": {
|
||||||
|
"name": "gitea_username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"access_token": {
|
||||||
|
"name": "access_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"name": "refresh_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"scopes": {
|
||||||
|
"name": "scopes",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'repo,repo:status,read:user,read:org'"
|
||||||
|
},
|
||||||
|
"last_authenticated_at": {
|
||||||
|
"name": "last_authenticated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"gitea_gitProviderId_git_provider_gitProviderId_fk": {
|
||||||
|
"name": "gitea_gitProviderId_git_provider_gitProviderId_fk",
|
||||||
|
"tableFrom": "gitea",
|
||||||
|
"tableTo": "git_provider",
|
||||||
|
"columnsFrom": [
|
||||||
|
"gitProviderId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"gitProviderId"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
"public.server": {
|
"public.server": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
@@ -5007,6 +5208,7 @@
|
|||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket",
|
"bitbucket",
|
||||||
|
"gitea",
|
||||||
"drop"
|
"drop"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -5103,6 +5305,7 @@
|
|||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket",
|
"bitbucket",
|
||||||
|
"gitea",
|
||||||
"raw"
|
"raw"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -5131,7 +5334,8 @@
|
|||||||
"values": [
|
"values": [
|
||||||
"github",
|
"github",
|
||||||
"gitlab",
|
"gitlab",
|
||||||
"bitbucket"
|
"bitbucket",
|
||||||
|
"gitea"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"public.serverStatus": {
|
"public.serverStatus": {
|
||||||
|
|||||||
@@ -534,10 +534,31 @@
|
|||||||
"tag": "0075_wild_xorn",
|
"tag": "0075_wild_xorn",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idx": 76,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742237840762,
|
||||||
|
"tag": "0076_tough_iron_patriot",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 77,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742241730000,
|
||||||
|
"tag": "0076_young_sharon_ventura",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"idx": 78,
|
"idx": 78,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1742112194375,
|
"when": 1742241730001,
|
||||||
|
"tag": "0077_chemical_dreadnoughts",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 79,
|
||||||
|
"version": "7",
|
||||||
|
"when": 17422417300002,
|
||||||
"tag": "0078_uneven_omega_sentinel",
|
"tag": "0078_uneven_omega_sentinel",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
|
|||||||
552
apps/dokploy/drizzle/meta/_journal.json.backup
Normal file
552
apps/dokploy/drizzle/meta/_journal.json.backup
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1713262741218,
|
||||||
|
"tag": "0000_reflective_puck",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1713761637676,
|
||||||
|
"tag": "0001_striped_tattoo",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1713763492341,
|
||||||
|
"tag": "0002_ambiguous_carlie_cooper",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 3,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1713947141424,
|
||||||
|
"tag": "0003_square_lightspeed",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 4,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1714004732716,
|
||||||
|
"tag": "0004_nice_tenebrous",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 5,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1715551130605,
|
||||||
|
"tag": "0005_cute_terror",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 6,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715563165991,
|
||||||
|
"tag": "0006_oval_jimmy_woo",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 7,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715563497100,
|
||||||
|
"tag": "0007_cute_guardsmen",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 8,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715564143641,
|
||||||
|
"tag": "0008_lazy_sage",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 9,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715564774423,
|
||||||
|
"tag": "0009_majestic_spencer_smythe",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 10,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715574037832,
|
||||||
|
"tag": "0010_lean_black_widow",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1715574230599,
|
||||||
|
"tag": "0011_petite_calypso",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 12,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1716015716708,
|
||||||
|
"tag": "0012_chubby_umar",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 13,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1716076179443,
|
||||||
|
"tag": "0013_blushing_starjammers",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 14,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1716715367982,
|
||||||
|
"tag": "0014_same_hammerhead",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 15,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1717564517104,
|
||||||
|
"tag": "0015_fearless_callisto",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 16,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1719109196484,
|
||||||
|
"tag": "0016_chunky_leopardon",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 17,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1719547174326,
|
||||||
|
"tag": "0017_minor_post",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 18,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1719928377858,
|
||||||
|
"tag": "0018_careful_killmonger",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 19,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721110706912,
|
||||||
|
"tag": "0019_heavy_freak",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 20,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721363861686,
|
||||||
|
"tag": "0020_fantastic_slapstick",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 21,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721370423752,
|
||||||
|
"tag": "0021_premium_sebastian_shaw",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 22,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721531163852,
|
||||||
|
"tag": "0022_warm_colonel_america",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 23,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721542782659,
|
||||||
|
"tag": "0023_icy_maverick",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 24,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721603595092,
|
||||||
|
"tag": "0024_dapper_supernaut",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 25,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721633853118,
|
||||||
|
"tag": "0025_lying_mephisto",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 26,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721979220929,
|
||||||
|
"tag": "0026_known_dormammu",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 27,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1722445099203,
|
||||||
|
"tag": "0027_red_lady_bullseye",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 28,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1722503439951,
|
||||||
|
"tag": "0028_jittery_eternity",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 29,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1722578386823,
|
||||||
|
"tag": "0029_colossal_zodiak",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 30,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1723608499147,
|
||||||
|
"tag": "0030_little_kabuki",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 31,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1723701656243,
|
||||||
|
"tag": "0031_steep_vulture",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 32,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1723705257806,
|
||||||
|
"tag": "0032_flashy_shadow_king",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 33,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1725250322137,
|
||||||
|
"tag": "0033_white_hawkeye",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 34,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1725256397019,
|
||||||
|
"tag": "0034_aspiring_secret_warriors",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 35,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1725429324584,
|
||||||
|
"tag": "0035_cool_gravity",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 36,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1725519351871,
|
||||||
|
"tag": "0036_tired_ronan",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 37,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1726988289562,
|
||||||
|
"tag": "0037_legal_namor",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 38,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1727942090102,
|
||||||
|
"tag": "0038_rapid_landau",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 39,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1728021127765,
|
||||||
|
"tag": "0039_many_tiger_shark",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 40,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1728780577084,
|
||||||
|
"tag": "0040_graceful_wolfsbane",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 41,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1729667438853,
|
||||||
|
"tag": "0041_huge_bruce_banner",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 42,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1729984439862,
|
||||||
|
"tag": "0042_fancy_havok",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 43,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1731873965888,
|
||||||
|
"tag": "0043_closed_naoko",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 44,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1731875539532,
|
||||||
|
"tag": "0044_sour_true_believers",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 45,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1732644181718,
|
||||||
|
"tag": "0045_smiling_blur",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 46,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1732851191048,
|
||||||
|
"tag": "0046_purple_sleeper",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 47,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1733599090582,
|
||||||
|
"tag": "0047_tidy_revanche",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 48,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1733599163710,
|
||||||
|
"tag": "0048_flat_expediter",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 49,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1733628762978,
|
||||||
|
"tag": "0049_dark_leopardon",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 50,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1733889104203,
|
||||||
|
"tag": "0050_nappy_wrecker",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 51,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1734241482851,
|
||||||
|
"tag": "0051_hard_gorgon",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 52,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1734809337308,
|
||||||
|
"tag": "0052_bumpy_luckman",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 53,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1735118844878,
|
||||||
|
"tag": "0053_broken_kulan_gath",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 54,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1736669421560,
|
||||||
|
"tag": "0054_nervous_spencer_smythe",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 55,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1736669623831,
|
||||||
|
"tag": "0055_next_serpent_society",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 56,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1736789918294,
|
||||||
|
"tag": "0056_majestic_skaar",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 57,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1737306063563,
|
||||||
|
"tag": "0057_tricky_living_tribunal",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 58,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1737612903012,
|
||||||
|
"tag": "0058_brown_sharon_carter",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 59,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1737615160768,
|
||||||
|
"tag": "0059_striped_bill_hollister",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 60,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1737929896838,
|
||||||
|
"tag": "0060_disable-aggressive-cache",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 61,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1738481304953,
|
||||||
|
"tag": "0061_many_molten_man",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 62,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1738482795112,
|
||||||
|
"tag": "0062_slippery_white_tiger",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 63,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1738522845992,
|
||||||
|
"tag": "0063_panoramic_dreadnoughts",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 64,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1738564387043,
|
||||||
|
"tag": "0064_previous_agent_brand",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 65,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1739087857244,
|
||||||
|
"tag": "0065_daily_zaladane",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 66,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1739426913392,
|
||||||
|
"tag": "0066_yielding_echo",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 67,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1740892043121,
|
||||||
|
"tag": "0067_condemned_sugar_man",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 68,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1740897756774,
|
||||||
|
"tag": "0068_complex_rhino",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 69,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741152916611,
|
||||||
|
"tag": "0069_legal_bill_hollister",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 70,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741322697251,
|
||||||
|
"tag": "0070_useful_serpent_society",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 71,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741559743256,
|
||||||
|
"tag": "0071_flimsy_plazm",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 72,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741593124105,
|
||||||
|
"tag": "0072_low_redwing",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 73,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741645208694,
|
||||||
|
"tag": "0073_dark_tigra",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 74,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741673569715,
|
||||||
|
"tag": "0074_military_miss_america",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 75,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742018928109,
|
||||||
|
"tag": "0075_wild_xorn",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 76,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742237840762,
|
||||||
|
"tag": "0076_tough_iron_patriot",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 77,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742238314349,
|
||||||
|
"tag": "0077_mature_tomorrow_man",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -5,23 +5,23 @@
|
|||||||
|
|
||||||
/** @type {import("next").NextConfig} */
|
/** @type {import("next").NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
},
|
},
|
||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
transpilePackages: ["@dokploy/server"],
|
transpilePackages: ["@dokploy/server"],
|
||||||
/**
|
/**
|
||||||
* If you are using `appDir` then you must comment the below `i18n` config out.
|
* If you are using `appDir` then you must comment the below `i18n` config out.
|
||||||
*
|
*
|
||||||
* @see https://github.com/vercel/next.js/issues/41980
|
* @see https://github.com/vercel/next.js/issues/41980
|
||||||
*/
|
*/
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: ["en"],
|
locales: ["en"],
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
"@trpc/client": "^10.43.6",
|
"@trpc/client": "^10.43.6",
|
||||||
"@trpc/next": "^10.43.6",
|
"@trpc/next": "^10.43.6",
|
||||||
"@trpc/react-query": "^10.43.6",
|
"@trpc/react-query": "^10.43.6",
|
||||||
"@trpc/server": "^10.43.6",
|
"@trpc/server": "^10.45.2",
|
||||||
"@uiw/codemirror-theme-github": "^4.22.1",
|
"@uiw/codemirror-theme-github": "^4.22.1",
|
||||||
"@uiw/react-codemirror": "^4.22.1",
|
"@uiw/react-codemirror": "^4.22.1",
|
||||||
"@xterm/addon-attach": "0.10.0",
|
"@xterm/addon-attach": "0.10.0",
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/lodash": "4.17.4",
|
"@types/lodash": "4.17.4",
|
||||||
"@types/micromatch": "4.0.9",
|
"@types/micromatch": "4.0.9",
|
||||||
"@types/node": "^18.17.0",
|
"@types/node": "^18.19.42",
|
||||||
"@types/node-os-utils": "1.3.4",
|
"@types/node-os-utils": "1.3.4",
|
||||||
"@types/node-schedule": "2.1.6",
|
"@types/node-schedule": "2.1.6",
|
||||||
"@types/nodemailer": "^6.4.15",
|
"@types/nodemailer": "^6.4.15",
|
||||||
@@ -197,8 +197,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"commitlint": {
|
"commitlint": {
|
||||||
"extends": [
|
"extends": ["@commitlint/config-conventional"]
|
||||||
"@commitlint/config-conventional"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,13 +112,6 @@ export default async function handler(
|
|||||||
res.status(301).json({ message: "Branch Not Match" });
|
res.status(301).json({ message: "Branch Not Match" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
<<<<<<< HEAD
|
|
||||||
} else if (sourceType === "gitea") {
|
|
||||||
const branchName = extractBranchName(req.headers, req.body);
|
|
||||||
if (!branchName || branchName !== application.giteaBranch) {
|
|
||||||
res.status(301).json({ message: "Branch Not Match" });
|
|
||||||
return;
|
|
||||||
=======
|
|
||||||
|
|
||||||
const commitedPaths = await extractCommitedPaths(
|
const commitedPaths = await extractCommitedPaths(
|
||||||
req.body,
|
req.body,
|
||||||
@@ -134,7 +127,12 @@ export default async function handler(
|
|||||||
if (!shouldDeployPaths) {
|
if (!shouldDeployPaths) {
|
||||||
res.status(301).json({ message: "Watch Paths Not Match" });
|
res.status(301).json({ message: "Watch Paths Not Match" });
|
||||||
return;
|
return;
|
||||||
>>>>>>> fork/canary
|
}
|
||||||
|
} else if (sourceType === "gitea") {
|
||||||
|
const branchName = extractBranchName(req.headers, req.body);
|
||||||
|
if (!branchName || branchName !== application.giteaBranch) {
|
||||||
|
res.status(301).json({ message: "Branch Not Match" });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { eq } from "drizzle-orm";
|
|||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import {
|
import {
|
||||||
extractBranchName,
|
extractBranchName,
|
||||||
extractCommitedPaths,
|
|
||||||
extractCommitMessage,
|
extractCommitMessage,
|
||||||
|
extractCommitedPaths,
|
||||||
extractHash,
|
extractHash,
|
||||||
} from "../[refreshToken]";
|
} from "../[refreshToken]";
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,41 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { findGiteaById } from '@dokploy/server';
|
import { findGitea, redirectWithError } from "./helper";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== "GET") {
|
||||||
return res.status(405).json({ error: 'Method not allowed' });
|
return res.status(405).json({ error: "Method not allowed" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { giteaId } = req.query;
|
const { giteaId } = req.query;
|
||||||
|
|
||||||
if (!giteaId || Array.isArray(giteaId)) {
|
if (!giteaId || Array.isArray(giteaId)) {
|
||||||
return res.status(400).json({ error: 'Invalid Gitea provider ID' });
|
return res.status(400).json({ error: "Invalid Gitea provider ID" });
|
||||||
}
|
}
|
||||||
|
|
||||||
let gitea;
|
const gitea = await findGitea(giteaId as string);
|
||||||
try {
|
if (!gitea || !gitea.clientId || !gitea.redirectUri) {
|
||||||
gitea = await findGiteaById(giteaId);
|
return redirectWithError(res, "Incomplete OAuth configuration");
|
||||||
} catch (findError) {
|
}
|
||||||
console.error('Error finding Gitea provider:', findError);
|
|
||||||
return res.status(404).json({ error: 'Failed to find Gitea provider' });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gitea.clientId || !gitea.redirectUri) {
|
// Generate the Gitea authorization URL
|
||||||
return res.status(400).json({
|
const authorizationUrl = new URL(`${gitea.giteaUrl}/login/oauth/authorize`);
|
||||||
error: 'Incomplete OAuth configuration',
|
authorizationUrl.searchParams.append("client_id", gitea.clientId as string);
|
||||||
missingClientId: !gitea.clientId,
|
authorizationUrl.searchParams.append("response_type", "code");
|
||||||
missingRedirectUri: !gitea.redirectUri
|
authorizationUrl.searchParams.append(
|
||||||
});
|
"redirect_uri",
|
||||||
}
|
gitea.redirectUri as string,
|
||||||
|
);
|
||||||
|
authorizationUrl.searchParams.append("scope", "read:user repo");
|
||||||
|
authorizationUrl.searchParams.append("state", giteaId as string);
|
||||||
|
|
||||||
// Use the state parameter to pass the giteaId
|
// Redirect user to Gitea authorization URL
|
||||||
// This is more secure than adding it to the redirect URI
|
return res.redirect(307, authorizationUrl.toString());
|
||||||
const state = giteaId;
|
} catch (error) {
|
||||||
|
console.error("Error initiating Gitea OAuth flow:", error);
|
||||||
const authorizationUrl = new URL(`${gitea.giteaUrl}/login/oauth/authorize`);
|
return res.status(500).json({ error: "Internal server error" });
|
||||||
authorizationUrl.searchParams.append('client_id', gitea.clientId);
|
}
|
||||||
authorizationUrl.searchParams.append('response_type', 'code');
|
}
|
||||||
authorizationUrl.searchParams.append('redirect_uri', gitea.redirectUri);
|
|
||||||
authorizationUrl.searchParams.append('scope', 'read:user repo');
|
|
||||||
authorizationUrl.searchParams.append('state', state);
|
|
||||||
|
|
||||||
// Redirect the user to the Gitea authorization page
|
|
||||||
res.redirect(307, authorizationUrl.toString());
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error initiating Gitea OAuth flow:', error);
|
|
||||||
return res.status(500).json({ error: 'Internal server error' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,186 +1,94 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { updateGitea } from "@dokploy/server";
|
||||||
import { findGiteaById, updateGitea } from '@dokploy/server';
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { type Gitea, findGitea, redirectWithError } from "./helper";
|
||||||
|
|
||||||
|
// Helper to parse the state parameter
|
||||||
|
const parseState = (state: string): string | null => {
|
||||||
|
try {
|
||||||
|
const stateObj =
|
||||||
|
state.startsWith("{") && state.endsWith("}") ? JSON.parse(state) : {};
|
||||||
|
return stateObj.giteaId || state || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to fetch access token from Gitea
|
||||||
|
const fetchAccessToken = async (gitea: Gitea, code: string) => {
|
||||||
|
const response = await fetch(`${gitea.giteaUrl}/login/oauth/access_token`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
client_id: gitea.clientId as string,
|
||||||
|
client_secret: gitea.clientSecret as string,
|
||||||
|
code,
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
redirect_uri: gitea.redirectUri || "",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
return response.ok
|
||||||
|
? JSON.parse(responseText)
|
||||||
|
: { error: "Token exchange failed", responseText };
|
||||||
|
};
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse,
|
||||||
) {
|
) {
|
||||||
try {
|
const { code, state } = req.query;
|
||||||
console.log('Full Callback Request:', {
|
|
||||||
query: req.query,
|
|
||||||
method: req.method,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
});
|
|
||||||
|
|
||||||
const { code, state } = req.query;
|
if (!code || Array.isArray(code) || !state || Array.isArray(state)) {
|
||||||
|
return redirectWithError(
|
||||||
|
res,
|
||||||
|
"Invalid authorization code or state parameter",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify received parameters
|
const giteaId = parseState(state as string);
|
||||||
console.log('Received Parameters:', {
|
if (!giteaId) return redirectWithError(res, "Invalid state format");
|
||||||
code: code ? 'Present' : 'Missing',
|
|
||||||
state: state ? 'Present' : 'Missing'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!code || Array.isArray(code)) {
|
const gitea = await findGitea(giteaId);
|
||||||
console.error('Invalid code:', code);
|
if (!gitea) return redirectWithError(res, "Failed to find Gitea provider");
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Invalid authorization code')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The state parameter now contains the giteaId
|
// Fetch the access token from Gitea
|
||||||
if (!state || Array.isArray(state)) {
|
const result = await fetchAccessToken(gitea, code as string);
|
||||||
console.error('Invalid state parameter:', state);
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Invalid state parameter')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the giteaId from the state parameter
|
if (result.error) {
|
||||||
let giteaId: string;
|
console.error("Token exchange failed:", result);
|
||||||
try {
|
return redirectWithError(res, result.error);
|
||||||
// The state could be a simple string or a JSON object
|
}
|
||||||
if (state.startsWith('{') && state.endsWith('}')) {
|
|
||||||
const stateObj = JSON.parse(state);
|
|
||||||
giteaId = stateObj.giteaId;
|
|
||||||
} else {
|
|
||||||
giteaId = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!giteaId) {
|
if (!result.access_token) {
|
||||||
throw new Error('giteaId not found in state parameter');
|
console.error("Missing access token:", result);
|
||||||
}
|
return redirectWithError(res, "No access token received");
|
||||||
} catch (parseError) {
|
}
|
||||||
console.error('Error parsing state parameter:', parseError);
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Invalid state format')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let gitea;
|
const expiresAt = result.expires_in
|
||||||
try {
|
? Math.floor(Date.now() / 1000) + result.expires_in
|
||||||
gitea = await findGiteaById(giteaId);
|
: null;
|
||||||
} catch (findError) {
|
|
||||||
console.error('Error finding Gitea provider:', findError);
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Failed to find Gitea provider')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extensive logging of Gitea provider details
|
try {
|
||||||
console.log('Gitea Provider Details:', {
|
const updatedGitea = await updateGitea(gitea.giteaId, {
|
||||||
id: gitea.giteaId,
|
accessToken: result.access_token,
|
||||||
url: gitea.giteaUrl,
|
refreshToken: result.refresh_token,
|
||||||
clientId: gitea.clientId ? 'Present' : 'Missing',
|
expiresAt,
|
||||||
clientSecret: gitea.clientSecret ? 'Present' : 'Missing',
|
...(result.organizationName
|
||||||
redirectUri: gitea.redirectUri
|
? { organizationName: result.organizationName }
|
||||||
});
|
: {}),
|
||||||
|
});
|
||||||
|
|
||||||
// Validate required OAuth parameters
|
console.log("Gitea provider updated successfully:", updatedGitea);
|
||||||
if (!gitea.clientId || !gitea.clientSecret) {
|
return res.redirect(
|
||||||
console.error('Missing OAuth configuration:', {
|
307,
|
||||||
hasClientId: !!gitea.clientId,
|
"/dashboard/settings/git-providers?connected=true",
|
||||||
hasClientSecret: !!gitea.clientSecret
|
);
|
||||||
});
|
} catch (updateError) {
|
||||||
return res.redirect(
|
console.error("Failed to update Gitea provider:", updateError);
|
||||||
307,
|
return redirectWithError(res, "Failed to store access token");
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Incomplete OAuth configuration')}`
|
}
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(`${gitea.giteaUrl}/login/oauth/access_token`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
"Accept": "application/json",
|
|
||||||
},
|
|
||||||
body: new URLSearchParams({
|
|
||||||
client_id: gitea.clientId as string,
|
|
||||||
client_secret: gitea.clientSecret as string,
|
|
||||||
code: code as string,
|
|
||||||
grant_type: "authorization_code",
|
|
||||||
redirect_uri: gitea.redirectUri || '',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log raw response details
|
|
||||||
const responseText = await response.text();
|
|
||||||
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
result = JSON.parse(responseText);
|
|
||||||
} catch (parseError) {
|
|
||||||
console.error('Failed to parse response:', {
|
|
||||||
error: parseError,
|
|
||||||
responseText
|
|
||||||
});
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Failed to parse token response')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error('Gitea token exchange failed:', {
|
|
||||||
result,
|
|
||||||
responseStatus: response.status
|
|
||||||
});
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent(result.error || 'Token exchange failed')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate token response
|
|
||||||
if (!result.access_token) {
|
|
||||||
console.error('Missing access token in response:', {
|
|
||||||
fullResponse: result
|
|
||||||
});
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('No access token received')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const expiresAt = result.expires_in
|
|
||||||
? Math.floor(Date.now() / 1000) + result.expires_in
|
|
||||||
: null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Perform the update
|
|
||||||
const updatedGitea = await updateGitea(gitea.giteaId, {
|
|
||||||
accessToken: result.access_token,
|
|
||||||
refreshToken: result.refresh_token,
|
|
||||||
expiresAt,
|
|
||||||
...(result.organizationName ? { organizationName: result.organizationName } : {}),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log successful update
|
|
||||||
console.log('Gitea provider updated successfully:', {
|
|
||||||
hasAccessToken: !!updatedGitea.accessToken,
|
|
||||||
hasRefreshToken: !!updatedGitea.refreshToken,
|
|
||||||
expiresAt: updatedGitea.expiresAt
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.redirect(307, "/dashboard/settings/git-providers?connected=true");
|
|
||||||
} catch (updateError) {
|
|
||||||
console.error('Failed to update Gitea provider:', {
|
|
||||||
error: updateError,
|
|
||||||
giteaId: gitea.giteaId
|
|
||||||
});
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Failed to store access token')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Comprehensive Callback Error:', error);
|
|
||||||
return res.redirect(
|
|
||||||
307,
|
|
||||||
`/dashboard/settings/git-providers?error=${encodeURIComponent('Internal server error')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
42
apps/dokploy/pages/api/providers/gitea/helper.ts
Normal file
42
apps/dokploy/pages/api/providers/gitea/helper.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { findGiteaById } from "@dokploy/server";
|
||||||
|
import type { NextApiResponse } from "next";
|
||||||
|
|
||||||
|
// Shared Gitea interface
|
||||||
|
export interface Gitea {
|
||||||
|
giteaId: string;
|
||||||
|
gitProviderId: string;
|
||||||
|
redirectUri: string | null;
|
||||||
|
accessToken: string | null;
|
||||||
|
refreshToken: string | null;
|
||||||
|
expiresAt: number | null;
|
||||||
|
giteaUrl: string;
|
||||||
|
clientId: string | null;
|
||||||
|
clientSecret: string | null;
|
||||||
|
organizationName?: string;
|
||||||
|
gitProvider: {
|
||||||
|
name: string;
|
||||||
|
gitProviderId: string;
|
||||||
|
providerType: "github" | "gitlab" | "bitbucket" | "gitea";
|
||||||
|
createdAt: string;
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared function to find Gitea by ID
|
||||||
|
export const findGitea = async (giteaId: string): Promise<Gitea | null> => {
|
||||||
|
try {
|
||||||
|
const gitea = await findGiteaById(giteaId);
|
||||||
|
return gitea;
|
||||||
|
} catch (findError) {
|
||||||
|
console.error("Error finding Gitea provider:", findError);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper for redirecting with error message
|
||||||
|
export const redirectWithError = (res: NextApiResponse, error: string) => {
|
||||||
|
return res.redirect(
|
||||||
|
307,
|
||||||
|
`/dashboard/settings/git-providers?error=${encodeURIComponent(error)}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -34,6 +34,15 @@ import {
|
|||||||
CommandInput,
|
CommandInput,
|
||||||
CommandItem,
|
CommandItem,
|
||||||
} from "@/components/ui/command";
|
} from "@/components/ui/command";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -47,6 +56,13 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
@@ -64,8 +80,8 @@ import {
|
|||||||
Loader2,
|
Loader2,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
Search,
|
Search,
|
||||||
X,
|
|
||||||
Trash2,
|
Trash2,
|
||||||
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
@@ -73,25 +89,9 @@ import type {
|
|||||||
} from "next";
|
} from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { type ReactElement, useMemo, useState, useEffect } from "react";
|
import { type ReactElement, useEffect, useMemo, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "@/components/ui/dialog";
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
|
|
||||||
export type Services = {
|
export type Services = {
|
||||||
appName: string;
|
appName: string;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ShowImport } from "@/components/dashboard/application/advanced/import/show-import";
|
||||||
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
||||||
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
|
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
|
||||||
import { AddCommandCompose } from "@/components/dashboard/compose/advanced/add-command";
|
import { AddCommandCompose } from "@/components/dashboard/compose/advanced/add-command";
|
||||||
@@ -47,7 +48,6 @@ import { useRouter } from "next/router";
|
|||||||
import { type ReactElement, useEffect, useState } from "react";
|
import { type ReactElement, useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import { ShowImport } from "@/components/dashboard/application/advanced/import/show-import";
|
|
||||||
|
|
||||||
type TabState =
|
type TabState =
|
||||||
| "projects"
|
| "projects"
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import { ShowExternalPostgresCredentials } from "@/components/dashboard/postgres
|
|||||||
import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres";
|
import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres";
|
||||||
import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials";
|
import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials";
|
||||||
import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres";
|
import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres";
|
||||||
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
|
import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
|||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
import React, { type ReactElement } from "react";
|
import type { ReactElement } from "react";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
|
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import { destinationRouter } from "./routers/destination";
|
|||||||
import { dockerRouter } from "./routers/docker";
|
import { dockerRouter } from "./routers/docker";
|
||||||
import { domainRouter } from "./routers/domain";
|
import { domainRouter } from "./routers/domain";
|
||||||
import { gitProviderRouter } from "./routers/git-provider";
|
import { gitProviderRouter } from "./routers/git-provider";
|
||||||
|
import { giteaRouter } from "./routers/gitea";
|
||||||
import { githubRouter } from "./routers/github";
|
import { githubRouter } from "./routers/github";
|
||||||
import { gitlabRouter } from "./routers/gitlab";
|
import { gitlabRouter } from "./routers/gitlab";
|
||||||
import { giteaRouter } from "./routers/gitea";
|
|
||||||
import { mariadbRouter } from "./routers/mariadb";
|
import { mariadbRouter } from "./routers/mariadb";
|
||||||
import { mongoRouter } from "./routers/mongo";
|
import { mongoRouter } from "./routers/mongo";
|
||||||
import { mountRouter } from "./routers/mount";
|
import { mountRouter } from "./routers/mount";
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import {
|
|||||||
checkServiceAccess,
|
checkServiceAccess,
|
||||||
} from "@dokploy/server/services/user";
|
} from "@dokploy/server/services/user";
|
||||||
import {
|
import {
|
||||||
getProviderHeaders,
|
|
||||||
type Model,
|
type Model,
|
||||||
|
getProviderHeaders,
|
||||||
} from "@dokploy/server/utils/ai/select-ai-provider";
|
} from "@dokploy/server/utils/ai/select-ai-provider";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import {
|
|||||||
apiSaveDockerProvider,
|
apiSaveDockerProvider,
|
||||||
apiSaveEnvironmentVariables,
|
apiSaveEnvironmentVariables,
|
||||||
apiSaveGitProvider,
|
apiSaveGitProvider,
|
||||||
|
apiSaveGiteaProvider,
|
||||||
apiSaveGithubProvider,
|
apiSaveGithubProvider,
|
||||||
apiSaveGitlabProvider,
|
apiSaveGitlabProvider,
|
||||||
apiSaveGiteaProvider,
|
|
||||||
apiUpdateApplication,
|
apiUpdateApplication,
|
||||||
applications,
|
applications,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
@@ -425,7 +425,7 @@ export const applicationRouter = createTRPCRouter({
|
|||||||
giteaProjectId: input.giteaProjectId,
|
giteaProjectId: input.giteaProjectId,
|
||||||
giteaPathNamespace: input.giteaPathNamespace,
|
giteaPathNamespace: input.giteaPathNamespace,
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
saveDockerProvider: protectedProcedure
|
saveDockerProvider: protectedProcedure
|
||||||
|
|||||||
@@ -9,23 +9,10 @@ import {
|
|||||||
apiUpdateCompose,
|
apiUpdateCompose,
|
||||||
compose as composeTable,
|
compose as composeTable,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
import { cleanQueuesByCompose, myQueue } from "@/server/queues/queueSetup";
|
|
||||||
import { generatePassword } from "@/templates/utils";
|
|
||||||
import {
|
|
||||||
type CompleteTemplate,
|
|
||||||
fetchTemplateFiles,
|
|
||||||
fetchTemplatesList,
|
|
||||||
} from "@dokploy/server/templates/github";
|
|
||||||
import { processTemplate } from "@dokploy/server/templates/processors";
|
|
||||||
import { TRPCError } from "@trpc/server";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { dump, load } from "js-yaml";
|
|
||||||
import _ from "lodash";
|
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
|
||||||
import { z } from "zod";
|
|
||||||
import type { DeploymentJob } from "@/server/queues/queue-types";
|
import type { DeploymentJob } from "@/server/queues/queue-types";
|
||||||
|
import { cleanQueuesByCompose, myQueue } from "@/server/queues/queueSetup";
|
||||||
import { deploy } from "@/server/utils/deploy";
|
import { deploy } from "@/server/utils/deploy";
|
||||||
|
import { generatePassword } from "@/templates/utils";
|
||||||
import {
|
import {
|
||||||
IS_CLOUD,
|
IS_CLOUD,
|
||||||
addDomainToCompose,
|
addDomainToCompose,
|
||||||
@@ -55,6 +42,19 @@ import {
|
|||||||
stopCompose,
|
stopCompose,
|
||||||
updateCompose,
|
updateCompose,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
import {
|
||||||
|
type CompleteTemplate,
|
||||||
|
fetchTemplateFiles,
|
||||||
|
fetchTemplatesList,
|
||||||
|
} from "@dokploy/server/templates/github";
|
||||||
|
import { processTemplate } from "@dokploy/server/templates/processors";
|
||||||
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { dump, load } from "js-yaml";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||||
|
|
||||||
export const composeRouter = createTRPCRouter({
|
export const composeRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
updateDestinationById,
|
updateDestinationById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { eq, desc } from "drizzle-orm";
|
import { desc, eq } from "drizzle-orm";
|
||||||
|
|
||||||
export const destinationRouter = createTRPCRouter({
|
export const destinationRouter = createTRPCRouter({
|
||||||
create: adminProcedure
|
create: adminProcedure
|
||||||
|
|||||||
@@ -1,238 +1,240 @@
|
|||||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||||
import {
|
import {
|
||||||
apiCreateGitea,
|
apiCreateGitea,
|
||||||
apiFindOneGitea,
|
apiFindGiteaBranches,
|
||||||
apiGiteaTestConnection,
|
apiFindOneGitea,
|
||||||
apiUpdateGitea,
|
apiGiteaTestConnection,
|
||||||
apiFindGiteaBranches,
|
apiUpdateGitea,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
|
|
||||||
import { db } from "@/server/db";
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
createGitea,
|
createGitea,
|
||||||
findGiteaById,
|
findGiteaById,
|
||||||
haveGiteaRequirements,
|
getGiteaBranches,
|
||||||
testGiteaConnection,
|
getGiteaRepositories,
|
||||||
updateGitProvider,
|
haveGiteaRequirements,
|
||||||
updateGitea,
|
testGiteaConnection,
|
||||||
getGiteaBranches,
|
updateGitProvider,
|
||||||
getGiteaRepositories,
|
updateGitea,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
|
||||||
// Gitea Router
|
// Gitea Router
|
||||||
export const giteaRouter = createTRPCRouter({
|
export const giteaRouter = createTRPCRouter({
|
||||||
// Create a new Gitea provider
|
// Create a new Gitea provider
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreateGitea)
|
.input(apiCreateGitea)
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
try {
|
try {
|
||||||
return await createGitea(input, ctx.session.activeOrganizationId);
|
return await createGitea(input, ctx.session.activeOrganizationId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: "Error creating this Gitea provider",
|
message: "Error creating this Gitea provider",
|
||||||
cause: error,
|
cause: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Fetch a specific Gitea provider by ID
|
// Fetch a specific Gitea provider by ID
|
||||||
one: protectedProcedure
|
one: protectedProcedure
|
||||||
.input(apiFindOneGitea)
|
.input(apiFindOneGitea)
|
||||||
.query(async ({ input, ctx }) => {
|
.query(async ({ input, ctx }) => {
|
||||||
const giteaProvider = await findGiteaById(input.giteaId);
|
const giteaProvider = await findGiteaById(input.giteaId);
|
||||||
if (
|
if (
|
||||||
giteaProvider.gitProvider.organizationId !==
|
giteaProvider.gitProvider.organizationId !==
|
||||||
ctx.session.activeOrganizationId
|
ctx.session.activeOrganizationId
|
||||||
) {
|
) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: "You are not allowed to access this Gitea provider",
|
message: "You are not allowed to access this Gitea provider",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return giteaProvider;
|
return giteaProvider;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Fetch all Gitea providers for the active organization
|
// Fetch all Gitea providers for the active organization
|
||||||
giteaProviders: protectedProcedure.query(async ({ ctx }) => {
|
giteaProviders: protectedProcedure.query(async ({ ctx }) => {
|
||||||
let result = await db.query.gitea.findMany({
|
let result = await db.query.gitea.findMany({
|
||||||
with: {
|
with: {
|
||||||
gitProvider: true,
|
gitProvider: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Filter by organization ID
|
// Filter by organization ID
|
||||||
result = result.filter(
|
result = result.filter(
|
||||||
(provider) =>
|
(provider) =>
|
||||||
provider.gitProvider.organizationId === ctx.session.activeOrganizationId
|
provider.gitProvider.organizationId ===
|
||||||
);
|
ctx.session.activeOrganizationId,
|
||||||
|
);
|
||||||
// Filter providers that meet the requirements
|
|
||||||
const filtered = result
|
|
||||||
.filter((provider) => haveGiteaRequirements(provider))
|
|
||||||
.map((provider) => {
|
|
||||||
return {
|
|
||||||
giteaId: provider.giteaId,
|
|
||||||
gitProvider: {
|
|
||||||
...provider.gitProvider,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return filtered;
|
// Filter providers that meet the requirements
|
||||||
}),
|
const filtered = result
|
||||||
|
.filter((provider) => haveGiteaRequirements(provider))
|
||||||
|
.map((provider) => {
|
||||||
|
return {
|
||||||
|
giteaId: provider.giteaId,
|
||||||
|
gitProvider: {
|
||||||
|
...provider.gitProvider,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch repositories from Gitea provider
|
return filtered;
|
||||||
getGiteaRepositories: protectedProcedure
|
}),
|
||||||
.input(apiFindOneGitea)
|
|
||||||
.query(async ({ input, ctx }) => {
|
|
||||||
const { giteaId } = input;
|
|
||||||
|
|
||||||
if (!giteaId) {
|
// Fetch repositories from Gitea provider
|
||||||
throw new TRPCError({
|
getGiteaRepositories: protectedProcedure
|
||||||
code: "BAD_REQUEST",
|
.input(apiFindOneGitea)
|
||||||
message: "Gitea provider ID is required.",
|
.query(async ({ input, ctx }) => {
|
||||||
});
|
const { giteaId } = input;
|
||||||
}
|
|
||||||
|
|
||||||
const giteaProvider = await findGiteaById(giteaId);
|
if (!giteaId) {
|
||||||
if (
|
throw new TRPCError({
|
||||||
giteaProvider.gitProvider.organizationId !==
|
code: "BAD_REQUEST",
|
||||||
ctx.session.activeOrganizationId
|
message: "Gitea provider ID is required.",
|
||||||
) {
|
});
|
||||||
throw new TRPCError({
|
}
|
||||||
code: "UNAUTHORIZED",
|
|
||||||
message: "You are not allowed to access this Gitea provider",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Call the service layer function to get repositories
|
|
||||||
console.log('Calling getGiteaRepositories with giteaId:', giteaId);
|
|
||||||
return await getGiteaRepositories(giteaId);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching Gitea repositories:', error);
|
|
||||||
throw new TRPCError({
|
|
||||||
code: "BAD_REQUEST",
|
|
||||||
message: error instanceof Error ? error.message : String(error),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Fetch branches of a specific Gitea repository
|
const giteaProvider = await findGiteaById(giteaId);
|
||||||
getGiteaBranches: protectedProcedure
|
if (
|
||||||
.input(apiFindGiteaBranches)
|
giteaProvider.gitProvider.organizationId !==
|
||||||
.query(async ({ input, ctx }) => {
|
ctx.session.activeOrganizationId
|
||||||
const { giteaId, owner, repositoryName } = input;
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "UNAUTHORIZED",
|
||||||
|
message: "You are not allowed to access this Gitea provider",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!giteaId || !owner || !repositoryName) {
|
try {
|
||||||
throw new TRPCError({
|
// Call the service layer function to get repositories
|
||||||
code: "BAD_REQUEST",
|
console.log("Calling getGiteaRepositories with giteaId:", giteaId);
|
||||||
message: "Gitea provider ID, owner, and repository name are required.",
|
return await getGiteaRepositories(giteaId);
|
||||||
});
|
} catch (error) {
|
||||||
}
|
console.error("Error fetching Gitea repositories:", error);
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
const giteaProvider = await findGiteaById(giteaId);
|
// Fetch branches of a specific Gitea repository
|
||||||
if (
|
getGiteaBranches: protectedProcedure
|
||||||
giteaProvider.gitProvider.organizationId !==
|
.input(apiFindGiteaBranches)
|
||||||
ctx.session.activeOrganizationId
|
.query(async ({ input, ctx }) => {
|
||||||
) {
|
const { giteaId, owner, repositoryName } = input;
|
||||||
throw new TRPCError({
|
|
||||||
code: "UNAUTHORIZED",
|
|
||||||
message: "You are not allowed to access this Gitea provider",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Call the service layer function with the required parameters
|
|
||||||
console.log('Calling getGiteaBranches with:', {
|
|
||||||
giteaId,
|
|
||||||
owner,
|
|
||||||
repo: repositoryName
|
|
||||||
});
|
|
||||||
|
|
||||||
return await getGiteaBranches({
|
|
||||||
giteaId,
|
|
||||||
owner,
|
|
||||||
repo: repositoryName,
|
|
||||||
id: 0 // Provide a default value for the optional id
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching Gitea branches:', error);
|
|
||||||
throw new TRPCError({
|
|
||||||
code: "BAD_REQUEST",
|
|
||||||
message: error instanceof Error ? error.message : String(error),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Test connection to Gitea provider
|
if (!giteaId || !owner || !repositoryName) {
|
||||||
testConnection: protectedProcedure
|
throw new TRPCError({
|
||||||
.input(apiGiteaTestConnection)
|
code: "BAD_REQUEST",
|
||||||
.mutation(async ({ input, ctx }) => {
|
message:
|
||||||
// Ensure giteaId is always a non-empty string
|
"Gitea provider ID, owner, and repository name are required.",
|
||||||
const giteaId = input.giteaId ?? '';
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
const giteaProvider = await findGiteaById(giteaId);
|
||||||
const giteaProvider = await findGiteaById(giteaId);
|
if (
|
||||||
if (
|
giteaProvider.gitProvider.organizationId !==
|
||||||
giteaProvider.gitProvider.organizationId !==
|
ctx.session.activeOrganizationId
|
||||||
ctx.session.activeOrganizationId
|
) {
|
||||||
) {
|
throw new TRPCError({
|
||||||
throw new TRPCError({
|
code: "UNAUTHORIZED",
|
||||||
code: "UNAUTHORIZED",
|
message: "You are not allowed to access this Gitea provider",
|
||||||
message: "You are not allowed to access this Gitea provider",
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const result = await testGiteaConnection({
|
|
||||||
giteaId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return `Found ${result} repositories`;
|
try {
|
||||||
} catch (error) {
|
// Call the service layer function with the required parameters
|
||||||
console.error('Gitea connection test error:', error);
|
console.log("Calling getGiteaBranches with:", {
|
||||||
throw new TRPCError({
|
giteaId,
|
||||||
code: "BAD_REQUEST",
|
owner,
|
||||||
message: error instanceof Error ? error.message : String(error),
|
repo: repositoryName,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Update an existing Gitea provider
|
return await getGiteaBranches({
|
||||||
update: protectedProcedure
|
giteaId,
|
||||||
.input(apiUpdateGitea)
|
owner,
|
||||||
.mutation(async ({ input, ctx }) => {
|
repo: repositoryName,
|
||||||
const giteaProvider = await findGiteaById(input.giteaId);
|
id: 0, // Provide a default value for the optional id
|
||||||
if (
|
});
|
||||||
giteaProvider.gitProvider.organizationId !==
|
} catch (error) {
|
||||||
ctx.session.activeOrganizationId
|
console.error("Error fetching Gitea branches:", error);
|
||||||
) {
|
throw new TRPCError({
|
||||||
throw new TRPCError({
|
code: "BAD_REQUEST",
|
||||||
code: "UNAUTHORIZED",
|
message: error instanceof Error ? error.message : String(error),
|
||||||
message: "You are not allowed to access this Gitea provider",
|
});
|
||||||
});
|
}
|
||||||
}
|
}),
|
||||||
|
|
||||||
console.log('Updating Gitea provider:', input);
|
|
||||||
|
|
||||||
if (input.name) {
|
|
||||||
await updateGitProvider(input.gitProviderId, {
|
|
||||||
name: input.name,
|
|
||||||
organizationId: ctx.session.activeOrganizationId,
|
|
||||||
});
|
|
||||||
|
|
||||||
await updateGitea(input.giteaId, {
|
// Test connection to Gitea provider
|
||||||
...input,
|
testConnection: protectedProcedure
|
||||||
});
|
.input(apiGiteaTestConnection)
|
||||||
} else {
|
.mutation(async ({ input, ctx }) => {
|
||||||
await updateGitea(input.giteaId, {
|
// Ensure giteaId is always a non-empty string
|
||||||
...input,
|
const giteaId = input.giteaId ?? "";
|
||||||
});
|
|
||||||
}
|
try {
|
||||||
|
const giteaProvider = await findGiteaById(giteaId);
|
||||||
return { success: true };
|
if (
|
||||||
}),
|
giteaProvider.gitProvider.organizationId !==
|
||||||
});
|
ctx.session.activeOrganizationId
|
||||||
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "UNAUTHORIZED",
|
||||||
|
message: "You are not allowed to access this Gitea provider",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testGiteaConnection({
|
||||||
|
giteaId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return `Found ${result} repositories`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gitea connection test error:", error);
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Update an existing Gitea provider
|
||||||
|
update: protectedProcedure
|
||||||
|
.input(apiUpdateGitea)
|
||||||
|
.mutation(async ({ input, ctx }) => {
|
||||||
|
const giteaProvider = await findGiteaById(input.giteaId);
|
||||||
|
if (
|
||||||
|
giteaProvider.gitProvider.organizationId !==
|
||||||
|
ctx.session.activeOrganizationId
|
||||||
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "UNAUTHORIZED",
|
||||||
|
message: "You are not allowed to access this Gitea provider",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Updating Gitea provider:", input);
|
||||||
|
|
||||||
|
if (input.name) {
|
||||||
|
await updateGitProvider(input.gitProviderId, {
|
||||||
|
name: input.name,
|
||||||
|
organizationId: ctx.session.activeOrganizationId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateGitea(input.giteaId, {
|
||||||
|
...input,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await updateGitea(input.giteaId, {
|
||||||
|
...input,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||||
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
apiChangeMariaDBStatus,
|
apiChangeMariaDBStatus,
|
||||||
apiCreateMariaDB,
|
apiCreateMariaDB,
|
||||||
apiDeployMariaDB,
|
apiDeployMariaDB,
|
||||||
apiFindOneMariaDB,
|
apiFindOneMariaDB,
|
||||||
|
apiRebuildMariadb,
|
||||||
apiResetMariadb,
|
apiResetMariadb,
|
||||||
apiSaveEnvironmentVariablesMariaDB,
|
apiSaveEnvironmentVariablesMariaDB,
|
||||||
apiSaveExternalPortMariaDB,
|
apiSaveExternalPortMariaDB,
|
||||||
apiUpdateMariaDB,
|
apiUpdateMariaDB,
|
||||||
apiRebuildMariadb,
|
|
||||||
mariadb as mariadbTable,
|
mariadb as mariadbTable,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
import { cancelJobs } from "@/server/utils/backup";
|
import { cancelJobs } from "@/server/utils/backup";
|
||||||
@@ -30,12 +31,11 @@ import {
|
|||||||
stopServiceRemote,
|
stopServiceRemote,
|
||||||
updateMariadbById,
|
updateMariadbById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
import { rebuildDatabase } from "@dokploy/server";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { observable } from "@trpc/server/observable";
|
import { observable } from "@trpc/server/observable";
|
||||||
import { z } from "zod";
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
import { z } from "zod";
|
||||||
import { rebuildDatabase } from "@dokploy/server";
|
|
||||||
export const mariadbRouter = createTRPCRouter({
|
export const mariadbRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreateMariaDB)
|
.input(apiCreateMariaDB)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||||
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
apiChangeMongoStatus,
|
apiChangeMongoStatus,
|
||||||
apiCreateMongo,
|
apiCreateMongo,
|
||||||
@@ -30,12 +31,11 @@ import {
|
|||||||
stopServiceRemote,
|
stopServiceRemote,
|
||||||
updateMongoById,
|
updateMongoById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
import { rebuildDatabase } from "@dokploy/server";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { observable } from "@trpc/server/observable";
|
import { observable } from "@trpc/server/observable";
|
||||||
import { z } from "zod";
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
import { z } from "zod";
|
||||||
import { rebuildDatabase } from "@dokploy/server";
|
|
||||||
export const mongoRouter = createTRPCRouter({
|
export const mongoRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreateMongo)
|
.input(apiCreateMongo)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
|
||||||
|
import { db } from "@/server/db";
|
||||||
import { cancelJobs } from "@/server/utils/backup";
|
import { cancelJobs } from "@/server/utils/backup";
|
||||||
import {
|
import {
|
||||||
IS_CLOUD,
|
IS_CLOUD,
|
||||||
@@ -36,7 +37,6 @@ import {
|
|||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { observable } from "@trpc/server/observable";
|
import { observable } from "@trpc/server/observable";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const mysqlRouter = createTRPCRouter({
|
export const mysqlRouter = createTRPCRouter({
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||||
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
apiChangePostgresStatus,
|
apiChangePostgresStatus,
|
||||||
apiCreatePostgres,
|
apiCreatePostgres,
|
||||||
@@ -33,9 +34,8 @@ import {
|
|||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { observable } from "@trpc/server/observable";
|
import { observable } from "@trpc/server/observable";
|
||||||
import { z } from "zod";
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
import { z } from "zod";
|
||||||
export const postgresRouter = createTRPCRouter({
|
export const postgresRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreatePostgres)
|
.input(apiCreatePostgres)
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ import {
|
|||||||
apiCreateRedis,
|
apiCreateRedis,
|
||||||
apiDeployRedis,
|
apiDeployRedis,
|
||||||
apiFindOneRedis,
|
apiFindOneRedis,
|
||||||
|
apiRebuildRedis,
|
||||||
apiResetRedis,
|
apiResetRedis,
|
||||||
apiSaveEnvironmentVariablesRedis,
|
apiSaveEnvironmentVariablesRedis,
|
||||||
apiSaveExternalPortRedis,
|
apiSaveExternalPortRedis,
|
||||||
apiUpdateRedis,
|
apiUpdateRedis,
|
||||||
redis as redisTable,
|
redis as redisTable,
|
||||||
apiRebuildRedis,
|
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
|
||||||
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
IS_CLOUD,
|
IS_CLOUD,
|
||||||
addNewService,
|
addNewService,
|
||||||
@@ -31,11 +32,10 @@ import {
|
|||||||
stopServiceRemote,
|
stopServiceRemote,
|
||||||
updateRedisById,
|
updateRedisById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
import { rebuildDatabase } from "@dokploy/server";
|
||||||
import { observable } from "@trpc/server/observable";
|
import { observable } from "@trpc/server/observable";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { rebuildDatabase } from "@dokploy/server";
|
|
||||||
export const redisRouter = createTRPCRouter({
|
export const redisRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreateRedis)
|
.input(apiCreateRedis)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
findUserById,
|
findUserById,
|
||||||
getDokployImage,
|
getDokployImage,
|
||||||
getDokployImageTag,
|
getDokployImageTag,
|
||||||
|
getLogCleanupStatus,
|
||||||
getUpdateData,
|
getUpdateData,
|
||||||
initializeTraefik,
|
initializeTraefik,
|
||||||
parseRawConfig,
|
parseRawConfig,
|
||||||
@@ -41,6 +42,8 @@ import {
|
|||||||
recreateDirectory,
|
recreateDirectory,
|
||||||
sendDockerCleanupNotifications,
|
sendDockerCleanupNotifications,
|
||||||
spawnAsync,
|
spawnAsync,
|
||||||
|
startLogCleanup,
|
||||||
|
stopLogCleanup,
|
||||||
updateLetsEncryptEmail,
|
updateLetsEncryptEmail,
|
||||||
updateServerById,
|
updateServerById,
|
||||||
updateServerTraefik,
|
updateServerTraefik,
|
||||||
@@ -48,9 +51,6 @@ import {
|
|||||||
writeConfig,
|
writeConfig,
|
||||||
writeMainConfig,
|
writeMainConfig,
|
||||||
writeTraefikConfigInPath,
|
writeTraefikConfigInPath,
|
||||||
startLogCleanup,
|
|
||||||
stopLogCleanup,
|
|
||||||
getLogCleanupStatus,
|
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { checkGPUStatus, setupGPUSupport } from "@dokploy/server";
|
import { checkGPUStatus, setupGPUSupport } from "@dokploy/server";
|
||||||
import { generateOpenApiDocument } from "@dokploy/trpc-openapi";
|
import { generateOpenApiDocument } from "@dokploy/trpc-openapi";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
IS_CLOUD,
|
IS_CLOUD,
|
||||||
|
createApiKey,
|
||||||
findOrganizationById,
|
findOrganizationById,
|
||||||
findUserById,
|
findUserById,
|
||||||
getUserByToken,
|
getUserByToken,
|
||||||
removeUserById,
|
removeUserById,
|
||||||
updateUser,
|
updateUser,
|
||||||
createApiKey,
|
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { db } from "@dokploy/server/db";
|
import { db } from "@dokploy/server/db";
|
||||||
import {
|
import {
|
||||||
@@ -13,12 +13,12 @@ import {
|
|||||||
apiAssignPermissions,
|
apiAssignPermissions,
|
||||||
apiFindOneToken,
|
apiFindOneToken,
|
||||||
apiUpdateUser,
|
apiUpdateUser,
|
||||||
|
apikey,
|
||||||
invitation,
|
invitation,
|
||||||
member,
|
member,
|
||||||
apikey,
|
|
||||||
} from "@dokploy/server/db/schema";
|
} from "@dokploy/server/db/schema";
|
||||||
import * as bcrypt from "bcrypt";
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import * as bcrypt from "bcrypt";
|
||||||
import { and, asc, eq, gt } from "drizzle-orm";
|
import { and, asc, eq, gt } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export function generate(schema: Schema): Template {
|
|||||||
"CLIENT_SECRET_GITLAB_LOGIN=",
|
"CLIENT_SECRET_GITLAB_LOGIN=",
|
||||||
"",
|
"",
|
||||||
"CLIENT_ID_GITEA_LOGIN=",
|
"CLIENT_ID_GITEA_LOGIN=",
|
||||||
"CLIENT_SECRET_GITEA_LOGIN=",
|
"CLIENT_SECRET_GITEA_LOGIN=",
|
||||||
"",
|
"",
|
||||||
"CAPTCHA_SECRET=",
|
"CAPTCHA_SECRET=",
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import { z } from "zod";
|
|||||||
import { bitbucket } from "./bitbucket";
|
import { bitbucket } from "./bitbucket";
|
||||||
import { deployments } from "./deployment";
|
import { deployments } from "./deployment";
|
||||||
import { domains } from "./domain";
|
import { domains } from "./domain";
|
||||||
|
import { gitea } from "./gitea";
|
||||||
import { github } from "./github";
|
import { github } from "./github";
|
||||||
import { gitlab } from "./gitlab";
|
import { gitlab } from "./gitlab";
|
||||||
import { gitea } from "./gitea";
|
|
||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { ports } from "./port";
|
import { ports } from "./port";
|
||||||
import { previewDeployments } from "./preview-deployments";
|
import { previewDeployments } from "./preview-deployments";
|
||||||
@@ -395,7 +395,9 @@ const createSchema = createInsertSchema(applications, {
|
|||||||
customGitUrl: z.string().optional(),
|
customGitUrl: z.string().optional(),
|
||||||
buildPath: z.string().optional(),
|
buildPath: z.string().optional(),
|
||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
sourceType: z.enum(["github", "docker", "git", "gitlab", "bitbucket", "gitea", "drop"]).optional(),
|
sourceType: z
|
||||||
|
.enum(["github", "docker", "git", "gitlab", "bitbucket", "gitea", "drop"])
|
||||||
|
.optional(),
|
||||||
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
||||||
buildType: z.enum([
|
buildType: z.enum([
|
||||||
"dockerfile",
|
"dockerfile",
|
||||||
@@ -556,4 +558,4 @@ export const apiUpdateApplication = createSchema
|
|||||||
.extend({
|
.extend({
|
||||||
applicationId: z.string().min(1),
|
applicationId: z.string().min(1),
|
||||||
})
|
})
|
||||||
.omit({ serverId: true });
|
.omit({ serverId: true });
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|||||||
import { bitbucket } from "./bitbucket";
|
import { bitbucket } from "./bitbucket";
|
||||||
import { deployments } from "./deployment";
|
import { deployments } from "./deployment";
|
||||||
import { domains } from "./domain";
|
import { domains } from "./domain";
|
||||||
|
import { gitea } from "./gitea";
|
||||||
import { github } from "./github";
|
import { github } from "./github";
|
||||||
import { gitlab } from "./gitlab";
|
import { gitlab } from "./gitlab";
|
||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
@@ -14,7 +15,6 @@ import { server } from "./server";
|
|||||||
import { applicationStatus } from "./shared";
|
import { applicationStatus } from "./shared";
|
||||||
import { sshKeys } from "./ssh-key";
|
import { sshKeys } from "./ssh-key";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
import { gitea } from "./gitea";
|
|
||||||
|
|
||||||
export const sourceTypeCompose = pgEnum("sourceTypeCompose", [
|
export const sourceTypeCompose = pgEnum("sourceTypeCompose", [
|
||||||
"git",
|
"git",
|
||||||
@@ -58,9 +58,9 @@ export const compose = pgTable("compose", {
|
|||||||
bitbucketOwner: text("bitbucketOwner"),
|
bitbucketOwner: text("bitbucketOwner"),
|
||||||
bitbucketBranch: text("bitbucketBranch"),
|
bitbucketBranch: text("bitbucketBranch"),
|
||||||
// Gitea
|
// Gitea
|
||||||
giteaRepository: text("giteaRepository"),
|
giteaRepository: text("giteaRepository"),
|
||||||
giteaOwner: text("giteaOwner"),
|
giteaOwner: text("giteaOwner"),
|
||||||
giteaBranch: text("giteaBranch"),
|
giteaBranch: text("giteaBranch"),
|
||||||
// Git
|
// Git
|
||||||
customGitUrl: text("customGitUrl"),
|
customGitUrl: text("customGitUrl"),
|
||||||
customGitBranch: text("customGitBranch"),
|
customGitBranch: text("customGitBranch"),
|
||||||
@@ -94,8 +94,8 @@ export const compose = pgTable("compose", {
|
|||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
}),
|
}),
|
||||||
giteaId: text("giteaId").references(() => gitea.giteaId, {
|
giteaId: text("giteaId").references(() => gitea.giteaId, {
|
||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
}),
|
}),
|
||||||
serverId: text("serverId").references(() => server.serverId, {
|
serverId: text("serverId").references(() => server.serverId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
@@ -126,9 +126,9 @@ export const composeRelations = relations(compose, ({ one, many }) => ({
|
|||||||
references: [bitbucket.bitbucketId],
|
references: [bitbucket.bitbucketId],
|
||||||
}),
|
}),
|
||||||
gitea: one(gitea, {
|
gitea: one(gitea, {
|
||||||
fields: [compose.giteaId],
|
fields: [compose.giteaId],
|
||||||
references: [gitea.giteaId],
|
references: [gitea.giteaId],
|
||||||
}),
|
}),
|
||||||
server: one(server, {
|
server: one(server, {
|
||||||
fields: [compose.serverId],
|
fields: [compose.serverId],
|
||||||
references: [server.serverId],
|
references: [server.serverId],
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { nanoid } from "nanoid";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { organization } from "./account";
|
import { organization } from "./account";
|
||||||
import { bitbucket } from "./bitbucket";
|
import { bitbucket } from "./bitbucket";
|
||||||
|
import { gitea } from "./gitea";
|
||||||
import { github } from "./github";
|
import { github } from "./github";
|
||||||
import { gitlab } from "./gitlab";
|
import { gitlab } from "./gitlab";
|
||||||
import { gitea } from "./gitea";
|
|
||||||
|
|
||||||
export const gitProviderType = pgEnum("gitProviderType", [
|
export const gitProviderType = pgEnum("gitProviderType", [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -7,31 +7,31 @@ import { gitProvider } from "./git-provider";
|
|||||||
|
|
||||||
// Gitea table definition
|
// Gitea table definition
|
||||||
export const gitea = pgTable("gitea", {
|
export const gitea = pgTable("gitea", {
|
||||||
giteaId: text("giteaId")
|
giteaId: text("giteaId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.primaryKey()
|
.primaryKey()
|
||||||
.$defaultFn(() => nanoid()), // Using nanoid for unique ID
|
.$defaultFn(() => nanoid()), // Using nanoid for unique ID
|
||||||
giteaUrl: text("giteaUrl").default("https://gitea.com").notNull(), // Default URL for Gitea
|
giteaUrl: text("giteaUrl").default("https://gitea.com").notNull(), // Default URL for Gitea
|
||||||
redirectUri: text("redirect_uri"),
|
redirectUri: text("redirect_uri"),
|
||||||
clientId: text("client_id"),
|
clientId: text("client_id"),
|
||||||
clientSecret: text("client_secret"),
|
clientSecret: text("client_secret"),
|
||||||
gitProviderId: text("gitProviderId")
|
gitProviderId: text("gitProviderId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => gitProvider.gitProviderId, { onDelete: "cascade" }),
|
.references(() => gitProvider.gitProviderId, { onDelete: "cascade" }),
|
||||||
giteaUsername: text("gitea_username"),
|
giteaUsername: text("gitea_username"),
|
||||||
accessToken: text("access_token"),
|
accessToken: text("access_token"),
|
||||||
refreshToken: text("refresh_token"),
|
refreshToken: text("refresh_token"),
|
||||||
expiresAt: integer("expires_at"),
|
expiresAt: integer("expires_at"),
|
||||||
scopes: text("scopes").default('repo,repo:status,read:user,read:org'),
|
scopes: text("scopes").default("repo,repo:status,read:user,read:org"),
|
||||||
lastAuthenticatedAt: integer("last_authenticated_at"),
|
lastAuthenticatedAt: integer("last_authenticated_at"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gitea relations with gitProvider
|
// Gitea relations with gitProvider
|
||||||
export const giteaProviderRelations = relations(gitea, ({ one }) => ({
|
export const giteaProviderRelations = relations(gitea, ({ one }) => ({
|
||||||
gitProvider: one(gitProvider, {
|
gitProvider: one(gitProvider, {
|
||||||
fields: [gitea.gitProviderId],
|
fields: [gitea.gitProviderId],
|
||||||
references: [gitProvider.gitProviderId],
|
references: [gitProvider.gitProviderId],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Create schema for Gitea
|
// Create schema for Gitea
|
||||||
@@ -39,58 +39,58 @@ const createSchema = createInsertSchema(gitea);
|
|||||||
|
|
||||||
// API schema for creating a Gitea instance
|
// API schema for creating a Gitea instance
|
||||||
export const apiCreateGitea = createSchema.extend({
|
export const apiCreateGitea = createSchema.extend({
|
||||||
clientId: z.string().optional(),
|
clientId: z.string().optional(),
|
||||||
clientSecret: z.string().optional(),
|
clientSecret: z.string().optional(),
|
||||||
gitProviderId: z.string().optional(),
|
gitProviderId: z.string().optional(),
|
||||||
redirectUri: z.string().optional(),
|
redirectUri: z.string().optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
giteaUrl: z.string().min(1),
|
giteaUrl: z.string().min(1),
|
||||||
giteaUsername: z.string().optional(),
|
giteaUsername: z.string().optional(),
|
||||||
accessToken: z.string().optional(),
|
accessToken: z.string().optional(),
|
||||||
refreshToken: z.string().optional(),
|
refreshToken: z.string().optional(),
|
||||||
expiresAt: z.number().optional(),
|
expiresAt: z.number().optional(),
|
||||||
organizationName: z.string().optional(),
|
organizationName: z.string().optional(),
|
||||||
scopes: z.string().optional(),
|
scopes: z.string().optional(),
|
||||||
lastAuthenticatedAt: z.number().optional(),
|
lastAuthenticatedAt: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// API schema for finding one Gitea instance
|
// API schema for finding one Gitea instance
|
||||||
export const apiFindOneGitea = createSchema
|
export const apiFindOneGitea = createSchema
|
||||||
.extend({
|
.extend({
|
||||||
giteaId: z.string().min(1),
|
giteaId: z.string().min(1),
|
||||||
})
|
})
|
||||||
.pick({ giteaId: true });
|
.pick({ giteaId: true });
|
||||||
|
|
||||||
// API schema for testing Gitea connection
|
// API schema for testing Gitea connection
|
||||||
export const apiGiteaTestConnection = createSchema
|
export const apiGiteaTestConnection = createSchema
|
||||||
.extend({
|
.extend({
|
||||||
organizationName: z.string().optional(),
|
organizationName: z.string().optional(),
|
||||||
})
|
})
|
||||||
.pick({ giteaId: true, organizationName: true });
|
.pick({ giteaId: true, organizationName: true });
|
||||||
|
|
||||||
export type ApiGiteaTestConnection = z.infer<typeof apiGiteaTestConnection>;
|
export type ApiGiteaTestConnection = z.infer<typeof apiGiteaTestConnection>;
|
||||||
|
|
||||||
// API schema for finding branches in Gitea
|
// API schema for finding branches in Gitea
|
||||||
export const apiFindGiteaBranches = z.object({
|
export const apiFindGiteaBranches = z.object({
|
||||||
id: z.number().optional(),
|
id: z.number().optional(),
|
||||||
owner: z.string().min(1),
|
owner: z.string().min(1),
|
||||||
repositoryName: z.string().min(1),
|
repositoryName: z.string().min(1),
|
||||||
giteaId: z.string().optional(),
|
giteaId: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// API schema for updating Gitea instance
|
// API schema for updating Gitea instance
|
||||||
export const apiUpdateGitea = createSchema.extend({
|
export const apiUpdateGitea = createSchema.extend({
|
||||||
clientId: z.string().optional(),
|
clientId: z.string().optional(),
|
||||||
clientSecret: z.string().optional(),
|
clientSecret: z.string().optional(),
|
||||||
redirectUri: z.string().optional(),
|
redirectUri: z.string().optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
giteaId: z.string().min(1),
|
giteaId: z.string().min(1),
|
||||||
giteaUrl: z.string().min(1),
|
giteaUrl: z.string().min(1),
|
||||||
giteaUsername: z.string().optional(),
|
giteaUsername: z.string().optional(),
|
||||||
accessToken: z.string().optional(),
|
accessToken: z.string().optional(),
|
||||||
refreshToken: z.string().optional(),
|
refreshToken: z.string().optional(),
|
||||||
expiresAt: z.number().optional(),
|
expiresAt: z.number().optional(),
|
||||||
organizationName: z.string().optional(),
|
organizationName: z.string().optional(),
|
||||||
scopes: z.string().optional(),
|
scopes: z.string().optional(),
|
||||||
lastAuthenticatedAt: z.number().optional(),
|
lastAuthenticatedAt: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { account, organization, apikey } from "./account";
|
import { account, apikey, organization } from "./account";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { certificateType } from "./shared";
|
import { certificateType } from "./shared";
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import type { IncomingMessage } from "node:http";
|
|||||||
import * as bcrypt from "bcrypt";
|
import * as bcrypt from "bcrypt";
|
||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||||
import { organization, twoFactor, apiKey } from "better-auth/plugins";
|
import { apiKey, organization, twoFactor } from "better-auth/plugins";
|
||||||
import { and, desc, eq } from "drizzle-orm";
|
import { and, desc, eq } from "drizzle-orm";
|
||||||
|
import { IS_CLOUD } from "../constants";
|
||||||
import { db } from "../db";
|
import { db } from "../db";
|
||||||
import * as schema from "../db/schema";
|
import * as schema from "../db/schema";
|
||||||
import { sendEmail } from "../verification/send-verification-email";
|
import { sendEmail } from "../verification/send-verification-email";
|
||||||
import { IS_CLOUD } from "../constants";
|
|
||||||
|
|
||||||
const { handler, api } = betterAuth({
|
const { handler, api } = betterAuth({
|
||||||
database: drizzleAdapter(db, {
|
database: drizzleAdapter(db, {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { generateObject } from "ai";
|
|||||||
import { desc, eq } from "drizzle-orm";
|
import { desc, eq } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { IS_CLOUD } from "../constants";
|
import { IS_CLOUD } from "../constants";
|
||||||
import { findServerById } from "./server";
|
|
||||||
import { findOrganizationById } from "./admin";
|
import { findOrganizationById } from "./admin";
|
||||||
|
import { findServerById } from "./server";
|
||||||
|
|
||||||
export const getAiSettingsByOrganizationId = async (organizationId: string) => {
|
export const getAiSettingsByOrganizationId = async (organizationId: string) => {
|
||||||
const aiSettings = await db.query.ai.findMany({
|
const aiSettings = await db.query.ai.findMany({
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ import {
|
|||||||
cloneGitRepository,
|
cloneGitRepository,
|
||||||
getCustomGitCloneCommand,
|
getCustomGitCloneCommand,
|
||||||
} from "@dokploy/server/utils/providers/git";
|
} from "@dokploy/server/utils/providers/git";
|
||||||
|
import {
|
||||||
|
cloneGiteaRepository,
|
||||||
|
getGiteaCloneCommand,
|
||||||
|
} from "@dokploy/server/utils/providers/gitea";
|
||||||
import {
|
import {
|
||||||
cloneGithubRepository,
|
cloneGithubRepository,
|
||||||
getGithubCloneCommand,
|
getGithubCloneCommand,
|
||||||
@@ -34,10 +38,6 @@ import {
|
|||||||
cloneGitlabRepository,
|
cloneGitlabRepository,
|
||||||
getGitlabCloneCommand,
|
getGitlabCloneCommand,
|
||||||
} from "@dokploy/server/utils/providers/gitlab";
|
} from "@dokploy/server/utils/providers/gitlab";
|
||||||
import {
|
|
||||||
cloneGiteaRepository,
|
|
||||||
getGiteaCloneCommand,
|
|
||||||
} from "@dokploy/server/utils/providers/gitea";
|
|
||||||
import { createTraefikConfig } from "@dokploy/server/utils/traefik/application";
|
import { createTraefikConfig } from "@dokploy/server/utils/traefik/application";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
@@ -318,10 +318,7 @@ export const deployRemoteApplication = async ({
|
|||||||
deployment.logPath,
|
deployment.logPath,
|
||||||
);
|
);
|
||||||
} else if (application.sourceType === "gitea") {
|
} else if (application.sourceType === "gitea") {
|
||||||
command += await getGiteaCloneCommand(
|
command += await getGiteaCloneCommand(application, deployment.logPath);
|
||||||
application,
|
|
||||||
deployment.logPath,
|
|
||||||
);
|
|
||||||
} else if (application.sourceType === "git") {
|
} else if (application.sourceType === "git") {
|
||||||
command += await getCustomGitCloneCommand(
|
command += await getCustomGitCloneCommand(
|
||||||
application,
|
application,
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ import {
|
|||||||
cloneGitRepository,
|
cloneGitRepository,
|
||||||
getCustomGitCloneCommand,
|
getCustomGitCloneCommand,
|
||||||
} from "@dokploy/server/utils/providers/git";
|
} from "@dokploy/server/utils/providers/git";
|
||||||
|
import {
|
||||||
|
cloneGiteaRepository,
|
||||||
|
getGiteaCloneCommand,
|
||||||
|
} from "@dokploy/server/utils/providers/gitea";
|
||||||
import {
|
import {
|
||||||
cloneGithubRepository,
|
cloneGithubRepository,
|
||||||
getGithubCloneCommand,
|
getGithubCloneCommand,
|
||||||
@@ -37,10 +41,6 @@ import {
|
|||||||
cloneGitlabRepository,
|
cloneGitlabRepository,
|
||||||
getGitlabCloneCommand,
|
getGitlabCloneCommand,
|
||||||
} from "@dokploy/server/utils/providers/gitlab";
|
} from "@dokploy/server/utils/providers/gitlab";
|
||||||
import {
|
|
||||||
cloneGiteaRepository,
|
|
||||||
getGiteaCloneCommand,
|
|
||||||
} from "@dokploy/server/utils/providers/gitea";
|
|
||||||
import {
|
import {
|
||||||
createComposeFile,
|
createComposeFile,
|
||||||
getCreateComposeFileCommand,
|
getCreateComposeFileCommand,
|
||||||
@@ -237,7 +237,7 @@ export const deployCompose = async ({
|
|||||||
await cloneGiteaRepository(compose, deployment.logPath, true);
|
await cloneGiteaRepository(compose, deployment.logPath, true);
|
||||||
} else if (compose.sourceType === "raw") {
|
} else if (compose.sourceType === "raw") {
|
||||||
await createComposeFile(compose, deployment.logPath);
|
await createComposeFile(compose, deployment.logPath);
|
||||||
}
|
}
|
||||||
await buildCompose(compose, deployment.logPath);
|
await buildCompose(compose, deployment.logPath);
|
||||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||||
await updateCompose(composeId, {
|
await updateCompose(composeId, {
|
||||||
@@ -360,9 +360,9 @@ export const deployRemoteCompose = async ({
|
|||||||
command += getCreateComposeFileCommand(compose, deployment.logPath);
|
command += getCreateComposeFileCommand(compose, deployment.logPath);
|
||||||
} else if (compose.sourceType === "gitea") {
|
} else if (compose.sourceType === "gitea") {
|
||||||
command += await getGiteaCloneCommand(
|
command += await getGiteaCloneCommand(
|
||||||
compose,
|
compose,
|
||||||
deployment.logPath,
|
deployment.logPath,
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,104 +1,100 @@
|
|||||||
import { db } from "@dokploy/server/db";
|
import { db } from "@dokploy/server/db";
|
||||||
import {
|
import {
|
||||||
type apiCreateGitea,
|
type apiCreateGitea,
|
||||||
gitProvider,
|
gitProvider,
|
||||||
gitea,
|
gitea,
|
||||||
} from "@dokploy/server/db/schema";
|
} from "@dokploy/server/db/schema";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
export type Gitea = typeof gitea.$inferSelect;
|
export type Gitea = typeof gitea.$inferSelect;
|
||||||
|
|
||||||
export const createGitea = async (
|
export const createGitea = async (
|
||||||
input: typeof apiCreateGitea._type,
|
input: typeof apiCreateGitea._type,
|
||||||
organizationId: string,
|
organizationId: string,
|
||||||
) => {
|
) => {
|
||||||
return await db.transaction(async (tx) => {
|
return await db.transaction(async (tx) => {
|
||||||
// Insert new Git provider (Gitea)
|
// Insert new Git provider (Gitea)
|
||||||
const newGitProvider = await tx
|
const newGitProvider = await tx
|
||||||
.insert(gitProvider)
|
.insert(gitProvider)
|
||||||
.values({
|
.values({
|
||||||
providerType: "gitea", // Set providerType to 'gitea'
|
providerType: "gitea", // Set providerType to 'gitea'
|
||||||
organizationId: organizationId,
|
organizationId: organizationId,
|
||||||
name: input.name,
|
name: input.name,
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
.then((response) => response[0]);
|
.then((response) => response[0]);
|
||||||
|
|
||||||
if (!newGitProvider) {
|
if (!newGitProvider) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: "Error creating the Git provider",
|
message: "Error creating the Git provider",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the Gitea data into the `gitea` table
|
// Insert the Gitea data into the `gitea` table
|
||||||
await tx
|
await tx
|
||||||
.insert(gitea)
|
.insert(gitea)
|
||||||
.values({
|
.values({
|
||||||
...input,
|
...input,
|
||||||
gitProviderId: newGitProvider?.gitProviderId,
|
gitProviderId: newGitProvider?.gitProviderId,
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
.then((response) => response[0]);
|
.then((response) => response[0]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const findGiteaById = async (giteaId: string) => {
|
export const findGiteaById = async (giteaId: string) => {
|
||||||
try {
|
try {
|
||||||
|
const giteaProviderResult = await db.query.gitea.findFirst({
|
||||||
const giteaProviderResult = await db.query.gitea.findFirst({
|
where: eq(gitea.giteaId, giteaId),
|
||||||
where: eq(gitea.giteaId, giteaId),
|
with: {
|
||||||
with: {
|
gitProvider: true,
|
||||||
gitProvider: true,
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
if (!giteaProviderResult) {
|
||||||
if (!giteaProviderResult) {
|
console.error("No Gitea Provider found:", { giteaId });
|
||||||
console.error('No Gitea Provider found:', { giteaId });
|
throw new TRPCError({
|
||||||
throw new TRPCError({
|
code: "NOT_FOUND",
|
||||||
code: "NOT_FOUND",
|
message: "Gitea Provider not found",
|
||||||
message: "Gitea Provider not found",
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
return giteaProviderResult;
|
||||||
return giteaProviderResult;
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error("Error finding Gitea Provider:", error);
|
||||||
console.error('Error finding Gitea Provider:', error);
|
throw error;
|
||||||
throw error;
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateGitea = async (
|
export const updateGitea = async (giteaId: string, input: Partial<Gitea>) => {
|
||||||
giteaId: string,
|
console.log("Updating Gitea Provider:", {
|
||||||
input: Partial<Gitea>,
|
giteaId,
|
||||||
) => {
|
updateData: {
|
||||||
console.log('Updating Gitea Provider:', {
|
accessTokenPresent: !!input.accessToken,
|
||||||
giteaId,
|
refreshTokenPresent: !!input.refreshToken,
|
||||||
updateData: {
|
expiresAt: input.expiresAt,
|
||||||
accessTokenPresent: !!input.accessToken,
|
},
|
||||||
refreshTokenPresent: !!input.refreshToken,
|
});
|
||||||
expiresAt: input.expiresAt,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updateResult = await db
|
const updateResult = await db
|
||||||
.update(gitea)
|
.update(gitea)
|
||||||
.set(input)
|
.set(input)
|
||||||
.where(eq(gitea.giteaId, giteaId))
|
.where(eq(gitea.giteaId, giteaId))
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
// Explicitly type the result and handle potential undefined
|
// Explicitly type the result and handle potential undefined
|
||||||
const result = updateResult[0] as Gitea | undefined;
|
const result = updateResult[0] as Gitea | undefined;
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
console.error('No rows were updated', { giteaId, input });
|
console.error("No rows were updated", { giteaId, input });
|
||||||
throw new Error(`Failed to update Gitea provider with ID ${giteaId}`);
|
throw new Error(`Failed to update Gitea provider with ID ${giteaId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating Gitea provider:', error);
|
console.error("Error updating Gitea provider:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import {
|
|||||||
} from "@dokploy/server/services/deployment";
|
} from "@dokploy/server/services/deployment";
|
||||||
import { findServerById } from "@dokploy/server/services/server";
|
import { findServerById } from "@dokploy/server/services/server";
|
||||||
import {
|
import {
|
||||||
|
TRAEFIK_HTTP3_PORT,
|
||||||
TRAEFIK_PORT,
|
TRAEFIK_PORT,
|
||||||
TRAEFIK_SSL_PORT,
|
TRAEFIK_SSL_PORT,
|
||||||
TRAEFIK_VERSION,
|
TRAEFIK_VERSION,
|
||||||
TRAEFIK_HTTP3_PORT,
|
|
||||||
getDefaultMiddlewares,
|
getDefaultMiddlewares,
|
||||||
getDefaultServerTraefikConfig,
|
getDefaultServerTraefikConfig,
|
||||||
} from "@dokploy/server/setup/traefik-setup";
|
} from "@dokploy/server/setup/traefik-setup";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { paths } from "@dokploy/server/constants";
|
import { paths } from "@dokploy/server/constants";
|
||||||
import { execAsync } from "../process/execAsync";
|
|
||||||
import { findAdmin } from "@dokploy/server/services/admin";
|
import { findAdmin } from "@dokploy/server/services/admin";
|
||||||
import { updateUser } from "@dokploy/server/services/user";
|
import { updateUser } from "@dokploy/server/services/user";
|
||||||
import { scheduleJob, scheduledJobs } from "node-schedule";
|
import { scheduleJob, scheduledJobs } from "node-schedule";
|
||||||
|
import { execAsync } from "../process/execAsync";
|
||||||
|
|
||||||
const LOG_CLEANUP_JOB_NAME = "access-log-cleanup";
|
const LOG_CLEANUP_JOB_NAME = "access-log-cleanup";
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import path from "node:path";
|
|||||||
import { getAllServers } from "@dokploy/server/services/server";
|
import { getAllServers } from "@dokploy/server/services/server";
|
||||||
import { scheduleJob } from "node-schedule";
|
import { scheduleJob } from "node-schedule";
|
||||||
import { db } from "../../db/index";
|
import { db } from "../../db/index";
|
||||||
|
import { findAdmin } from "../../services/admin";
|
||||||
import {
|
import {
|
||||||
cleanUpDockerBuilder,
|
cleanUpDockerBuilder,
|
||||||
cleanUpSystemPrune,
|
cleanUpSystemPrune,
|
||||||
cleanUpUnusedImages,
|
cleanUpUnusedImages,
|
||||||
} from "../docker/utils";
|
} from "../docker/utils";
|
||||||
import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup";
|
import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup";
|
||||||
|
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||||
import { runMariadbBackup } from "./mariadb";
|
import { runMariadbBackup } from "./mariadb";
|
||||||
import { runMongoBackup } from "./mongo";
|
import { runMongoBackup } from "./mongo";
|
||||||
import { runMySqlBackup } from "./mysql";
|
import { runMySqlBackup } from "./mysql";
|
||||||
import { runPostgresBackup } from "./postgres";
|
import { runPostgresBackup } from "./postgres";
|
||||||
import { findAdmin } from "../../services/admin";
|
|
||||||
import { getS3Credentials } from "./utils";
|
import { getS3Credentials } from "./utils";
|
||||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
|
||||||
|
|
||||||
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
||||||
import { startLogCleanup } from "../access-log/handler";
|
import { startLogCleanup } from "../access-log/handler";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
||||||
import type { Destination } from "@dokploy/server/services/destination";
|
import type { Destination } from "@dokploy/server/services/destination";
|
||||||
import { scheduleJob, scheduledJobs } from "node-schedule";
|
import { scheduleJob, scheduledJobs } from "node-schedule";
|
||||||
|
import { keepLatestNBackups } from ".";
|
||||||
import { runMariadbBackup } from "./mariadb";
|
import { runMariadbBackup } from "./mariadb";
|
||||||
import { runMongoBackup } from "./mongo";
|
import { runMongoBackup } from "./mongo";
|
||||||
import { runMySqlBackup } from "./mysql";
|
import { runMySqlBackup } from "./mysql";
|
||||||
import { runPostgresBackup } from "./postgres";
|
import { runPostgresBackup } from "./postgres";
|
||||||
import { keepLatestNBackups } from ".";
|
|
||||||
|
|
||||||
export const scheduleBackup = (backup: BackupSchedule) => {
|
export const scheduleBackup = (backup: BackupSchedule) => {
|
||||||
const { schedule, backupId, databaseType, postgres, mysql, mongo, mariadb } =
|
const { schedule, backupId, databaseType, postgres, mysql, mongo, mariadb } =
|
||||||
|
|||||||
@@ -112,118 +112,120 @@ export const getBuildCommand = (
|
|||||||
|
|
||||||
export const mechanizeDockerContainer = async (
|
export const mechanizeDockerContainer = async (
|
||||||
application: ApplicationNested,
|
application: ApplicationNested,
|
||||||
) => {
|
) => {
|
||||||
console.log(`Starting to mechanize Docker container for ${application.appName}`);
|
console.log(
|
||||||
|
`Starting to mechanize Docker container for ${application.appName}`,
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
appName,
|
appName,
|
||||||
env,
|
env,
|
||||||
mounts,
|
mounts,
|
||||||
cpuLimit,
|
cpuLimit,
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
cpuReservation,
|
cpuReservation,
|
||||||
command,
|
command,
|
||||||
ports,
|
ports,
|
||||||
} = application;
|
} = application;
|
||||||
|
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
cpuLimit,
|
cpuLimit,
|
||||||
cpuReservation,
|
cpuReservation,
|
||||||
});
|
});
|
||||||
|
|
||||||
const volumesMount = generateVolumeMounts(mounts);
|
const volumesMount = generateVolumeMounts(mounts);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
HealthCheck,
|
HealthCheck,
|
||||||
RestartPolicy,
|
RestartPolicy,
|
||||||
Placement,
|
Placement,
|
||||||
Labels,
|
Labels,
|
||||||
Mode,
|
Mode,
|
||||||
RollbackConfig,
|
RollbackConfig,
|
||||||
UpdateConfig,
|
UpdateConfig,
|
||||||
Networks,
|
Networks,
|
||||||
} = generateConfigContainer(application);
|
} = generateConfigContainer(application);
|
||||||
|
|
||||||
const bindsMount = generateBindMounts(mounts);
|
const bindsMount = generateBindMounts(mounts);
|
||||||
const filesMount = generateFileMounts(appName, application);
|
const filesMount = generateFileMounts(appName, application);
|
||||||
const envVariables = prepareEnvironmentVariables(
|
const envVariables = prepareEnvironmentVariables(
|
||||||
env,
|
env,
|
||||||
application.project.env,
|
application.project.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
const image = getImageName(application);
|
const image = getImageName(application);
|
||||||
const authConfig = getAuthConfig(application);
|
const authConfig = getAuthConfig(application);
|
||||||
const docker = await getRemoteDocker(application.serverId);
|
const docker = await getRemoteDocker(application.serverId);
|
||||||
|
|
||||||
const settings: CreateServiceOptions = {
|
const settings: CreateServiceOptions = {
|
||||||
authconfig: authConfig,
|
authconfig: authConfig,
|
||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
|
||||||
ContainerSpec: {
|
|
||||||
HealthCheck,
|
|
||||||
Image: image,
|
|
||||||
Env: envVariables,
|
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
|
||||||
...(command
|
|
||||||
? {
|
|
||||||
Command: ["/bin/sh"],
|
|
||||||
Args: ["-c", command],
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
Labels,
|
|
||||||
},
|
|
||||||
Networks,
|
|
||||||
RestartPolicy,
|
|
||||||
Placement,
|
|
||||||
Resources: {
|
|
||||||
...resources,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode,
|
|
||||||
RollbackConfig,
|
|
||||||
EndpointSpec: {
|
|
||||||
Ports: ports.map((port) => ({
|
|
||||||
Protocol: port.protocol,
|
|
||||||
TargetPort: port.targetPort,
|
|
||||||
PublishedPort: port.publishedPort,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
UpdateConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log(`Attempting to find existing service: ${appName}`);
|
|
||||||
const service = docker.getService(appName);
|
|
||||||
const inspect = await service.inspect();
|
|
||||||
console.log(`Found existing service, updating: ${appName}`);
|
|
||||||
|
|
||||||
await service.update({
|
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
|
||||||
...settings,
|
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
...settings.TaskTemplate,
|
ContainerSpec: {
|
||||||
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
HealthCheck,
|
||||||
|
Image: image,
|
||||||
|
Env: envVariables,
|
||||||
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
|
...(command
|
||||||
|
? {
|
||||||
|
Command: ["/bin/sh"],
|
||||||
|
Args: ["-c", command],
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
Labels,
|
||||||
|
},
|
||||||
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Resources: {
|
||||||
|
...resources,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
Mode,
|
||||||
console.log(`Service updated successfully: ${appName}`);
|
RollbackConfig,
|
||||||
|
EndpointSpec: {
|
||||||
|
Ports: ports.map((port) => ({
|
||||||
|
Protocol: port.protocol,
|
||||||
|
TargetPort: port.targetPort,
|
||||||
|
PublishedPort: port.publishedPort,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
UpdateConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`Attempting to find existing service: ${appName}`);
|
||||||
|
const service = docker.getService(appName);
|
||||||
|
const inspect = await service.inspect();
|
||||||
|
console.log(`Found existing service, updating: ${appName}`);
|
||||||
|
|
||||||
|
await service.update({
|
||||||
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(`Service updated successfully: ${appName}`);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
const errorMessage =
|
||||||
console.log(`Service not found or error: ${errorMessage}`);
|
error instanceof Error ? error.message : "Unknown error";
|
||||||
console.log(`Creating new service: ${appName}`);
|
console.log(`Service not found or error: ${errorMessage}`);
|
||||||
|
console.log(`Creating new service: ${appName}`);
|
||||||
try {
|
|
||||||
await docker.createService(settings);
|
try {
|
||||||
console.log(`Service created successfully: ${appName}`);
|
await docker.createService(settings);
|
||||||
} catch (createError: unknown) {
|
console.log(`Service created successfully: ${appName}`);
|
||||||
const createErrorMessage = createError instanceof Error
|
} catch (createError: unknown) {
|
||||||
? createError.message
|
const createErrorMessage =
|
||||||
: 'Unknown error';
|
createError instanceof Error ? createError.message : "Unknown error";
|
||||||
console.error(`Failed to create service: ${createErrorMessage}`);
|
console.error(`Failed to create service: ${createErrorMessage}`);
|
||||||
throw createError;
|
throw createError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const buildNixpacks = async (
|
|||||||
for (const env of envVariables) {
|
for (const env of envVariables) {
|
||||||
args.push("--env", env);
|
args.push("--env", env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publishDirectory) {
|
if (publishDirectory) {
|
||||||
/* No need for any start command, since we'll use nginx later on */
|
/* No need for any start command, since we'll use nginx later on */
|
||||||
args.push("--no-error-without-start");
|
args.push("--no-error-without-start");
|
||||||
@@ -90,10 +90,11 @@ export const buildNixpacks = async (
|
|||||||
await spawnAsync("docker", ["rm", buildContainerId], writeToStream);
|
await spawnAsync("docker", ["rm", buildContainerId], writeToStream);
|
||||||
} catch (rmError) {
|
} catch (rmError) {
|
||||||
// Ignore errors from container removal
|
// Ignore errors from container removal
|
||||||
const errorMessage = rmError instanceof Error
|
const errorMessage =
|
||||||
? rmError.message
|
rmError instanceof Error
|
||||||
: 'Unknown container cleanup error';
|
? rmError.message
|
||||||
|
: "Unknown container cleanup error";
|
||||||
|
|
||||||
// Just log it but don't let it cause another error
|
// Just log it but don't let it cause another error
|
||||||
writeToStream(`Container cleanup attempt: ${errorMessage}\n`);
|
writeToStream(`Container cleanup attempt: ${errorMessage}\n`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
|
import { createHash } from "node:crypto";
|
||||||
import type { WriteStream } from "node:fs";
|
import type { WriteStream } from "node:fs";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
import type { ApplicationNested } from ".";
|
import type { ApplicationNested } from ".";
|
||||||
import { prepareEnvironmentVariables } from "../docker/utils";
|
import { prepareEnvironmentVariables } from "../docker/utils";
|
||||||
import { getBuildAppDirectory } from "../filesystem/directory";
|
import { getBuildAppDirectory } from "../filesystem/directory";
|
||||||
import { spawnAsync } from "../process/spawnAsync";
|
|
||||||
import { execAsync } from "../process/execAsync";
|
import { execAsync } from "../process/execAsync";
|
||||||
import { nanoid } from "nanoid";
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
import { createHash } from "node:crypto";
|
|
||||||
|
|
||||||
const calculateSecretsHash = (envVariables: string[]): string => {
|
const calculateSecretsHash = (envVariables: string[]): string => {
|
||||||
const hash = createHash("sha256");
|
const hash = createHash("sha256");
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { deployPostgres } from "@dokploy/server/services/postgres";
|
|
||||||
import { execAsyncRemote } from "../process/execAsync";
|
|
||||||
import { execAsync } from "../process/execAsync";
|
|
||||||
import { deployMySql } from "@dokploy/server/services/mysql";
|
|
||||||
import { deployMariadb } from "@dokploy/server/services/mariadb";
|
|
||||||
import { deployMongo } from "@dokploy/server/services/mongo";
|
|
||||||
import { deployRedis } from "@dokploy/server/services/redis";
|
|
||||||
import { removeService } from "../docker/utils";
|
|
||||||
import { db } from "@dokploy/server/db";
|
import { db } from "@dokploy/server/db";
|
||||||
import {
|
import {
|
||||||
postgres,
|
|
||||||
mysql,
|
|
||||||
mariadb,
|
mariadb,
|
||||||
mongo,
|
mongo,
|
||||||
|
mysql,
|
||||||
|
postgres,
|
||||||
redis,
|
redis,
|
||||||
} from "@dokploy/server/db/schema";
|
} from "@dokploy/server/db/schema";
|
||||||
|
import { deployMariadb } from "@dokploy/server/services/mariadb";
|
||||||
|
import { deployMongo } from "@dokploy/server/services/mongo";
|
||||||
|
import { deployMySql } from "@dokploy/server/services/mysql";
|
||||||
|
import { deployPostgres } from "@dokploy/server/services/postgres";
|
||||||
|
import { deployRedis } from "@dokploy/server/services/redis";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import { removeService } from "../docker/utils";
|
||||||
|
import { execAsyncRemote } from "../process/execAsync";
|
||||||
|
import { execAsync } from "../process/execAsync";
|
||||||
|
|
||||||
type DatabaseType = "postgres" | "mysql" | "mariadb" | "mongo" | "redis";
|
type DatabaseType = "postgres" | "mysql" | "mariadb" | "mongo" | "redis";
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
cloneGitRawRepository,
|
cloneGitRawRepository,
|
||||||
cloneRawGitRepositoryRemote,
|
cloneRawGitRepositoryRemote,
|
||||||
} from "../providers/git";
|
} from "../providers/git";
|
||||||
|
import { cloneRawGiteaRepository } from "../providers/gitea";
|
||||||
import {
|
import {
|
||||||
cloneRawGithubRepository,
|
cloneRawGithubRepository,
|
||||||
cloneRawGithubRepositoryRemote,
|
cloneRawGithubRepositoryRemote,
|
||||||
@@ -22,10 +23,6 @@ import {
|
|||||||
cloneRawGitlabRepository,
|
cloneRawGitlabRepository,
|
||||||
cloneRawGitlabRepositoryRemote,
|
cloneRawGitlabRepositoryRemote,
|
||||||
} from "../providers/gitlab";
|
} from "../providers/gitlab";
|
||||||
import {
|
|
||||||
cloneRawGiteaRepository,
|
|
||||||
cloneRawGiteaRepositoryRemote,
|
|
||||||
} from "../providers/gitea";
|
|
||||||
import {
|
import {
|
||||||
createComposeFileRaw,
|
createComposeFileRaw,
|
||||||
createComposeFileRawRemote,
|
createComposeFileRawRemote,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user