mirror of
https://github.com/crabwise-ai/crabwalk.git
synced 2026-08-14 00:57:52 +00:00
feat(monitor): add copy session key button to SessionNode header
- Copy icon positioned left of status indicator - Click copies full session key to clipboard - Animated feedback: copy → checkmark for 1.5s - stopPropagation prevents node selection interference
This commit is contained in:
committed by
luccast
parent
648539033c
commit
3949991b6c
@@ -1,7 +1,7 @@
|
||||
import { memo, useMemo } from 'react'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
import { Handle, Position } from '@xyflow/react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Users, User, Clock } from 'lucide-react'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { Users, User, Clock, Copy, Check } from 'lucide-react'
|
||||
import { StatusIndicator } from './StatusIndicator'
|
||||
import type { MonitorSession } from '~/integrations/clawdbot'
|
||||
|
||||
@@ -36,6 +36,8 @@ export const SessionNode = memo(function SessionNode({
|
||||
data,
|
||||
selected,
|
||||
}: SessionNodeProps) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
// Detect if this is a subagent session by checking if platform is "subagent" or if key contains "subagent"
|
||||
const isSubagent = data.platform === 'subagent' || data.key.includes('subagent') || Boolean(data.spawnedBy)
|
||||
const platformIcon = isSubagent ? platformIcons.subagent : (platformIcons[data.platform] ?? '📱')
|
||||
@@ -46,6 +48,13 @@ export const SessionNode = memo(function SessionNode({
|
||||
return formatRelativeTime(data.lastActivityAt)
|
||||
}, [data.lastActivityAt])
|
||||
|
||||
const handleCopyKey = useCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
navigator.clipboard.writeText(data.key)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 1500)
|
||||
}, [data.key])
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
@@ -73,7 +82,38 @@ export const SessionNode = memo(function SessionNode({
|
||||
<span className="font-display text-xs font-semibold uppercase tracking-wide text-gray-200">
|
||||
{displayPlatform}
|
||||
</span>
|
||||
<StatusIndicator status={data.status} size="sm" />
|
||||
<div className="ml-auto flex items-center gap-1.5">
|
||||
<button
|
||||
onClick={handleCopyKey}
|
||||
className="p-1 rounded hover:bg-shell-700 transition-colors"
|
||||
title={`Copy key: ${data.key}`}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
{copied ? (
|
||||
<motion.div
|
||||
key="check"
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.8, opacity: 0 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
>
|
||||
<Check size={12} className="text-neon-mint" />
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="copy"
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.8, opacity: 0 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
>
|
||||
<Copy size={12} className="text-shell-400 hover:text-shell-200" />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</button>
|
||||
<StatusIndicator status={data.status} size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
|
||||
Reference in New Issue
Block a user