Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot] 2026-04-18 12:03:53 +00:00
parent e0b7fa9942
commit 11d8c0c19a
7 changed files with 1229 additions and 0 deletions

170
src/hooks/use-cronjobs.ts Normal file
View file

@ -0,0 +1,170 @@
"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/hooks/use-auth";
export interface ScheduledJob {
id: string;
user_id: string;
agent_instance_id: string;
name: string;
description: string | null;
natural_language_input: string;
cron_expression: string;
human_readable: string;
action_prompt: string;
required_mcp_slugs: string[];
status: "active" | "paused" | "auto_paused";
auto_paused_reason: string | null;
last_run_at: string | null;
next_run_at: string | null;
timezone: string;
created_at: string;
updated_at: string;
}
function normalizeJob(row: Record<string, unknown>): ScheduledJob {
return {
...(row as ScheduledJob),
required_mcp_slugs: Array.isArray(row.required_mcp_slugs)
? (row.required_mcp_slugs as string[])
: [],
};
}
export function useCronjobs() {
const { user } = useAuth();
return useQuery({
queryKey: ["cronjobs", user?.id],
enabled: !!user,
queryFn: async (): Promise<ScheduledJob[]> => {
const { data, error } = await supabase
.from("scheduled_jobs")
.select("*")
.eq("user_id", user!.id)
.order("created_at", { ascending: false });
if (error) throw error;
return (data ?? []).map(normalizeJob);
},
});
}
export function useCronjob(id: string | undefined) {
const { user } = useAuth();
return useQuery({
queryKey: ["cronjob", id, user?.id],
enabled: !!user && !!id,
queryFn: async (): Promise<ScheduledJob | null> => {
const { data, error } = await supabase
.from("scheduled_jobs")
.select("*")
.eq("id", id!)
.eq("user_id", user!.id)
.maybeSingle();
if (error) throw error;
return data ? normalizeJob(data) : null;
},
});
}
export function useUserJobsLimits() {
const { user } = useAuth();
return useQuery({
queryKey: ["user-jobs-limits", user?.id],
enabled: !!user,
queryFn: async () => {
const { data, error } = await supabase
.from("user_jobs_limits")
.select("*")
.eq("user_id", user!.id)
.maybeSingle();
if (error) throw error;
return data as {
user_id: string;
plan_slug: string | null;
current_jobs_count: number | null;
max_jobs: number | null;
} | null;
},
});
}
export interface CreateJobInput {
agent_instance_id: string;
name: string;
description?: string | null;
natural_language_input: string;
cron_expression: string;
human_readable: string;
action_prompt: string;
required_mcp_slugs: string[];
timezone: string;
next_run_at: string | null;
}
export function useCreateCronjob() {
const { user } = useAuth();
const qc = useQueryClient();
return useMutation({
mutationFn: async (input: CreateJobInput) => {
const { data, error } = await supabase
.from("scheduled_jobs")
.insert({
user_id: user!.id,
agent_instance_id: input.agent_instance_id,
name: input.name,
description: input.description ?? null,
natural_language_input: input.natural_language_input,
cron_expression: input.cron_expression,
human_readable: input.human_readable,
action_prompt: input.action_prompt,
required_mcp_slugs: input.required_mcp_slugs,
timezone: input.timezone,
next_run_at: input.next_run_at,
status: "active",
})
.select("*")
.single();
if (error) throw error;
return normalizeJob(data);
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["cronjobs"] });
qc.invalidateQueries({ queryKey: ["user-jobs-limits"] });
},
});
}
export function useUpdateCronjobStatus() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ id, status }: { id: string; status: "active" | "paused" }) => {
const update: Record<string, unknown> = { status };
if (status === "paused") update.auto_paused_reason = null;
const { error } = await supabase
.from("scheduled_jobs")
.update(update)
.eq("id", id);
if (error) throw error;
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["cronjobs"] });
qc.invalidateQueries({ queryKey: ["cronjob"] });
},
});
}
export function useDeleteCronjob() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id: string) => {
const { error } = await supabase.from("scheduled_jobs").delete().eq("id", id);
if (error) throw error;
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["cronjobs"] });
qc.invalidateQueries({ queryKey: ["user-jobs-limits"] });
},
});
}