mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
Rolled back comments into separate branch
This commit is contained in:
@@ -1,106 +0,0 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { X } from 'lucide-react'
|
||||
import { useCommentStore } from '@/stores/comments/store'
|
||||
import { NodeProps } from 'reactflow'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface CommentBlockData {
|
||||
id: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export function CommentBlock({ data }: NodeProps<CommentBlockData>) {
|
||||
const [text, setText] = useState(data.text)
|
||||
const [isEditing, setIsEditing] = useState(!data.text)
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
||||
const { updateComment, removeComment } = useCommentStore()
|
||||
|
||||
useEffect(() => {
|
||||
if (isEditing && textareaRef.current) {
|
||||
textareaRef.current.focus()
|
||||
}
|
||||
}, [isEditing])
|
||||
|
||||
const handleBlur = () => {
|
||||
setIsEditing(false)
|
||||
setIsExpanded(false)
|
||||
if (text.trim()) {
|
||||
updateComment(data.id, text)
|
||||
} else {
|
||||
removeComment(data.id)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
setIsExpanded(true)
|
||||
if (!text) {
|
||||
setIsEditing(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExpanded) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'w-6 h-6 rounded-full bg-white border border-gray-200 shadow-sm cursor-pointer',
|
||||
'hover:shadow-md transition-all duration-200 ease-in-out transform scale-100',
|
||||
'flex items-center justify-center'
|
||||
)}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={() => setIsExpanded(true)}
|
||||
>
|
||||
<div className="w-2 h-2 rounded-full bg-yellow-500" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={cn(
|
||||
'w-[240px] shadow-md select-none relative cursor-default focus:outline-none focus-visible:ring-0',
|
||||
'bg-white hover:bg-gray-50/50',
|
||||
'border border-gray-200',
|
||||
'transition-all duration-200 ease-in-out transform scale-100',
|
||||
'animate-in fade-in-0 zoom-in-95'
|
||||
)}
|
||||
onMouseLeave={() => !isEditing && setIsExpanded(false)}
|
||||
>
|
||||
<div className="flex items-center justify-between p-2 border-b border-gray-200 cursor-grab active:cursor-grabbing">
|
||||
<div className="text-sm font-medium text-gray-600">Note</div>
|
||||
<button
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
removeComment(data.id)
|
||||
}}
|
||||
>
|
||||
<X className="h-4 w-4 text-gray-400 hover:text-gray-600" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-2.5" onClick={() => setIsEditing(true)}>
|
||||
{isEditing ? (
|
||||
<Textarea
|
||||
ref={textareaRef}
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={handleBlur}
|
||||
className={cn(
|
||||
'min-h-[80px] max-h-[240px] resize-none',
|
||||
'bg-transparent border-0 outline-none focus:outline-none focus-visible:ring-0 focus:ring-0 p-0',
|
||||
'text-sm text-gray-900 placeholder:text-gray-400'
|
||||
)}
|
||||
placeholder="Type your note here..."
|
||||
/>
|
||||
) : (
|
||||
<div className="text-sm text-gray-900 whitespace-pre-wrap cursor-text">
|
||||
{text}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -16,13 +16,10 @@ import { NotificationList } from '@/app/w/components/notifications/notifications
|
||||
import { WorkflowNode } from '../workflow-node/workflow-node'
|
||||
import { CustomEdge } from '../custom-edge/custom-edge'
|
||||
import { initializeStateLogger } from '@/stores/workflow/logger'
|
||||
import { useCommentStore } from '@/stores/comments/store'
|
||||
import { CommentBlock } from '../comment-block/comment-block'
|
||||
|
||||
// Define custom node and edge types for ReactFlow
|
||||
const nodeTypes: NodeTypes = {
|
||||
workflowBlock: WorkflowNode,
|
||||
commentBlock: CommentBlock,
|
||||
}
|
||||
const edgeTypes: EdgeTypes = { custom: CustomEdge }
|
||||
|
||||
@@ -48,8 +45,6 @@ export function WorkflowCanvas() {
|
||||
} = useWorkflowStore()
|
||||
const { addNotification } = useNotificationStore()
|
||||
const { project } = useReactFlow()
|
||||
const { comments, isCommentMode, addComment, updateCommentPosition } =
|
||||
useCommentStore()
|
||||
|
||||
// Transform blocks into ReactFlow node format
|
||||
const nodes = Object.values(blocks).map((block) => ({
|
||||
@@ -70,16 +65,11 @@ export function WorkflowCanvas() {
|
||||
(changes: any) => {
|
||||
changes.forEach((change: any) => {
|
||||
if (change.type === 'position' && change.position) {
|
||||
if (change.id.startsWith('comment-')) {
|
||||
const commentId = change.id.replace('comment-', '')
|
||||
updateCommentPosition(commentId, change.position)
|
||||
} else {
|
||||
updateBlockPosition(change.id, change.position)
|
||||
}
|
||||
updateBlockPosition(change.id, change.position)
|
||||
}
|
||||
})
|
||||
},
|
||||
[updateBlockPosition, updateCommentPosition]
|
||||
[updateBlockPosition]
|
||||
)
|
||||
|
||||
// Handle edge removal and updates
|
||||
@@ -147,23 +137,11 @@ export function WorkflowCanvas() {
|
||||
setSelectedEdgeId(null)
|
||||
}, [])
|
||||
|
||||
// Update onPaneClick to handle comment mode
|
||||
const onPaneClick = useCallback(
|
||||
(event: React.MouseEvent) => {
|
||||
setSelectedBlockId(null)
|
||||
setSelectedEdgeId(null)
|
||||
|
||||
if (isCommentMode) {
|
||||
const reactFlowBounds = event.currentTarget.getBoundingClientRect()
|
||||
const position = project({
|
||||
x: event.clientX - reactFlowBounds.left,
|
||||
y: event.clientY - reactFlowBounds.top,
|
||||
})
|
||||
addComment(position)
|
||||
}
|
||||
},
|
||||
[isCommentMode, project, addComment]
|
||||
)
|
||||
// Update onPaneClick to clear selections
|
||||
const onPaneClick = useCallback((event: React.MouseEvent) => {
|
||||
setSelectedBlockId(null)
|
||||
setSelectedEdgeId(null)
|
||||
}, [])
|
||||
|
||||
// Update selected edge when clicking on connections
|
||||
const onEdgeClick = useCallback((event: React.MouseEvent, edge: any) => {
|
||||
@@ -204,20 +182,11 @@ export function WorkflowCanvas() {
|
||||
},
|
||||
}))
|
||||
|
||||
// Create comment nodes
|
||||
const commentNodes = Object.values(comments).map((comment) => ({
|
||||
id: `comment-${comment.id}`,
|
||||
type: 'commentBlock',
|
||||
position: comment.position,
|
||||
data: { id: comment.id, text: comment.text },
|
||||
draggable: true,
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-[calc(100vh-4rem)]">
|
||||
<NotificationList />
|
||||
<ReactFlow
|
||||
nodes={[...nodes, ...commentNodes]}
|
||||
nodes={nodes}
|
||||
edges={edgesWithSelection}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@/components/ui/alert-dialog'
|
||||
import { useCommentStore } from '@/stores/comments/store'
|
||||
|
||||
export function ControlBar() {
|
||||
const { notifications, getWorkflowNotifications } = useNotificationStore()
|
||||
@@ -45,7 +44,6 @@ export function ControlBar() {
|
||||
const [, forceUpdate] = useState({})
|
||||
const { isExecuting, handleRunWorkflow } = useWorkflowExecution()
|
||||
const router = useRouter()
|
||||
const { isCommentMode, toggleCommentMode } = useCommentStore()
|
||||
|
||||
// Use client-side only rendering for the timestamp
|
||||
const [mounted, setMounted] = useState(false)
|
||||
@@ -165,22 +163,6 @@ export function ControlBar() {
|
||||
<TooltipContent>Delete Workflow</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={isCommentMode ? 'secondary' : 'ghost'}
|
||||
size="icon"
|
||||
onClick={toggleCommentMode}
|
||||
>
|
||||
<MessageSquare className="h-5 w-5" />
|
||||
<span className="sr-only">Toggle Comment Mode</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{isCommentMode ? 'Exit Comment Mode' : 'Add Comments'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Workflow</AlertDialogTitle>
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { create } from 'zustand'
|
||||
import { devtools, persist } from 'zustand/middleware'
|
||||
|
||||
export interface Comment {
|
||||
id: string
|
||||
text: string
|
||||
position: { x: number; y: number }
|
||||
createdAt: number
|
||||
}
|
||||
|
||||
interface CommentStore {
|
||||
comments: Record<string, Comment>
|
||||
isCommentMode: boolean
|
||||
addComment: (position: { x: number; y: number }) => void
|
||||
updateComment: (id: string, text: string) => void
|
||||
updateCommentPosition: (id: string, position: { x: number; y: number }) => void
|
||||
removeComment: (id: string) => void
|
||||
toggleCommentMode: () => void
|
||||
}
|
||||
|
||||
export const useCommentStore = create<CommentStore>()(
|
||||
devtools(
|
||||
persist(
|
||||
(set) => ({
|
||||
comments: {},
|
||||
isCommentMode: false,
|
||||
|
||||
addComment: (position) => {
|
||||
const id = crypto.randomUUID()
|
||||
set((state) => ({
|
||||
comments: {
|
||||
...state.comments,
|
||||
[id]: {
|
||||
id,
|
||||
text: '',
|
||||
position,
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
},
|
||||
isCommentMode: false,
|
||||
}))
|
||||
},
|
||||
|
||||
updateComment: (id, text) => {
|
||||
set((state) => ({
|
||||
comments: {
|
||||
...state.comments,
|
||||
[id]: {
|
||||
...state.comments[id],
|
||||
text,
|
||||
},
|
||||
},
|
||||
}))
|
||||
},
|
||||
|
||||
updateCommentPosition: (id, position) => {
|
||||
set((state) => ({
|
||||
comments: {
|
||||
...state.comments,
|
||||
[id]: {
|
||||
...state.comments[id],
|
||||
position,
|
||||
},
|
||||
},
|
||||
}))
|
||||
},
|
||||
|
||||
removeComment: (id) => {
|
||||
set((state) => {
|
||||
const newComments = { ...state.comments }
|
||||
delete newComments[id]
|
||||
return { comments: newComments }
|
||||
})
|
||||
},
|
||||
|
||||
toggleCommentMode: () => {
|
||||
set((state) => ({ isCommentMode: !state.isCommentMode }))
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'comments-storage',
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user