refactor: modularize canvas component by extracting low-level logic into dedicated helper modules
- Removed unused imports and functions from canvas.tsx to streamline the codebase. - Introduced several helper modules for improved organization and maintainability, including canvas-helpers, canvas-node-change-helpers, and canvas-media-utils. - Updated documentation in CLAUDE.md to reflect changes in the canvas architecture and the purpose of new internal modules.
This commit is contained in:
70
components/canvas/canvas-generation-failures.ts
Normal file
70
components/canvas/canvas-generation-failures.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
import type { Doc } from "@/convex/_generated/dataModel";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { msg } from "@/lib/toast-messages";
|
||||
|
||||
import {
|
||||
GENERATION_FAILURE_THRESHOLD,
|
||||
GENERATION_FAILURE_WINDOW_MS,
|
||||
} from "./canvas-helpers";
|
||||
|
||||
export function useGenerationFailureWarnings(
|
||||
convexNodes: Doc<"nodes">[] | undefined,
|
||||
): void {
|
||||
const recentGenerationFailureTimestampsRef = useRef<number[]>([]);
|
||||
const previousNodeStatusRef = useRef<Map<string, string | undefined>>(new Map());
|
||||
const hasInitializedGenerationFailureTrackingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!convexNodes) return;
|
||||
|
||||
const nextNodeStatusMap = new Map<string, string | undefined>();
|
||||
let detectedGenerationFailures = 0;
|
||||
|
||||
for (const node of convexNodes) {
|
||||
nextNodeStatusMap.set(node._id, node.status);
|
||||
|
||||
if (node.type !== "ai-image") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const previousStatus = previousNodeStatusRef.current.get(node._id);
|
||||
if (
|
||||
hasInitializedGenerationFailureTrackingRef.current &&
|
||||
node.status === "error" &&
|
||||
previousStatus !== "error"
|
||||
) {
|
||||
detectedGenerationFailures += 1;
|
||||
}
|
||||
}
|
||||
|
||||
previousNodeStatusRef.current = nextNodeStatusMap;
|
||||
|
||||
if (!hasInitializedGenerationFailureTrackingRef.current) {
|
||||
hasInitializedGenerationFailureTrackingRef.current = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (detectedGenerationFailures === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const recentFailures = recentGenerationFailureTimestampsRef.current.filter(
|
||||
(timestamp) => now - timestamp <= GENERATION_FAILURE_WINDOW_MS,
|
||||
);
|
||||
|
||||
for (let index = 0; index < detectedGenerationFailures; index += 1) {
|
||||
recentFailures.push(now);
|
||||
}
|
||||
|
||||
if (recentFailures.length >= GENERATION_FAILURE_THRESHOLD) {
|
||||
toast.warning(msg.ai.openrouterIssues.title, msg.ai.openrouterIssues.desc);
|
||||
recentGenerationFailureTimestampsRef.current = [];
|
||||
return;
|
||||
}
|
||||
|
||||
recentGenerationFailureTimestampsRef.current = recentFailures;
|
||||
}, [convexNodes]);
|
||||
}
|
||||
Reference in New Issue
Block a user