mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
refactor(patches): unify patch handling for applications and composes
- Updated the PatchEditor and ShowPatches components to accept a unified `id` and `type` prop, replacing the previous separate `applicationId` and `composeId` props. - Refactored API calls in the patch router to handle both application and compose types, improving code clarity and maintainability. - Enhanced the UI to provide consistent behavior for creating and managing patches across different types.
This commit is contained in:
@@ -19,11 +19,10 @@ import {
|
||||
} from "@/components/ui/card";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { api } from "@/utils/api";
|
||||
import type { RouterOutputs } from "@/utils/api";
|
||||
|
||||
interface Props {
|
||||
applicationId?: string;
|
||||
composeId?: string;
|
||||
id: string;
|
||||
type: "application" | "compose";
|
||||
repoPath: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
@@ -35,12 +34,7 @@ type DirectoryEntry = {
|
||||
children?: DirectoryEntry[];
|
||||
};
|
||||
|
||||
export const PatchEditor = ({
|
||||
applicationId,
|
||||
composeId,
|
||||
repoPath,
|
||||
onClose,
|
||||
}: Props) => {
|
||||
export const PatchEditor = ({ id, type, repoPath, onClose }: Props) => {
|
||||
const [selectedFile, setSelectedFile] = useState<string | null>(null);
|
||||
const [fileContent, setFileContent] = useState<string>("");
|
||||
const [originalContent, setOriginalContent] = useState<string>("");
|
||||
@@ -49,14 +43,12 @@ export const PatchEditor = ({
|
||||
);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
// Fetch directory tree
|
||||
const { data: directories, isLoading: isDirLoading } =
|
||||
api.patch.readRepoDirectories.useQuery(
|
||||
{ applicationId, composeId, repoPath },
|
||||
{ id: id, type, repoPath },
|
||||
{ enabled: !!repoPath },
|
||||
);
|
||||
|
||||
// Save mutation
|
||||
const saveAsPatch = api.patch.saveFileAsPatch.useMutation({
|
||||
onSuccess: (result) => {
|
||||
setIsSaving(false);
|
||||
@@ -77,8 +69,8 @@ export const PatchEditor = ({
|
||||
const { data: fileData, isFetching: isFileLoading } =
|
||||
api.patch.readRepoFile.useQuery(
|
||||
{
|
||||
applicationId,
|
||||
composeId,
|
||||
id: id || "",
|
||||
type,
|
||||
repoPath,
|
||||
filePath: selectedFile || "",
|
||||
},
|
||||
@@ -114,8 +106,8 @@ export const PatchEditor = ({
|
||||
if (!selectedFile) return;
|
||||
setIsSaving(true);
|
||||
saveAsPatch.mutate({
|
||||
applicationId,
|
||||
composeId,
|
||||
id,
|
||||
type,
|
||||
repoPath,
|
||||
filePath: selectedFile,
|
||||
content: fileContent,
|
||||
@@ -142,8 +134,11 @@ export const PatchEditor = ({
|
||||
return (
|
||||
<div key={entry.path}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleFolder(entry.path)}
|
||||
className={`w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted/50 rounded-md transition-colors`}
|
||||
className={
|
||||
"w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted/50 rounded-md transition-colors"
|
||||
}
|
||||
style={{ paddingLeft: `${depth * 12 + 8}px` }}
|
||||
>
|
||||
<ChevronRight
|
||||
@@ -163,6 +158,7 @@ export const PatchEditor = ({
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={entry.path}
|
||||
onClick={() => handleFileSelect(entry.path)}
|
||||
className={`w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted/50 rounded-md transition-colors ${
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import {
|
||||
AlertCircle,
|
||||
ChevronRight,
|
||||
File,
|
||||
Folder,
|
||||
Loader2,
|
||||
Power,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { File, FilePlus2, Loader2, Trash2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -28,122 +19,81 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { api } from "@/utils/api";
|
||||
import type { RouterOutputs } from "@/utils/api";
|
||||
import { PatchEditor } from "./patch-editor";
|
||||
|
||||
interface Props {
|
||||
applicationId?: string;
|
||||
composeId?: string;
|
||||
id: string;
|
||||
type: "application" | "compose";
|
||||
}
|
||||
|
||||
type Patch = RouterOutputs["patch"]["byApplicationId"][number];
|
||||
|
||||
export const ShowPatches = ({ applicationId, composeId }: Props) => {
|
||||
export const ShowPatches = ({ id, type }: Props) => {
|
||||
const [selectedFile, setSelectedFile] = useState<string | null>(null);
|
||||
const [repoPath, setRepoPath] = useState<string | null>(null);
|
||||
const [isLoadingRepo, setIsLoadingRepo] = useState(false);
|
||||
|
||||
const utils = api.useUtils();
|
||||
|
||||
// Fetch patches
|
||||
// Fetch patches
|
||||
const { data: appPatches, isLoading: isAppPatchesLoading } =
|
||||
api.patch.byApplicationId.useQuery(
|
||||
{ applicationId: applicationId! },
|
||||
{ enabled: !!applicationId },
|
||||
);
|
||||
const queryMap = {
|
||||
application: () =>
|
||||
api.patch.byApplicationId.useQuery(
|
||||
{ applicationId: id },
|
||||
{ enabled: !!id },
|
||||
),
|
||||
compose: () =>
|
||||
api.patch.byComposeId.useQuery({ composeId: id }, { enabled: !!id }),
|
||||
};
|
||||
|
||||
const { data: composePatches, isLoading: isComposePatchesLoading } =
|
||||
api.patch.byComposeId.useQuery(
|
||||
{ composeId: composeId! },
|
||||
{ enabled: !!composeId },
|
||||
);
|
||||
const { data: patches, isLoading: isPatchesLoading } = queryMap[type]
|
||||
? queryMap[type]()
|
||||
: api.patch.byApplicationId.useQuery(
|
||||
{ applicationId: id },
|
||||
{ enabled: !!id },
|
||||
);
|
||||
|
||||
const patches = applicationId ? appPatches : composePatches;
|
||||
const isPatchesLoading = applicationId
|
||||
? isAppPatchesLoading
|
||||
: isComposePatchesLoading;
|
||||
|
||||
// Mutations
|
||||
const deletePatch = api.patch.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
toast.success("Patch deleted");
|
||||
if (applicationId) {
|
||||
utils.patch.byApplicationId.invalidate({ applicationId });
|
||||
} else if (composeId) {
|
||||
utils.patch.byComposeId.invalidate({ composeId });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Failed to delete patch");
|
||||
},
|
||||
});
|
||||
|
||||
const togglePatch = api.patch.toggleEnabled.useMutation({
|
||||
onSuccess: () => {
|
||||
toast.success("Patch updated");
|
||||
if (applicationId) {
|
||||
utils.patch.byApplicationId.invalidate({ applicationId });
|
||||
} else if (composeId) {
|
||||
utils.patch.byComposeId.invalidate({ composeId });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Failed to update patch");
|
||||
},
|
||||
});
|
||||
const mutationMap = {
|
||||
application: () => api.patch.delete.useMutation(),
|
||||
compose: () => api.patch.delete.useMutation(),
|
||||
};
|
||||
|
||||
const ensureRepo = api.patch.ensureRepo.useMutation();
|
||||
|
||||
const handleOpenEditor = async () => {
|
||||
setIsLoadingRepo(true);
|
||||
const toastId = toast.loading("Syncing repository...");
|
||||
ensureRepo.mutate(
|
||||
{ applicationId, composeId },
|
||||
{
|
||||
onSuccess: (path) => {
|
||||
setRepoPath(path);
|
||||
setIsLoadingRepo(false);
|
||||
toast.dismiss(toastId);
|
||||
},
|
||||
onError: () => {
|
||||
setIsLoadingRepo(false);
|
||||
toast.dismiss(toastId);
|
||||
toast.error("Failed to load repository");
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
const togglePatch = api.patch.toggleEnabled.useMutation();
|
||||
|
||||
const handleDeletePatch = (patchId: string) => {
|
||||
deletePatch.mutate({ patchId });
|
||||
};
|
||||
|
||||
const handleTogglePatch = (patchId: string, enabled: boolean) => {
|
||||
togglePatch.mutate({ patchId, enabled });
|
||||
};
|
||||
const { mutateAsync } = mutationMap[type]
|
||||
? mutationMap[type]()
|
||||
: api.patch.delete.useMutation();
|
||||
|
||||
const handleCloseEditor = () => {
|
||||
setSelectedFile(null);
|
||||
setRepoPath(null);
|
||||
if (applicationId) {
|
||||
utils.patch.byApplicationId.invalidate({ applicationId });
|
||||
} else if (composeId) {
|
||||
utils.patch.byComposeId.invalidate({ composeId });
|
||||
}
|
||||
};
|
||||
|
||||
if (repoPath) {
|
||||
return (
|
||||
<PatchEditor
|
||||
applicationId={applicationId}
|
||||
composeId={composeId}
|
||||
repoPath={repoPath}
|
||||
id={id}
|
||||
type={type}
|
||||
repoPath={repoPath || ""}
|
||||
onClose={handleCloseEditor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const handleOpenEditor = async () => {
|
||||
setIsLoadingRepo(true);
|
||||
await ensureRepo
|
||||
.mutateAsync({ id, type })
|
||||
.then((result) => {
|
||||
setRepoPath(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingRepo(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
@@ -154,25 +104,39 @@ export const ShowPatches = ({ applicationId, composeId }: Props) => {
|
||||
applied after cloning the repository and before building.
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button onClick={handleOpenEditor} disabled={isLoadingRepo}>
|
||||
{isLoadingRepo && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
Create Patch
|
||||
</Button>
|
||||
{patches && patches?.length > 0 && (
|
||||
<Button onClick={handleOpenEditor} disabled={isLoadingRepo}>
|
||||
{isLoadingRepo && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
<FilePlus2 className="mr-2 h-4 w-4" />
|
||||
Create Patch
|
||||
</Button>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{isPatchesLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="h-6 w-6 animate-spin" />
|
||||
</div>
|
||||
) : !patches || patches.length === 0 ? (
|
||||
<Alert>
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertTitle>No patches</AlertTitle>
|
||||
<AlertDescription>
|
||||
No patches have been created for this application yet. Click
|
||||
"Create Patch" to add modifications to your code during build.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : patches?.length === 0 ? (
|
||||
<div className="flex min-h-[40vh] w-full flex-col items-center justify-center gap-4 rounded-lg border border-dashed p-8">
|
||||
<div className="rounded-full bg-muted p-4">
|
||||
<FilePlus2 className="h-10 w-10 text-muted-foreground" />
|
||||
</div>
|
||||
<div className="space-y-1 text-center">
|
||||
<p className="text-sm font-medium">No patches yet</p>
|
||||
<p className="max-w-sm text-sm text-muted-foreground">
|
||||
Add file patches to modify your repo before each build—configs,
|
||||
env, or code. Create your first patch to get started.
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={handleOpenEditor} disabled={isLoadingRepo}>
|
||||
{isLoadingRepo && (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
)}
|
||||
<FilePlus2 className="mr-2 h-4 w-4" />
|
||||
Create Patch
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
@@ -183,7 +147,7 @@ export const ShowPatches = ({ applicationId, composeId }: Props) => {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{patches.map((patch: Patch) => (
|
||||
{patches?.map((patch) => (
|
||||
<TableRow key={patch.patchId}>
|
||||
<TableCell className="font-mono text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -194,16 +158,49 @@ export const ShowPatches = ({ applicationId, composeId }: Props) => {
|
||||
<TableCell>
|
||||
<Switch
|
||||
checked={patch.enabled}
|
||||
onCheckedChange={(checked) =>
|
||||
handleTogglePatch(patch.patchId, checked)
|
||||
}
|
||||
onCheckedChange={(checked) => {
|
||||
togglePatch
|
||||
.mutateAsync({
|
||||
patchId: patch.patchId,
|
||||
enabled: checked,
|
||||
})
|
||||
.then(() => {
|
||||
toast.success("Patch updated");
|
||||
utils.patch.byApplicationId.invalidate({
|
||||
applicationId: id,
|
||||
});
|
||||
utils.patch.byComposeId.invalidate({
|
||||
composeId: id,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingRepo(false);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleDeletePatch(patch.patchId)}
|
||||
onClick={() => {
|
||||
mutateAsync({ patchId: patch.patchId })
|
||||
.then(() => {
|
||||
toast.success("Patch deleted");
|
||||
utils.patch.byApplicationId.invalidate({
|
||||
applicationId: id,
|
||||
});
|
||||
utils.patch.byComposeId.invalidate({
|
||||
composeId: id,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.message);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</Button>
|
||||
|
||||
@@ -26,11 +26,11 @@ import { ShowDomains } from "@/components/dashboard/application/domains/show-dom
|
||||
import { ShowEnvironment } from "@/components/dashboard/application/environment/show";
|
||||
import { ShowGeneralApplication } from "@/components/dashboard/application/general/show";
|
||||
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
|
||||
import { ShowPatches } from "@/components/dashboard/application/patches/show-patches";
|
||||
import { ShowPreviewDeployments } from "@/components/dashboard/application/preview-deployments/show-preview-deployments";
|
||||
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
|
||||
import { UpdateApplication } from "@/components/dashboard/application/update-application";
|
||||
import { ShowVolumeBackups } from "@/components/dashboard/application/volume-backups/show-volume-backups";
|
||||
import { ShowPatches } from "@/components/dashboard/application/patches/show-patches";
|
||||
import { DeleteService } from "@/components/dashboard/compose/delete-service";
|
||||
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
|
||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||
@@ -365,7 +365,7 @@ const Service = (
|
||||
</TabsContent>
|
||||
<TabsContent value="patches" className="w-full">
|
||||
<div className="flex flex-col gap-4 pt-2.5">
|
||||
<ShowPatches applicationId={applicationId} />
|
||||
<ShowPatches id={applicationId} type="application" />
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="advanced">
|
||||
|
||||
@@ -17,9 +17,9 @@ import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes
|
||||
import { ShowDeployments } from "@/components/dashboard/application/deployments/show-deployments";
|
||||
import { ShowDomains } from "@/components/dashboard/application/domains/show-domains";
|
||||
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
|
||||
import { ShowPatches } from "@/components/dashboard/application/patches/show-patches";
|
||||
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
|
||||
import { ShowVolumeBackups } from "@/components/dashboard/application/volume-backups/show-volume-backups";
|
||||
import { ShowPatches } from "@/components/dashboard/application/patches/show-patches";
|
||||
import { AddCommandCompose } from "@/components/dashboard/compose/advanced/add-command";
|
||||
import { IsolatedDeploymentTab } from "@/components/dashboard/compose/advanced/add-isolation";
|
||||
import { DeleteService } from "@/components/dashboard/compose/delete-service";
|
||||
@@ -367,7 +367,7 @@ const Service = (
|
||||
|
||||
<TabsContent value="patches" className="w-full">
|
||||
<div className="flex flex-col gap-4 pt-2.5">
|
||||
<ShowPatches composeId={composeId} />
|
||||
<ShowPatches id={composeId} type="compose" />
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
ensurePatchRepo,
|
||||
findApplicationById,
|
||||
findComposeById,
|
||||
findPatchByFilePath,
|
||||
findPatchById,
|
||||
findPatchesByApplicationId,
|
||||
findPatchesByComposeId,
|
||||
findPatchByFilePath,
|
||||
generatePatch,
|
||||
readPatchRepoDirectory,
|
||||
readPatchRepoFile,
|
||||
@@ -218,13 +218,13 @@ export const patchRouter = createTRPCRouter({
|
||||
ensureRepo: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
applicationId: z.string().optional(),
|
||||
composeId: z.string().optional(),
|
||||
id: z.string(),
|
||||
type: z.enum(["application", "compose"]),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (input.applicationId) {
|
||||
const app = await findApplicationById(input.applicationId);
|
||||
if (input.type === "application") {
|
||||
const app = await findApplicationById(input.id);
|
||||
if (
|
||||
app.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -253,8 +253,8 @@ export const patchRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
if (input.composeId) {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (input.type === "compose") {
|
||||
const compose = await findComposeById(input.id);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -285,21 +285,21 @@ export const patchRouter = createTRPCRouter({
|
||||
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Either applicationId or composeId must be provided",
|
||||
message: "Either application or compose must be provided",
|
||||
});
|
||||
}),
|
||||
|
||||
readRepoDirectories: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
applicationId: z.string().optional(),
|
||||
composeId: z.string().optional(),
|
||||
id: z.string(),
|
||||
type: z.enum(["application", "compose"]),
|
||||
repoPath: z.string(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (input.applicationId) {
|
||||
const app = await findApplicationById(input.applicationId);
|
||||
if (input.type === "application") {
|
||||
const app = await findApplicationById(input.id);
|
||||
if (
|
||||
app.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -312,8 +312,8 @@ export const patchRouter = createTRPCRouter({
|
||||
return await readPatchRepoDirectory(input.repoPath, app.serverId);
|
||||
}
|
||||
|
||||
if (input.composeId) {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (input.type === "compose") {
|
||||
const compose = await findComposeById(input.id);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -328,15 +328,15 @@ export const patchRouter = createTRPCRouter({
|
||||
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Either applicationId or composeId must be provided",
|
||||
message: "Either application or compose must be provided",
|
||||
});
|
||||
}),
|
||||
|
||||
readRepoFile: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
applicationId: z.string().optional(),
|
||||
composeId: z.string().optional(),
|
||||
id: z.string(),
|
||||
type: z.enum(["application", "compose"]),
|
||||
repoPath: z.string(),
|
||||
filePath: z.string(),
|
||||
}),
|
||||
@@ -345,8 +345,8 @@ export const patchRouter = createTRPCRouter({
|
||||
let serverId: string | null = null;
|
||||
let patchContent: string | undefined;
|
||||
|
||||
if (input.applicationId) {
|
||||
const app = await findApplicationById(input.applicationId);
|
||||
if (input.type === "application") {
|
||||
const app = await findApplicationById(input.id);
|
||||
if (
|
||||
app.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -361,14 +361,14 @@ export const patchRouter = createTRPCRouter({
|
||||
// Check if patch exists for this file
|
||||
const existingPatch = await findPatchByFilePath(
|
||||
input.filePath,
|
||||
input.applicationId,
|
||||
input.id,
|
||||
undefined,
|
||||
);
|
||||
if (existingPatch?.enabled) {
|
||||
patchContent = existingPatch.content;
|
||||
}
|
||||
} else if (input.composeId) {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
} else if (input.type === "compose") {
|
||||
const compose = await findComposeById(input.id);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -384,7 +384,7 @@ export const patchRouter = createTRPCRouter({
|
||||
const existingPatch = await findPatchByFilePath(
|
||||
input.filePath,
|
||||
undefined,
|
||||
input.composeId,
|
||||
input.id,
|
||||
);
|
||||
if (existingPatch?.enabled) {
|
||||
patchContent = existingPatch.content;
|
||||
@@ -407,8 +407,8 @@ export const patchRouter = createTRPCRouter({
|
||||
saveFileAsPatch: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
applicationId: z.string().optional(),
|
||||
composeId: z.string().optional(),
|
||||
id: z.string(),
|
||||
type: z.enum(["application", "compose"]),
|
||||
repoPath: z.string(),
|
||||
filePath: z.string(),
|
||||
content: z.string(),
|
||||
@@ -417,8 +417,8 @@ export const patchRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
let serverId: string | null = null;
|
||||
|
||||
if (input.applicationId) {
|
||||
const app = await findApplicationById(input.applicationId);
|
||||
if (input.type === "application") {
|
||||
const app = await findApplicationById(input.id);
|
||||
if (
|
||||
app.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -429,8 +429,8 @@ export const patchRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
serverId = app.serverId;
|
||||
} else if (input.composeId) {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
} else if (input.type === "compose") {
|
||||
const compose = await findComposeById(input.id);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
@@ -444,7 +444,7 @@ export const patchRouter = createTRPCRouter({
|
||||
} else {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Either applicationId or composeId must be provided",
|
||||
message: "Either application or compose must be provided",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -460,8 +460,8 @@ export const patchRouter = createTRPCRouter({
|
||||
// No changes - remove existing patch if any
|
||||
const existingPatch = await findPatchByFilePath(
|
||||
input.filePath,
|
||||
input.applicationId,
|
||||
input.composeId,
|
||||
input.id,
|
||||
input.id,
|
||||
);
|
||||
if (existingPatch) {
|
||||
await deletePatch(existingPatch.patchId);
|
||||
@@ -472,8 +472,8 @@ export const patchRouter = createTRPCRouter({
|
||||
// Check if patch exists
|
||||
const existingPatch = await findPatchByFilePath(
|
||||
input.filePath,
|
||||
input.applicationId,
|
||||
input.composeId,
|
||||
input.id,
|
||||
input.id,
|
||||
);
|
||||
|
||||
if (existingPatch) {
|
||||
@@ -487,8 +487,8 @@ export const patchRouter = createTRPCRouter({
|
||||
filePath: input.filePath,
|
||||
content: patchContent,
|
||||
enabled: true,
|
||||
applicationId: input.applicationId,
|
||||
composeId: input.composeId,
|
||||
applicationId: input.id,
|
||||
composeId: input.id,
|
||||
});
|
||||
|
||||
return { deleted: false, patchId: newPatch.patchId };
|
||||
|
||||
@@ -132,6 +132,8 @@ export const readPatchRepoDirectory = async (
|
||||
// Use git ls-tree to get tracked files only
|
||||
const command = `cd "${repoPath}" && git ls-tree -r --name-only HEAD`;
|
||||
|
||||
console.log("command", command);
|
||||
|
||||
let stdout: string;
|
||||
try {
|
||||
if (serverId) {
|
||||
|
||||
Reference in New Issue
Block a user