Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 9 additions & 42 deletions apps/app/src/components/processing/ProcessingActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import {
useReprocessJob,
useRetryProcessingJob,
useRetryProcessingStep,
useTweakAndReprocessStep,
} from "@/lib/api/processing";
import type { ProcessingJob, ProcessingStep } from "@curatedotfun/types";
import { Loader2, RefreshCcw, RotateCw, Wand2 } from "lucide-react";
import { Loader2, RefreshCcw, RotateCw } from "lucide-react";

interface ProcessingActionsProps {
job: ProcessingJob;
Expand All @@ -23,7 +22,6 @@ export function ProcessingActions({ job, step }: ProcessingActionsProps) {
const retryJob = useRetryProcessingJob();
const retryStep = useRetryProcessingStep();
const reprocessJob = useReprocessJob();
const tweakAndReprocessStep = useTweakAndReprocessStep();

const handleRetry = () => {
if (step) {
Expand All @@ -37,65 +35,34 @@ export function ProcessingActions({ job, step }: ProcessingActionsProps) {
reprocessJob.mutate({ jobId: job.id });
};

const handleTweakAndReprocess = (newInput: string) => {
if (step) {
tweakAndReprocessStep.mutate({ stepId: step.id, newInput });
}
};

return (
<TooltipProvider>
<div className="flex items-center gap-2">
{step && (
{!step && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={() =>
handleTweakAndReprocess(JSON.stringify(step.input, null, 2))
}
disabled={tweakAndReprocessStep.isPending}
onClick={handleReprocessWithLatestConfig}
disabled={reprocessJob.isPending}
>
{tweakAndReprocessStep.isPending ? (
{reprocessJob.isPending ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<Wand2 className="mr-2 h-4 w-4" />
<RefreshCcw className="mr-2 h-4 w-4" />
)}
Tweak
Reprocess
</Button>
</TooltipTrigger>
<TooltipContent>
<p>
Modify the input of this step and re-run the job from this
point.
Create a new processing job for this submission using the latest
feed configuration.
</p>
</TooltipContent>
</Tooltip>
)}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={handleReprocessWithLatestConfig}
disabled={reprocessJob.isPending}
>
{reprocessJob.isPending ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<RefreshCcw className="mr-2 h-4 w-4" />
)}
Reprocess
</Button>
</TooltipTrigger>
<TooltipContent>
<p>
Create a new processing job for this submission using the latest
feed configuration.
</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
Expand Down
23 changes: 22 additions & 1 deletion apps/app/src/components/processing/ProcessingHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import {
import { Badge } from "../ui/badge";
import { format } from "date-fns";
import { Loader2 } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";

interface ProcessingHistoryProps {
submissionId: string;
Expand Down Expand Up @@ -56,7 +62,21 @@ export function ProcessingHistory({
const jobColumns = [
jobColumnHelper.accessor("id", {
header: "Job ID",
cell: (info) => info.getValue(),
cell: (info) => {
const jobId = info.getValue();
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<span className="font-mono">{jobId.substring(0, 8)}...</span>
</TooltipTrigger>
<TooltipContent>
<p>{jobId}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
},
}),
jobColumnHelper.accessor("status", {
header: "Status",
Expand Down Expand Up @@ -174,6 +194,7 @@ export function ProcessingHistory({
return (
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => {
setSelectedStep(step);
Expand Down
122 changes: 112 additions & 10 deletions apps/app/src/lib/api/processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
ProcessingStepsResponse,
} from "@curatedotfun/types";
import { useApiQuery, useApiMutation } from "../../hooks/api-client";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "@/hooks/use-toast";

/**
* Fetch processing jobs for a submission
Expand All @@ -14,6 +16,20 @@ export function useProcessingJobs(
feedId: string | null,
options?: { enabled?: boolean },
) {
const query = useApiQuery<ProcessingJobsResponse, Error, ProcessingJob[]>(
["processingJobs", submissionId, feedId],
`/processing/jobs/${submissionId}?feedId=${feedId}`,
{
enabled:
options?.enabled !== undefined
? options.enabled && !!submissionId && !!feedId
: !!submissionId && !!feedId,
select: (data) => data.data.jobs,
},
);

const isProcessing = query.data?.some((job) => job.status === "processing");

return useApiQuery<ProcessingJobsResponse, Error, ProcessingJob[]>(
["processingJobs", submissionId, feedId],
`/processing/jobs/${submissionId}?feedId=${feedId}`,
Expand All @@ -23,6 +39,7 @@ export function useProcessingJobs(
? options.enabled && !!submissionId && !!feedId
: !!submissionId && !!feedId,
select: (data) => data.data.jobs,
refetchInterval: isProcessing ? 5000 : false,
},
);
}
Expand All @@ -34,13 +51,26 @@ export function useProcessingSteps(
jobId: string | null,
options?: { enabled?: boolean },
) {
const query = useApiQuery<ProcessingStepsResponse, Error, ProcessingStep[]>(
["processingSteps", jobId],
`/processing/jobs/${jobId}/steps`,
{
enabled:
options?.enabled !== undefined ? options.enabled && !!jobId : !!jobId,
select: (data) => data.data.steps,
},
);

const isProcessing = query.data?.some((step) => step.status === "processing");

return useApiQuery<ProcessingStepsResponse, Error, ProcessingStep[]>(
["processingSteps", jobId],
`/processing/jobs/${jobId}/steps`,
{
enabled:
options?.enabled !== undefined ? options.enabled && !!jobId : !!jobId,
select: (data) => data.data.steps,
refetchInterval: isProcessing ? 5000 : false,
},
);
}
Expand All @@ -49,6 +79,7 @@ export function useProcessingSteps(
* Retry a failed processing job
*/
export function useRetryProcessingJob() {
const queryClient = useQueryClient();
return useApiMutation<
{ success: boolean; job: ProcessingJob },
unknown,
Expand All @@ -60,9 +91,24 @@ export function useRetryProcessingJob() {
message: "retryProcessingJob",
},
{
onSuccess: () => {
// Invalidate processing jobs queries to refresh the data
// This will be handled by the query client's invalidateQueries method
onSuccess: (data) => {
toast({
title: "Success",
description: "Job retry triggered successfully.",
variant: "success",
});
queryClient.invalidateQueries({
queryKey: ["processingJobs", data.job.submissionId],
});
},
onError: (error) => {
toast({
title: "Error",
description: `Failed to retry job: ${
error instanceof Error ? error.message : "Unknown error"
}`,
variant: "destructive",
});
},
},
);
Expand All @@ -72,6 +118,7 @@ export function useRetryProcessingJob() {
* Retry processing from a specific failed step
*/
export function useRetryProcessingStep() {
const queryClient = useQueryClient();
return useApiMutation<
{ success: boolean; job: ProcessingJob },
unknown,
Expand All @@ -83,9 +130,27 @@ export function useRetryProcessingStep() {
message: "retryProcessingStep",
},
{
onSuccess: () => {
// Invalidate processing jobs and steps queries to refresh the data
// This will be handled by the query client's invalidateQueries method
onSuccess: (data) => {
toast({
title: "Success",
description: "Step retry triggered successfully.",
variant: "success",
});
queryClient.invalidateQueries({
queryKey: ["processingSteps", data.job.id],
});
queryClient.invalidateQueries({
queryKey: ["processingJobs", data.job.submissionId],
});
},
onError: (error) => {
toast({
title: "Error",
description: `Failed to retry step: ${
error instanceof Error ? error.message : "Unknown error"
}`,
variant: "destructive",
});
},
},
);
Expand All @@ -95,6 +160,7 @@ export function useRetryProcessingStep() {
* Reprocess a job with the latest config
*/
export function useReprocessJob() {
const queryClient = useQueryClient();
return useApiMutation<
{ success: boolean; job: ProcessingJob },
unknown,
Expand All @@ -106,8 +172,24 @@ export function useReprocessJob() {
message: "reprocessJob",
},
{
onSuccess: () => {
// Invalidate queries to refresh job list
onSuccess: (data) => {
toast({
title: "Success",
description: "Reprocessing job triggered successfully.",
variant: "success",
});
queryClient.invalidateQueries({
queryKey: ["processingJobs", data.job.submissionId],
});
},
onError: (error) => {
toast({
title: "Error",
description: `Failed to reprocess job: ${
error instanceof Error ? error.message : "Unknown error"
}`,
variant: "destructive",
});
},
},
);
Expand All @@ -117,6 +199,7 @@ export function useReprocessJob() {
* Tweak a step's input and reprocess from that point
*/
export function useTweakAndReprocessStep() {
const queryClient = useQueryClient();
return useApiMutation<
{ success: boolean; job: ProcessingJob },
unknown,
Expand All @@ -128,8 +211,27 @@ export function useTweakAndReprocessStep() {
message: "tweakAndReprocessStep",
},
{
onSuccess: () => {
// Invalidate queries to refresh job list
onSuccess: (data) => {
toast({
title: "Success",
description: "Tweak and reprocess triggered successfully.",
variant: "success",
});
queryClient.invalidateQueries({
queryKey: ["processingSteps", data.job.id],
});
queryClient.invalidateQueries({
queryKey: ["processingJobs", data.job.submissionId],
});
},
onError: (error) => {
toast({
title: "Error",
description: `Failed to tweak and reprocess: ${
error instanceof Error ? error.message : "Unknown error"
}`,
variant: "destructive",
});
},
},
);
Expand Down
Loading