@burdenoff/microfe-vibecontrols 2026.623.1 → 2026.623.2

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.
Files changed (293) hide show
  1. package/dist/components/actions/ActionCard.js +2 -2
  2. package/dist/components/actions/ActionCard.js.map +1 -1
  3. package/dist/components/actions/ExecutionHistory.js +1 -1
  4. package/dist/components/actions/ExecutionHistory.js.map +1 -1
  5. package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
  6. package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
  7. package/dist/components/agent-manager/AgentManagerChatPane.js +2 -2
  8. package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
  9. package/dist/components/agent-manager/AgentManagerInputArea.js +4 -4
  10. package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
  11. package/dist/components/agent-manager/AgentManagerLayout.js +1 -1
  12. package/dist/components/agent-manager/AgentManagerLayout.js.map +1 -1
  13. package/dist/components/agent-manager/AgentManagerMessageItem.js +1 -1
  14. package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
  15. package/dist/components/agent-manager/AgentManagerSidebar.js +5 -5
  16. package/dist/components/agent-manager/AgentManagerSidebar.js.map +1 -1
  17. package/dist/components/agent-manager/AgentManagerTab.js +1 -1
  18. package/dist/components/agent-manager/AgentManagerTab.js.map +1 -1
  19. package/dist/components/agent-manager/AgentManagerTabBar.js +1 -1
  20. package/dist/components/agent-manager/AgentManagerTabBar.js.map +1 -1
  21. package/dist/components/agent-manager/BridleConfigPanel.js +23 -23
  22. package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
  23. package/dist/components/agent-manager/PluginInstallModal.js +1 -1
  24. package/dist/components/agent-manager/PluginInstallModal.js.map +1 -1
  25. package/dist/components/agent-manager/ProfilesPanel.js +5 -5
  26. package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
  27. package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
  28. package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
  29. package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
  30. package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
  31. package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
  32. package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
  33. package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
  34. package/dist/components/agent-manager/detail/SessionConfigPanel.js.map +1 -1
  35. package/dist/components/agent-manager/detail/SessionLogsPanel.js +5 -5
  36. package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
  37. package/dist/components/agent-manager/detail/SessionToolsPanel.js +1 -1
  38. package/dist/components/agent-manager/detail/SessionToolsPanel.js.map +1 -1
  39. package/dist/components/agent-manager/dialogs/NewSessionDialog.js +2 -2
  40. package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
  41. package/dist/components/agent-manager/dialogs/RenameSessionDialog.js +1 -1
  42. package/dist/components/agent-manager/dialogs/RenameSessionDialog.js.map +1 -1
  43. package/dist/components/agents/AgentCard.js +14 -11
  44. package/dist/components/agents/AgentCard.js.map +1 -1
  45. package/dist/components/ai/AIContextsTab.js +1 -1
  46. package/dist/components/ai/AIContextsTab.js.map +1 -1
  47. package/dist/components/ai/AIOverviewTab.js +4 -4
  48. package/dist/components/ai/AIOverviewTab.js.map +1 -1
  49. package/dist/components/ai/AIPlanPanel.js +4 -4
  50. package/dist/components/ai/AIPlanPanel.js.map +1 -1
  51. package/dist/components/ai/AIPlaygroundTab.js +1 -1
  52. package/dist/components/ai/AIPlaygroundTab.js.map +1 -1
  53. package/dist/components/ai/AIPromptsTab.js +2 -2
  54. package/dist/components/ai/AIPromptsTab.js.map +1 -1
  55. package/dist/components/ai/AIProviderCredentialsCard.js +4 -4
  56. package/dist/components/ai/AIProviderCredentialsCard.js.map +1 -1
  57. package/dist/components/ai/AIQueueTab.js +4 -4
  58. package/dist/components/ai/AIQueueTab.js.map +1 -1
  59. package/dist/components/ai/AISessionsTab.js +4 -4
  60. package/dist/components/ai/AISessionsTab.js.map +1 -1
  61. package/dist/components/ai/AITasksTab.js +1 -1
  62. package/dist/components/ai/AITasksTab.js.map +1 -1
  63. package/dist/components/ai/ClaudeCredentialsCard.js +3 -3
  64. package/dist/components/ai/ClaudeCredentialsCard.js.map +1 -1
  65. package/dist/components/ai/PluginHarnessPicker.js +3 -3
  66. package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
  67. package/dist/components/analytics/AnalyticsBreakdownChart.js +8 -8
  68. package/dist/components/analytics/AnalyticsBreakdownChart.js.map +1 -1
  69. package/dist/components/analytics/AnalyticsTimeSeriesChart.js +5 -5
  70. package/dist/components/analytics/AnalyticsTimeSeriesChart.js.map +1 -1
  71. package/dist/components/audit/AuditDeleteDialog.js +2 -2
  72. package/dist/components/audit/AuditDeleteDialog.js.map +1 -1
  73. package/dist/components/audit/AuditExportButton.js +5 -5
  74. package/dist/components/audit/AuditExportButton.js.map +1 -1
  75. package/dist/components/audit/AuditLogDetail.js +9 -9
  76. package/dist/components/audit/AuditLogDetail.js.map +1 -1
  77. package/dist/components/audit/AuditLogFilters.js +1 -1
  78. package/dist/components/audit/AuditLogFilters.js.map +1 -1
  79. package/dist/components/audit/AuditLogStats.js +1 -1
  80. package/dist/components/audit/AuditLogStats.js.map +1 -1
  81. package/dist/components/audit/AuditLogTable.js +28 -28
  82. package/dist/components/audit/AuditLogTable.js.map +1 -1
  83. package/dist/components/catalog/CatalogCard.js +3 -3
  84. package/dist/components/catalog/CatalogCard.js.map +1 -1
  85. package/dist/components/catalog/CatalogForm.js +1 -1
  86. package/dist/components/catalog/CatalogForm.js.map +1 -1
  87. package/dist/components/common/ActionAgentTargetNotice.js +6 -6
  88. package/dist/components/common/ActionAgentTargetNotice.js.map +1 -1
  89. package/dist/components/common/CommandEditor.js +1 -1
  90. package/dist/components/common/CommandEditor.js.map +1 -1
  91. package/dist/components/docs/DocsPageTree.js +1 -1
  92. package/dist/components/docs/DocsPageTree.js.map +1 -1
  93. package/dist/components/docs/DocsPreviewPanel.js +1 -1
  94. package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
  95. package/dist/components/docs/DocsRevisionHistory.js +4 -4
  96. package/dist/components/docs/DocsRevisionHistory.js.map +1 -1
  97. package/dist/components/docs/DocsSettingsPanel.js +7 -7
  98. package/dist/components/docs/DocsSettingsPanel.js.map +1 -1
  99. package/dist/components/docs/DocsTabPanel.js +1 -1
  100. package/dist/components/docs/DocsTabPanel.js.map +1 -1
  101. package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
  102. package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
  103. package/dist/components/graph/MeshDeployWizard.js +3 -3
  104. package/dist/components/graph/MeshDeployWizard.js.map +1 -1
  105. package/dist/components/graph/MeshRequestPanel.js +2 -2
  106. package/dist/components/graph/MeshRequestPanel.js.map +1 -1
  107. package/dist/components/idp-components/ComponentCard.js +5 -5
  108. package/dist/components/idp-components/ComponentCard.js.map +1 -1
  109. package/dist/components/idp-components/ComponentForm.js +1 -1
  110. package/dist/components/idp-components/ComponentForm.js.map +1 -1
  111. package/dist/components/idp-components/DependencyGraphTab.js +7 -7
  112. package/dist/components/idp-components/DependencyGraphTab.js.map +1 -1
  113. package/dist/components/logs/LogViewer.js +14 -14
  114. package/dist/components/logs/LogViewer.js.map +1 -1
  115. package/dist/components/notes/NoteCard.js +1 -1
  116. package/dist/components/notes/NoteCard.js.map +1 -1
  117. package/dist/components/notes/NoteEditor.js +2 -2
  118. package/dist/components/notes/NoteEditor.js.map +1 -1
  119. package/dist/components/notes/NoteList.js +1 -1
  120. package/dist/components/notes/NoteList.js.map +1 -1
  121. package/dist/components/notes/NotesTabPanel.js +1 -1
  122. package/dist/components/notes/NotesTabPanel.js.map +1 -1
  123. package/dist/components/scorecard/ScorecardEmptyState.js +1 -1
  124. package/dist/components/scorecard/ScorecardEmptyState.js.map +1 -1
  125. package/dist/components/scorecard/ScorecardPanel.js +3 -3
  126. package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
  127. package/dist/components/security/SecurityScanList.js +11 -11
  128. package/dist/components/security/SecurityScanList.js.map +1 -1
  129. package/dist/components/sessions/SessionCard.js +26 -19
  130. package/dist/components/sessions/SessionCard.js.map +1 -1
  131. package/dist/components/sessions/SessionStatusBadge.js +7 -7
  132. package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
  133. package/dist/components/shared/AgentSelector.js +4 -4
  134. package/dist/components/shared/AgentSelector.js.map +1 -1
  135. package/dist/components/shared/AgentSetupBanner.js +3 -3
  136. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  137. package/dist/components/shared/Card.js +4 -4
  138. package/dist/components/shared/Card.js.map +1 -1
  139. package/dist/components/shared/ErrorState.js +15 -9
  140. package/dist/components/shared/ErrorState.js.map +1 -1
  141. package/dist/components/shared/FilterDropdown.js +2 -2
  142. package/dist/components/shared/FilterDropdown.js.map +1 -1
  143. package/dist/components/shared/PageSkeleton.js +6 -6
  144. package/dist/components/shared/PageSkeleton.js.map +1 -1
  145. package/dist/components/shared/SearchInput.js +1 -1
  146. package/dist/components/shared/SearchInput.js.map +1 -1
  147. package/dist/components/shared/StatCard.js +7 -7
  148. package/dist/components/shared/StatCard.js.map +1 -1
  149. package/dist/components/templates/PublishTemplateForm.js +2 -2
  150. package/dist/components/templates/PublishTemplateForm.js.map +1 -1
  151. package/dist/components/templates/TemplateCard.js +5 -5
  152. package/dist/components/templates/TemplateCard.js.map +1 -1
  153. package/dist/components/templates/TemplateWizard.js +2 -2
  154. package/dist/components/templates/TemplateWizard.js.map +1 -1
  155. package/dist/components/tunnels/DomainVerificationBadge.js +4 -4
  156. package/dist/components/tunnels/DomainVerificationBadge.js.map +1 -1
  157. package/dist/components/tunnels/ProviderBadge.js +1 -1
  158. package/dist/components/tunnels/ProviderBadge.js.map +1 -1
  159. package/dist/components/tunnels/TunnelCard.js +16 -16
  160. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  161. package/dist/components/tunnels/TunnelCreateWizard.js +1 -1
  162. package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
  163. package/dist/components/tunnels/TunnelPublicAccessPanel.js +1 -1
  164. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  165. package/dist/components/tunnels/TunnelStatusBadge.js +4 -4
  166. package/dist/components/tunnels/TunnelStatusBadge.js.map +1 -1
  167. package/dist/components/vibecalendar/LogsDrawer.js +2 -2
  168. package/dist/components/vibecalendar/LogsDrawer.js.map +1 -1
  169. package/dist/components/vibecalendar/ScheduleTaskModal.js +5 -5
  170. package/dist/components/vibecalendar/ScheduleTaskModal.js.map +1 -1
  171. package/dist/components/vibecalendar/VibeCalAgendaView.js +2 -2
  172. package/dist/components/vibecalendar/VibeCalAgendaView.js.map +1 -1
  173. package/dist/components/vibecalendar/VibeCalDayView.js +3 -3
  174. package/dist/components/vibecalendar/VibeCalDayView.js.map +1 -1
  175. package/dist/components/vibecalendar/VibeCalMonthView.js +1 -1
  176. package/dist/components/vibecalendar/VibeCalMonthView.js.map +1 -1
  177. package/dist/components/vibecalendar/VibeCalWeekView.js +4 -4
  178. package/dist/components/vibecalendar/VibeCalWeekView.js.map +1 -1
  179. package/dist/components/vibecalendar/VibeCalendarHeader.js +4 -4
  180. package/dist/components/vibecalendar/VibeCalendarHeader.js.map +1 -1
  181. package/dist/components/vibecalendar/VibeTaskBlock.js +2 -2
  182. package/dist/components/vibecalendar/VibeTaskBlock.js.map +1 -1
  183. package/dist/components/vibecalendar/types.js +6 -6
  184. package/dist/components/vibecalendar/types.js.map +1 -1
  185. package/dist/components/vibedeck/VibeDeckButtonForm.js +9 -9
  186. package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
  187. package/dist/components/vibedeck/VibeDeckButtonTile.js +6 -6
  188. package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
  189. package/dist/components/vibedeck/VibeDeckExecutionLog.js +10 -10
  190. package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
  191. package/dist/components/vibedeck/VibeDeckForm.js +8 -8
  192. package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
  193. package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
  194. package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
  195. package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +2 -2
  196. package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
  197. package/dist/components/vibedeck/VibeDeckSwitcher.js +8 -8
  198. package/dist/components/vibedeck/VibeDeckSwitcher.js.map +1 -1
  199. package/dist/components/vibes/VibeCard.js +22 -18
  200. package/dist/components/vibes/VibeCard.js.map +1 -1
  201. package/dist/components/vibes/VibeList.js +16 -12
  202. package/dist/components/vibes/VibeList.js.map +1 -1
  203. package/dist/pages/ActionsPage.js +4 -3
  204. package/dist/pages/ActionsPage.js.map +1 -1
  205. package/dist/pages/AgentDetailsPage.js +9 -9
  206. package/dist/pages/AgentDetailsPage.js.map +1 -1
  207. package/dist/pages/AgentsLandingPage.js +4 -4
  208. package/dist/pages/AgentsLandingPage.js.map +1 -1
  209. package/dist/pages/AgentsPage.js +14 -14
  210. package/dist/pages/AgentsPage.js.map +1 -1
  211. package/dist/pages/AnalyticsPage.js +8 -8
  212. package/dist/pages/AnalyticsPage.js.map +1 -1
  213. package/dist/pages/CatalogDetailPage.js +11 -11
  214. package/dist/pages/CatalogDetailPage.js.map +1 -1
  215. package/dist/pages/CatalogPage.js +12 -9
  216. package/dist/pages/CatalogPage.js.map +1 -1
  217. package/dist/pages/ComponentDetailPage.js +7 -7
  218. package/dist/pages/ComponentDetailPage.js.map +1 -1
  219. package/dist/pages/ComponentsPage.js +12 -9
  220. package/dist/pages/ComponentsPage.js.map +1 -1
  221. package/dist/pages/EnvTopologyPage.js +2 -2
  222. package/dist/pages/EnvTopologyPage.js.map +1 -1
  223. package/dist/pages/GettingStartedPage.js +12 -12
  224. package/dist/pages/GettingStartedPage.js.map +1 -1
  225. package/dist/pages/HealthPage.js +12 -12
  226. package/dist/pages/HealthPage.js.map +1 -1
  227. package/dist/pages/LogsPage.js +4 -4
  228. package/dist/pages/LogsPage.js.map +1 -1
  229. package/dist/pages/NoteDetailsPage.js +5 -5
  230. package/dist/pages/NoteDetailsPage.js.map +1 -1
  231. package/dist/pages/OverviewPage.js +74 -41
  232. package/dist/pages/OverviewPage.js.map +1 -1
  233. package/dist/pages/PluginsCatalogPage.js +6 -3
  234. package/dist/pages/PluginsCatalogPage.js.map +1 -1
  235. package/dist/pages/ScheduledJobDetailPage.js +7 -7
  236. package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
  237. package/dist/pages/SessionDetailsPage.js +21 -21
  238. package/dist/pages/SessionDetailsPage.js.map +1 -1
  239. package/dist/pages/SessionsPage.js +20 -20
  240. package/dist/pages/SessionsPage.js.map +1 -1
  241. package/dist/pages/SettingsPage.js +64 -52
  242. package/dist/pages/SettingsPage.js.map +1 -1
  243. package/dist/pages/SharedSessionPage.js +21 -21
  244. package/dist/pages/SharedSessionPage.js.map +1 -1
  245. package/dist/pages/SharedVibeDeckPage.js +5 -5
  246. package/dist/pages/SharedVibeDeckPage.js.map +1 -1
  247. package/dist/pages/TargetDetailsPage.js +56 -65
  248. package/dist/pages/TargetDetailsPage.js.map +1 -1
  249. package/dist/pages/TargetsPage.js +4 -4
  250. package/dist/pages/TargetsPage.js.map +1 -1
  251. package/dist/pages/TemplateDetailPage.js +10 -10
  252. package/dist/pages/TemplateDetailPage.js.map +1 -1
  253. package/dist/pages/TemplatesPage.js +6 -5
  254. package/dist/pages/TemplatesPage.js.map +1 -1
  255. package/dist/pages/VibeAuditPage.js +3 -3
  256. package/dist/pages/VibeAuditPage.js.map +1 -1
  257. package/dist/pages/VibeCalendarPage.js +3 -3
  258. package/dist/pages/VibeCalendarPage.js.map +1 -1
  259. package/dist/pages/VibeDeckPage.js +3 -3
  260. package/dist/pages/VibeDeckPage.js.map +1 -1
  261. package/dist/pages/VibeDetailsPage.js +15 -15
  262. package/dist/pages/VibeDetailsPage.js.map +1 -1
  263. package/dist/pages/VibeTaskDetailPage.js +5 -5
  264. package/dist/pages/VibeTaskDetailPage.js.map +1 -1
  265. package/dist/pages/VibesPage.js +18 -18
  266. package/dist/pages/VibesPage.js.map +1 -1
  267. package/dist/pages/WebhooksPage.js +11 -11
  268. package/dist/pages/WebhooksPage.js.map +1 -1
  269. package/dist/pages/ai/AIBookmarksPage.js +1 -1
  270. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  271. package/dist/pages/ai/AISessionDetailPage.js +6 -6
  272. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  273. package/dist/pages/tunnels/AuditTab.js +1 -1
  274. package/dist/pages/tunnels/AuditTab.js.map +1 -1
  275. package/dist/pages/tunnels/DomainsTab.js +1 -1
  276. package/dist/pages/tunnels/DomainsTab.js.map +1 -1
  277. package/dist/pages/tunnels/ProvidersTab.js +1 -1
  278. package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
  279. package/dist/pages/tunnels/SessionsTab.js +1 -1
  280. package/dist/pages/tunnels/SessionsTab.js.map +1 -1
  281. package/dist/pages/tunnels/TunnelDetailsPage.js +3 -3
  282. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  283. package/dist/pages/tunnels/UsageTab.js +1 -1
  284. package/dist/pages/tunnels/UsageTab.js.map +1 -1
  285. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +16 -16
  286. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  287. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +1 -1
  288. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  289. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +52 -49
  290. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  291. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +9 -9
  292. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  293. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"VibeDeckButtonForm.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckButtonForm.tsx"],"sourcesContent":["import { type FC, useState, useMemo, useCallback } from 'react';\nimport { X, Plus, Search, ChevronDown, Unlink } from 'lucide-react';\nimport { useListActionsQuery, useCreateActionMutation } from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { CommandEditor } from '../common/CommandEditor';\nimport { languageForInterpreter } from '../common/commandHighlight';\nimport { ActionAgentTargetNotice } from '../common/ActionAgentTargetNotice';\n\ninterface Agent {\n id: string;\n name: string;\n isActive: boolean;\n}\n\ninterface ActionData {\n id: string;\n name: string;\n displayName: string | null;\n actionType: string;\n command: string | null;\n script: string | null;\n scriptInterpreter: string | null;\n webhookUrl: string | null;\n webhookMethod: string | null;\n targetAgentId: string | null;\n targetPlatformFilter: string | null;\n workingDirectory: string | null;\n category: string | null;\n}\n\ninterface ButtonFormData {\n label: string;\n icon: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n // Temporary fields for creating a new action inline\n actionType: 'COMMAND' | 'SCRIPT' | 'WEBHOOK';\n command: string;\n workingDirectory: string;\n targetAgentId: string;\n script: string;\n scriptInterpreter: string;\n webhookUrl: string;\n webhookMethod: string;\n webhookHeaders: Array<{ key: string; value: string }>;\n webhookBody: string;\n webhookAuthType: string;\n webhookAuthValue: string;\n}\n\ntype ButtonFormInitialData = Partial<Omit<ButtonFormData, 'webhookHeaders'>> & {\n webhookHeaders?: Array<{ key: string; value: string }> | Record<string, string> | null;\n};\n\ninterface VibeDeckButtonFormProps {\n initialData?: ButtonFormInitialData;\n agents: Agent[];\n onSubmit: (data: ButtonFormData) => void;\n onCancel: () => void;\n isLoading: boolean;\n title: string;\n gridColumns?: number;\n gridRows?: number;\n buttonRow?: number;\n buttonColumn?: number;\n}\n\nconst colorOptions = [\n { value: '', label: 'Default' },\n { value: 'red', label: 'Red' },\n { value: 'green', label: 'Green' },\n { value: 'blue', label: 'Blue' },\n { value: 'yellow', label: 'Yellow' },\n { value: 'purple', label: 'Purple' },\n { value: 'orange', label: 'Orange' },\n { value: 'cyan', label: 'Cyan' },\n { value: 'pink', label: 'Pink' },\n];\n\nconst httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nconst interpreters = [\n { value: 'bash', label: 'Bash' },\n { value: 'sh', label: 'Shell (sh)' },\n { value: 'zsh', label: 'Zsh' },\n { value: 'python', label: 'Python' },\n { value: 'python3', label: 'Python 3' },\n { value: 'node', label: 'Node.js' },\n { value: 'bun', label: 'Bun' },\n { value: 'ruby', label: 'Ruby' },\n { value: 'perl', label: 'Perl' },\n];\n\nfunction parseHeadersToArray(\n headers: Array<{ key: string; value: string }> | Record<string, string> | null | undefined\n): Array<{ key: string; value: string }> {\n if (!headers) return [];\n if (Array.isArray(headers)) return headers;\n return Object.entries(headers).map(([key, value]) => ({ key, value: String(value) }));\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 60);\n}\n\nexport const VibeDeckButtonForm: FC<VibeDeckButtonFormProps> = ({\n initialData,\n agents,\n onSubmit,\n onCancel,\n isLoading,\n title,\n gridColumns,\n gridRows,\n buttonRow,\n buttonColumn,\n}) => {\n const tr = useTr();\n const DEFAULT_MAX_SPAN = 4;\n const maxRowSpan = Math.max(\n 1,\n gridRows != null && buttonRow != null ? gridRows - buttonRow : DEFAULT_MAX_SPAN\n );\n const maxColSpan = Math.max(\n 1,\n gridColumns != null && buttonColumn != null ? gridColumns - buttonColumn : DEFAULT_MAX_SPAN\n );\n\n // Action selection state\n const [selectedActionId, setSelectedActionId] = useState<string>(initialData?.actionId || '');\n const [actionSearchQuery, setActionSearchQuery] = useState('');\n const [isActionDropdownOpen, setIsActionDropdownOpen] = useState(false);\n const [isCreatingNewAction, setIsCreatingNewAction] = useState(false);\n\n // Fetch available actions\n const { data: actionsData } = useListActionsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n });\n const [createActionMutation] = useCreateActionMutation();\n\n const availableActions: ActionData[] = useMemo(\n () =>\n (actionsData?.actions?.items || []).map(\n (a: {\n id: string;\n name: string;\n displayName?: string | null;\n actionType: string;\n command?: string | null;\n script?: string | null;\n scriptInterpreter?: string | null;\n webhookUrl?: string | null;\n webhookMethod?: string | null;\n targetAgentId?: string | null;\n targetPlatformFilter?: string | null;\n workingDirectory?: string | null;\n category?: string | null;\n }) => ({\n id: a.id,\n name: a.name,\n displayName: a.displayName || null,\n actionType: a.actionType,\n command: a.command || null,\n script: a.script || null,\n scriptInterpreter: a.scriptInterpreter || null,\n webhookUrl: a.webhookUrl || null,\n webhookMethod: a.webhookMethod || null,\n targetAgentId: a.targetAgentId || null,\n targetPlatformFilter: a.targetPlatformFilter || null,\n workingDirectory: a.workingDirectory || null,\n category: a.category || null,\n })\n ),\n [actionsData]\n );\n\n const selectedAction = useMemo(\n () => availableActions.find((a) => a.id === selectedActionId) || null,\n [availableActions, selectedActionId]\n );\n\n const filteredActions = useMemo(() => {\n if (!actionSearchQuery.trim()) return availableActions;\n const q = actionSearchQuery.toLowerCase();\n return availableActions.filter(\n (a) =>\n a.name.toLowerCase().includes(q) ||\n (a.displayName && a.displayName.toLowerCase().includes(q)) ||\n a.actionType.toLowerCase().includes(q)\n );\n }, [availableActions, actionSearchQuery]);\n\n const [form, setForm] = useState<ButtonFormData>({\n label: initialData?.label || '',\n icon: initialData?.icon || '',\n color: initialData?.color || '',\n category: initialData?.category || '',\n keyboardShortcut: initialData?.keyboardShortcut || '',\n confirmationRequired: initialData?.confirmationRequired || false,\n rowSpan: Math.min(initialData?.rowSpan || 1, maxRowSpan),\n colSpan: Math.min(initialData?.colSpan || 1, maxColSpan),\n actionId: initialData?.actionId || '',\n // Legacy fields for creating new action\n actionType: initialData?.actionType || 'COMMAND',\n command: initialData?.command || '',\n workingDirectory: initialData?.workingDirectory || '',\n targetAgentId: initialData?.targetAgentId || '',\n script: initialData?.script || '',\n scriptInterpreter: initialData?.scriptInterpreter || 'bash',\n webhookUrl: initialData?.webhookUrl || '',\n webhookMethod: initialData?.webhookMethod || 'POST',\n webhookHeaders: parseHeadersToArray(initialData?.webhookHeaders),\n webhookBody: initialData?.webhookBody || '',\n webhookAuthType: initialData?.webhookAuthType || '',\n webhookAuthValue: initialData?.webhookAuthValue || '',\n });\n\n const handleSelectAction = (action: ActionData) => {\n setSelectedActionId(action.id);\n setIsActionDropdownOpen(false);\n setActionSearchQuery('');\n setIsCreatingNewAction(false);\n setForm((prev) => ({\n ...prev,\n actionId: action.id,\n actionType: action.actionType as 'COMMAND' | 'SCRIPT' | 'WEBHOOK',\n command: action.command || '',\n script: action.script || '',\n scriptInterpreter: action.scriptInterpreter || 'bash',\n webhookUrl: action.webhookUrl || '',\n webhookMethod: action.webhookMethod || 'POST',\n workingDirectory: action.workingDirectory || '',\n targetAgentId: action.targetAgentId || '',\n category: action.category || prev.category,\n }));\n };\n\n const handleUnlinkAction = () => {\n setSelectedActionId('');\n setForm((prev) => ({ ...prev, actionId: '' }));\n };\n\n const addHeader = () => {\n setForm({ ...form, webhookHeaders: [...form.webhookHeaders, { key: '', value: '' }] });\n };\n\n const removeHeader = (index: number) => {\n setForm({ ...form, webhookHeaders: form.webhookHeaders.filter((_, i) => i !== index) });\n };\n\n const updateHeader = (index: number, field: 'key' | 'value', val: string) => {\n const updated = [...form.webhookHeaders];\n updated[index] = { ...updated[index], [field]: val };\n setForm({ ...form, webhookHeaders: updated });\n };\n\n const hasSelectedAction = !!selectedActionId;\n const isActionFieldsReadOnly = hasSelectedAction && !isCreatingNewAction;\n\n const isNewActionValid =\n (form.actionType === 'COMMAND' && form.command.trim()) ||\n (form.actionType === 'SCRIPT' && form.script.trim()) ||\n (form.actionType === 'WEBHOOK' && form.webhookUrl.trim());\n\n const isValid = form.label.trim() && (hasSelectedAction || isNewActionValid);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // If creating new action inline, create it first\n if (!hasSelectedAction && isCreatingNewAction) {\n try {\n const actionName =\n slugify(form.label || 'vibedeck-action') + '-' + Date.now().toString(36);\n const result = await createActionMutation({\n variables: {\n input: {\n name: actionName,\n displayName: form.label,\n actionType: form.actionType,\n command: form.actionType === 'COMMAND' ? form.command : undefined,\n script: form.actionType === 'SCRIPT' ? form.script : undefined,\n scriptInterpreter:\n form.actionType === 'SCRIPT' ? form.scriptInterpreter : undefined,\n webhookUrl: form.actionType === 'WEBHOOK' ? form.webhookUrl : undefined,\n webhookMethod: form.actionType === 'WEBHOOK' ? form.webhookMethod : undefined,\n webhookBody: form.actionType === 'WEBHOOK' ? form.webhookBody : undefined,\n webhookAuthType: form.actionType === 'WEBHOOK' ? form.webhookAuthType : undefined,\n webhookAuthValue: form.actionType === 'WEBHOOK' ? form.webhookAuthValue : undefined,\n workingDirectory: form.workingDirectory || undefined,\n targetAgentId: form.targetAgentId || undefined,\n category: form.category || undefined,\n confirmationRequired: form.confirmationRequired,\n },\n },\n refetchQueries: ['ListActions'],\n });\n\n const newActionId = result.data?.createAction?.id;\n if (newActionId) {\n onSubmit({ ...form, actionId: newActionId });\n return;\n }\n } catch {\n // Fall through\n }\n }\n\n onSubmit({ ...form, actionId: selectedActionId });\n },\n [form, hasSelectedAction, isCreatingNewAction, selectedActionId, createActionMutation, onSubmit]\n );\n\n // -- Shared CSS classes --\n const inputCls =\n 'w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n const readOnlyCls = 'opacity-70 cursor-not-allowed';\n const sectionLabel = 'block text-sm font-medium text-text-secondary mb-1';\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay backdrop-blur-sm\">\n <div className=\"bg-bg-elevated border border-border-default rounded-xl shadow-xl w-full max-w-lg mx-4 max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-elevated z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"p-1 rounded hover:bg-bg-tertiary text-text-tertiary\"\n >\n <X size={18} />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-6 space-y-4\">\n {/* Label */}\n <div>\n <label className={sectionLabel}>\n {tr('vibecontrols.vibedeck.buttonForm.label', 'Label')} *\n </label>\n <input\n aria-label=\"Deploy Staging\"\n type=\"text\"\n value={form.label}\n onChange={(e) => setForm({ ...form, label: e.target.value })}\n className={inputCls}\n placeholder=\"Deploy Staging\"\n required\n />\n </div>\n\n {/* ── Action Selection ── */}\n <div>\n <label className={sectionLabel}>\n {tr('vibecontrols.vibedeck.buttonForm.action', 'Action')} *\n </label>\n\n {/* Selected action card */}\n {selectedAction ? (\n <div className=\"flex items-center gap-2 px-3 py-2.5 rounded-lg border border-action-primary-bg/40 bg-bg-secondary\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-text-primary truncate\">\n {selectedAction.displayName || selectedAction.name}\n </div>\n <div className=\"text-xs text-text-tertiary flex items-center gap-1\">\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-action-primary-bg/10 text-action-primary-bg\">\n {selectedAction.actionType}\n </span>\n {selectedAction.command && (\n <span className=\"font-mono truncate\">\n {selectedAction.command.length > 35\n ? `${selectedAction.command.slice(0, 35)}...`\n : selectedAction.command}\n </span>\n )}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={handleUnlinkAction}\n className=\"p-1.5 rounded hover:bg-bg-tertiary text-text-tertiary hover:text-status-error-text\"\n title=\"Change action\"\n >\n <Unlink size={14} />\n </button>\n </div>\n ) : null}\n\n {/* Surface the agent this action runs on (and warn if it's unhealthy\n or gone) right where the action is linked to the button. */}\n {selectedAction && (\n <div className=\"mt-2\">\n <ActionAgentTargetNotice action={selectedAction} />\n </div>\n )}\n\n {!selectedAction && (\n /* Search for existing action or create new */\n <div className=\"space-y-2\">\n <div className=\"relative\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={actionSearchQuery}\n onChange={(e) => {\n setActionSearchQuery(e.target.value);\n setIsActionDropdownOpen(true);\n setIsCreatingNewAction(false);\n }}\n onFocus={() => setIsActionDropdownOpen(true)}\n onBlur={() => setTimeout(() => setIsActionDropdownOpen(false), 200)}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary text-sm focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n placeholder={tr(\n 'vibecontrols.vibedeck.buttonForm.searchActions',\n 'Search existing actions...'\n )}\n />\n {isActionDropdownOpen && (\n <div className=\"absolute z-50 mt-1 w-full max-h-48 overflow-y-auto rounded-lg border border-border-default shadow-xl bg-bg-elevated\">\n {filteredActions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-text-tertiary\">No actions found</div>\n ) : (\n filteredActions.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelectAction(action)}\n className=\"w-full text-left px-3 py-2 hover:bg-bg-tertiary\"\n >\n <div className=\"text-sm font-medium\">\n {action.displayName || action.name}\n </div>\n <div className=\"text-xs text-text-tertiary\">{action.actionType}</div>\n </button>\n ))\n )}\n </div>\n )}\n </div>\n\n {!isCreatingNewAction && (\n <button\n type=\"button\"\n onClick={() => setIsCreatingNewAction(true)}\n className=\"flex items-center gap-1.5 text-sm text-action-primary-bg hover:opacity-80\"\n >\n <Plus size={14} />{' '}\n {tr('vibecontrols.vibedeck.buttonForm.createNewAction', 'Create new action')}\n </button>\n )}\n </div>\n )}\n </div>\n\n {/* ── New Action Fields (if creating new) ── */}\n {isCreatingNewAction && (\n <div className=\"p-4 rounded-lg bg-bg-secondary/50 border border-dashed border-border-default space-y-4\">\n <div>\n <label htmlFor=\"vibedeckbuttonform-23\" className={sectionLabel}>\n Action Type\n </label>\n <select\n id=\"vibedeckbuttonform-23\"\n value={form.actionType}\n onChange={(e) => setForm({ ...form, actionType: e.target.value as any })}\n className={inputCls}\n >\n <option value=\"COMMAND\">Command</option>\n <option value=\"SCRIPT\">Script</option>\n <option value=\"WEBHOOK\">Webhook</option>\n </select>\n </div>\n\n {form.actionType === 'COMMAND' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-22\" className={sectionLabel}>\n Command *\n </label>\n <CommandEditor\n id=\"vibedeckbuttonform-22\"\n aria-label=\"control\"\n language=\"shell\"\n value={form.command}\n onChange={(e) => setForm({ ...form, command: e.target.value })}\n rows={2}\n required\n />\n </div>\n )}\n\n {form.actionType === 'SCRIPT' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-21\" className={sectionLabel}>\n Script *\n </label>\n <CommandEditor\n id=\"vibedeckbuttonform-21\"\n aria-label=\"control\"\n language={languageForInterpreter(form.scriptInterpreter)}\n value={form.script}\n onChange={(e) => setForm({ ...form, script: e.target.value })}\n rows={4}\n required\n />\n </div>\n )}\n\n {form.actionType === 'WEBHOOK' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-20\" className={sectionLabel}>\n URL *\n </label>\n <input\n id=\"vibedeckbuttonform-20\"\n aria-label=\"control\"\n type=\"url\"\n value={form.webhookUrl}\n onChange={(e) => setForm({ ...form, webhookUrl: e.target.value })}\n className={inputCls}\n required\n />\n </div>\n )}\n </div>\n )}\n\n {/* ── Appearance ── */}\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"vibedeckbuttonform-19\" className={sectionLabel}>\n Color\n </label>\n <select\n id=\"vibedeckbuttonform-19\"\n value={form.color}\n onChange={(e) => setForm({ ...form, color: e.target.value })}\n className={inputCls}\n >\n {colorOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"vibedeckbuttonform-18\" className={sectionLabel}>\n Category\n </label>\n <input\n id=\"vibedeckbuttonform-18\"\n aria-label=\"control\"\n type=\"text\"\n value={form.category}\n onChange={(e) => setForm({ ...form, category: e.target.value })}\n className={inputCls}\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2\">\n <input\n aria-label=\"confReq\"\n type=\"checkbox\"\n checked={form.confirmationRequired}\n onChange={(e) => setForm({ ...form, confirmationRequired: e.target.checked })}\n id=\"confReq\"\n />\n <label htmlFor=\"confReq\" className=\"text-sm\">\n {tr('vibecontrols.vibedeck.buttonForm.requireConfirmation', 'Require confirmation')}\n </label>\n </div>\n </div>\n\n {/* Submit */}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-tertiary\"\n >\n {tr('vibecontrols.vibedeck.buttonForm.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isLoading || !isValid}\n className=\"px-4 py-2 rounded-lg text-sm bg-action-primary-bg text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {isLoading\n ? tr('vibecontrols.vibedeck.buttonForm.saving', 'Saving...')\n : tr('vibecontrols.vibedeck.buttonForm.save', 'Save')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeDeckButtonForm.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckButtonForm.tsx"],"sourcesContent":["import { type FC, useState, useMemo, useCallback } from 'react';\nimport { X, Plus, Search, ChevronDown, Unlink } from 'lucide-react';\nimport { useListActionsQuery, useCreateActionMutation } from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { CommandEditor } from '../common/CommandEditor';\nimport { languageForInterpreter } from '../common/commandHighlight';\nimport { ActionAgentTargetNotice } from '../common/ActionAgentTargetNotice';\n\ninterface Agent {\n id: string;\n name: string;\n isActive: boolean;\n}\n\ninterface ActionData {\n id: string;\n name: string;\n displayName: string | null;\n actionType: string;\n command: string | null;\n script: string | null;\n scriptInterpreter: string | null;\n webhookUrl: string | null;\n webhookMethod: string | null;\n targetAgentId: string | null;\n targetPlatformFilter: string | null;\n workingDirectory: string | null;\n category: string | null;\n}\n\ninterface ButtonFormData {\n label: string;\n icon: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n // Temporary fields for creating a new action inline\n actionType: 'COMMAND' | 'SCRIPT' | 'WEBHOOK';\n command: string;\n workingDirectory: string;\n targetAgentId: string;\n script: string;\n scriptInterpreter: string;\n webhookUrl: string;\n webhookMethod: string;\n webhookHeaders: Array<{ key: string; value: string }>;\n webhookBody: string;\n webhookAuthType: string;\n webhookAuthValue: string;\n}\n\ntype ButtonFormInitialData = Partial<Omit<ButtonFormData, 'webhookHeaders'>> & {\n webhookHeaders?: Array<{ key: string; value: string }> | Record<string, string> | null;\n};\n\ninterface VibeDeckButtonFormProps {\n initialData?: ButtonFormInitialData;\n agents: Agent[];\n onSubmit: (data: ButtonFormData) => void;\n onCancel: () => void;\n isLoading: boolean;\n title: string;\n gridColumns?: number;\n gridRows?: number;\n buttonRow?: number;\n buttonColumn?: number;\n}\n\nconst colorOptions = [\n { value: '', label: 'Default' },\n { value: 'red', label: 'Red' },\n { value: 'green', label: 'Green' },\n { value: 'blue', label: 'Blue' },\n { value: 'yellow', label: 'Yellow' },\n { value: 'purple', label: 'Purple' },\n { value: 'orange', label: 'Orange' },\n { value: 'cyan', label: 'Cyan' },\n { value: 'pink', label: 'Pink' },\n];\n\nconst httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nconst interpreters = [\n { value: 'bash', label: 'Bash' },\n { value: 'sh', label: 'Shell (sh)' },\n { value: 'zsh', label: 'Zsh' },\n { value: 'python', label: 'Python' },\n { value: 'python3', label: 'Python 3' },\n { value: 'node', label: 'Node.js' },\n { value: 'bun', label: 'Bun' },\n { value: 'ruby', label: 'Ruby' },\n { value: 'perl', label: 'Perl' },\n];\n\nfunction parseHeadersToArray(\n headers: Array<{ key: string; value: string }> | Record<string, string> | null | undefined\n): Array<{ key: string; value: string }> {\n if (!headers) return [];\n if (Array.isArray(headers)) return headers;\n return Object.entries(headers).map(([key, value]) => ({ key, value: String(value) }));\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 60);\n}\n\nexport const VibeDeckButtonForm: FC<VibeDeckButtonFormProps> = ({\n initialData,\n agents,\n onSubmit,\n onCancel,\n isLoading,\n title,\n gridColumns,\n gridRows,\n buttonRow,\n buttonColumn,\n}) => {\n const tr = useTr();\n const DEFAULT_MAX_SPAN = 4;\n const maxRowSpan = Math.max(\n 1,\n gridRows != null && buttonRow != null ? gridRows - buttonRow : DEFAULT_MAX_SPAN\n );\n const maxColSpan = Math.max(\n 1,\n gridColumns != null && buttonColumn != null ? gridColumns - buttonColumn : DEFAULT_MAX_SPAN\n );\n\n // Action selection state\n const [selectedActionId, setSelectedActionId] = useState<string>(initialData?.actionId || '');\n const [actionSearchQuery, setActionSearchQuery] = useState('');\n const [isActionDropdownOpen, setIsActionDropdownOpen] = useState(false);\n const [isCreatingNewAction, setIsCreatingNewAction] = useState(false);\n\n // Fetch available actions\n const { data: actionsData } = useListActionsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n });\n const [createActionMutation] = useCreateActionMutation();\n\n const availableActions: ActionData[] = useMemo(\n () =>\n (actionsData?.actions?.items || []).map(\n (a: {\n id: string;\n name: string;\n displayName?: string | null;\n actionType: string;\n command?: string | null;\n script?: string | null;\n scriptInterpreter?: string | null;\n webhookUrl?: string | null;\n webhookMethod?: string | null;\n targetAgentId?: string | null;\n targetPlatformFilter?: string | null;\n workingDirectory?: string | null;\n category?: string | null;\n }) => ({\n id: a.id,\n name: a.name,\n displayName: a.displayName || null,\n actionType: a.actionType,\n command: a.command || null,\n script: a.script || null,\n scriptInterpreter: a.scriptInterpreter || null,\n webhookUrl: a.webhookUrl || null,\n webhookMethod: a.webhookMethod || null,\n targetAgentId: a.targetAgentId || null,\n targetPlatformFilter: a.targetPlatformFilter || null,\n workingDirectory: a.workingDirectory || null,\n category: a.category || null,\n })\n ),\n [actionsData]\n );\n\n const selectedAction = useMemo(\n () => availableActions.find((a) => a.id === selectedActionId) || null,\n [availableActions, selectedActionId]\n );\n\n const filteredActions = useMemo(() => {\n if (!actionSearchQuery.trim()) return availableActions;\n const q = actionSearchQuery.toLowerCase();\n return availableActions.filter(\n (a) =>\n a.name.toLowerCase().includes(q) ||\n (a.displayName && a.displayName.toLowerCase().includes(q)) ||\n a.actionType.toLowerCase().includes(q)\n );\n }, [availableActions, actionSearchQuery]);\n\n const [form, setForm] = useState<ButtonFormData>({\n label: initialData?.label || '',\n icon: initialData?.icon || '',\n color: initialData?.color || '',\n category: initialData?.category || '',\n keyboardShortcut: initialData?.keyboardShortcut || '',\n confirmationRequired: initialData?.confirmationRequired || false,\n rowSpan: Math.min(initialData?.rowSpan || 1, maxRowSpan),\n colSpan: Math.min(initialData?.colSpan || 1, maxColSpan),\n actionId: initialData?.actionId || '',\n // Legacy fields for creating new action\n actionType: initialData?.actionType || 'COMMAND',\n command: initialData?.command || '',\n workingDirectory: initialData?.workingDirectory || '',\n targetAgentId: initialData?.targetAgentId || '',\n script: initialData?.script || '',\n scriptInterpreter: initialData?.scriptInterpreter || 'bash',\n webhookUrl: initialData?.webhookUrl || '',\n webhookMethod: initialData?.webhookMethod || 'POST',\n webhookHeaders: parseHeadersToArray(initialData?.webhookHeaders),\n webhookBody: initialData?.webhookBody || '',\n webhookAuthType: initialData?.webhookAuthType || '',\n webhookAuthValue: initialData?.webhookAuthValue || '',\n });\n\n const handleSelectAction = (action: ActionData) => {\n setSelectedActionId(action.id);\n setIsActionDropdownOpen(false);\n setActionSearchQuery('');\n setIsCreatingNewAction(false);\n setForm((prev) => ({\n ...prev,\n actionId: action.id,\n actionType: action.actionType as 'COMMAND' | 'SCRIPT' | 'WEBHOOK',\n command: action.command || '',\n script: action.script || '',\n scriptInterpreter: action.scriptInterpreter || 'bash',\n webhookUrl: action.webhookUrl || '',\n webhookMethod: action.webhookMethod || 'POST',\n workingDirectory: action.workingDirectory || '',\n targetAgentId: action.targetAgentId || '',\n category: action.category || prev.category,\n }));\n };\n\n const handleUnlinkAction = () => {\n setSelectedActionId('');\n setForm((prev) => ({ ...prev, actionId: '' }));\n };\n\n const addHeader = () => {\n setForm({ ...form, webhookHeaders: [...form.webhookHeaders, { key: '', value: '' }] });\n };\n\n const removeHeader = (index: number) => {\n setForm({ ...form, webhookHeaders: form.webhookHeaders.filter((_, i) => i !== index) });\n };\n\n const updateHeader = (index: number, field: 'key' | 'value', val: string) => {\n const updated = [...form.webhookHeaders];\n updated[index] = { ...updated[index], [field]: val };\n setForm({ ...form, webhookHeaders: updated });\n };\n\n const hasSelectedAction = !!selectedActionId;\n const isActionFieldsReadOnly = hasSelectedAction && !isCreatingNewAction;\n\n const isNewActionValid =\n (form.actionType === 'COMMAND' && form.command.trim()) ||\n (form.actionType === 'SCRIPT' && form.script.trim()) ||\n (form.actionType === 'WEBHOOK' && form.webhookUrl.trim());\n\n const isValid = form.label.trim() && (hasSelectedAction || isNewActionValid);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // If creating new action inline, create it first\n if (!hasSelectedAction && isCreatingNewAction) {\n try {\n const actionName =\n slugify(form.label || 'vibedeck-action') + '-' + Date.now().toString(36);\n const result = await createActionMutation({\n variables: {\n input: {\n name: actionName,\n displayName: form.label,\n actionType: form.actionType,\n command: form.actionType === 'COMMAND' ? form.command : undefined,\n script: form.actionType === 'SCRIPT' ? form.script : undefined,\n scriptInterpreter:\n form.actionType === 'SCRIPT' ? form.scriptInterpreter : undefined,\n webhookUrl: form.actionType === 'WEBHOOK' ? form.webhookUrl : undefined,\n webhookMethod: form.actionType === 'WEBHOOK' ? form.webhookMethod : undefined,\n webhookBody: form.actionType === 'WEBHOOK' ? form.webhookBody : undefined,\n webhookAuthType: form.actionType === 'WEBHOOK' ? form.webhookAuthType : undefined,\n webhookAuthValue: form.actionType === 'WEBHOOK' ? form.webhookAuthValue : undefined,\n workingDirectory: form.workingDirectory || undefined,\n targetAgentId: form.targetAgentId || undefined,\n category: form.category || undefined,\n confirmationRequired: form.confirmationRequired,\n },\n },\n refetchQueries: ['ListActions'],\n });\n\n const newActionId = result.data?.createAction?.id;\n if (newActionId) {\n onSubmit({ ...form, actionId: newActionId });\n return;\n }\n } catch {\n // Fall through\n }\n }\n\n onSubmit({ ...form, actionId: selectedActionId });\n },\n [form, hasSelectedAction, isCreatingNewAction, selectedActionId, createActionMutation, onSubmit]\n );\n\n // -- Shared CSS classes --\n const inputCls =\n 'w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n const readOnlyCls = 'opacity-70 cursor-not-allowed';\n const sectionLabel = 'block text-sm font-medium text-text-secondary mb-1';\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay backdrop-blur-sm\">\n <div className=\"bg-bg-elevated border border-border-default rounded-xl shadow-xl w-full max-w-lg mx-4 max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-elevated z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"p-1 rounded hover:bg-bg-sunken text-text-tertiary\"\n >\n <X size={18} />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-6 space-y-4\">\n {/* Label */}\n <div>\n <label className={sectionLabel}>\n {tr('vibecontrols.vibedeck.buttonForm.label', 'Label')} *\n </label>\n <input\n aria-label=\"Deploy Staging\"\n type=\"text\"\n value={form.label}\n onChange={(e) => setForm({ ...form, label: e.target.value })}\n className={inputCls}\n placeholder=\"Deploy Staging\"\n required\n />\n </div>\n\n {/* ── Action Selection ── */}\n <div>\n <label className={sectionLabel}>\n {tr('vibecontrols.vibedeck.buttonForm.action', 'Action')} *\n </label>\n\n {/* Selected action card */}\n {selectedAction ? (\n <div className=\"flex items-center gap-2 px-3 py-2.5 rounded-lg border border-[var(--color-accent-soft)] bg-bg-surface\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-text-primary truncate\">\n {selectedAction.displayName || selectedAction.name}\n </div>\n <div className=\"text-xs text-text-tertiary flex items-center gap-1\">\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-[var(--color-accent-soft)] text-action-primary-bg\">\n {selectedAction.actionType}\n </span>\n {selectedAction.command && (\n <span className=\"font-mono truncate\">\n {selectedAction.command.length > 35\n ? `${selectedAction.command.slice(0, 35)}...`\n : selectedAction.command}\n </span>\n )}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={handleUnlinkAction}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-text-tertiary hover:text-status-error-text\"\n title=\"Change action\"\n >\n <Unlink size={14} />\n </button>\n </div>\n ) : null}\n\n {/* Surface the agent this action runs on (and warn if it's unhealthy\n or gone) right where the action is linked to the button. */}\n {selectedAction && (\n <div className=\"mt-2\">\n <ActionAgentTargetNotice action={selectedAction} />\n </div>\n )}\n\n {!selectedAction && (\n /* Search for existing action or create new */\n <div className=\"space-y-2\">\n <div className=\"relative\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={actionSearchQuery}\n onChange={(e) => {\n setActionSearchQuery(e.target.value);\n setIsActionDropdownOpen(true);\n setIsCreatingNewAction(false);\n }}\n onFocus={() => setIsActionDropdownOpen(true)}\n onBlur={() => setTimeout(() => setIsActionDropdownOpen(false), 200)}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n placeholder={tr(\n 'vibecontrols.vibedeck.buttonForm.searchActions',\n 'Search existing actions...'\n )}\n />\n {isActionDropdownOpen && (\n <div className=\"absolute z-50 mt-1 w-full max-h-48 overflow-y-auto rounded-lg border border-border-default shadow-xl bg-bg-elevated\">\n {filteredActions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-text-tertiary\">No actions found</div>\n ) : (\n filteredActions.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelectAction(action)}\n className=\"w-full text-left px-3 py-2 hover:bg-bg-sunken\"\n >\n <div className=\"text-sm font-medium\">\n {action.displayName || action.name}\n </div>\n <div className=\"text-xs text-text-tertiary\">{action.actionType}</div>\n </button>\n ))\n )}\n </div>\n )}\n </div>\n\n {!isCreatingNewAction && (\n <button\n type=\"button\"\n onClick={() => setIsCreatingNewAction(true)}\n className=\"flex items-center gap-1.5 text-sm text-action-primary-bg hover:opacity-80\"\n >\n <Plus size={14} />{' '}\n {tr('vibecontrols.vibedeck.buttonForm.createNewAction', 'Create new action')}\n </button>\n )}\n </div>\n )}\n </div>\n\n {/* ── New Action Fields (if creating new) ── */}\n {isCreatingNewAction && (\n <div className=\"p-4 rounded-lg bg-bg-sunken border border-dashed border-border-default space-y-4\">\n <div>\n <label htmlFor=\"vibedeckbuttonform-23\" className={sectionLabel}>\n Action Type\n </label>\n <select\n id=\"vibedeckbuttonform-23\"\n value={form.actionType}\n onChange={(e) => setForm({ ...form, actionType: e.target.value as any })}\n className={inputCls}\n >\n <option value=\"COMMAND\">Command</option>\n <option value=\"SCRIPT\">Script</option>\n <option value=\"WEBHOOK\">Webhook</option>\n </select>\n </div>\n\n {form.actionType === 'COMMAND' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-22\" className={sectionLabel}>\n Command *\n </label>\n <CommandEditor\n id=\"vibedeckbuttonform-22\"\n aria-label=\"control\"\n language=\"shell\"\n value={form.command}\n onChange={(e) => setForm({ ...form, command: e.target.value })}\n rows={2}\n required\n />\n </div>\n )}\n\n {form.actionType === 'SCRIPT' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-21\" className={sectionLabel}>\n Script *\n </label>\n <CommandEditor\n id=\"vibedeckbuttonform-21\"\n aria-label=\"control\"\n language={languageForInterpreter(form.scriptInterpreter)}\n value={form.script}\n onChange={(e) => setForm({ ...form, script: e.target.value })}\n rows={4}\n required\n />\n </div>\n )}\n\n {form.actionType === 'WEBHOOK' && (\n <div>\n <label htmlFor=\"vibedeckbuttonform-20\" className={sectionLabel}>\n URL *\n </label>\n <input\n id=\"vibedeckbuttonform-20\"\n aria-label=\"control\"\n type=\"url\"\n value={form.webhookUrl}\n onChange={(e) => setForm({ ...form, webhookUrl: e.target.value })}\n className={inputCls}\n required\n />\n </div>\n )}\n </div>\n )}\n\n {/* ── Appearance ── */}\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"vibedeckbuttonform-19\" className={sectionLabel}>\n Color\n </label>\n <select\n id=\"vibedeckbuttonform-19\"\n value={form.color}\n onChange={(e) => setForm({ ...form, color: e.target.value })}\n className={inputCls}\n >\n {colorOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"vibedeckbuttonform-18\" className={sectionLabel}>\n Category\n </label>\n <input\n id=\"vibedeckbuttonform-18\"\n aria-label=\"control\"\n type=\"text\"\n value={form.category}\n onChange={(e) => setForm({ ...form, category: e.target.value })}\n className={inputCls}\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2\">\n <input\n aria-label=\"confReq\"\n type=\"checkbox\"\n checked={form.confirmationRequired}\n onChange={(e) => setForm({ ...form, confirmationRequired: e.target.checked })}\n id=\"confReq\"\n />\n <label htmlFor=\"confReq\" className=\"text-sm\">\n {tr('vibecontrols.vibedeck.buttonForm.requireConfirmation', 'Require confirmation')}\n </label>\n </div>\n </div>\n\n {/* Submit */}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-sunken\"\n >\n {tr('vibecontrols.vibedeck.buttonForm.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isLoading || !isValid}\n className=\"px-4 py-2 rounded-lg text-sm bg-action-primary-bg text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {isLoading\n ? tr('vibecontrols.vibedeck.buttonForm.saving', 'Saving...')\n : tr('vibecontrols.vibedeck.buttonForm.save', 'Save')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -24,9 +24,9 @@ var h = ({ button: h, onExecute: g, onEdit: _, onDelete: v, canUpdate: y, canDel
24
24
  pink: "border-accent-purple/40 bg-gradient-to-br from-accent-purple/15 to-accent-purple/5 hover:shadow-accent-purple/20"
25
25
  }, A = "border-border-default bg-bg-elevated/80 backdrop-blur-md shadow-lg hover:border-border-focus hover:shadow-xl", j = D ? h.color && k[h.color] ? `${k[h.color]} backdrop-blur-md shadow-lg hover:shadow-xl` : A : h.color && O[h.color] ? `${O[h.color]} backdrop-blur-md shadow-md hover:shadow-lg` : A, M = h.action?.actionType || h.actionType, N = h.action?.command ?? h.command, P = h.action?.script ?? null, F = h.action?.webhookUrl ?? h.webhookUrl, I = h.action?.displayName || h.action?.name || null, L = M === "WEBHOOK", R = M === "SCRIPT", z = L ? i : R ? r : c, B = L ? `${h.webhookMethod || "POST"} ${F || ""}` : R ? `Script (${h.scriptInterpreter || "bash"})${P ? `: ${P.slice(0, 60)}` : ""}` : `${N || ""}${h.keyboardShortcut ? ` (${h.keyboardShortcut})` : ""}`, V = () => {
26
26
  D && x && !S && g(h.id);
27
- }, H = C === "executing" ? "ring-2 ring-action-primary-bg/60 ring-offset-1" : C === "success" ? "ring-2 ring-status-success-border/50 ring-offset-1" : C === "error" ? "ring-2 ring-status-error-border/50 ring-offset-1" : "", U = C === "executing" ? "border-action-primary-bg/60" : C === "success" ? "border-status-success-border/50" : C === "error" ? "border-status-error-border/50" : "", W = D ? x && !S : y;
27
+ }, H = C === "executing" ? "ring-2 ring-action-primary-bg ring-offset-1" : C === "success" ? "ring-2 ring-status-success-border ring-offset-1" : C === "error" ? "ring-2 ring-status-error-border ring-offset-1" : "", U = C === "executing" ? "border-[var(--color-accent-soft)]" : C === "success" ? "border-status-success-border" : C === "error" ? "border-status-error-border" : "", W = D ? x && !S : y;
28
28
  return /* @__PURE__ */ m(f.div, {
29
- className: `relative group h-full ${H} ${w ? "ring-2 ring-action-primary-bg ring-offset-1" : ""} ${T ? "ring-2 ring-action-primary-bg/40 ring-offset-1" : ""} ${W ? "cursor-pointer" : ""} rounded-lg focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:outline-none`,
29
+ className: `relative group h-full ${H} ${w ? "ring-2 ring-action-primary-bg ring-offset-1" : ""} ${T ? "ring-2 ring-[var(--color-focus-ring)] ring-offset-1" : ""} ${W ? "cursor-pointer" : ""} rounded-lg focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:outline-none`,
30
30
  whileHover: W ? { scale: 1.03 } : void 0,
31
31
  whileTap: W ? { scale: .97 } : void 0,
32
32
  transition: { duration: .15 },
@@ -42,11 +42,11 @@ var h = ({ button: h, onExecute: g, onEdit: _, onDelete: v, canUpdate: y, canDel
42
42
  title: B,
43
43
  children: [
44
44
  L && h.webhookMethod && /* @__PURE__ */ p("span", {
45
- className: `absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-tertiary/80 rounded px-1 py-0.5 uppercase ${!D && E ? "top-8" : "top-1.5"}`,
45
+ className: `absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-sunken rounded px-1 py-0.5 uppercase ${!D && E ? "top-8" : "top-1.5"}`,
46
46
  children: h.webhookMethod
47
47
  }),
48
48
  R && h.scriptInterpreter && /* @__PURE__ */ p("span", {
49
- className: `absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-tertiary/80 rounded px-1 py-0.5 ${!D && E ? "top-8" : "top-1.5"}`,
49
+ className: `absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-sunken rounded px-1 py-0.5 ${!D && E ? "top-8" : "top-1.5"}`,
50
50
  children: h.scriptInterpreter
51
51
  }),
52
52
  !D && E && /* @__PURE__ */ p("div", {
@@ -71,7 +71,7 @@ var h = ({ button: h, onExecute: g, onEdit: _, onDelete: v, canUpdate: y, canDel
71
71
  children: h.label
72
72
  }),
73
73
  I && /* @__PURE__ */ p("span", {
74
- className: "text-[10px] text-action-primary-bg/70 font-medium truncate max-w-full px-1",
74
+ className: "text-[10px] text-action-primary-bg font-medium truncate max-w-full px-1",
75
75
  children: I
76
76
  }),
77
77
  h.category && /* @__PURE__ */ p("span", {
@@ -151,7 +151,7 @@ var h = ({ button: h, onExecute: g, onEdit: _, onDelete: v, canUpdate: y, canDel
151
151
  D && x && C !== "executing" && /* @__PURE__ */ p("div", {
152
152
  className: "absolute inset-0 rounded-lg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200 bg-bg-elevated/40 backdrop-blur-[1px]",
153
153
  children: /* @__PURE__ */ p("div", {
154
- className: "size-10 rounded-full bg-status-success-bg/90 flex items-center justify-center shadow-md",
154
+ className: "size-10 rounded-full bg-status-success-bg-subtle flex items-center justify-center shadow-md",
155
155
  children: /* @__PURE__ */ p(s, {
156
156
  size: 18,
157
157
  className: "text-status-success-text ml-0.5"
@@ -1 +1 @@
1
- {"version":3,"file":"VibeDeckButtonTile.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckButtonTile.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Play,\n Pencil,\n Trash2,\n Terminal,\n Globe,\n FileCode,\n AlertTriangle,\n Check,\n X,\n Loader2,\n} from 'lucide-react';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\n\ninterface ActionRef {\n id: string;\n name: string;\n displayName: string | null;\n actionType: string;\n command: string | null;\n script: string | null;\n webhookUrl: string | null;\n targetAgentId: string | null;\n}\n\ninterface ButtonData {\n id: string;\n label: string;\n icon: string | null;\n color: string | null;\n command: string | null;\n actionType: string;\n category: string | null;\n confirmationRequired: boolean;\n keyboardShortcut: string | null;\n targetAgentId: string | null;\n scriptInterpreter: string | null;\n webhookUrl: string | null;\n webhookMethod: string | null;\n actionId?: string | null;\n action?: ActionRef | null;\n}\n\ninterface VibeDeckButtonTileProps {\n button: ButtonData;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDelete: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n executing?: boolean;\n /** Visual feedback state after execution completes */\n executionStatus?: 'idle' | 'executing' | 'success' | 'error';\n isDragOver?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n previewMode?: boolean;\n}\n\nexport const VibeDeckButtonTile: FC<VibeDeckButtonTileProps> = ({\n button,\n onExecute,\n onEdit,\n onDelete,\n canUpdate,\n canDelete,\n canExecute,\n executing = false,\n executionStatus = 'idle',\n isDragOver = false,\n selected = false,\n onToggleSelect,\n previewMode = false,\n}) => {\n const colorClasses: Record<string, string> = {\n red: 'border-status-error-border/30 bg-status-error-bg-subtle',\n green: 'border-status-success-border/30 bg-status-success-bg-subtle',\n blue: 'border-accent-blue/30 bg-accent-blue-subtle',\n yellow: 'border-status-warning-border/30 bg-status-warning-bg-subtle',\n purple: 'border-accent-purple/30 bg-accent-purple-subtle',\n orange: 'border-status-warning-border/30 bg-status-warning-bg-subtle',\n cyan: 'border-accent-teal/30 bg-accent-teal-subtle',\n pink: 'border-accent-purple/30 bg-accent-purple-subtle',\n };\n\n const previewColorClasses: Record<string, string> = {\n red: 'border-status-error-border/40 bg-gradient-to-br from-status-error-bg/15 to-status-error-bg/5 hover:shadow-status-error-bg/20',\n green:\n 'border-status-success-border/40 bg-gradient-to-br from-status-success-bg/15 to-status-success-bg/5 hover:shadow-status-success-bg/20',\n blue: 'border-accent-blue/40 bg-gradient-to-br from-accent-blue/15 to-accent-blue/5 hover:shadow-accent-blue/20',\n yellow:\n 'border-status-warning-border/40 bg-gradient-to-br from-status-warning-bg/15 to-status-warning-bg/5 hover:shadow-status-warning-bg/20',\n purple:\n 'border-accent-purple/40 bg-gradient-to-br from-accent-purple/15 to-accent-purple/5 hover:shadow-accent-purple/20',\n orange:\n 'border-status-warning-border/40 bg-gradient-to-br from-status-warning-bg/15 to-status-warning-bg/5 hover:shadow-status-warning-bg/20',\n cyan: 'border-accent-teal/40 bg-gradient-to-br from-accent-teal/15 to-accent-teal/5 hover:shadow-accent-teal/20',\n pink: 'border-accent-purple/40 bg-gradient-to-br from-accent-purple/15 to-accent-purple/5 hover:shadow-accent-purple/20',\n };\n\n // Glass-button visual: frosted background + soft border + shadow that\n // intensifies on hover. Per the round-3 streamdeck redesign, both\n // preview and edit modes share the same base treatment so the deck\n // feels consistent — only the per-color tint differs.\n const glassBase =\n 'border-border-default bg-bg-elevated/80 backdrop-blur-md shadow-lg hover:border-border-focus hover:shadow-xl';\n const tileColor = previewMode\n ? button.color && previewColorClasses[button.color]\n ? `${previewColorClasses[button.color]} backdrop-blur-md shadow-lg hover:shadow-xl`\n : glassBase\n : button.color && colorClasses[button.color]\n ? `${colorClasses[button.color]} backdrop-blur-md shadow-md hover:shadow-lg`\n : glassBase;\n\n // Prefer action fields when linked, fall back to inline (deprecated) fields\n const effectiveActionType = button.action?.actionType || button.actionType;\n const effectiveCommand = button.action?.command ?? button.command;\n const effectiveScript = button.action?.script ?? null;\n const effectiveWebhookUrl = button.action?.webhookUrl ?? button.webhookUrl;\n const actionName = button.action?.displayName || button.action?.name || null;\n\n const isWebhook = effectiveActionType === 'WEBHOOK';\n const isScript = effectiveActionType === 'SCRIPT';\n const ActionIcon = isWebhook ? Globe : isScript ? FileCode : Terminal;\n const tooltip = isWebhook\n ? `${button.webhookMethod || 'POST'} ${effectiveWebhookUrl || ''}`\n : isScript\n ? `Script (${button.scriptInterpreter || 'bash'})${effectiveScript ? `: ${effectiveScript.slice(0, 60)}` : ''}`\n : `${effectiveCommand || ''}${button.keyboardShortcut ? ` (${button.keyboardShortcut})` : ''}`;\n\n // In preview mode, the entire tile is clickable to execute\n const handleTileClick = () => {\n if (previewMode && canExecute && !executing) {\n onExecute(button.id);\n }\n };\n\n // Status-dependent styles\n const statusRing =\n executionStatus === 'executing'\n ? 'ring-2 ring-action-primary-bg/60 ring-offset-1'\n : executionStatus === 'success'\n ? 'ring-2 ring-status-success-border/50 ring-offset-1'\n : executionStatus === 'error'\n ? 'ring-2 ring-status-error-border/50 ring-offset-1'\n : '';\n\n const statusBorderOverride =\n executionStatus === 'executing'\n ? 'border-action-primary-bg/60'\n : executionStatus === 'success'\n ? 'border-status-success-border/50'\n : executionStatus === 'error'\n ? 'border-status-error-border/50'\n : '';\n\n // Calm hover + tap motion — drops the previous jumpy executing\n // `animate={{scale}}` loop. Per round-3 UX, the whole tile is the click\n // target so we apply the press-down motion at the wrapper level.\n const tileClickable = previewMode ? canExecute && !executing : canUpdate;\n\n return (\n <motion.div\n className={`relative group h-full ${statusRing} ${isDragOver ? 'ring-2 ring-action-primary-bg ring-offset-1' : ''} ${selected ? 'ring-2 ring-action-primary-bg/40 ring-offset-1' : ''} ${tileClickable ? 'cursor-pointer' : ''} rounded-lg focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:outline-none`}\n whileHover={tileClickable ? { scale: 1.03 } : undefined}\n whileTap={tileClickable ? { scale: 0.97 } : undefined}\n transition={{ duration: 0.15 }}\n >\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (handleTileClick as (...a: unknown[]) => unknown)();\n }\n }}\n onClick={handleTileClick}\n className={`w-full h-full min-h-[80px] rounded-lg border-2 p-3 flex flex-col items-center justify-center gap-2 transition-all duration-200 ${tileColor} ${statusBorderOverride} ${executionStatus === 'executing' ? 'animate-pulse' : ''}`}\n title={tooltip}\n >\n {/* Top-left: webhook method or script interpreter badge */}\n {isWebhook && button.webhookMethod && (\n <span\n className={`absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-tertiary/80 rounded px-1 py-0.5 uppercase ${!previewMode && onToggleSelect ? 'top-8' : 'top-1.5'}`}\n >\n {button.webhookMethod}\n </span>\n )}\n {isScript && button.scriptInterpreter && (\n <span\n className={`absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-tertiary/80 rounded px-1 py-0.5 ${!previewMode && onToggleSelect ? 'top-8' : 'top-1.5'}`}\n >\n {button.scriptInterpreter}\n </span>\n )}\n\n {!previewMode && onToggleSelect && (\n <div\n className=\"absolute top-1.5 left-1.5 z-10\"\n onClick={(event) => event.stopPropagation()}\n >\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe deck button ${button.label}`}\n />\n </div>\n )}\n\n {/* Bottom-left: confirmation required warning */}\n {button.confirmationRequired && (\n <AlertTriangle\n size={10}\n className=\"absolute bottom-1.5 left-1.5 text-status-warning-text\"\n />\n )}\n\n <ActionIcon\n size={previewMode ? 24 : 20}\n className={previewMode ? 'text-text-primary' : 'text-text-secondary'}\n />\n <span\n className={`font-medium text-text-primary text-center leading-tight line-clamp-2 ${previewMode ? 'text-base' : 'text-sm'}`}\n >\n {button.label}\n </span>\n {actionName && (\n <span className=\"text-[10px] text-action-primary-bg/70 font-medium truncate max-w-full px-1\">\n {actionName}\n </span>\n )}\n {button.category && (\n <span className=\"text-[10px] text-text-tertiary uppercase tracking-wider\">\n {button.category}\n </span>\n )}\n\n {/* Execution status indicator */}\n <AnimatePresence>\n {executionStatus === 'executing' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-action-primary-bg flex items-center justify-center shadow-sm\">\n <Loader2 size={11} className=\"text-text-inverse animate-spin\" />\n </div>\n </motion.div>\n )}\n {executionStatus === 'success' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-status-success-bg flex items-center justify-center shadow-sm\">\n <Check size={11} className=\"text-text-inverse\" strokeWidth={3} />\n </div>\n </motion.div>\n )}\n {executionStatus === 'error' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-status-error-bg flex items-center justify-center shadow-sm\">\n <X size={11} className=\"text-text-inverse\" strokeWidth={3} />\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Preview mode: centered play overlay on hover */}\n {previewMode && canExecute && executionStatus !== 'executing' && (\n <div className=\"absolute inset-0 rounded-lg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200 bg-bg-elevated/40 backdrop-blur-[1px]\">\n <div className=\"size-10 rounded-full bg-status-success-bg/90 flex items-center justify-center shadow-md\">\n <Play size={18} className=\"text-status-success-text ml-0.5\" />\n </div>\n </div>\n )}\n </div>\n\n {/* Prominent Play button — calm, centred-top, glass-styled.\n Round-3 redesign drops the jumpy scale loop and bumps the size\n so the action is obvious in edit mode without competing with\n the tile's drag handle on hover. */}\n {!previewMode && canExecute && (\n <motion.button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onExecute(button.id);\n }}\n disabled={executing}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n transition={{ duration: 0.15 }}\n className=\"absolute -top-3 left-1/2 -translate-x-1/2 size-14 rounded-full bg-action-primary-bg text-action-primary-text shadow-xl flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity duration-200 z-20\"\n title=\"Execute\"\n aria-label=\"Execute button\"\n >\n <Play size={20} className=\"ml-0.5\" />\n </motion.button>\n )}\n\n {/* Bottom-right: Edit / Delete — visible on hover in edit mode only */}\n {!previewMode && (canUpdate || canDelete) && (\n <div className=\"absolute bottom-0.5 right-0.5 flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity\">\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(button.id);\n }}\n className=\"p-1 rounded bg-bg-elevated/80 hover:bg-bg-elevated text-text-tertiary hover:text-text-primary shadow-sm\"\n title=\"Edit\"\n >\n <Pencil size={12} />\n </button>\n )}\n {canDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(button.id);\n }}\n className=\"p-1 rounded bg-bg-elevated/80 hover:bg-bg-elevated text-text-tertiary hover:text-status-error-text shadow-sm\"\n title=\"Delete\"\n >\n <Trash2 size={12} />\n </button>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeDeckButtonTile.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckButtonTile.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Play,\n Pencil,\n Trash2,\n Terminal,\n Globe,\n FileCode,\n AlertTriangle,\n Check,\n X,\n Loader2,\n} from 'lucide-react';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\n\ninterface ActionRef {\n id: string;\n name: string;\n displayName: string | null;\n actionType: string;\n command: string | null;\n script: string | null;\n webhookUrl: string | null;\n targetAgentId: string | null;\n}\n\ninterface ButtonData {\n id: string;\n label: string;\n icon: string | null;\n color: string | null;\n command: string | null;\n actionType: string;\n category: string | null;\n confirmationRequired: boolean;\n keyboardShortcut: string | null;\n targetAgentId: string | null;\n scriptInterpreter: string | null;\n webhookUrl: string | null;\n webhookMethod: string | null;\n actionId?: string | null;\n action?: ActionRef | null;\n}\n\ninterface VibeDeckButtonTileProps {\n button: ButtonData;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDelete: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n executing?: boolean;\n /** Visual feedback state after execution completes */\n executionStatus?: 'idle' | 'executing' | 'success' | 'error';\n isDragOver?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n previewMode?: boolean;\n}\n\nexport const VibeDeckButtonTile: FC<VibeDeckButtonTileProps> = ({\n button,\n onExecute,\n onEdit,\n onDelete,\n canUpdate,\n canDelete,\n canExecute,\n executing = false,\n executionStatus = 'idle',\n isDragOver = false,\n selected = false,\n onToggleSelect,\n previewMode = false,\n}) => {\n const colorClasses: Record<string, string> = {\n red: 'border-status-error-border/30 bg-status-error-bg-subtle',\n green: 'border-status-success-border/30 bg-status-success-bg-subtle',\n blue: 'border-accent-blue/30 bg-accent-blue-subtle',\n yellow: 'border-status-warning-border/30 bg-status-warning-bg-subtle',\n purple: 'border-accent-purple/30 bg-accent-purple-subtle',\n orange: 'border-status-warning-border/30 bg-status-warning-bg-subtle',\n cyan: 'border-accent-teal/30 bg-accent-teal-subtle',\n pink: 'border-accent-purple/30 bg-accent-purple-subtle',\n };\n\n const previewColorClasses: Record<string, string> = {\n red: 'border-status-error-border/40 bg-gradient-to-br from-status-error-bg/15 to-status-error-bg/5 hover:shadow-status-error-bg/20',\n green:\n 'border-status-success-border/40 bg-gradient-to-br from-status-success-bg/15 to-status-success-bg/5 hover:shadow-status-success-bg/20',\n blue: 'border-accent-blue/40 bg-gradient-to-br from-accent-blue/15 to-accent-blue/5 hover:shadow-accent-blue/20',\n yellow:\n 'border-status-warning-border/40 bg-gradient-to-br from-status-warning-bg/15 to-status-warning-bg/5 hover:shadow-status-warning-bg/20',\n purple:\n 'border-accent-purple/40 bg-gradient-to-br from-accent-purple/15 to-accent-purple/5 hover:shadow-accent-purple/20',\n orange:\n 'border-status-warning-border/40 bg-gradient-to-br from-status-warning-bg/15 to-status-warning-bg/5 hover:shadow-status-warning-bg/20',\n cyan: 'border-accent-teal/40 bg-gradient-to-br from-accent-teal/15 to-accent-teal/5 hover:shadow-accent-teal/20',\n pink: 'border-accent-purple/40 bg-gradient-to-br from-accent-purple/15 to-accent-purple/5 hover:shadow-accent-purple/20',\n };\n\n // Glass-button visual: frosted background + soft border + shadow that\n // intensifies on hover. Per the round-3 streamdeck redesign, both\n // preview and edit modes share the same base treatment so the deck\n // feels consistent — only the per-color tint differs.\n const glassBase =\n 'border-border-default bg-bg-elevated/80 backdrop-blur-md shadow-lg hover:border-border-focus hover:shadow-xl';\n const tileColor = previewMode\n ? button.color && previewColorClasses[button.color]\n ? `${previewColorClasses[button.color]} backdrop-blur-md shadow-lg hover:shadow-xl`\n : glassBase\n : button.color && colorClasses[button.color]\n ? `${colorClasses[button.color]} backdrop-blur-md shadow-md hover:shadow-lg`\n : glassBase;\n\n // Prefer action fields when linked, fall back to inline (deprecated) fields\n const effectiveActionType = button.action?.actionType || button.actionType;\n const effectiveCommand = button.action?.command ?? button.command;\n const effectiveScript = button.action?.script ?? null;\n const effectiveWebhookUrl = button.action?.webhookUrl ?? button.webhookUrl;\n const actionName = button.action?.displayName || button.action?.name || null;\n\n const isWebhook = effectiveActionType === 'WEBHOOK';\n const isScript = effectiveActionType === 'SCRIPT';\n const ActionIcon = isWebhook ? Globe : isScript ? FileCode : Terminal;\n const tooltip = isWebhook\n ? `${button.webhookMethod || 'POST'} ${effectiveWebhookUrl || ''}`\n : isScript\n ? `Script (${button.scriptInterpreter || 'bash'})${effectiveScript ? `: ${effectiveScript.slice(0, 60)}` : ''}`\n : `${effectiveCommand || ''}${button.keyboardShortcut ? ` (${button.keyboardShortcut})` : ''}`;\n\n // In preview mode, the entire tile is clickable to execute\n const handleTileClick = () => {\n if (previewMode && canExecute && !executing) {\n onExecute(button.id);\n }\n };\n\n // Status-dependent styles\n const statusRing =\n executionStatus === 'executing'\n ? 'ring-2 ring-action-primary-bg ring-offset-1'\n : executionStatus === 'success'\n ? 'ring-2 ring-status-success-border ring-offset-1'\n : executionStatus === 'error'\n ? 'ring-2 ring-status-error-border ring-offset-1'\n : '';\n\n const statusBorderOverride =\n executionStatus === 'executing'\n ? 'border-[var(--color-accent-soft)]'\n : executionStatus === 'success'\n ? 'border-status-success-border'\n : executionStatus === 'error'\n ? 'border-status-error-border'\n : '';\n\n // Calm hover + tap motion — drops the previous jumpy executing\n // `animate={{scale}}` loop. Per round-3 UX, the whole tile is the click\n // target so we apply the press-down motion at the wrapper level.\n const tileClickable = previewMode ? canExecute && !executing : canUpdate;\n\n return (\n <motion.div\n className={`relative group h-full ${statusRing} ${isDragOver ? 'ring-2 ring-action-primary-bg ring-offset-1' : ''} ${selected ? 'ring-2 ring-[var(--color-focus-ring)] ring-offset-1' : ''} ${tileClickable ? 'cursor-pointer' : ''} rounded-lg focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:outline-none`}\n whileHover={tileClickable ? { scale: 1.03 } : undefined}\n whileTap={tileClickable ? { scale: 0.97 } : undefined}\n transition={{ duration: 0.15 }}\n >\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (handleTileClick as (...a: unknown[]) => unknown)();\n }\n }}\n onClick={handleTileClick}\n className={`w-full h-full min-h-[80px] rounded-lg border-2 p-3 flex flex-col items-center justify-center gap-2 transition-all duration-200 ${tileColor} ${statusBorderOverride} ${executionStatus === 'executing' ? 'animate-pulse' : ''}`}\n title={tooltip}\n >\n {/* Top-left: webhook method or script interpreter badge */}\n {isWebhook && button.webhookMethod && (\n <span\n className={`absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-sunken rounded px-1 py-0.5 uppercase ${!previewMode && onToggleSelect ? 'top-8' : 'top-1.5'}`}\n >\n {button.webhookMethod}\n </span>\n )}\n {isScript && button.scriptInterpreter && (\n <span\n className={`absolute left-1.5 text-[9px] font-bold text-text-tertiary bg-bg-sunken rounded px-1 py-0.5 ${!previewMode && onToggleSelect ? 'top-8' : 'top-1.5'}`}\n >\n {button.scriptInterpreter}\n </span>\n )}\n\n {!previewMode && onToggleSelect && (\n <div\n className=\"absolute top-1.5 left-1.5 z-10\"\n onClick={(event) => event.stopPropagation()}\n >\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe deck button ${button.label}`}\n />\n </div>\n )}\n\n {/* Bottom-left: confirmation required warning */}\n {button.confirmationRequired && (\n <AlertTriangle\n size={10}\n className=\"absolute bottom-1.5 left-1.5 text-status-warning-text\"\n />\n )}\n\n <ActionIcon\n size={previewMode ? 24 : 20}\n className={previewMode ? 'text-text-primary' : 'text-text-secondary'}\n />\n <span\n className={`font-medium text-text-primary text-center leading-tight line-clamp-2 ${previewMode ? 'text-base' : 'text-sm'}`}\n >\n {button.label}\n </span>\n {actionName && (\n <span className=\"text-[10px] text-action-primary-bg font-medium truncate max-w-full px-1\">\n {actionName}\n </span>\n )}\n {button.category && (\n <span className=\"text-[10px] text-text-tertiary uppercase tracking-wider\">\n {button.category}\n </span>\n )}\n\n {/* Execution status indicator */}\n <AnimatePresence>\n {executionStatus === 'executing' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-action-primary-bg flex items-center justify-center shadow-sm\">\n <Loader2 size={11} className=\"text-text-inverse animate-spin\" />\n </div>\n </motion.div>\n )}\n {executionStatus === 'success' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-status-success-bg flex items-center justify-center shadow-sm\">\n <Check size={11} className=\"text-text-inverse\" strokeWidth={3} />\n </div>\n </motion.div>\n )}\n {executionStatus === 'error' && (\n <motion.div\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n className=\"absolute top-1.5 right-1.5 z-10\"\n >\n <div className=\"size-5 rounded-full bg-status-error-bg flex items-center justify-center shadow-sm\">\n <X size={11} className=\"text-text-inverse\" strokeWidth={3} />\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Preview mode: centered play overlay on hover */}\n {previewMode && canExecute && executionStatus !== 'executing' && (\n <div className=\"absolute inset-0 rounded-lg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200 bg-bg-elevated/40 backdrop-blur-[1px]\">\n <div className=\"size-10 rounded-full bg-status-success-bg-subtle flex items-center justify-center shadow-md\">\n <Play size={18} className=\"text-status-success-text ml-0.5\" />\n </div>\n </div>\n )}\n </div>\n\n {/* Prominent Play button — calm, centred-top, glass-styled.\n Round-3 redesign drops the jumpy scale loop and bumps the size\n so the action is obvious in edit mode without competing with\n the tile's drag handle on hover. */}\n {!previewMode && canExecute && (\n <motion.button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onExecute(button.id);\n }}\n disabled={executing}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n transition={{ duration: 0.15 }}\n className=\"absolute -top-3 left-1/2 -translate-x-1/2 size-14 rounded-full bg-action-primary-bg text-action-primary-text shadow-xl flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity duration-200 z-20\"\n title=\"Execute\"\n aria-label=\"Execute button\"\n >\n <Play size={20} className=\"ml-0.5\" />\n </motion.button>\n )}\n\n {/* Bottom-right: Edit / Delete — visible on hover in edit mode only */}\n {!previewMode && (canUpdate || canDelete) && (\n <div className=\"absolute bottom-0.5 right-0.5 flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity\">\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(button.id);\n }}\n className=\"p-1 rounded bg-bg-elevated/80 hover:bg-bg-elevated text-text-tertiary hover:text-text-primary shadow-sm\"\n title=\"Edit\"\n >\n <Pencil size={12} />\n </button>\n )}\n {canDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(button.id);\n }}\n className=\"p-1 rounded bg-bg-elevated/80 hover:bg-bg-elevated text-text-tertiary hover:text-status-error-text shadow-sm\"\n title=\"Delete\"\n >\n <Trash2 size={12} />\n </button>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":"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"}
@@ -55,10 +55,10 @@ var y = ({ status: e }) => {
55
55
  success: "Success",
56
56
  error: "Failed"
57
57
  }, S = {
58
- pending: "bg-bg-tertiary text-text-tertiary",
59
- running: "bg-action-primary-bg/10 text-action-primary-bg",
60
- success: "bg-status-success-bg/10 text-status-success-text",
61
- error: "bg-status-error-bg/10 text-status-error-text"
58
+ pending: "bg-bg-sunken text-text-tertiary",
59
+ running: "bg-[var(--color-accent-soft)] text-action-primary-bg",
60
+ success: "bg-status-success-bg-subtle text-status-success-text",
61
+ error: "bg-status-error-bg-subtle text-status-error-text"
62
62
  }, C = ({ entries: o, expanded: s, onToggleExpanded: c, onClear: C }) => {
63
63
  let w = e(), T = n(null);
64
64
  if (t(() => {
@@ -70,7 +70,7 @@ var y = ({ status: e }) => {
70
70
  children: [/* @__PURE__ */ g("button", {
71
71
  type: "button",
72
72
  onClick: c,
73
- className: "w-full flex items-center justify-between px-4 py-2.5 hover:bg-bg-secondary/50 transition-colors",
73
+ className: "w-full flex items-center justify-between px-4 py-2.5 hover:bg-bg-sunken transition-colors",
74
74
  children: [/* @__PURE__ */ g("div", {
75
75
  className: "flex items-center gap-3",
76
76
  children: [
@@ -86,18 +86,18 @@ var y = ({ status: e }) => {
86
86
  className: "flex items-center gap-2",
87
87
  children: [
88
88
  E > 0 && /* @__PURE__ */ g("span", {
89
- className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-action-primary-bg/10 text-action-primary-bg",
89
+ className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-[var(--color-accent-soft)] text-action-primary-bg",
90
90
  children: [/* @__PURE__ */ h(l, {
91
91
  size: 10,
92
92
  className: "animate-spin"
93
93
  }), E]
94
94
  }),
95
95
  D > 0 && /* @__PURE__ */ g("span", {
96
- className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-success-bg/10 text-status-success-text",
96
+ className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-success-bg-subtle text-status-success-text",
97
97
  children: [/* @__PURE__ */ h(r, { size: 10 }), D]
98
98
  }),
99
99
  O > 0 && /* @__PURE__ */ g("span", {
100
- className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-error-bg/10 text-status-error-text",
100
+ className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-error-bg-subtle text-status-error-text",
101
101
  children: [/* @__PURE__ */ h(f, { size: 10 }), O]
102
102
  }),
103
103
  /* @__PURE__ */ g("span", {
@@ -118,7 +118,7 @@ var y = ({ status: e }) => {
118
118
  onClick: (e) => {
119
119
  e.stopPropagation(), C();
120
120
  },
121
- className: "p-1 rounded hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors",
121
+ className: "p-1 rounded hover:bg-bg-sunken text-text-tertiary hover:text-text-primary transition-colors",
122
122
  title: "Clear log",
123
123
  children: /* @__PURE__ */ h(d, { size: 12 })
124
124
  }), h(s ? i : a, {
@@ -145,7 +145,7 @@ var y = ({ status: e }) => {
145
145
  ref: T,
146
146
  className: "max-h-[240px] overflow-y-auto divide-y divide-border-default/50",
147
147
  children: o.map((e) => /* @__PURE__ */ g("div", {
148
- className: `px-4 py-2.5 flex items-start gap-3 text-sm transition-colors ${e.status === "running" ? "bg-action-primary-bg/5" : ""}`,
148
+ className: `px-4 py-2.5 flex items-start gap-3 text-sm transition-colors ${e.status === "running" ? "bg-[var(--color-accent-soft)]" : ""}`,
149
149
  children: [
150
150
  /* @__PURE__ */ h("div", {
151
151
  className: "pt-0.5 shrink-0",
@@ -1 +1 @@
1
- {"version":3,"file":"VibeDeckExecutionLog.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckExecutionLog.tsx"],"sourcesContent":["import { type FC, useRef, useEffect } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Terminal,\n Globe,\n FileCode,\n Check,\n X,\n Loader2,\n Clock,\n ChevronDown,\n ChevronUp,\n Trash2,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface ExecutionLogEntry {\n id: string;\n buttonId: string;\n buttonLabel: string;\n actionType: 'COMMAND' | 'SCRIPT' | 'WEBHOOK';\n command?: string | null;\n status: 'pending' | 'running' | 'success' | 'error';\n output?: string | null;\n exitCode?: number | null;\n webhookStatusCode?: number | null;\n startedAt: Date;\n completedAt?: Date | null;\n error?: string | null;\n}\n\ninterface VibeDeckExecutionLogProps {\n entries: ExecutionLogEntry[];\n expanded: boolean;\n onToggleExpanded: () => void;\n onClear: () => void;\n}\n\nfunction formatDuration(start: Date, end?: Date | null): string {\n const ms = (end ? end.getTime() : Date.now()) - start.getTime();\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;\n}\n\nfunction formatTime(date: Date): string {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nconst StatusIcon: FC<{ status: ExecutionLogEntry['status'] }> = ({ status }) => {\n switch (status) {\n case 'pending':\n return <Clock size={14} className=\"text-text-tertiary\" />;\n case 'running':\n return <Loader2 size={14} className=\"text-action-primary-bg animate-spin\" />;\n case 'success':\n return <Check size={14} className=\"text-status-success-text\" />;\n case 'error':\n return <X size={14} className=\"text-status-error-text\" />;\n }\n};\n\nconst ActionTypeIcon: FC<{ type: string }> = ({ type }) => {\n switch (type) {\n case 'WEBHOOK':\n return <Globe size={12} className=\"text-text-tertiary\" />;\n case 'SCRIPT':\n return <FileCode size={12} className=\"text-text-tertiary\" />;\n default:\n return <Terminal size={12} className=\"text-text-tertiary\" />;\n }\n};\n\nconst statusLabel: Record<string, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Failed',\n};\n\nconst statusBadgeClass: Record<string, string> = {\n pending: 'bg-bg-tertiary text-text-tertiary',\n running: 'bg-action-primary-bg/10 text-action-primary-bg',\n success: 'bg-status-success-bg/10 text-status-success-text',\n error: 'bg-status-error-bg/10 text-status-error-text',\n};\n\nexport const VibeDeckExecutionLog: FC<VibeDeckExecutionLogProps> = ({\n entries,\n expanded,\n onToggleExpanded,\n onClear,\n}) => {\n const tr = useTr();\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new entries arrive\n useEffect(() => {\n if (scrollRef.current && expanded) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n }\n }, [entries.length, expanded]);\n\n if (entries.length === 0) return null;\n\n const runningCount = entries.filter((e) => e.status === 'running').length;\n const successCount = entries.filter((e) => e.status === 'success').length;\n const errorCount = entries.filter((e) => e.status === 'error').length;\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface overflow-hidden\">\n {/* Header bar — always visible */}\n <button\n type=\"button\"\n onClick={onToggleExpanded}\n className=\"w-full flex items-center justify-between px-4 py-2.5 hover:bg-bg-secondary/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <Terminal size={14} className=\"text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.vibedeck.executionLog.title', 'Execution Log')}\n </span>\n <div className=\"flex items-center gap-2\">\n {runningCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-action-primary-bg/10 text-action-primary-bg\">\n <Loader2 size={10} className=\"animate-spin\" />\n {runningCount}\n </span>\n )}\n {successCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-success-bg/10 text-status-success-text\">\n <Check size={10} />\n {successCount}\n </span>\n )}\n {errorCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-error-bg/10 text-status-error-text\">\n <X size={10} />\n {errorCount}\n </span>\n )}\n <span className=\"text-xs text-text-tertiary\">{entries.length} total</span>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {expanded && (\n <span\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClear();\n }\n }}\n onClick={(e) => {\n e.stopPropagation();\n onClear();\n }}\n className=\"p-1 rounded hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Clear log\"\n >\n <Trash2 size={12} />\n </span>\n )}\n {expanded ? (\n <ChevronDown size={14} className=\"text-text-tertiary\" />\n ) : (\n <ChevronUp size={14} className=\"text-text-tertiary\" />\n )}\n </div>\n </button>\n\n {/* Log entries — expandable */}\n <AnimatePresence>\n {expanded && (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: 0.2 }}\n className=\"overflow-hidden\"\n >\n <div className=\"border-t border-border-default\" />\n <div\n ref={scrollRef}\n className=\"max-h-[240px] overflow-y-auto divide-y divide-border-default/50\"\n >\n {entries.map((entry) => (\n <div\n key={entry.id}\n className={`px-4 py-2.5 flex items-start gap-3 text-sm transition-colors ${\n entry.status === 'running' ? 'bg-action-primary-bg/5' : ''\n }`}\n >\n {/* Status icon */}\n <div className=\"pt-0.5 shrink-0\">\n <StatusIcon status={entry.status} />\n </div>\n\n {/* Main content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-text-primary truncate\">\n {entry.buttonLabel}\n </span>\n <span\n className={`inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold uppercase ${statusBadgeClass[entry.status]}`}\n >\n {statusLabel[entry.status]}\n </span>\n <span className=\"flex items-center gap-1 text-text-tertiary\">\n <ActionTypeIcon type={entry.actionType} />\n </span>\n </div>\n\n {/* Command or detail */}\n {entry.command && (\n <div className=\"mt-0.5 text-xs text-text-tertiary font-mono truncate\">\n {entry.command}\n </div>\n )}\n\n {/* Output (collapsed, show first line) */}\n {entry.output && (\n <pre className=\"mt-1 text-[11px] font-mono text-text-secondary bg-bg-sunken rounded px-2 py-1 max-h-16 overflow-y-auto whitespace-pre-wrap\">\n {entry.output}\n </pre>\n )}\n\n {/* Error message */}\n {entry.error && (\n <div className=\"mt-1 text-xs text-status-error-text font-mono\">\n {entry.error}\n </div>\n )}\n </div>\n\n {/* Timing */}\n <div className=\"shrink-0 text-right\">\n <div className=\"text-[10px] text-text-tertiary\">\n {formatTime(entry.startedAt)}\n </div>\n <div className=\"text-[10px] text-text-tertiary font-mono\">\n {formatDuration(entry.startedAt, entry.completedAt)}\n </div>\n {entry.exitCode != null && entry.exitCode !== 0 && (\n <div className=\"text-[10px] text-status-error-text font-mono\">\n exit {entry.exitCode}\n </div>\n )}\n {entry.webhookStatusCode != null && (\n <div\n className={`text-[10px] font-mono ${entry.webhookStatusCode >= 400 ? 'text-status-error-text' : 'text-text-tertiary'}`}\n >\n HTTP {entry.webhookStatusCode}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeDeckExecutionLog.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckExecutionLog.tsx"],"sourcesContent":["import { type FC, useRef, useEffect } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Terminal,\n Globe,\n FileCode,\n Check,\n X,\n Loader2,\n Clock,\n ChevronDown,\n ChevronUp,\n Trash2,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface ExecutionLogEntry {\n id: string;\n buttonId: string;\n buttonLabel: string;\n actionType: 'COMMAND' | 'SCRIPT' | 'WEBHOOK';\n command?: string | null;\n status: 'pending' | 'running' | 'success' | 'error';\n output?: string | null;\n exitCode?: number | null;\n webhookStatusCode?: number | null;\n startedAt: Date;\n completedAt?: Date | null;\n error?: string | null;\n}\n\ninterface VibeDeckExecutionLogProps {\n entries: ExecutionLogEntry[];\n expanded: boolean;\n onToggleExpanded: () => void;\n onClear: () => void;\n}\n\nfunction formatDuration(start: Date, end?: Date | null): string {\n const ms = (end ? end.getTime() : Date.now()) - start.getTime();\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;\n}\n\nfunction formatTime(date: Date): string {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nconst StatusIcon: FC<{ status: ExecutionLogEntry['status'] }> = ({ status }) => {\n switch (status) {\n case 'pending':\n return <Clock size={14} className=\"text-text-tertiary\" />;\n case 'running':\n return <Loader2 size={14} className=\"text-action-primary-bg animate-spin\" />;\n case 'success':\n return <Check size={14} className=\"text-status-success-text\" />;\n case 'error':\n return <X size={14} className=\"text-status-error-text\" />;\n }\n};\n\nconst ActionTypeIcon: FC<{ type: string }> = ({ type }) => {\n switch (type) {\n case 'WEBHOOK':\n return <Globe size={12} className=\"text-text-tertiary\" />;\n case 'SCRIPT':\n return <FileCode size={12} className=\"text-text-tertiary\" />;\n default:\n return <Terminal size={12} className=\"text-text-tertiary\" />;\n }\n};\n\nconst statusLabel: Record<string, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Failed',\n};\n\nconst statusBadgeClass: Record<string, string> = {\n pending: 'bg-bg-sunken text-text-tertiary',\n running: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n success: 'bg-status-success-bg-subtle text-status-success-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\nexport const VibeDeckExecutionLog: FC<VibeDeckExecutionLogProps> = ({\n entries,\n expanded,\n onToggleExpanded,\n onClear,\n}) => {\n const tr = useTr();\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new entries arrive\n useEffect(() => {\n if (scrollRef.current && expanded) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n }\n }, [entries.length, expanded]);\n\n if (entries.length === 0) return null;\n\n const runningCount = entries.filter((e) => e.status === 'running').length;\n const successCount = entries.filter((e) => e.status === 'success').length;\n const errorCount = entries.filter((e) => e.status === 'error').length;\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface overflow-hidden\">\n {/* Header bar — always visible */}\n <button\n type=\"button\"\n onClick={onToggleExpanded}\n className=\"w-full flex items-center justify-between px-4 py-2.5 hover:bg-bg-sunken transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <Terminal size={14} className=\"text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.vibedeck.executionLog.title', 'Execution Log')}\n </span>\n <div className=\"flex items-center gap-2\">\n {runningCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-[var(--color-accent-soft)] text-action-primary-bg\">\n <Loader2 size={10} className=\"animate-spin\" />\n {runningCount}\n </span>\n )}\n {successCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-success-bg-subtle text-status-success-text\">\n <Check size={10} />\n {successCount}\n </span>\n )}\n {errorCount > 0 && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-status-error-bg-subtle text-status-error-text\">\n <X size={10} />\n {errorCount}\n </span>\n )}\n <span className=\"text-xs text-text-tertiary\">{entries.length} total</span>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {expanded && (\n <span\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClear();\n }\n }}\n onClick={(e) => {\n e.stopPropagation();\n onClear();\n }}\n className=\"p-1 rounded hover:bg-bg-sunken text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Clear log\"\n >\n <Trash2 size={12} />\n </span>\n )}\n {expanded ? (\n <ChevronDown size={14} className=\"text-text-tertiary\" />\n ) : (\n <ChevronUp size={14} className=\"text-text-tertiary\" />\n )}\n </div>\n </button>\n\n {/* Log entries — expandable */}\n <AnimatePresence>\n {expanded && (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: 0.2 }}\n className=\"overflow-hidden\"\n >\n <div className=\"border-t border-border-default\" />\n <div\n ref={scrollRef}\n className=\"max-h-[240px] overflow-y-auto divide-y divide-border-default/50\"\n >\n {entries.map((entry) => (\n <div\n key={entry.id}\n className={`px-4 py-2.5 flex items-start gap-3 text-sm transition-colors ${\n entry.status === 'running' ? 'bg-[var(--color-accent-soft)]' : ''\n }`}\n >\n {/* Status icon */}\n <div className=\"pt-0.5 shrink-0\">\n <StatusIcon status={entry.status} />\n </div>\n\n {/* Main content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-text-primary truncate\">\n {entry.buttonLabel}\n </span>\n <span\n className={`inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold uppercase ${statusBadgeClass[entry.status]}`}\n >\n {statusLabel[entry.status]}\n </span>\n <span className=\"flex items-center gap-1 text-text-tertiary\">\n <ActionTypeIcon type={entry.actionType} />\n </span>\n </div>\n\n {/* Command or detail */}\n {entry.command && (\n <div className=\"mt-0.5 text-xs text-text-tertiary font-mono truncate\">\n {entry.command}\n </div>\n )}\n\n {/* Output (collapsed, show first line) */}\n {entry.output && (\n <pre className=\"mt-1 text-[11px] font-mono text-text-secondary bg-bg-sunken rounded px-2 py-1 max-h-16 overflow-y-auto whitespace-pre-wrap\">\n {entry.output}\n </pre>\n )}\n\n {/* Error message */}\n {entry.error && (\n <div className=\"mt-1 text-xs text-status-error-text font-mono\">\n {entry.error}\n </div>\n )}\n </div>\n\n {/* Timing */}\n <div className=\"shrink-0 text-right\">\n <div className=\"text-[10px] text-text-tertiary\">\n {formatTime(entry.startedAt)}\n </div>\n <div className=\"text-[10px] text-text-tertiary font-mono\">\n {formatDuration(entry.startedAt, entry.completedAt)}\n </div>\n {entry.exitCode != null && entry.exitCode !== 0 && (\n <div className=\"text-[10px] text-status-error-text font-mono\">\n exit {entry.exitCode}\n </div>\n )}\n {entry.webhookStatusCode != null && (\n <div\n className={`text-[10px] font-mono ${entry.webhookStatusCode >= 400 ? 'text-status-error-text' : 'text-text-tertiary'}`}\n >\n HTTP {entry.webhookStatusCode}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -103,7 +103,7 @@ var a = [
103
103
  }), /* @__PURE__ */ r("button", {
104
104
  type: "button",
105
105
  onClick: l,
106
- className: "p-1 rounded hover:bg-bg-tertiary text-text-tertiary",
106
+ className: "p-1 rounded hover:bg-bg-sunken text-text-tertiary",
107
107
  children: /* @__PURE__ */ r(n, { size: 18 })
108
108
  })]
109
109
  }), /* @__PURE__ */ i("form", {
@@ -123,7 +123,7 @@ var a = [
123
123
  ...g,
124
124
  name: e.target.value
125
125
  }),
126
- className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
126
+ className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
127
127
  placeholder: m("vibeDeck.namePlaceholder", "My Vibe Deck"),
128
128
  required: !0
129
129
  })] }),
@@ -137,7 +137,7 @@ var a = [
137
137
  ...g,
138
138
  description: e.target.value
139
139
  }),
140
- className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none",
140
+ className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none",
141
141
  rows: 2,
142
142
  placeholder: m("vibeDeck.descriptionPlaceholder", "Optional description...")
143
143
  })] }),
@@ -150,7 +150,7 @@ var a = [
150
150
  ...g,
151
151
  colorTheme: e.target.value
152
152
  }),
153
- className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
153
+ className: "w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
154
154
  children: h.map((e) => /* @__PURE__ */ r("option", {
155
155
  value: e.value,
156
156
  children: e.label
@@ -170,7 +170,7 @@ var a = [
170
170
  gridColumns: e.cols,
171
171
  gridRows: e.rows
172
172
  }),
173
- className: `px-3 py-1.5 rounded-lg text-sm border transition-colors ${g.gridColumns === e.cols && g.gridRows === e.rows ? "border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-tertiary"}`,
173
+ className: `px-3 py-1.5 rounded-lg text-sm border transition-colors ${g.gridColumns === e.cols && g.gridRows === e.rows ? "border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-sunken"}`,
174
174
  children: e.label
175
175
  }, e.label))
176
176
  }),
@@ -191,7 +191,7 @@ var a = [
191
191
  ...g,
192
192
  gridColumns: parseInt(e.target.value) || 4
193
193
  }),
194
- className: "w-full px-2 py-1 rounded border border-border-default bg-bg-secondary text-text-primary text-sm"
194
+ className: "w-full px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm"
195
195
  })]
196
196
  }), /* @__PURE__ */ i("div", {
197
197
  className: "flex-1",
@@ -208,7 +208,7 @@ var a = [
208
208
  ...g,
209
209
  gridRows: parseInt(e.target.value) || 3
210
210
  }),
211
- className: "w-full px-2 py-1 rounded border border-border-default bg-bg-secondary text-text-primary text-sm"
211
+ className: "w-full px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm"
212
212
  })]
213
213
  })]
214
214
  })
@@ -222,7 +222,7 @@ var a = [
222
222
  children: [/* @__PURE__ */ r("button", {
223
223
  type: "button",
224
224
  onClick: l,
225
- className: "px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-tertiary transition-colors",
225
+ className: "px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-sunken transition-colors",
226
226
  children: m("vibeDeck.cancel", "Cancel")
227
227
  }), /* @__PURE__ */ r("button", {
228
228
  type: "submit",
@@ -1 +1 @@
1
- {"version":3,"file":"VibeDeckForm.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckForm.tsx"],"sourcesContent":["import { type FC, type ReactNode, useState } from 'react';\nimport { X } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface VibeDeckFormData {\n name: string;\n description: string;\n icon: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n buttonSize: string;\n}\n\ninterface VibeDeckFormProps {\n initialData?: Partial<VibeDeckFormData>;\n onSubmit: (data: VibeDeckFormData) => void;\n onCancel: () => void;\n isLoading: boolean;\n title: string;\n /** Optional extra content rendered below the form fields (e.g. tag picker in edit mode) */\n extraSection?: ReactNode;\n}\n\nconst colorOptionKeys: { value: string; labelKey: string; fallback: string }[] = [\n { value: '', labelKey: 'vibeDeck.colorDefault', fallback: 'Default' },\n { value: 'blue', labelKey: 'vibeDeck.colorBlue', fallback: 'Blue' },\n { value: 'green', labelKey: 'vibeDeck.colorGreen', fallback: 'Green' },\n { value: 'red', labelKey: 'vibeDeck.colorRed', fallback: 'Red' },\n { value: 'purple', labelKey: 'vibeDeck.colorPurple', fallback: 'Purple' },\n { value: 'orange', labelKey: 'vibeDeck.colorOrange', fallback: 'Orange' },\n { value: 'cyan', labelKey: 'vibeDeck.colorCyan', fallback: 'Cyan' },\n { value: 'pink', labelKey: 'vibeDeck.colorPink', fallback: 'Pink' },\n];\n\nconst gridPresets = [\n { label: '3x3', cols: 3, rows: 3 },\n { label: '4x3', cols: 4, rows: 3 },\n { label: '4x4', cols: 4, rows: 4 },\n { label: '5x3', cols: 5, rows: 3 },\n { label: '5x4', cols: 5, rows: 4 },\n { label: '6x4', cols: 6, rows: 4 },\n];\n\nexport const VibeDeckForm: FC<VibeDeckFormProps> = ({\n initialData,\n onSubmit,\n onCancel,\n isLoading,\n title,\n extraSection,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const colorOptions = colorOptionKeys.map((opt) => ({\n value: opt.value,\n label: tr(opt.labelKey, opt.fallback),\n }));\n\n const [form, setForm] = useState<VibeDeckFormData>({\n name: initialData?.name || '',\n description: initialData?.description || '',\n icon: initialData?.icon || '',\n colorTheme: initialData?.colorTheme || '',\n gridColumns: initialData?.gridColumns || 4,\n gridRows: initialData?.gridRows || 3,\n buttonSize: initialData?.buttonSize || 'md',\n });\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onSubmit(form);\n };\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay backdrop-blur-sm\">\n <div className=\"bg-bg-elevated border border-border-default rounded-xl shadow-xl w-full max-w-md mx-4\">\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"p-1 rounded hover:bg-bg-tertiary text-text-tertiary\"\n >\n <X size={18} />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-6 space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.name', 'Name')} *\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n placeholder={tr('vibeDeck.namePlaceholder', 'My Vibe Deck')}\n required\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.description', 'Description')}\n </label>\n <textarea\n aria-label=\"control\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n rows={2}\n placeholder={tr('vibeDeck.descriptionPlaceholder', 'Optional description...')}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.colorTheme', 'Color Theme')}\n </label>\n <select\n value={form.colorTheme}\n onChange={(e) => setForm({ ...form, colorTheme: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-secondary text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {colorOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.gridLayout', 'Grid Layout')}\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {gridPresets.map((preset) => {\n const isActive = form.gridColumns === preset.cols && form.gridRows === preset.rows;\n return (\n <button\n key={preset.label}\n type=\"button\"\n onClick={() =>\n setForm({ ...form, gridColumns: preset.cols, gridRows: preset.rows })\n }\n className={`px-3 py-1.5 rounded-lg text-sm border transition-colors ${\n isActive\n ? 'border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-tertiary'\n }`}\n >\n {preset.label}\n </button>\n );\n })}\n </div>\n <div className=\"flex gap-2 mt-2\">\n <div className=\"flex-1\">\n <label className=\"text-xs text-text-tertiary\">\n {tr('vibeDeck.columns', 'Columns')}\n </label>\n <input\n aria-label=\"control\"\n type=\"number\"\n min={1}\n max={10}\n value={form.gridColumns}\n onChange={(e) => setForm({ ...form, gridColumns: parseInt(e.target.value) || 4 })}\n className=\"w-full px-2 py-1 rounded border border-border-default bg-bg-secondary text-text-primary text-sm\"\n />\n </div>\n <div className=\"flex-1\">\n <label className=\"text-xs text-text-tertiary\">{tr('vibeDeck.rows', 'Rows')}</label>\n <input\n aria-label=\"control\"\n type=\"number\"\n min={1}\n max={10}\n value={form.gridRows}\n onChange={(e) => setForm({ ...form, gridRows: parseInt(e.target.value) || 3 })}\n className=\"w-full px-2 py-1 rounded border border-border-default bg-bg-secondary text-text-primary text-sm\"\n />\n </div>\n </div>\n </div>\n\n {extraSection && (\n <div className=\"border-t border-border-default pt-4\">{extraSection}</div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-tertiary transition-colors\"\n >\n {tr('vibeDeck.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isLoading || !form.name.trim()}\n className=\"px-4 py-2 rounded-lg text-sm bg-action-primary-bg text-action-primary-text hover:opacity-90 transition-opacity disabled:opacity-50\"\n >\n {isLoading ? tr('vibeDeck.saving', 'Saving...') : tr('vibeDeck.save', 'Save')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeDeckForm.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckForm.tsx"],"sourcesContent":["import { type FC, type ReactNode, useState } from 'react';\nimport { X } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface VibeDeckFormData {\n name: string;\n description: string;\n icon: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n buttonSize: string;\n}\n\ninterface VibeDeckFormProps {\n initialData?: Partial<VibeDeckFormData>;\n onSubmit: (data: VibeDeckFormData) => void;\n onCancel: () => void;\n isLoading: boolean;\n title: string;\n /** Optional extra content rendered below the form fields (e.g. tag picker in edit mode) */\n extraSection?: ReactNode;\n}\n\nconst colorOptionKeys: { value: string; labelKey: string; fallback: string }[] = [\n { value: '', labelKey: 'vibeDeck.colorDefault', fallback: 'Default' },\n { value: 'blue', labelKey: 'vibeDeck.colorBlue', fallback: 'Blue' },\n { value: 'green', labelKey: 'vibeDeck.colorGreen', fallback: 'Green' },\n { value: 'red', labelKey: 'vibeDeck.colorRed', fallback: 'Red' },\n { value: 'purple', labelKey: 'vibeDeck.colorPurple', fallback: 'Purple' },\n { value: 'orange', labelKey: 'vibeDeck.colorOrange', fallback: 'Orange' },\n { value: 'cyan', labelKey: 'vibeDeck.colorCyan', fallback: 'Cyan' },\n { value: 'pink', labelKey: 'vibeDeck.colorPink', fallback: 'Pink' },\n];\n\nconst gridPresets = [\n { label: '3x3', cols: 3, rows: 3 },\n { label: '4x3', cols: 4, rows: 3 },\n { label: '4x4', cols: 4, rows: 4 },\n { label: '5x3', cols: 5, rows: 3 },\n { label: '5x4', cols: 5, rows: 4 },\n { label: '6x4', cols: 6, rows: 4 },\n];\n\nexport const VibeDeckForm: FC<VibeDeckFormProps> = ({\n initialData,\n onSubmit,\n onCancel,\n isLoading,\n title,\n extraSection,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const colorOptions = colorOptionKeys.map((opt) => ({\n value: opt.value,\n label: tr(opt.labelKey, opt.fallback),\n }));\n\n const [form, setForm] = useState<VibeDeckFormData>({\n name: initialData?.name || '',\n description: initialData?.description || '',\n icon: initialData?.icon || '',\n colorTheme: initialData?.colorTheme || '',\n gridColumns: initialData?.gridColumns || 4,\n gridRows: initialData?.gridRows || 3,\n buttonSize: initialData?.buttonSize || 'md',\n });\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onSubmit(form);\n };\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay backdrop-blur-sm\">\n <div className=\"bg-bg-elevated border border-border-default rounded-xl shadow-xl w-full max-w-md mx-4\">\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"p-1 rounded hover:bg-bg-sunken text-text-tertiary\"\n >\n <X size={18} />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-6 space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.name', 'Name')} *\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n placeholder={tr('vibeDeck.namePlaceholder', 'My Vibe Deck')}\n required\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.description', 'Description')}\n </label>\n <textarea\n aria-label=\"control\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n rows={2}\n placeholder={tr('vibeDeck.descriptionPlaceholder', 'Optional description...')}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr('vibeDeck.colorTheme', 'Color Theme')}\n </label>\n <select\n value={form.colorTheme}\n onChange={(e) => setForm({ ...form, colorTheme: e.target.value })}\n className=\"w-full px-3 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n {colorOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.gridLayout', 'Grid Layout')}\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {gridPresets.map((preset) => {\n const isActive = form.gridColumns === preset.cols && form.gridRows === preset.rows;\n return (\n <button\n key={preset.label}\n type=\"button\"\n onClick={() =>\n setForm({ ...form, gridColumns: preset.cols, gridRows: preset.rows })\n }\n className={`px-3 py-1.5 rounded-lg text-sm border transition-colors ${\n isActive\n ? 'border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {preset.label}\n </button>\n );\n })}\n </div>\n <div className=\"flex gap-2 mt-2\">\n <div className=\"flex-1\">\n <label className=\"text-xs text-text-tertiary\">\n {tr('vibeDeck.columns', 'Columns')}\n </label>\n <input\n aria-label=\"control\"\n type=\"number\"\n min={1}\n max={10}\n value={form.gridColumns}\n onChange={(e) => setForm({ ...form, gridColumns: parseInt(e.target.value) || 4 })}\n className=\"w-full px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm\"\n />\n </div>\n <div className=\"flex-1\">\n <label className=\"text-xs text-text-tertiary\">{tr('vibeDeck.rows', 'Rows')}</label>\n <input\n aria-label=\"control\"\n type=\"number\"\n min={1}\n max={10}\n value={form.gridRows}\n onChange={(e) => setForm({ ...form, gridRows: parseInt(e.target.value) || 3 })}\n className=\"w-full px-2 py-1 rounded border border-border-default bg-bg-surface text-text-primary text-sm\"\n />\n </div>\n </div>\n </div>\n\n {extraSection && (\n <div className=\"border-t border-border-default pt-4\">{extraSection}</div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 rounded-lg text-sm text-text-secondary hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibeDeck.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isLoading || !form.name.trim()}\n className=\"px-4 py-2 rounded-lg text-sm bg-action-primary-bg text-action-primary-text hover:opacity-90 transition-opacity disabled:opacity-50\"\n >\n {isLoading ? tr('vibeDeck.saving', 'Saving...') : tr('vibeDeck.save', 'Save')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}