Compare commits

...
Author SHA1 Message Date
Michael Chung c8a9f0bc31 Merge branch 'main' into feature/undo-redo 2025-04-14 22:53:23 -04:00
Michael Chung 4afa753212 branch: undo-redo 2025-04-14 19:06:26 -04:00
6 changed files with 188 additions and 11 deletions
@@ -55,7 +55,7 @@ export class Engine {
private uiLayer: Konva.Layer;
private previewLayer: Konva.Layer;
private offScreenCanvas: OffscreenCanvas;
private realTimeDrawEngine: RealTimeDrawEngine;
public realTimeDrawEngine: RealTimeDrawEngine;
private nodesManager: NodesManager;
private nodeIsolator: NodeIsolator;
private nodeTransformer: NodeTransformer;
@@ -66,8 +66,8 @@ export class Engine {
private backgroundNode: ShapeNode | null = null;
private sceneManager: SceneManager;
private undoStackManager: UndoStackManager;
private commandManager: CommandManager;
public undoStackManager: UndoStackManager;
public commandManager: CommandManager;
private videoExtractionHandler: VideoExtractionHandler;
public segmentationButtonCanBePressed: boolean = true;
@@ -1,14 +1,14 @@
import { useCallback, useRef } from "react";
import { UndoRedo } from "~/components/reusable/UndoRedoController/UndoRedo";
// Components
import { KonvaCanvasContainer } from "./KonvaCanvasContainer";
import { ContextualButtonRetry } from "./ContextualButtonRetry";
import { ContextualToolbarNode } from "./ContextualToolbarNode";
import { ContextualLoadingBar } from "./ContextualLoadingBar";
import { SignaledCanvasDragDropFiles } from "./SignaledCanvasDragDropFiles";
import { SignaledDialogs } from "./SignaledDialogs";
import { SignaledToolbarMain } from "./SignaledToolbarMain";
import { SignaledToolbarVideoExtraction } from "./SignaledToolbarVideoExtraction";
import { PromptBox } from "~/components/PromptBox";
// The KonvaApp is the root of the Konva stage
// and only entry point for anything in Konva JS
@@ -22,9 +22,6 @@ import { useLayoutContext } from "./contextSignals/layout";
// common hooks
import { useRenderCounter } from "~/hooks/useRenderCounter";
import { useNavigate } from "react-router-dom";
import { SignaledMagicBox } from "./SignaledMagicBox";
import { SignaledPromptSlider } from "./SignaledPromptSlider";
import { SignaledPromptText } from "./SignaledPromptText";
export const KonvaRootComponent = ({
className,
@@ -53,11 +50,13 @@ export const KonvaRootComponent = ({
return (
<>
<UndoRedo>
<KonvaCanvasContainer
ref={konvaContainerCallbackRef}
className={className}
// retreive the classNames from the parent for sizing/styling
/>
{/* <SignaledMagicBox /> */}
<SignaledCanvasDragDropFiles
openAddImage={appUiContext.openAddImage}
@@ -77,6 +76,7 @@ export const KonvaRootComponent = ({
{/* <ContextualLoadingBar /> */}
<ContextualToolbarNode />
{/* <ContextualButtonRetry /> */}
</UndoRedo>
</>
);
};
@@ -30,7 +30,6 @@ export const Main = withProtectionRoute(() => {
useSignals();
const realtimeEngineRef = useRef<EngineType | null>(null);
const generationEngineRef = useRef<GenerationEngine | null>(null);
const appModeValue = appMode.value;
@@ -0,0 +1,58 @@
import { useRef } from "react";
import { useCallback, useContext, ReactNode } from "react";
import { EngineType } from "~/KonvaApp";
import { Engine } from "~/KonvaApp/Engine";
interface UndoRedoProps {
children: ReactNode;
}
/**
* A transparent component that provides undo/redo functionality
* with keyboard shortcuts for macOS (Command+Z, Command+Shift+Z)
*/
export const UndoRedo = ({
children,
}: UndoRedoProps) => {
const engineRef = useRef<EngineType | null>(null);
// Set up keyboard shortcuts for macOS
useCallback(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const engine = engineRef.current;
if (!engine) {
console.error('Engine reference is not available for undo/redo operations');
return;
}
// Command+Z for Undo
// Ctrl+Shift+Z for Redo (Windows/Linux alternative)
if (e.ctrlKey && e.shiftKey && e.key === 'z') {
e.preventDefault();
}
// Delete key handling
if ((e.key === 'Delete' || e.key === 'Backspace')) {
e.preventDefault();
engine.commandManager.deleteNodes();
}
if (e.metaKey && e.key === 'z' && !e.shiftKey) {
e.preventDefault();
engine.undoStackManager.undo();
}
// Command+Shift+Z for Redo
if (e.metaKey && e.key === 'z' && e.shiftKey) {
e.preventDefault();
engine.undoStackManager.undo();
engine.realTimeDrawEngine.render();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [engineRef]);
return children;
};
+120
View File
@@ -0,0 +1,120 @@
{
"success": true,
"jobs": [
{
"created_at": "2024-03-20T10:15:30Z",
"job_token": "job_123456789",
"maybe_result": {
"entity_token": "entity_987654321",
"entity_type": "image",
"maybe_public_bucket_media_path": "https://storage.example.com/media/image123.jpg",
"maybe_successfully_completed_at": "2024-03-20T10:20:45Z",
"media_links": {
"cdn_url": "https://cdn.example.com/media/image123.jpg",
"maybe_thumbnail_template": "https://cdn.example.com/media/image123_{WIDTH}.jpg",
"maybe_video_previews": null
}
},
"request": {
"inference_category": "image_generation",
"maybe_model_title": "Stable Diffusion v2.1",
"maybe_model_token": "model_abc123",
"maybe_model_type": "diffusion",
"maybe_raw_inference_text": null,
"maybe_style_name": "anime"
},
"status": {
"attempt_count": 1,
"maybe_assigned_cluster": "cluster-1",
"maybe_assigned_worker": "worker-xyz",
"maybe_current_execution_duration_seconds": 315,
"maybe_extra_status_description": "Processing at 85%",
"maybe_failure_category": null,
"maybe_first_started_at": "2024-03-20T10:15:35Z",
"progress_percentage": 85,
"requires_keepalive": false,
"status": "running"
},
"updated_at": "2024-03-20T10:20:45Z"
},
{
"created_at": "2024-03-20T09:30:15Z",
"job_token": "job_987654321",
"maybe_result": {
"entity_token": "entity_123456789",
"entity_type": "video",
"maybe_public_bucket_media_path": "https://storage.example.com/media/video456.mp4",
"maybe_successfully_completed_at": "2024-03-20T09:45:30Z",
"media_links": {
"cdn_url": "https://cdn.example.com/media/video456.mp4",
"maybe_thumbnail_template": null,
"maybe_video_previews": {
"animated": {
"url": "https://cdn.example.com/previews/video456_animated.mp4"
},
"animated_thumbnail_template": [
"https://cdn.example.com/previews/video456_animated_{WIDTH}.jpg"
],
"still": {
"url": "https://cdn.example.com/previews/video456_still.jpg"
},
"still_thumbnail_template": [
"https://cdn.example.com/previews/video456_still_{WIDTH}.jpg"
]
}
}
},
"request": {
"inference_category": "video_generation",
"maybe_lipsync_details": {
"face_driver_media_file_token": "media_face123",
"source_media_file_token": "media_source456"
},
"maybe_model_title": "Video Diffusion Model",
"maybe_model_token": "model_def456",
"maybe_model_type": "video_diffusion",
"maybe_raw_inference_text": null,
"maybe_style_name": "realistic"
},
"status": {
"attempt_count": 1,
"maybe_assigned_cluster": "cluster-2",
"maybe_assigned_worker": "worker-abc",
"maybe_current_execution_duration_seconds": null,
"maybe_extra_status_description": null,
"maybe_failure_category": null,
"maybe_first_started_at": "2024-03-20T09:30:20Z",
"progress_percentage": 100,
"requires_keepalive": false,
"status": "completed"
},
"updated_at": "2024-03-20T09:45:30Z"
},
{
"created_at": "2024-03-20T11:00:00Z",
"job_token": "job_456789123",
"maybe_result": null,
"request": {
"inference_category": "text_to_speech",
"maybe_model_title": "TTS Model v3",
"maybe_model_token": "model_ghi789",
"maybe_model_type": "tts",
"maybe_raw_inference_text": "Hello, this is a sample text for TTS conversion.",
"maybe_style_name": null
},
"status": {
"attempt_count": 2,
"maybe_assigned_cluster": "cluster-3",
"maybe_assigned_worker": null,
"maybe_current_execution_duration_seconds": null,
"maybe_extra_status_description": "Failed to process audio",
"maybe_failure_category": "processing_error",
"maybe_first_started_at": "2024-03-20T11:00:05Z",
"progress_percentage": 0,
"requires_keepalive": true,
"status": "failed"
},
"updated_at": "2024-03-20T11:15:00Z"
}
]
}