refactor: Update Gitea provider components and API handling

- Adjusted GiteaProviderSchema to ensure watchPaths are correctly initialized and validated.
- Refactored SaveGiteaProvider and SaveGiteaProviderCompose components for improved state management and UI consistency.
- Simplified API router methods for Gitea, enhancing readability and error handling.
- Updated database schema and service functions for better clarity and maintainability.
- Removed unnecessary comments and improved logging for better debugging.
This commit is contained in:
Mauricio Siu
2025-03-23 03:27:19 -06:00
parent fc7eff94b6
commit 9359ee7a04
6 changed files with 316 additions and 539 deletions

View File

@@ -67,13 +67,13 @@ const GiteaProviderSchema = z.object({
.object({
repo: z.string().min(1, "Repo is required"),
owner: z.string().min(1, "Owner is required"),
giteaPathNamespace: z.string().min(1),
giteaPathNamespace: z.string(),
id: z.number().nullable(),
watchPaths: z.array(z.string()).default([]),
})
.required(),
branch: z.string().min(1, "Branch is required"),
giteaId: z.string().min(1, "Gitea Provider is required"),
watchPaths: z.array(z.string()).default([]),
});
type GiteaProvider = z.infer<typeof GiteaProviderSchema>;
@@ -97,10 +97,10 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
repo: "",
giteaPathNamespace: "",
id: null,
watchPaths: [],
},
giteaId: "",
branch: "",
watchPaths: [],
},
resolver: zodResolver(GiteaProviderSchema),
});
@@ -146,10 +146,10 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
owner: data.giteaOwner || "",
giteaPathNamespace: data.giteaPathNamespace || "",
id: data.giteaProjectId,
watchPaths: data.watchPaths || [],
},
buildPath: data.giteaBuildPath || "/",
giteaId: data.giteaId || "",
watchPaths: data.watchPaths || [],
});
}
}, [form.reset, data, form]);
@@ -164,7 +164,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
applicationId,
giteaProjectId: data.repository.id,
giteaPathNamespace: data.repository.giteaPathNamespace,
watchPaths: data.repository.watchPaths,
watchPaths: data.watchPaths,
})
.then(async () => {
toast.success("Service Provider Saved");
@@ -198,7 +198,6 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
repo: "",
id: null,
giteaPathNamespace: "",
watchPaths: [],
});
form.setValue("branch", "");
}}
@@ -285,7 +284,6 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
repo: repo.name,
id: repo.id,
giteaPathNamespace: repo.name,
watchPaths: [],
});
form.setValue("branch", "");
}}
@@ -413,7 +411,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
/>
<FormField
control={form.control}
name="repository.watchPaths"
name="watchPaths"
render={({ field }) => (
<FormItem className="md:col-span-2">
<div className="flex items-center gap-2">

View File

@@ -41,7 +41,7 @@ import { cn } from "@/lib/utils";
import { api } from "@/utils/api";
import type { Branch, Repository } from "@/utils/gitea-utils";
import { zodResolver } from "@hookform/resolvers/zod";
import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
import { CheckIcon, ChevronsUpDown, Plus, X } from "lucide-react";
import Link from "next/link";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
@@ -55,7 +55,7 @@ const GiteaProviderSchema = z.object({
repo: z.string().min(1, "Repo is required"),
owner: z.string().min(1, "Owner is required"),
id: z.number().nullable(),
giteaPathNamespace: z.string().min(1),
giteaPathNamespace: z.string(),
})
.required(),
branch: z.string().min(1, "Branch is required"),
@@ -95,6 +95,8 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
const repository = form.watch("repository");
const giteaId = form.watch("giteaId");
console.log(repository);
const {
data: repositories,
isLoading: isLoadingRepositories,
@@ -126,6 +128,7 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
useEffect(() => {
if (data) {
console.log(data.giteaRepository);
form.reset({
branch: data.giteaBranch || "",
repository: {
@@ -452,20 +455,20 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
/>
<Button
type="button"
variant="secondary"
variant="outline"
size="icon"
onClick={() => {
const input = document.querySelector(
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
'input[placeholder*="Enter a path"]',
) as HTMLInputElement;
const value = input.value.trim();
if (value) {
const newPaths = [...(field.value || []), value];
form.setValue("watchPaths", newPaths);
const path = input.value.trim();
if (path) {
field.onChange([...field.value, path]);
input.value = "";
}
}}
>
Add
<Plus className="size-4" />
</Button>
</div>
</FormControl>
@@ -475,13 +478,11 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
/>
</div>
<Button
type="submit"
className="w-full"
disabled={isSavingGiteaProvider || !form.formState.isDirty}
>
{isSavingGiteaProvider ? "Saving..." : "Save Gitea Provider"}
</Button>
<div className="flex justify-end">
<Button type="submit" isLoading={isSavingGiteaProvider}>
Save
</Button>
</div>
</form>
</Form>
</div>

View File

@@ -22,49 +22,36 @@ import {
import { TRPCError } from "@trpc/server";
export const giteaRouter = createTRPCRouter({
// Create a new Gitea provider
create: protectedProcedure
.input(apiCreateGitea)
.mutation(
async ({
input,
ctx,
}: { input: typeof apiCreateGitea._input; ctx: any }) => {
try {
return await createGitea(input, ctx.session.activeOrganizationId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error creating this Gitea provider",
cause: error,
});
}
},
),
.mutation(async ({ input, ctx }) => {
try {
return await createGitea(input, ctx.session.activeOrganizationId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error creating this Gitea provider",
cause: error,
});
}
}),
// Fetch a specific Gitea provider by ID
one: protectedProcedure
.input(apiFindOneGitea)
.query(
async ({
input,
ctx,
}: { input: typeof apiFindOneGitea._input; ctx: any }) => {
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",
});
}
return giteaProvider;
},
),
.query(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",
});
}
return giteaProvider;
}),
// Fetch all Gitea providers for the active organization
giteaProviders: protectedProcedure.query(async ({ ctx }: { ctx: any }) => {
let result = await db.query.gitea.findMany({
with: {
@@ -72,14 +59,12 @@ export const giteaRouter = createTRPCRouter({
},
});
// Filter by organization ID
result = result.filter(
(provider) =>
provider.gitProvider.organizationId ===
ctx.session.activeOrganizationId,
);
// Filter providers that meet the requirements
const filtered = result
.filter((provider) => haveGiteaRequirements(provider))
.map((provider) => {
@@ -94,64 +79,88 @@ export const giteaRouter = createTRPCRouter({
return filtered;
}),
// Fetch repositories from Gitea provider
getGiteaRepositories: protectedProcedure
.input(apiFindOneGitea)
.query(
async ({
input,
ctx,
}: { input: typeof apiFindOneGitea._input; ctx: any }) => {
const { giteaId } = input;
.query(async ({ input, ctx }) => {
const { giteaId } = input;
if (!giteaId) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Gitea provider ID is required.",
});
}
if (!giteaId) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Gitea provider ID is required.",
});
}
const giteaProvider = await findGiteaById(giteaId);
if (
giteaProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitea provider",
});
}
const giteaProvider = await findGiteaById(giteaId);
if (
giteaProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitea provider",
});
}
try {
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),
});
}
},
),
try {
const repositories = await getGiteaRepositories(giteaId);
console.log(repositories);
return repositories;
} 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
getGiteaBranches: protectedProcedure
.input(apiFindGiteaBranches)
.query(
async ({
input,
ctx,
}: { input: typeof apiFindGiteaBranches._input; ctx: any }) => {
const { giteaId, owner, repositoryName } = input;
.query(async ({ input, ctx }) => {
const { giteaId, owner, repositoryName } = input;
if (!giteaId || !owner || !repositoryName) {
throw new TRPCError({
code: "BAD_REQUEST",
message:
"Gitea provider ID, owner, and repository name are required.",
});
}
if (!giteaId || !owner || !repositoryName) {
throw new TRPCError({
code: "BAD_REQUEST",
message:
"Gitea provider ID, owner, and repository name are required.",
});
}
const giteaProvider = await findGiteaById(giteaId);
if (
giteaProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitea provider",
});
}
try {
return await getGiteaBranches({
giteaId,
owner,
repo: repositoryName,
id: 0,
});
} catch (error) {
console.error("Error fetching Gitea branches:", error);
throw new TRPCError({
code: "BAD_REQUEST",
message: error instanceof Error ? error.message : String(error),
});
}
}),
testConnection: protectedProcedure
.input(apiGiteaTestConnection)
.mutation(async ({ input, ctx }) => {
const giteaId = input.giteaId ?? "";
try {
const giteaProvider = await findGiteaById(giteaId);
if (
giteaProvider.gitProvider.organizationId !==
@@ -163,97 +172,49 @@ export const giteaRouter = createTRPCRouter({
});
}
try {
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),
});
}
},
),
const result = await testGiteaConnection({
giteaId,
});
// Test connection to Gitea provider
testConnection: protectedProcedure
.input(apiGiteaTestConnection)
.mutation(
async ({
input,
ctx,
}: { input: typeof apiGiteaTestConnection._input; ctx: any }) => {
const giteaId = input.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),
});
}
}),
try {
const giteaProvider = await findGiteaById(giteaId);
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,
}: { input: typeof apiUpdateGitea._input; ctx: any }) => {
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",
});
}
.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,
});
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,
});
}
await updateGitea(input.giteaId, {
...input,
});
} else {
await updateGitea(input.giteaId, {
...input,
});
}
return { success: true };
},
),
return { success: true };
}),
});