import { Download, FolderOpen, Hammer, Play, RefreshCw, Square, Trash2 } from 'lucide-react' import type { LucideIcon } from 'lucide-react' import type React from 'react' export type ModuleListRowItem = { state: 'running' | 'stopped' | 'uninstalled' category: string name: string parameters: string[] cpu: number | null memory: number | null runtime: string } type ModuleActionTone = 'install' | 'start' | 'warning' | 'delete' | 'neutral' type ModuleListRowProps = { dark: boolean module: Module installing: boolean controlling: boolean bulkControlling: boolean onAddModuleTab: (module: Module) => void onOpenSource: (module: Module) => void onOpenParameters: (module: Module) => void onInstallModule: (module: Module) => void onDeleteModule: (module: Module) => void onStartModule: (module: Module) => void onBuildModule: (module: Module) => void onStopModule: (module: Module) => void onRestartModule: (module: Module) => void } const stateLabel: Record = { running: '실행 중', stopped: '정지됨', uninstalled: '미설치' } function actionButtonClass(dark: boolean, tone: ModuleActionTone, busy: boolean): string { return [ 'group/action relative grid h-7 w-7 cursor-pointer place-items-center rounded-md border transition', busy ? 'opacity-55' : '', tone === 'install' ? dark ? 'border-[#2f8dff]/45 bg-[#2f8dff]/18 text-[#9cc8ff] hover:bg-[#2f8dff]/26' : 'border-[#2f8dff]/35 bg-[#edf6ff] text-[#1d5fae] hover:bg-[#dfefff]' : tone === 'start' ? dark ? 'border-[#2fbda0]/35 bg-[#2fbda0]/10 text-[#80ddc7] hover:bg-[#2fbda0]/18' : 'border-[#2fbda0]/28 bg-[#effbf7] text-[#177553] hover:bg-[#e1f7ee]' : tone === 'warning' ? dark ? 'border-[#f59e0b]/25 bg-[#f59e0b]/8 text-[#e8b76b] hover:bg-[#f59e0b]/14' : 'border-[#f59e0b]/22 bg-[#fff8e8] text-[#9a6814] hover:bg-[#fff1cf]' : tone === 'delete' ? dark ? 'border-[#ef4444]/20 bg-white/[0.03] text-[#e87979] hover:border-[#ef4444]/40 hover:bg-[#ef4444]/10 hover:text-[#ffb4b4]' : 'border-[#ef4444]/18 bg-white text-[#c25a5a] hover:border-[#ef4444]/32 hover:bg-[#fff4f4] hover:text-[#b42323]' : dark ? 'border-white/15 bg-white/[0.04] text-white/60 hover:bg-white/10 hover:text-white' : 'border-[#cfd6e4] bg-white text-[#687284] hover:bg-[#eef1f7] hover:text-[#111520]' ].join(' ') } function TooltipLabel({ dark, children }: { dark: boolean; children: React.ReactNode }): React.JSX.Element { return ( {children} ) } export default function ModuleListRow({ dark, module, installing, controlling, bulkControlling, onAddModuleTab, onOpenSource, onOpenParameters, onInstallModule, onDeleteModule, onStartModule, onBuildModule, onStopModule, onRestartModule }: ModuleListRowProps): React.JSX.Element { const selectable = module.state !== 'uninstalled' const busy = installing || controlling const parameters = Array.isArray(module.parameters) ? module.parameters : [] const stateStyle: Record = { running: dark ? 'bg-[#12372d] text-[#72e2b5]' : 'bg-[#dff8ed] text-[#177553]', stopped: dark ? 'bg-white/8 text-white/45' : 'bg-[#edf0f5] text-[#687284]', uninstalled: dark ? 'bg-[#2d2d2d] text-white/45' : 'bg-[#edf0f5] text-[#687284]' } const controlActions: Array<{ label: string Icon: LucideIcon tone: ModuleActionTone action: (module: Module) => void }> = module.state === 'running' ? [ { label: '재시작', Icon: RefreshCw, tone: 'neutral', action: onRestartModule }, { label: '중지', Icon: Square, tone: 'warning', action: onStopModule } ] : module.state === 'stopped' && controlling ? [ { label: '빌드', Icon: Hammer, tone: 'neutral', action: onBuildModule }, { label: '중지', Icon: Square, tone: 'warning', action: onStopModule } ] : module.state === 'stopped' ? [ { label: '빌드', Icon: Hammer, tone: 'neutral', action: onBuildModule }, { label: '실행', Icon: Play, tone: 'start', action: onStartModule } ] : [] const installAction = module.state === 'uninstalled' ? { label: '설치', Icon: Download, tone: 'install' as ModuleActionTone } : { label: '삭제', Icon: Trash2, tone: 'delete' as ModuleActionTone } const installActionDisabled = busy || (module.state !== 'uninstalled' && module.state !== 'stopped') return (
{ if (selectable) onOpenSource(module) }} className={[ 'grid h-[58px] grid-cols-[88px_115px_minmax(220px,1fr)_105px_132px_70px] items-center px-3 text-[12px] transition', 'cursor-default', selectable ? dark ? 'text-white/70 hover:bg-white/[0.045]' : 'text-[#4f596b] hover:bg-[#f5f7fb]' : dark ? 'text-white/42' : 'text-[#8a94a5]' ].join(' ')} > {stateLabel[module.state]} {module.category} {module.name} {module.runtime} {selectable && ( )} {controlActions.map(({ label, Icon, tone, action }) => ( (() => { const canCancelBuild = module.state === 'stopped' && controlling && label === '중지' const disabled = bulkControlling || (busy && !canCancelBuild) return ( ) })() ))}
) }