11import PublishWorkflowModal from "@/components/modals/publish-workflow-modal" ;
22import { EditorContext } from "@/components/providers/editor-context-provider" ;
3+ import { DragEventTypeEnum } from "@/lib/enums" ;
34import { useRegisterMenuAction } from "@/lib/hooks/menu-actions/use-register-menu-action" ;
45import { useAppInfo } from "@/lib/hooks/use-app-info" ;
56import useCanvasWorkflow from "@/lib/hooks/use-canvas-workflow" ;
67import { useTabViewManager } from "@/lib/hooks/use-tab-view-manager" ;
78import {
9+ AppDragData ,
810 AppInfoModalContent ,
911 AppNodeData ,
1012 AppViewConfig ,
1113 CanvasViewConfig ,
14+ ExtensionApp ,
1215} from "@/lib/types" ;
13- import { Button } from "@heroui/react" ;
16+ import { addToast , Button } from "@heroui/react" ;
1417import {
1518 addEdge ,
1619 applyEdgeChanges ,
@@ -28,7 +31,16 @@ import {
2831 useViewport ,
2932} from "@xyflow/react" ;
3033import "@xyflow/react/dist/style.css" ;
31- import { useCallback , useContext , useEffect , useRef , useState } from "react" ;
34+ import { useTheme } from "next-themes" ;
35+ import {
36+ memo ,
37+ useCallback ,
38+ useContext ,
39+ useEffect ,
40+ useRef ,
41+ useState ,
42+ } from "react" ;
43+ import { v4 } from "uuid" ;
3244import Icon from "../../misc/icon" ;
3345import AppNode from "./nodes/app-node/app-node" ;
3446import "./theme.css" ;
@@ -63,7 +75,7 @@ export default function CanvasView({
6375 const editorContext = useContext ( EditorContext ) ;
6476
6577 const { openAppInfoModal } = useAppInfo ( ) ;
66-
78+ const { resolvedTheme } = useTheme ( ) ;
6779 const {
6880 localEdges,
6981 localNodes,
@@ -76,7 +88,8 @@ export default function CanvasView({
7688 } = useCanvasWorkflow ( config . initialWorkflowContent ) ;
7789 const viewport = useViewport ( ) ;
7890 const { screenToFlowPosition } = useReactFlow ( ) ;
79- const { deleteAppViewInCanvasView } = useTabViewManager ( ) ;
91+ const { deleteAppViewInCanvasView, createAppViewInCanvasView } =
92+ useTabViewManager ( ) ;
8093
8194 const [ isPublishModalOpen , setIsPublishModalOpen ] = useState ( false ) ;
8295
@@ -270,6 +283,50 @@ export default function CanvasView({
270283 ref = { containerRef }
271284 className = "bg-content3 text-content3-foreground relative h-full w-full"
272285 id = { config . viewId }
286+ onDragOver = { ( e ) => {
287+ const types = e . dataTransfer . types ;
288+ if (
289+ types . includes ( `application/${ DragEventTypeEnum . App . toLowerCase ( ) } ` )
290+ ) {
291+ e . preventDefault ( ) ; // allow drop
292+ e . dataTransfer . dropEffect = "copy" ;
293+ } else {
294+ e . dataTransfer . dropEffect = "none" ;
295+ }
296+ } }
297+ onDrop = { ( e ) => {
298+ const dataText = e . dataTransfer . getData (
299+ `application/${ DragEventTypeEnum . App . toLowerCase ( ) } ` ,
300+ ) ;
301+ if ( ! dataText ) {
302+ return ;
303+ }
304+ console . log ( "Dropped item:" , dataText ) ;
305+ try {
306+ const data = JSON . parse ( dataText ) as AppDragData ;
307+ e . preventDefault ( ) ;
308+
309+ const app : ExtensionApp = data . app ;
310+ const config : AppViewConfig = {
311+ app : app . config . id ,
312+ viewId : `${ app . config . id } -${ v4 ( ) } ` ,
313+ recommendedHeight : app . config . recommendedHeight ,
314+ recommendedWidth : app . config . recommendedWidth ,
315+ } ;
316+ createAppViewInCanvasView ( config ) ;
317+ } catch ( error ) {
318+ addToast ( {
319+ title : "Failed to open app" ,
320+ description : "The dropped app data is invalid." ,
321+ color : "danger" ,
322+ } ) ;
323+ } finally {
324+ editorContext ?. setEditorStates ( ( prev ) => ( {
325+ ...prev ,
326+ isDraggingOverCanvas : false ,
327+ } ) ) ;
328+ }
329+ } }
273330 >
274331 < ReactFlow
275332 nodes = { localNodes ?? [ ] }
@@ -297,6 +354,7 @@ export default function CanvasView({
297354 } }
298355 maxZoom = { 4 }
299356 minZoom = { 0.1 }
357+ colorMode = { resolvedTheme === "dark" ? "dark" : "light" }
300358 >
301359 < Background id = { config . viewId } variant = { BackgroundVariant . Dots } />
302360 </ ReactFlow >
@@ -323,3 +381,16 @@ export default function CanvasView({
323381 </ div >
324382 ) ;
325383}
384+
385+ export const MemoizedCanvasView = memo (
386+ ( {
387+ config,
388+ isActive,
389+ tabName,
390+ } : {
391+ config : CanvasViewConfig ;
392+ isActive : boolean ;
393+ tabName : string ;
394+ } ) => < CanvasView config = { config } isActive = { isActive } tabName = { tabName } /> ,
395+ ) ;
396+ MemoizedCanvasView . displayName = "MemoizedCanvasView" ;
0 commit comments