@burdenoff/microfe-vibecontrols 2026.623.4 → 2026.624.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VibeControlsRoutes.js +161 -149
- package/dist/VibeControlsRoutes.js.map +1 -1
- package/dist/components/agents/AgentCard.js +12 -9
- package/dist/components/agents/AgentCard.js.map +1 -1
- package/dist/components/catalog/CatalogCard.js +9 -12
- package/dist/components/catalog/CatalogCard.js.map +1 -1
- package/dist/components/idp-components/ComponentCard.js +9 -12
- package/dist/components/idp-components/ComponentCard.js.map +1 -1
- package/dist/components/notes/NoteCard.js +9 -12
- package/dist/components/notes/NoteCard.js.map +1 -1
- package/dist/components/sessions/SessionCard.js +9 -12
- package/dist/components/sessions/SessionCard.js.map +1 -1
- package/dist/components/shared/Card.js +1 -1
- package/dist/components/shared/Card.js.map +1 -1
- package/dist/components/shared/StatCard.js +1 -1
- package/dist/components/shared/StatCard.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +1 -1
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/pages/AgentGraphPage.js +1 -1
- package/dist/pages/AgentGraphPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionCard.js","names":[],"sources":["../../../src/components/sessions/SessionCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Terminal,\n Clock,\n MoreVertical,\n Play,\n Square,\n RotateCcw,\n Trash2,\n Share2,\n} from 'lucide-react';\nimport { SessionStatusBadge } from './SessionStatusBadge';\nimport { AgentInfoPopover, TargetInfoPopover } from './EntityInfoPopover';\nimport type { Session } from './types';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface SessionCardProps {\n session: Session;\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n /** Callback to open the share dialog */\n onShare?: (session: Session) => void;\n /** Whether this card is selected for bulk operations */\n selected?: boolean;\n /** Toggle selection for bulk operations */\n onToggleSelect?: () => void;\n className?: string;\n}\n\nconst sessionTypeIcons: Record<string, string> = {\n TMUX: '🖥️',\n SSH: '🔐',\n TERMINAL: '💻',\n SCRIPT: '📜',\n CUSTOM: '⚙️',\n};\n\n/**\n * SessionCard - Display terminal session information\n */\nexport const SessionCard: FC<SessionCardProps> = ({\n session,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n selected = false,\n onToggleSelect,\n className = '',\n}) => {\n const tr = useTr();\n const [showMenu, setShowMenu] = useState(false);\n\n const formatTime = (timestamp: string | undefined | null) => {\n if (!timestamp) return 'Never';\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return 'Just now';\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n const isRunning = session.status === 'RUNNING';\n const isStopped = session.status === 'STOPPED' || session.status === 'TERMINATED';\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border rounded-card shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer ${selected ? 'border-transparent ring-1 ring-[var(--color-focus-ring)] bg-[var(--color-accent-soft)]' : 'border-border-subtle'} ${className}`}\n onClick={() => onOpen?.(session)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div className=\"flex-shrink-0 pt-0.5\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => {\n e.stopPropagation();\n onToggleSelect();\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"size-4 rounded border-border-default cursor-pointer\"\n />\n </div>\n )}\n <div className=\"flex-shrink-0 size-9 sm:size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Terminal className=\"size-4 sm:size-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5 sm:gap-2 flex-wrap\">\n <h3 className=\"font-semibold text-text-primary truncate max-w-[120px] sm:max-w-none text-sm sm:text-base tracking-tight\">\n {session.name}\n </h3>\n <span className=\"text-base sm:text-lg flex-shrink-0\">\n {sessionTypeIcons[session.type] || '💻'}\n </span>\n </div>\n <p className=\"text-xs sm:text-sm text-text-secondary\">{session.type}</p>\n {session.agent && (\n <div className=\"mt-1.5 flex items-center gap-1 flex-wrap\">\n <AgentInfoPopover agent={session.agent} />\n {session.agent.target && <TargetInfoPopover target={session.agent.target} />}\n </div>\n )}\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <SessionStatusBadge status={session.status} />\n {(onStart || onStop || onRestart || onTerminate) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"inline-flex size-8 items-center justify-center rounded-button text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n aria-label={tr('vibecontrols.sessions.card.actions', 'Session actions')}\n >\n <MoreVertical className=\"size-4\" aria-hidden=\"true\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1.5 w-44 bg-bg-elevated border border-border-subtle rounded-card shadow-elevation-3 z-10 overflow-hidden py-1\"\n >\n {isStopped && onStart && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onStart(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Play className=\"size-4\" />\n {tr('vibecontrols.sessions.card.start', 'Start')}\n </motion.button>\n )}\n {isRunning && onStop && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onStop(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Square className=\"size-4\" />\n {tr('vibecontrols.sessions.card.stop', 'Stop')}\n </motion.button>\n )}\n {isRunning && onRestart && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onRestart(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <RotateCcw className=\"size-4\" />\n {tr('vibecontrols.sessions.card.restart', 'Restart')}\n </motion.button>\n )}\n {isRunning && onOpenTerminal && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onOpenTerminal(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Terminal className=\"size-4\" />\n {tr('vibecontrols.sessions.card.openTerminal', 'Open Terminal')}\n </motion.button>\n )}\n {isRunning && onShare && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Share2 className=\"size-4\" />\n {tr('vibecontrols.sessions.card.shareSession', 'Share Session')}\n </motion.button>\n )}\n {onTerminate && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onTerminate(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <Trash2 className=\"size-4\" />\n {tr('vibecontrols.sessions.card.terminate', 'Terminate')}\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )}\n </div>\n </div>\n\n {/* Provider-native session name (e.g. tmux session name like\n `vibe-051c9c62`). Surfaced so users can recognise their session\n if they ever need to attach from a CLI (`tmux attach -t …`)\n and so reconnect-after-restart flows are obvious. */}\n {(() => {\n const meta = (session.metadata as Record<string, unknown> | null) || {};\n const externalName =\n (typeof meta.tmuxSessionName === 'string' && meta.tmuxSessionName) ||\n (typeof meta.weztermWorkspace === 'string' && meta.weztermWorkspace) ||\n (typeof meta.zellijSessionName === 'string' && meta.zellijSessionName) ||\n (typeof meta.externalSessionName === 'string' && meta.externalSessionName) ||\n session.providerSessionName ||\n null;\n return externalName ? (\n <div\n className=\"mt-3 text-[10px] font-mono text-text-muted\"\n title={`Provider session: ${externalName}`}\n data-testid=\"session-card-external-name\"\n >\n <span className=\"opacity-70\">{session.type.toLowerCase()}: </span>\n <span className=\"break-all\">{externalName}</span>\n </div>\n ) : null;\n })()}\n\n {session.command && (\n <div className=\"mt-4 text-xs font-mono bg-bg-sunken/60 px-2 py-1.5 rounded truncate text-text-secondary\">\n $ {session.command}\n </div>\n )}\n\n {session.lastOutput && (\n <div className=\"mt-2 text-xs font-mono bg-bg-sunken/60 text-status-success-text px-2 py-1.5 rounded truncate\">\n {session.lastOutput}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-between text-sm text-text-secondary\">\n <div className=\"flex items-center gap-2\">\n <Clock className=\"size-4\" />\n <span className=\"tabular-nums\">{formatTime(session.updatedAt)}</span>\n </div>\n {session.pid && <span className=\"text-xs font-mono tabular-nums\">PID: {session.pid}</span>}\n </div>\n </motion.div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionCard.js","names":[],"sources":["../../../src/components/sessions/SessionCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Terminal,\n Clock,\n MoreVertical,\n Play,\n Square,\n RotateCcw,\n Trash2,\n Share2,\n} from 'lucide-react';\nimport { SessionStatusBadge } from './SessionStatusBadge';\nimport { AgentInfoPopover, TargetInfoPopover } from './EntityInfoPopover';\nimport type { Session } from './types';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface SessionCardProps {\n session: Session;\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n /** Callback to open the share dialog */\n onShare?: (session: Session) => void;\n /** Whether this card is selected for bulk operations */\n selected?: boolean;\n /** Toggle selection for bulk operations */\n onToggleSelect?: () => void;\n className?: string;\n}\n\nconst sessionTypeIcons: Record<string, string> = {\n TMUX: '🖥️',\n SSH: '🔐',\n TERMINAL: '💻',\n SCRIPT: '📜',\n CUSTOM: '⚙️',\n};\n\n/**\n * SessionCard - Display terminal session information\n */\nexport const SessionCard: FC<SessionCardProps> = ({\n session,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n selected = false,\n onToggleSelect,\n className = '',\n}) => {\n const tr = useTr();\n const [showMenu, setShowMenu] = useState(false);\n\n const formatTime = (timestamp: string | undefined | null) => {\n if (!timestamp) return 'Never';\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return 'Just now';\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n const isRunning = session.status === 'RUNNING';\n const isStopped = session.status === 'STOPPED' || session.status === 'TERMINATED';\n\n return (\n <motion.div\n whileHover={{ transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border rounded-card shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer ${selected ? 'border-transparent ring-1 ring-[var(--color-focus-ring)] bg-[var(--color-accent-soft)]' : 'border-border-subtle'} ${className}`}\n onClick={() => onOpen?.(session)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div className=\"flex-shrink-0 pt-0.5\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => {\n e.stopPropagation();\n onToggleSelect();\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"size-4 rounded border-border-default cursor-pointer\"\n />\n </div>\n )}\n <div className=\"flex-shrink-0 size-9 sm:size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Terminal className=\"size-4 sm:size-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5 sm:gap-2 flex-wrap\">\n <h3 className=\"font-semibold text-text-primary truncate max-w-[120px] sm:max-w-none text-sm sm:text-base tracking-tight\">\n {session.name}\n </h3>\n <span className=\"text-base sm:text-lg flex-shrink-0\">\n {sessionTypeIcons[session.type] || '💻'}\n </span>\n </div>\n <p className=\"text-xs sm:text-sm text-text-secondary\">{session.type}</p>\n {session.agent && (\n <div className=\"mt-1.5 flex items-center gap-1 flex-wrap\">\n <AgentInfoPopover agent={session.agent} />\n {session.agent.target && <TargetInfoPopover target={session.agent.target} />}\n </div>\n )}\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <SessionStatusBadge status={session.status} />\n {(onStart || onStop || onRestart || onTerminate) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"inline-flex size-8 items-center justify-center rounded-button text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n aria-label={tr('vibecontrols.sessions.card.actions', 'Session actions')}\n >\n <MoreVertical className=\"size-4\" aria-hidden=\"true\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1.5 w-44 bg-bg-elevated border border-border-subtle rounded-card shadow-elevation-3 z-10 overflow-hidden py-1\"\n >\n {isStopped && onStart && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onStart(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Play className=\"size-4\" />\n {tr('vibecontrols.sessions.card.start', 'Start')}\n </motion.button>\n )}\n {isRunning && onStop && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onStop(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Square className=\"size-4\" />\n {tr('vibecontrols.sessions.card.stop', 'Stop')}\n </motion.button>\n )}\n {isRunning && onRestart && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onRestart(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <RotateCcw className=\"size-4\" />\n {tr('vibecontrols.sessions.card.restart', 'Restart')}\n </motion.button>\n )}\n {isRunning && onOpenTerminal && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onOpenTerminal(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Terminal className=\"size-4\" />\n {tr('vibecontrols.sessions.card.openTerminal', 'Open Terminal')}\n </motion.button>\n )}\n {isRunning && onShare && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onShare(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Share2 className=\"size-4\" />\n {tr('vibecontrols.sessions.card.shareSession', 'Share Session')}\n </motion.button>\n )}\n {onTerminate && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onTerminate(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <Trash2 className=\"size-4\" />\n {tr('vibecontrols.sessions.card.terminate', 'Terminate')}\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )}\n </div>\n </div>\n\n {/* Provider-native session name (e.g. tmux session name like\n `vibe-051c9c62`). Surfaced so users can recognise their session\n if they ever need to attach from a CLI (`tmux attach -t …`)\n and so reconnect-after-restart flows are obvious. */}\n {(() => {\n const meta = (session.metadata as Record<string, unknown> | null) || {};\n const externalName =\n (typeof meta.tmuxSessionName === 'string' && meta.tmuxSessionName) ||\n (typeof meta.weztermWorkspace === 'string' && meta.weztermWorkspace) ||\n (typeof meta.zellijSessionName === 'string' && meta.zellijSessionName) ||\n (typeof meta.externalSessionName === 'string' && meta.externalSessionName) ||\n session.providerSessionName ||\n null;\n return externalName ? (\n <div\n className=\"mt-3 text-[10px] font-mono text-text-muted\"\n title={`Provider session: ${externalName}`}\n data-testid=\"session-card-external-name\"\n >\n <span className=\"opacity-70\">{session.type.toLowerCase()}: </span>\n <span className=\"break-all\">{externalName}</span>\n </div>\n ) : null;\n })()}\n\n {session.command && (\n <div className=\"mt-4 text-xs font-mono bg-bg-sunken/60 px-2 py-1.5 rounded truncate text-text-secondary\">\n $ {session.command}\n </div>\n )}\n\n {session.lastOutput && (\n <div className=\"mt-2 text-xs font-mono bg-bg-sunken/60 text-status-success-text px-2 py-1.5 rounded truncate\">\n {session.lastOutput}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-between text-sm text-text-secondary\">\n <div className=\"flex items-center gap-2\">\n <Clock className=\"size-4\" />\n <span className=\"tabular-nums\">{formatTime(session.updatedAt)}</span>\n </div>\n {session.pid && <span className=\"text-xs font-mono tabular-nums\">PID: {session.pid}</span>}\n </div>\n </motion.div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ function t({ children: t, className: n = "", onClick: r, hoverable: i = !1, padd
|
|
|
8
8
|
lg: "p-6"
|
|
9
9
|
}[a]}`;
|
|
10
10
|
return /* @__PURE__ */ e(r ? "button" : "div", {
|
|
11
|
-
className: `${o} ${i || r ? "hover:border-border-strong hover:shadow-elevation-2
|
|
11
|
+
className: `${o} ${i || r ? "hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer" : ""} ${n}`,
|
|
12
12
|
onClick: r,
|
|
13
13
|
children: t
|
|
14
14
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.js","names":[],"sources":["../../../src/components/shared/Card.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n onClick?: () => void;\n hoverable?: boolean;\n padding?: 'none' | 'sm' | 'md' | 'lg';\n}\n\nexport function Card({\n children,\n className = '',\n onClick,\n hoverable = false,\n padding = 'md',\n}: CardProps) {\n const paddingStyles = {\n none: '',\n sm: 'p-4',\n md: 'p-5',\n lg: 'p-6',\n };\n\n const baseStyles = `bg-bg-surface border border-border-subtle rounded-card shadow-elevation-1 ${paddingStyles[padding]}`;\n const isInteractive = hoverable || !!onClick;\n\n // Boff UI interactive card: calm border + elevation lift + ≤2px translate on\n // hover. `transition-all duration-200` with the easing token; reduced-motion\n // is handled globally so the lift is safe.\n const interactiveStyles = isInteractive\n ? 'hover:border-border-strong hover:shadow-elevation-2
|
|
1
|
+
{"version":3,"file":"Card.js","names":[],"sources":["../../../src/components/shared/Card.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n onClick?: () => void;\n hoverable?: boolean;\n padding?: 'none' | 'sm' | 'md' | 'lg';\n}\n\nexport function Card({\n children,\n className = '',\n onClick,\n hoverable = false,\n padding = 'md',\n}: CardProps) {\n const paddingStyles = {\n none: '',\n sm: 'p-4',\n md: 'p-5',\n lg: 'p-6',\n };\n\n const baseStyles = `bg-bg-surface border border-border-subtle rounded-card shadow-elevation-1 ${paddingStyles[padding]}`;\n const isInteractive = hoverable || !!onClick;\n\n // Boff UI interactive card: calm border + elevation lift + ≤2px translate on\n // hover. `transition-all duration-200` with the easing token; reduced-motion\n // is handled globally so the lift is safe.\n const interactiveStyles = isInteractive\n ? 'hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer'\n : '';\n\n const Component = onClick ? 'button' : 'div';\n\n return (\n <Component className={`${baseStyles} ${interactiveStyles} ${className}`} onClick={onClick}>\n {children}\n </Component>\n );\n}\n\ninterface CardHeaderProps {\n title: string;\n subtitle?: string;\n action?: ReactNode;\n icon?: ReactNode;\n}\n\nexport function CardHeader({ title, subtitle, action, icon }: CardHeaderProps) {\n return (\n <div className=\"flex items-start justify-between gap-3 mb-4\">\n <div className=\"flex items-start gap-3 min-w-0\">\n {icon && (\n <div className=\"flex-shrink-0 size-9 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n {icon}\n </div>\n )}\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-text-primary truncate tracking-tight\">{title}</h3>\n {subtitle && <p className=\"text-sm text-text-secondary truncate\">{subtitle}</p>}\n </div>\n </div>\n {action && <div className=\"flex-shrink-0\">{action}</div>}\n </div>\n );\n}\n\ninterface CardContentProps {\n children: ReactNode;\n className?: string;\n}\n\nexport function CardContent({ children, className = '' }: CardContentProps) {\n return <div className={className}>{children}</div>;\n}\n\ninterface CardFooterProps {\n children: ReactNode;\n className?: string;\n}\n\nexport function CardFooter({ children, className = '' }: CardFooterProps) {\n return <div className={`mt-5 pt-4 border-t border-border-subtle ${className}`}>{children}</div>;\n}\n"],"mappings":";;AAUA,SAAgB,EAAK,EACnB,aACA,eAAY,IACZ,YACA,eAAY,IACZ,aAAU,QACE;CAQZ,IAAM,IAAa,6EAPG;EACpB,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,CAE6G;AAY9G,QACE,kBAHgB,IAAU,WAAW,OAGrC;EAAW,WAAW,GAAG,EAAW,GAZhB,KAAe,IAMjC,mIACA,GAKuD,GAAG;EAAsB;EAC/E;EACS,CAAA"}
|
|
@@ -10,7 +10,7 @@ function o({ title: o, value: s, subtitle: c, icon: l, trend: u, variant: d = "d
|
|
|
10
10
|
success: "bg-status-success-bg-subtle",
|
|
11
11
|
warning: "bg-status-warning-bg-subtle",
|
|
12
12
|
error: "bg-status-error-bg-subtle"
|
|
13
|
-
}[d]} ${f ? "hover:border-border-strong hover:shadow-elevation-2
|
|
13
|
+
}[d]} ${f ? "hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left" : ""}`,
|
|
14
14
|
children: /* @__PURE__ */ i("div", {
|
|
15
15
|
className: "flex flex-col gap-2.5",
|
|
16
16
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/components/shared/StatCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { AnimatedCounter } from '@burdenoff/fe-libs/shared/motion';\n\ninterface StatCardProps {\n title: string;\n value: string | number;\n subtitle?: string;\n icon?: ReactNode;\n trend?: {\n value: number;\n label?: string;\n };\n variant?: 'default' | 'success' | 'warning' | 'error';\n onClick?: () => void;\n}\n\nexport function StatCard({\n title,\n value,\n subtitle,\n icon,\n trend,\n variant = 'default',\n onClick,\n}: StatCardProps) {\n const variantStyles = {\n default: 'bg-bg-surface',\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n error: 'bg-status-error-bg-subtle',\n };\n\n // Subtle tint + same-hue saturated text (passes AA in both themes); the old\n // solid `bg-status-X-bg` + `text-status-X-text` was same-hue low-contrast.\n // The neutral/default tile uses the brand accent wash so metric cards lead\n // with the theme accent rather than a flat grey.\n const iconVariantStyles = {\n default: 'bg-[var(--color-accent-soft)] text-text-primary',\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n };\n\n const Component = onClick ? 'button' : 'div';\n\n return (\n <Component\n onClick={onClick}\n className={`p-5 rounded-card border border-border-subtle shadow-elevation-1 ${variantStyles[variant]} ${onClick ? 'hover:border-border-strong hover:shadow-elevation-2
|
|
1
|
+
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/components/shared/StatCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { AnimatedCounter } from '@burdenoff/fe-libs/shared/motion';\n\ninterface StatCardProps {\n title: string;\n value: string | number;\n subtitle?: string;\n icon?: ReactNode;\n trend?: {\n value: number;\n label?: string;\n };\n variant?: 'default' | 'success' | 'warning' | 'error';\n onClick?: () => void;\n}\n\nexport function StatCard({\n title,\n value,\n subtitle,\n icon,\n trend,\n variant = 'default',\n onClick,\n}: StatCardProps) {\n const variantStyles = {\n default: 'bg-bg-surface',\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n error: 'bg-status-error-bg-subtle',\n };\n\n // Subtle tint + same-hue saturated text (passes AA in both themes); the old\n // solid `bg-status-X-bg` + `text-status-X-text` was same-hue low-contrast.\n // The neutral/default tile uses the brand accent wash so metric cards lead\n // with the theme accent rather than a flat grey.\n const iconVariantStyles = {\n default: 'bg-[var(--color-accent-soft)] text-text-primary',\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n };\n\n const Component = onClick ? 'button' : 'div';\n\n return (\n <Component\n onClick={onClick}\n className={`p-5 rounded-card border border-border-subtle shadow-elevation-1 ${variantStyles[variant]} ${onClick ? 'hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left' : ''}`}\n >\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-medium text-text-secondary\">{title}</p>\n {icon && (\n <div\n className={`flex-shrink-0 size-9 rounded-lg flex items-center justify-center ${iconVariantStyles[variant]} [&>svg]:w-4 [&>svg]:h-4`}\n >\n {icon}\n </div>\n )}\n </div>\n <div className=\"text-2xl font-semibold text-text-primary tabular-nums\">\n {typeof value === 'number' ? <AnimatedCounter value={value} /> : value}\n </div>\n {subtitle && <p className=\"text-xs text-text-secondary\">{subtitle}</p>}\n {trend && (\n <div className=\"flex items-center gap-1\">\n {trend.value > 0 ? (\n <TrendingUp className=\"size-4 text-status-success-text\" />\n ) : trend.value < 0 ? (\n <TrendingDown className=\"size-4 text-status-error-text\" />\n ) : (\n <Minus className=\"size-4 text-text-secondary\" />\n )}\n <span\n className={`text-xs font-medium tabular-nums ${\n trend.value > 0\n ? 'text-status-success-text'\n : trend.value < 0\n ? 'text-status-error-text'\n : 'text-text-secondary'\n }`}\n >\n {trend.value > 0 ? '+' : ''}\n {trend.value}%\n </span>\n {trend.label && <span className=\"text-xs text-text-secondary\">{trend.label}</span>}\n </div>\n )}\n </div>\n </Component>\n );\n}\n"],"mappings":";;;;AAiBA,SAAgB,EAAS,EACvB,UACA,UACA,aACA,SACA,UACA,aAAU,WACV,cACgB;AAqBhB,QACE,kBAHgB,IAAU,WAAW,OAGrC;EACW;EACT,WAAW,mEAvBO;GACpB,SAAS;GACT,SAAS;GACT,SAAS;GACT,OAAO;GACR,CAkB+F,GAAS,GAAG,IAAU,oJAAoJ;YAEtQ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAA2C;MAAU,CAAA,EACjE,KACC,kBAAC,OAAD;MACE,WAAW,oEAnBG;OACxB,SAAS;OACT,SAAS;OACT,SAAS;OACT,OAAO;OACR,CAc4G,GAAS;gBAEzG;MACG,CAAA,CAEJ;;IACN,kBAAC,OAAD;KAAK,WAAU;eACZ,OAAO,KAAU,WAAW,kBAAC,GAAD,EAAwB,UAAS,CAAA,GAAG;KAC7D,CAAA;IACL,KAAY,kBAAC,KAAD;KAAG,WAAU;eAA+B;KAAa,CAAA;IACrE,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAM,QAAQ,IACb,kBAAC,GAAD,EAAY,WAAU,mCAAoC,CAAA,GACxD,EAAM,QAAQ,IAChB,kBAAC,GAAD,EAAc,WAAU,iCAAkC,CAAA,GAE1D,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA;MAElD,kBAAC,QAAD;OACE,WAAW,oCACT,EAAM,QAAQ,IACV,6BACA,EAAM,QAAQ,IACZ,2BACA;iBANV;QASG,EAAM,QAAQ,IAAI,MAAM;QACxB,EAAM;QAAM;QACR;;MACN,EAAM,SAAS,kBAAC,QAAD;OAAM,WAAU;iBAA+B,EAAM;OAAa,CAAA;MAC9E;;IAEJ;;EACI,CAAA"}
|
|
@@ -18,7 +18,7 @@ function m({ tunnel: m, isPending: h = !1, onOpen: g, onStart: _, onStop: v, onD
|
|
|
18
18
|
opacity: 1,
|
|
19
19
|
y: 0
|
|
20
20
|
},
|
|
21
|
-
className: "rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2
|
|
21
|
+
className: "rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)]",
|
|
22
22
|
children: [/* @__PURE__ */ p("div", {
|
|
23
23
|
className: "flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",
|
|
24
24
|
children: [/* @__PURE__ */ p("button", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n // Mutation callbacks are optional: the parent omits them when the actor\n // lacks the permission (tunnel:execute for start/stop, tunnel:delete), so\n // the corresponding control is hidden rather than 403-ing on click.\n onStart?: (id: string) => void;\n onStop?: (id: string) => void;\n onDelete?: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2
|
|
1
|
+
{"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n // Mutation callbacks are optional: the parent omits them when the actor\n // lacks the permission (tunnel:execute for start/stop, tunnel:delete), so\n // the corresponding control is hidden rather than 403-ing on click.\n onStart?: (id: string) => void;\n onStop?: (id: string) => void;\n onDelete?: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)]\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded-button\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1.5\">\n <h3 className=\"text-base font-semibold text-text-primary truncate tracking-tight\">\n {tunnel.name}\n </h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs font-mono text-text-muted mt-1 tabular-nums\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-button border border-border-subtle bg-bg-sunken px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1.5 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && onStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-button bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text hover:bg-action-primary-bgHover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <Play className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && onStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n >\n <Square className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-2 py-1.5 text-xs text-status-error-text hover:bg-status-error-bg-subtle hover:border-status-error-border transition-colors\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n )}\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-4 rounded-button border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAO;QACL,CAAA;OACL,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,mBAAoB,CAAA,EAC3C,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,gCAAiC,CAAA,EACnD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KAAY,KACX,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,mBAAoB,CAAA,EACnC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KAAW,KACV,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,mBAAoB,CAAA,EACrC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACD,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KAEP;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
|
|
@@ -148,7 +148,7 @@ function y() {
|
|
|
148
148
|
});
|
|
149
149
|
let $ = I.length > 0;
|
|
150
150
|
return /* @__PURE__ */ _(_e, {
|
|
151
|
-
className: "flex h-full min-h-0 flex-col",
|
|
151
|
+
className: "flex h-full min-h-0 flex-col px-6 lg:px-8 pt-6",
|
|
152
152
|
children: [
|
|
153
153
|
/* @__PURE__ */ g(o, {
|
|
154
154
|
title: x("nav.agentGraph", "Agent Mesh"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent MESH graph.\n *\n * Agents are first-class nodes; AgentMeshLinks are the directed agent->agent\n * edges. Supports root-agent scoping, RBAC permission editing on links, a\n * \"Deploy Agent\" wizard, and an on-demand mesh request panel + per-node\n * quick-actions.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network, Rocket, Send, ShieldAlert } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { notify } from '@/lib/toast';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentMeshGraphQuery,\n useUpdateMeshLinkPermissionsMutation,\n useStartMeshAgentSessionMutation,\n useWakeMeshAgentMutation,\n useAgentConnectionConfigQuery,\n} from '@/generated/wspace-operations';\nimport { MeshSessionKind } from '@/generated/wspace-types';\nimport type { GetAgentMeshGraphQuery } from '@/generated/wspace-operations';\nimport { MeshGraphView } from '@/components/graph/MeshGraphView';\nimport { MeshDeployWizard } from '@/components/graph/MeshDeployWizard';\nimport { MeshRequestPanel } from '@/components/graph/MeshRequestPanel';\nimport { MeshNodeActions } from '@/components/graph/MeshNodeActions';\nimport type { MeshAgentUi, MeshLinkUi } from '@/components/graph/meshTypes';\n\nexport function AgentGraphPage() {\n const { workspaceId, currentUser } = useVibeControls();\n const navigate = useVibeNavigate();\n const tr = useTr();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const { agents: cachedAgents } = useCachedInitialData();\n\n const scopeOptions = useMemo(\n () =>\n cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n })),\n [cachedAgents, tr]\n );\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n refetch,\n } = useGetAgentMeshGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedMeshGraph: GetAgentMeshGraphQuery['agentMeshGraph'] | undefined =\n graphData?.agentMeshGraph ?? previousData?.agentMeshGraph;\n\n type MeshGraphAgent = GetAgentMeshGraphQuery['agentMeshGraph']['agents'][number];\n type MeshGraphLink = GetAgentMeshGraphQuery['agentMeshGraph']['meshLinks'][number];\n\n // Map generated shapes (enum target.type) into the plain UI shapes.\n const meshAgents = useMemo<MeshAgentUi[]>(\n () =>\n (resolvedMeshGraph?.agents ?? []).map((a: MeshGraphAgent) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n platform: a.platform,\n version: a.version,\n isActive: a.isActive,\n ownerUserId: a.ownerUserId ?? null,\n targetId: a.targetId,\n tunnelStatus: a.tunnelStatus ?? null,\n target: a.target\n ? {\n id: a.target.id,\n name: a.target.name,\n type: String(a.target.type),\n host: a.target.host ?? null,\n }\n : null,\n })),\n [resolvedMeshGraph]\n );\n\n const meshLinks = useMemo<MeshLinkUi[]>(\n () =>\n (resolvedMeshGraph?.meshLinks ?? []).map((l: MeshGraphLink) => ({\n id: l.id,\n workspaceId: l.workspaceId,\n status: l.status,\n permissions: l.permissions,\n scopes: l.scopes,\n label: l.label ?? null,\n description: l.description ?? null,\n createdAt: l.createdAt,\n updatedAt: l.updatedAt,\n sourceAgent: { id: l.sourceAgent.id, name: l.sourceAgent.name },\n destinationAgent: {\n id: l.destinationAgent.id,\n name: l.destinationAgent.name,\n hostname: l.destinationAgent.hostname,\n target: l.destinationAgent.target\n ? {\n id: l.destinationAgent.target.id,\n name: l.destinationAgent.target.name,\n type: String(l.destinationAgent.target.type),\n host: l.destinationAgent.target.host ?? null,\n }\n : null,\n },\n })),\n [resolvedMeshGraph]\n );\n\n const isGraphLoading = loading;\n const isInitialLoad = isGraphLoading && !resolvedMeshGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedMeshGraph);\n\n // Source agents available to act as deploy root / request root: prefer the\n // mesh agents (already scoped), fall back to the cached fleet.\n const sourceAgents = useMemo(\n () =>\n meshAgents.length > 0\n ? meshAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n }))\n : cachedAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n })),\n [meshAgents, cachedAgents]\n );\n\n const [updateMeshLinkPerms] = useUpdateMeshLinkPermissionsMutation();\n const [startMeshSession] = useStartMeshAgentSessionMutation();\n const [wakeMeshAgent] = useWakeMeshAgentMutation();\n\n // ── UI panels ──────────────────────────────────────────────────────────\n const [showDeployWizard, setShowDeployWizard] = useState(false);\n const [deploySeedSourceId, setDeploySeedSourceId] = useState<string | null>(null);\n const [showRequestPanel, setShowRequestPanel] = useState(false);\n const [requestDestinationId, setRequestDestinationId] = useState<string | null>(null);\n const [actionsForAgentId, setActionsForAgentId] = useState<string | null>(null);\n\n const handleUpdatePermissions = useCallback(\n async (meshLinkId: string, perms: string[], scopes: string[]) => {\n await updateMeshLinkPerms({\n variables: { meshLinkId, input: { permissions: perms, scopes } },\n });\n await refetch();\n },\n [refetch, updateMeshLinkPerms]\n );\n\n // The \"request root\" is the scoped root agent, else the first source agent.\n const requestRootAgentId = rootAgentId ?? sourceAgents[0]?.id ?? null;\n\n const handleStartTerminal = useCallback(\n async (agentId: string) => {\n setActionsForAgentId(null);\n // For a DIRECT / root agent, prefer the existing terminal flow.\n if (requestRootAgentId && agentId === requestRootAgentId) {\n navigate(`/agents/${agentId}?tab=terminal`);\n return;\n }\n if (!requestRootAgentId) {\n notify.error(\n tr('mesh.terminal.noRoot', 'No reachable root agent to start a terminal from.')\n );\n return;\n }\n try {\n await startMeshSession({\n variables: {\n rootAgentId: requestRootAgentId,\n destinationAgentId: agentId,\n input: { kind: MeshSessionKind.Terminal },\n },\n });\n // If the agent route ever lands, navigate; for now this rarely succeeds.\n navigate(`/agents/${agentId}?tab=terminal`);\n } catch {\n notify.info(tr('mesh.terminal.comingSoon', 'Deep-terminal coming soon'));\n }\n },\n [requestRootAgentId, startMeshSession, navigate, tr]\n );\n\n const handleRunCommand = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setRequestDestinationId(agentId);\n setShowRequestPanel(true);\n }, []);\n\n const handleDeployFromHere = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setDeploySeedSourceId(agentId);\n setShowDeployWizard(true);\n }, []);\n\n const handleWakeViaSsh = useCallback(\n async (agentId: string) => {\n const agentName = meshAgents.find((a) => a.id === agentId)?.name ?? agentId;\n notify.info(tr('mesh.wake.starting', 'Reconnecting {{name}} over SSH…', { name: agentName }));\n try {\n const { data } = await wakeMeshAgent({ variables: { agentId } });\n const result = data?.wakeMeshAgent;\n if (result?.ok) {\n notify.success(tr('mesh.wake.success', '{{name}} is back online', { name: agentName }));\n await refetch();\n } else {\n notify.error(\n result?.error ??\n tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n }\n } catch (err) {\n notify.error(\n err instanceof Error\n ? err.message\n : tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n } finally {\n setActionsForAgentId(null);\n }\n },\n [meshAgents, wakeMeshAgent, refetch, tr]\n );\n\n const handleOpenAgent = useCallback(\n (agentId: string) => {\n setActionsForAgentId(null);\n navigate(`/agents/${agentId}`);\n },\n [navigate]\n );\n\n const handleNodeClick = useCallback((agentId: string) => {\n setActionsForAgentId(agentId);\n }, []);\n\n const actionsAgent = useMemo(\n () => meshAgents.find((a) => a.id === actionsForAgentId) ?? null,\n [meshAgents, actionsForAgentId]\n );\n\n if (permissionsLoading)\n return <LoadingState message={tr('agentGraph.loadingPermissions', 'Loading permissions...')} />;\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <EmptyState\n icon={<ShieldAlert className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'agentGraph.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n />\n );\n\n const hasAgents = meshAgents.length > 0;\n\n return (\n <MotionPage className=\"flex h-full min-h-0 flex-col\">\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Mesh')}\n description={tr(\n 'agentGraph.meshDescription',\n 'Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops.'\n )}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRequestPanel((v) => !v);\n setRequestDestinationId(null);\n }}\n >\n <Send className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.requestPanelToggle', 'Mesh request')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n setDeploySeedSourceId(rootAgentId);\n setShowDeployWizard(true);\n }}\n disabled={sourceAgents.length === 0}\n >\n <Rocket className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.deployButton', 'Deploy Agent')}\n </Button>\n </div>\n }\n />\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent mesh...')} />\n )}\n\n {!isGraphLoading && error && !hasAgents && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && !hasAgents && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noAgentsConnected', 'No agents in the mesh')}\n description={tr(\n 'agentGraph.noAgentsDescription',\n 'Deploy an agent to start building your agent mesh topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Mesh in VibeControls and how do I deploy agents?\" />\n }\n />\n )}\n\n {showRequestPanel && (\n <div className=\"mt-4\">\n <MeshRequestPanel\n rootAgentId={requestRootAgentId}\n destinations={meshAgents}\n initialDestinationId={requestDestinationId}\n onClose={() => setShowRequestPanel(false)}\n />\n </div>\n )}\n\n {(hasAgents || scopeValue || isRefreshingGraph) && (\n <>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <GitBranch className=\"size-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.meshCountSummary', '{{agents}} agents, {{links}} links', {\n agents: meshAgents.length,\n links: meshLinks.length,\n })}\n </span>\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2\n className=\"size-3.5 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"shrink-0 text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </span>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n setRootAgentId(v || null);\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAllAgents', 'All agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !hasAgents && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeAgentDescription',\n 'No agents match the selected scope. Clear the filter to view the full mesh.'\n )}\n />\n )}\n\n {(hasAgents || isRefreshingGraph) && (\n <div className=\"relative mt-4 min-h-[24rem] flex-1\" aria-busy={isRefreshingGraph}>\n <MeshGraphView\n agents={meshAgents}\n meshLinks={meshLinks}\n currentUserId={currentUser?.id ?? null}\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeClick}\n fullHeight\n />\n\n {/* Node quick-actions popover */}\n {actionsAgent && (\n <div className=\"absolute right-4 top-4 z-20\">\n <MeshNodeActions\n agent={actionsAgent}\n onRunCommand={handleRunCommand}\n onStartTerminal={(id) => void handleStartTerminal(id)}\n onDeployFromHere={handleDeployFromHere}\n onWakeViaSsh={handleWakeViaSsh}\n onOpenAgent={handleOpenAgent}\n onClose={() => setActionsForAgentId(null)}\n />\n </div>\n )}\n\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div\n role=\"status\"\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-[var(--shadow-elevation-2)]\"\n >\n <Loader2\n className=\"size-4 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {showDeployWizard && (\n <MeshDeployWizard\n sourceAgents={sourceAgents}\n initialSourceAgentId={deploySeedSourceId}\n availablePermissions={availablePermissions}\n onClose={() => setShowDeployWizard(false)}\n onCompleted={() => {\n void refetch();\n }}\n />\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent MESH graph.\n *\n * Agents are first-class nodes; AgentMeshLinks are the directed agent->agent\n * edges. Supports root-agent scoping, RBAC permission editing on links, a\n * \"Deploy Agent\" wizard, and an on-demand mesh request panel + per-node\n * quick-actions.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network, Rocket, Send, ShieldAlert } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { notify } from '@/lib/toast';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentMeshGraphQuery,\n useUpdateMeshLinkPermissionsMutation,\n useStartMeshAgentSessionMutation,\n useWakeMeshAgentMutation,\n useAgentConnectionConfigQuery,\n} from '@/generated/wspace-operations';\nimport { MeshSessionKind } from '@/generated/wspace-types';\nimport type { GetAgentMeshGraphQuery } from '@/generated/wspace-operations';\nimport { MeshGraphView } from '@/components/graph/MeshGraphView';\nimport { MeshDeployWizard } from '@/components/graph/MeshDeployWizard';\nimport { MeshRequestPanel } from '@/components/graph/MeshRequestPanel';\nimport { MeshNodeActions } from '@/components/graph/MeshNodeActions';\nimport type { MeshAgentUi, MeshLinkUi } from '@/components/graph/meshTypes';\n\nexport function AgentGraphPage() {\n const { workspaceId, currentUser } = useVibeControls();\n const navigate = useVibeNavigate();\n const tr = useTr();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const { agents: cachedAgents } = useCachedInitialData();\n\n const scopeOptions = useMemo(\n () =>\n cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n })),\n [cachedAgents, tr]\n );\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n refetch,\n } = useGetAgentMeshGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedMeshGraph: GetAgentMeshGraphQuery['agentMeshGraph'] | undefined =\n graphData?.agentMeshGraph ?? previousData?.agentMeshGraph;\n\n type MeshGraphAgent = GetAgentMeshGraphQuery['agentMeshGraph']['agents'][number];\n type MeshGraphLink = GetAgentMeshGraphQuery['agentMeshGraph']['meshLinks'][number];\n\n // Map generated shapes (enum target.type) into the plain UI shapes.\n const meshAgents = useMemo<MeshAgentUi[]>(\n () =>\n (resolvedMeshGraph?.agents ?? []).map((a: MeshGraphAgent) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n platform: a.platform,\n version: a.version,\n isActive: a.isActive,\n ownerUserId: a.ownerUserId ?? null,\n targetId: a.targetId,\n tunnelStatus: a.tunnelStatus ?? null,\n target: a.target\n ? {\n id: a.target.id,\n name: a.target.name,\n type: String(a.target.type),\n host: a.target.host ?? null,\n }\n : null,\n })),\n [resolvedMeshGraph]\n );\n\n const meshLinks = useMemo<MeshLinkUi[]>(\n () =>\n (resolvedMeshGraph?.meshLinks ?? []).map((l: MeshGraphLink) => ({\n id: l.id,\n workspaceId: l.workspaceId,\n status: l.status,\n permissions: l.permissions,\n scopes: l.scopes,\n label: l.label ?? null,\n description: l.description ?? null,\n createdAt: l.createdAt,\n updatedAt: l.updatedAt,\n sourceAgent: { id: l.sourceAgent.id, name: l.sourceAgent.name },\n destinationAgent: {\n id: l.destinationAgent.id,\n name: l.destinationAgent.name,\n hostname: l.destinationAgent.hostname,\n target: l.destinationAgent.target\n ? {\n id: l.destinationAgent.target.id,\n name: l.destinationAgent.target.name,\n type: String(l.destinationAgent.target.type),\n host: l.destinationAgent.target.host ?? null,\n }\n : null,\n },\n })),\n [resolvedMeshGraph]\n );\n\n const isGraphLoading = loading;\n const isInitialLoad = isGraphLoading && !resolvedMeshGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedMeshGraph);\n\n // Source agents available to act as deploy root / request root: prefer the\n // mesh agents (already scoped), fall back to the cached fleet.\n const sourceAgents = useMemo(\n () =>\n meshAgents.length > 0\n ? meshAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n }))\n : cachedAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n })),\n [meshAgents, cachedAgents]\n );\n\n const [updateMeshLinkPerms] = useUpdateMeshLinkPermissionsMutation();\n const [startMeshSession] = useStartMeshAgentSessionMutation();\n const [wakeMeshAgent] = useWakeMeshAgentMutation();\n\n // ── UI panels ──────────────────────────────────────────────────────────\n const [showDeployWizard, setShowDeployWizard] = useState(false);\n const [deploySeedSourceId, setDeploySeedSourceId] = useState<string | null>(null);\n const [showRequestPanel, setShowRequestPanel] = useState(false);\n const [requestDestinationId, setRequestDestinationId] = useState<string | null>(null);\n const [actionsForAgentId, setActionsForAgentId] = useState<string | null>(null);\n\n const handleUpdatePermissions = useCallback(\n async (meshLinkId: string, perms: string[], scopes: string[]) => {\n await updateMeshLinkPerms({\n variables: { meshLinkId, input: { permissions: perms, scopes } },\n });\n await refetch();\n },\n [refetch, updateMeshLinkPerms]\n );\n\n // The \"request root\" is the scoped root agent, else the first source agent.\n const requestRootAgentId = rootAgentId ?? sourceAgents[0]?.id ?? null;\n\n const handleStartTerminal = useCallback(\n async (agentId: string) => {\n setActionsForAgentId(null);\n // For a DIRECT / root agent, prefer the existing terminal flow.\n if (requestRootAgentId && agentId === requestRootAgentId) {\n navigate(`/agents/${agentId}?tab=terminal`);\n return;\n }\n if (!requestRootAgentId) {\n notify.error(\n tr('mesh.terminal.noRoot', 'No reachable root agent to start a terminal from.')\n );\n return;\n }\n try {\n await startMeshSession({\n variables: {\n rootAgentId: requestRootAgentId,\n destinationAgentId: agentId,\n input: { kind: MeshSessionKind.Terminal },\n },\n });\n // If the agent route ever lands, navigate; for now this rarely succeeds.\n navigate(`/agents/${agentId}?tab=terminal`);\n } catch {\n notify.info(tr('mesh.terminal.comingSoon', 'Deep-terminal coming soon'));\n }\n },\n [requestRootAgentId, startMeshSession, navigate, tr]\n );\n\n const handleRunCommand = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setRequestDestinationId(agentId);\n setShowRequestPanel(true);\n }, []);\n\n const handleDeployFromHere = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setDeploySeedSourceId(agentId);\n setShowDeployWizard(true);\n }, []);\n\n const handleWakeViaSsh = useCallback(\n async (agentId: string) => {\n const agentName = meshAgents.find((a) => a.id === agentId)?.name ?? agentId;\n notify.info(tr('mesh.wake.starting', 'Reconnecting {{name}} over SSH…', { name: agentName }));\n try {\n const { data } = await wakeMeshAgent({ variables: { agentId } });\n const result = data?.wakeMeshAgent;\n if (result?.ok) {\n notify.success(tr('mesh.wake.success', '{{name}} is back online', { name: agentName }));\n await refetch();\n } else {\n notify.error(\n result?.error ??\n tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n }\n } catch (err) {\n notify.error(\n err instanceof Error\n ? err.message\n : tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n } finally {\n setActionsForAgentId(null);\n }\n },\n [meshAgents, wakeMeshAgent, refetch, tr]\n );\n\n const handleOpenAgent = useCallback(\n (agentId: string) => {\n setActionsForAgentId(null);\n navigate(`/agents/${agentId}`);\n },\n [navigate]\n );\n\n const handleNodeClick = useCallback((agentId: string) => {\n setActionsForAgentId(agentId);\n }, []);\n\n const actionsAgent = useMemo(\n () => meshAgents.find((a) => a.id === actionsForAgentId) ?? null,\n [meshAgents, actionsForAgentId]\n );\n\n if (permissionsLoading)\n return <LoadingState message={tr('agentGraph.loadingPermissions', 'Loading permissions...')} />;\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <EmptyState\n icon={<ShieldAlert className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'agentGraph.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n />\n );\n\n const hasAgents = meshAgents.length > 0;\n\n return (\n <MotionPage className=\"flex h-full min-h-0 flex-col px-6 lg:px-8 pt-6\">\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Mesh')}\n description={tr(\n 'agentGraph.meshDescription',\n 'Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops.'\n )}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRequestPanel((v) => !v);\n setRequestDestinationId(null);\n }}\n >\n <Send className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.requestPanelToggle', 'Mesh request')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n setDeploySeedSourceId(rootAgentId);\n setShowDeployWizard(true);\n }}\n disabled={sourceAgents.length === 0}\n >\n <Rocket className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.deployButton', 'Deploy Agent')}\n </Button>\n </div>\n }\n />\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent mesh...')} />\n )}\n\n {!isGraphLoading && error && !hasAgents && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && !hasAgents && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noAgentsConnected', 'No agents in the mesh')}\n description={tr(\n 'agentGraph.noAgentsDescription',\n 'Deploy an agent to start building your agent mesh topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Mesh in VibeControls and how do I deploy agents?\" />\n }\n />\n )}\n\n {showRequestPanel && (\n <div className=\"mt-4\">\n <MeshRequestPanel\n rootAgentId={requestRootAgentId}\n destinations={meshAgents}\n initialDestinationId={requestDestinationId}\n onClose={() => setShowRequestPanel(false)}\n />\n </div>\n )}\n\n {(hasAgents || scopeValue || isRefreshingGraph) && (\n <>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <GitBranch className=\"size-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.meshCountSummary', '{{agents}} agents, {{links}} links', {\n agents: meshAgents.length,\n links: meshLinks.length,\n })}\n </span>\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2\n className=\"size-3.5 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"shrink-0 text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </span>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n setRootAgentId(v || null);\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAllAgents', 'All agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !hasAgents && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeAgentDescription',\n 'No agents match the selected scope. Clear the filter to view the full mesh.'\n )}\n />\n )}\n\n {(hasAgents || isRefreshingGraph) && (\n <div className=\"relative mt-4 min-h-[24rem] flex-1\" aria-busy={isRefreshingGraph}>\n <MeshGraphView\n agents={meshAgents}\n meshLinks={meshLinks}\n currentUserId={currentUser?.id ?? null}\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeClick}\n fullHeight\n />\n\n {/* Node quick-actions popover */}\n {actionsAgent && (\n <div className=\"absolute right-4 top-4 z-20\">\n <MeshNodeActions\n agent={actionsAgent}\n onRunCommand={handleRunCommand}\n onStartTerminal={(id) => void handleStartTerminal(id)}\n onDeployFromHere={handleDeployFromHere}\n onWakeViaSsh={handleWakeViaSsh}\n onOpenAgent={handleOpenAgent}\n onClose={() => setActionsForAgentId(null)}\n />\n </div>\n )}\n\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div\n role=\"status\"\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-[var(--shadow-elevation-2)]\"\n >\n <Loader2\n className=\"size-4 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {showDeployWizard && (\n <MeshDeployWizard\n sourceAgents={sourceAgents}\n initialSourceAgentId={deploySeedSourceId}\n availablePermissions={availablePermissions}\n onClose={() => setShowDeployWizard(false)}\n onCompleted={() => {\n void refetch();\n }}\n />\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-vibecontrols",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.624.1",
|
|
4
4
|
"description": "VibeControls microfrontend for Burdenoff products",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"license": "PROPRIETARY",
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@apollo/client": "4.1.9",
|
|
62
|
-
"@burdenoff/fe-libs": "2026.
|
|
62
|
+
"@burdenoff/fe-libs": "2026.623.6",
|
|
63
63
|
"@tanstack/react-query": "^5.90.16",
|
|
64
64
|
"@xyflow/react": "^12.10.2",
|
|
65
65
|
"clsx": "^2.1.1",
|