import { Boxes, Check, Clock3, EllipsisVertical, FileText, Hammer, MessageSquareText, RefreshCw, RotateCcw, Save, Settings2, SlidersHorizontal, TriangleAlert, Trash2, Waypoints } from 'lucide-react'; import type { RefObject } from 'react'; import { ProtectedSearchInput } from '../../../components/ProtectedSearchInput'; import { LucentIconButton } from '../../../components/lucent/LucentIconButton'; import type { BotState } from '../../../types/bot'; import { isPreviewableWorkspaceFile } from '../utils'; import type { WorkspaceNode } from '../types'; import { WorkspaceEntriesList } from './WorkspaceEntriesList'; import './DashboardMenus.css'; import './RuntimePanel.css'; interface RuntimePanelLabels { agent: string; autoRefresh: string; base: string; channels: string; clearHistory: string; cronViewer: string; download: string; emptyDir: string; envParams: string; exportHistory: string; fileNotPreviewable: string; folder: string; goUp: string; goUpTitle: string; loadingDir: string; mcp: string; more: string; noPreviewFile: string; openingPreview: string; openFolderTitle: string; params: string; previewTitle: string; refreshHint: string; restart: string; runtime: string; searchAction: string; skills: string; topic: string; workspaceHint: string; workspaceOutputs: string; workspaceSearchNoResult: string; workspaceSearchPlaceholder: string; clearSearch: string; } interface RuntimePanelProps { selectedBot?: BotState; selectedBotEnabled: boolean; operatingBotId: string | null; runtimeMenuOpen: boolean; runtimeMenuRef: RefObject; displayState: string; workspaceError: string; workspacePathDisplay: string; workspaceLoading: boolean; workspaceQuery: string; workspaceSearchInputName: string; workspaceSearchLoading: boolean; filteredWorkspaceEntries: WorkspaceNode[]; workspaceParentPath: string | null; workspaceFileLoading: boolean; workspaceDownloadExtensionSet: ReadonlySet; workspaceAutoRefresh: boolean; isCompactHidden: boolean; showCompactSurface: boolean; emptyStateText: string; labels: RuntimePanelLabels; onRestartBot: (botId: string, dockerStatus: string) => Promise | void; onToggleRuntimeMenu: () => void; onOpenBaseConfig: () => Promise | void; onOpenParamConfig: () => Promise | void; onOpenChannelConfig: () => Promise | void; onOpenTopicConfig: () => Promise | void; onOpenEnvParams: () => Promise | void; onOpenSkills: () => Promise | void; onOpenMcpConfig: () => Promise | void; onOpenCronJobs: () => Promise | void; onOpenAgentFiles: () => Promise | void; onExportHistory: () => void; onClearHistory: () => Promise | void; onRefreshWorkspace: () => Promise | void; onWorkspaceQueryChange: (value: string) => void; onWorkspaceQueryClear: () => void; onWorkspaceQuerySearch: () => void; onToggleWorkspaceAutoRefresh: () => void; onLoadWorkspaceTree: (botId: string, path?: string) => Promise | void; onOpenWorkspaceFilePreview: (path: string) => Promise | void; onShowWorkspaceHoverCard: (node: WorkspaceNode, anchor: HTMLElement) => void; onHideWorkspaceHoverCard: () => void; } export function RuntimePanel({ selectedBot, selectedBotEnabled, operatingBotId, runtimeMenuOpen, runtimeMenuRef, displayState, workspaceError, workspacePathDisplay, workspaceLoading, workspaceQuery, workspaceSearchInputName, workspaceSearchLoading, filteredWorkspaceEntries, workspaceParentPath, workspaceFileLoading, workspaceDownloadExtensionSet, workspaceAutoRefresh, isCompactHidden, showCompactSurface, emptyStateText, labels, onRestartBot, onToggleRuntimeMenu, onOpenBaseConfig, onOpenParamConfig, onOpenChannelConfig, onOpenTopicConfig, onOpenEnvParams, onOpenSkills, onOpenMcpConfig, onOpenCronJobs, onOpenAgentFiles, onExportHistory, onClearHistory, onRefreshWorkspace, onWorkspaceQueryChange, onWorkspaceQueryClear, onWorkspaceQuerySearch, onToggleWorkspaceAutoRefresh, onLoadWorkspaceTree, onOpenWorkspaceFilePreview, onShowWorkspaceHoverCard, onHideWorkspaceHoverCard, }: RuntimePanelProps) { const normalizedWorkspaceQuery = workspaceQuery.trim().toLowerCase(); const hasVisibleWorkspaceEntries = filteredWorkspaceEntries.length > 0; const visibleWorkspaceFiles = filteredWorkspaceEntries.filter((entry) => entry.type === 'file'); const hasVisiblePreviewableFiles = visibleWorkspaceFiles.some((entry) => isPreviewableWorkspaceFile(entry, workspaceDownloadExtensionSet), ); const showWorkspaceEmptyState = !workspaceLoading && !workspaceSearchLoading && !workspaceError && !hasVisibleWorkspaceEntries; const showNoPreviewableFilesHint = !workspaceError && !normalizedWorkspaceQuery && visibleWorkspaceFiles.length > 0 && !hasVisiblePreviewableFiles; return (
{selectedBot ? (

{labels.runtime}

void onRestartBot(selectedBot.id, selectedBot.docker_status)} disabled={operatingBotId === selectedBot.id || !selectedBotEnabled} tooltip={labels.restart} aria-label={labels.restart} > {runtimeMenuOpen ? (
) : null}
{selectedBot.llm_model || '-'}
{String(displayState || 'IDLE').toUpperCase()}
{displayState === 'TOOL_CALL' ? : null} {displayState === 'SUCCESS' ? : null} {displayState === 'ERROR' ? : null}
{labels.workspaceOutputs}
{workspaceError ?
{workspaceError}
: null}
{workspacePathDisplay}
void onRefreshWorkspace()} tooltip={labels.refreshHint} aria-label={labels.refreshHint} >
{workspaceLoading || workspaceSearchLoading ? (
{labels.loadingDir}
) : ( <> {(workspaceParentPath !== null || hasVisibleWorkspaceEntries) ? ( ) : null} {showWorkspaceEmptyState ? (
{normalizedWorkspaceQuery ? labels.workspaceSearchNoResult : labels.emptyDir}
) : null} )}
{workspaceFileLoading ? labels.openingPreview : labels.workspaceHint}
{showNoPreviewableFilesHint ? (
{labels.noPreviewFile}
) : null}
) : (
{emptyStateText}
)}
); }