@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.
- package/dist/components/actions/ActionCard.js +2 -2
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/actions/ExecutionHistory.js +1 -1
- package/dist/components/actions/ExecutionHistory.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerChatPane.js +2 -2
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +4 -4
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerSidebar.js +5 -5
- package/dist/components/agent-manager/AgentManagerSidebar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js.map +1 -1
- package/dist/components/agent-manager/BridleConfigPanel.js +23 -23
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js.map +1 -1
- package/dist/components/agent-manager/ProfilesPanel.js +5 -5
- package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
- package/dist/components/agent-manager/detail/SessionConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionLogsPanel.js +5 -5
- package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js.map +1 -1
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js +2 -2
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js.map +1 -1
- package/dist/components/agents/AgentCard.js +14 -11
- package/dist/components/agents/AgentCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +1 -1
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AIOverviewTab.js +4 -4
- package/dist/components/ai/AIOverviewTab.js.map +1 -1
- package/dist/components/ai/AIPlanPanel.js +4 -4
- package/dist/components/ai/AIPlanPanel.js.map +1 -1
- package/dist/components/ai/AIPlaygroundTab.js +1 -1
- package/dist/components/ai/AIPlaygroundTab.js.map +1 -1
- package/dist/components/ai/AIPromptsTab.js +2 -2
- package/dist/components/ai/AIPromptsTab.js.map +1 -1
- package/dist/components/ai/AIProviderCredentialsCard.js +4 -4
- package/dist/components/ai/AIProviderCredentialsCard.js.map +1 -1
- package/dist/components/ai/AIQueueTab.js +4 -4
- package/dist/components/ai/AIQueueTab.js.map +1 -1
- package/dist/components/ai/AISessionsTab.js +4 -4
- package/dist/components/ai/AISessionsTab.js.map +1 -1
- package/dist/components/ai/AITasksTab.js +1 -1
- package/dist/components/ai/AITasksTab.js.map +1 -1
- package/dist/components/ai/ClaudeCredentialsCard.js +3 -3
- package/dist/components/ai/ClaudeCredentialsCard.js.map +1 -1
- package/dist/components/ai/PluginHarnessPicker.js +3 -3
- package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
- package/dist/components/analytics/AnalyticsBreakdownChart.js +8 -8
- package/dist/components/analytics/AnalyticsBreakdownChart.js.map +1 -1
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js +5 -5
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js.map +1 -1
- package/dist/components/audit/AuditDeleteDialog.js +2 -2
- package/dist/components/audit/AuditDeleteDialog.js.map +1 -1
- package/dist/components/audit/AuditExportButton.js +5 -5
- package/dist/components/audit/AuditExportButton.js.map +1 -1
- package/dist/components/audit/AuditLogDetail.js +9 -9
- package/dist/components/audit/AuditLogDetail.js.map +1 -1
- package/dist/components/audit/AuditLogFilters.js +1 -1
- package/dist/components/audit/AuditLogFilters.js.map +1 -1
- package/dist/components/audit/AuditLogStats.js +1 -1
- package/dist/components/audit/AuditLogStats.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js +28 -28
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/catalog/CatalogCard.js +3 -3
- package/dist/components/catalog/CatalogCard.js.map +1 -1
- package/dist/components/catalog/CatalogForm.js +1 -1
- package/dist/components/catalog/CatalogForm.js.map +1 -1
- package/dist/components/common/ActionAgentTargetNotice.js +6 -6
- package/dist/components/common/ActionAgentTargetNotice.js.map +1 -1
- package/dist/components/common/CommandEditor.js +1 -1
- package/dist/components/common/CommandEditor.js.map +1 -1
- package/dist/components/docs/DocsPageTree.js +1 -1
- package/dist/components/docs/DocsPageTree.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +1 -1
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsRevisionHistory.js +4 -4
- package/dist/components/docs/DocsRevisionHistory.js.map +1 -1
- package/dist/components/docs/DocsSettingsPanel.js +7 -7
- package/dist/components/docs/DocsSettingsPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +1 -1
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
- package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
- package/dist/components/graph/MeshDeployWizard.js +3 -3
- package/dist/components/graph/MeshDeployWizard.js.map +1 -1
- package/dist/components/graph/MeshRequestPanel.js +2 -2
- package/dist/components/graph/MeshRequestPanel.js.map +1 -1
- package/dist/components/idp-components/ComponentCard.js +5 -5
- package/dist/components/idp-components/ComponentCard.js.map +1 -1
- package/dist/components/idp-components/ComponentForm.js +1 -1
- package/dist/components/idp-components/ComponentForm.js.map +1 -1
- package/dist/components/idp-components/DependencyGraphTab.js +7 -7
- package/dist/components/idp-components/DependencyGraphTab.js.map +1 -1
- package/dist/components/logs/LogViewer.js +14 -14
- package/dist/components/logs/LogViewer.js.map +1 -1
- package/dist/components/notes/NoteCard.js +1 -1
- package/dist/components/notes/NoteCard.js.map +1 -1
- package/dist/components/notes/NoteEditor.js +2 -2
- package/dist/components/notes/NoteEditor.js.map +1 -1
- package/dist/components/notes/NoteList.js +1 -1
- package/dist/components/notes/NoteList.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +1 -1
- package/dist/components/notes/NotesTabPanel.js.map +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js.map +1 -1
- package/dist/components/scorecard/ScorecardPanel.js +3 -3
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/security/SecurityScanList.js +11 -11
- package/dist/components/security/SecurityScanList.js.map +1 -1
- package/dist/components/sessions/SessionCard.js +26 -19
- package/dist/components/sessions/SessionCard.js.map +1 -1
- package/dist/components/sessions/SessionStatusBadge.js +7 -7
- package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
- package/dist/components/shared/AgentSelector.js +4 -4
- package/dist/components/shared/AgentSelector.js.map +1 -1
- package/dist/components/shared/AgentSetupBanner.js +3 -3
- package/dist/components/shared/AgentSetupBanner.js.map +1 -1
- package/dist/components/shared/Card.js +4 -4
- package/dist/components/shared/Card.js.map +1 -1
- package/dist/components/shared/ErrorState.js +15 -9
- package/dist/components/shared/ErrorState.js.map +1 -1
- package/dist/components/shared/FilterDropdown.js +2 -2
- package/dist/components/shared/FilterDropdown.js.map +1 -1
- package/dist/components/shared/PageSkeleton.js +6 -6
- package/dist/components/shared/PageSkeleton.js.map +1 -1
- package/dist/components/shared/SearchInput.js +1 -1
- package/dist/components/shared/SearchInput.js.map +1 -1
- package/dist/components/shared/StatCard.js +7 -7
- package/dist/components/shared/StatCard.js.map +1 -1
- package/dist/components/templates/PublishTemplateForm.js +2 -2
- package/dist/components/templates/PublishTemplateForm.js.map +1 -1
- package/dist/components/templates/TemplateCard.js +5 -5
- package/dist/components/templates/TemplateCard.js.map +1 -1
- package/dist/components/templates/TemplateWizard.js +2 -2
- package/dist/components/templates/TemplateWizard.js.map +1 -1
- package/dist/components/tunnels/DomainVerificationBadge.js +4 -4
- package/dist/components/tunnels/DomainVerificationBadge.js.map +1 -1
- package/dist/components/tunnels/ProviderBadge.js +1 -1
- package/dist/components/tunnels/ProviderBadge.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +16 -16
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
- package/dist/components/tunnels/TunnelStatusBadge.js +4 -4
- package/dist/components/tunnels/TunnelStatusBadge.js.map +1 -1
- package/dist/components/vibecalendar/LogsDrawer.js +2 -2
- package/dist/components/vibecalendar/LogsDrawer.js.map +1 -1
- package/dist/components/vibecalendar/ScheduleTaskModal.js +5 -5
- package/dist/components/vibecalendar/ScheduleTaskModal.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalAgendaView.js +2 -2
- package/dist/components/vibecalendar/VibeCalAgendaView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalDayView.js +3 -3
- package/dist/components/vibecalendar/VibeCalDayView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalWeekView.js +4 -4
- package/dist/components/vibecalendar/VibeCalWeekView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalendarHeader.js +4 -4
- package/dist/components/vibecalendar/VibeCalendarHeader.js.map +1 -1
- package/dist/components/vibecalendar/VibeTaskBlock.js +2 -2
- package/dist/components/vibecalendar/VibeTaskBlock.js.map +1 -1
- package/dist/components/vibecalendar/types.js +6 -6
- package/dist/components/vibecalendar/types.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonForm.js +9 -9
- package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonTile.js +6 -6
- package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckExecutionLog.js +10 -10
- package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckForm.js +8 -8
- package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
- package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +2 -2
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckSwitcher.js +8 -8
- package/dist/components/vibedeck/VibeDeckSwitcher.js.map +1 -1
- package/dist/components/vibes/VibeCard.js +22 -18
- package/dist/components/vibes/VibeCard.js.map +1 -1
- package/dist/components/vibes/VibeList.js +16 -12
- package/dist/components/vibes/VibeList.js.map +1 -1
- package/dist/pages/ActionsPage.js +4 -3
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +9 -9
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsLandingPage.js +4 -4
- package/dist/pages/AgentsLandingPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +14 -14
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +8 -8
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +11 -11
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +12 -9
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +7 -7
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +12 -9
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/EnvTopologyPage.js +2 -2
- package/dist/pages/EnvTopologyPage.js.map +1 -1
- package/dist/pages/GettingStartedPage.js +12 -12
- package/dist/pages/GettingStartedPage.js.map +1 -1
- package/dist/pages/HealthPage.js +12 -12
- package/dist/pages/HealthPage.js.map +1 -1
- package/dist/pages/LogsPage.js +4 -4
- package/dist/pages/LogsPage.js.map +1 -1
- package/dist/pages/NoteDetailsPage.js +5 -5
- package/dist/pages/NoteDetailsPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +74 -41
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/PluginsCatalogPage.js +6 -3
- package/dist/pages/PluginsCatalogPage.js.map +1 -1
- package/dist/pages/ScheduledJobDetailPage.js +7 -7
- package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +21 -21
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +20 -20
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SettingsPage.js +64 -52
- package/dist/pages/SettingsPage.js.map +1 -1
- package/dist/pages/SharedSessionPage.js +21 -21
- package/dist/pages/SharedSessionPage.js.map +1 -1
- package/dist/pages/SharedVibeDeckPage.js +5 -5
- package/dist/pages/SharedVibeDeckPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +56 -65
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +4 -4
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +10 -10
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +6 -5
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js +3 -3
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeCalendarPage.js +3 -3
- package/dist/pages/VibeCalendarPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +3 -3
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +15 -15
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibeTaskDetailPage.js +5 -5
- package/dist/pages/VibeTaskDetailPage.js.map +1 -1
- package/dist/pages/VibesPage.js +18 -18
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/WebhooksPage.js +11 -11
- package/dist/pages/WebhooksPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +1 -1
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +6 -6
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/tunnels/AuditTab.js +1 -1
- package/dist/pages/tunnels/AuditTab.js.map +1 -1
- package/dist/pages/tunnels/DomainsTab.js +1 -1
- package/dist/pages/tunnels/DomainsTab.js.map +1 -1
- package/dist/pages/tunnels/ProvidersTab.js +1 -1
- package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
- package/dist/pages/tunnels/SessionsTab.js +1 -1
- package/dist/pages/tunnels/SessionsTab.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +3 -3
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/UsageTab.js +1 -1
- package/dist/pages/tunnels/UsageTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +16 -16
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +52 -49
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +9 -9
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ function y({ vibe: e, onOpen: t, onActivate: a, onOpenInEditor: u, onArchive: f,
|
|
|
15
15
|
onKeyDown: (n) => {
|
|
16
16
|
(n.key === "Enter" || n.key === " ") && (n.preventDefault(), t?.(e));
|
|
17
17
|
},
|
|
18
|
-
className: "p-
|
|
18
|
+
className: "p-5 border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 hover:border-border-strong hover:shadow-elevation-2 cursor-pointer transition-all duration-200",
|
|
19
19
|
onClick: () => t?.(e),
|
|
20
20
|
children: [
|
|
21
21
|
/* @__PURE__ */ v("div", {
|
|
@@ -65,7 +65,7 @@ function y({ vibe: e, onOpen: t, onActivate: a, onOpenInEditor: u, onArchive: f,
|
|
|
65
65
|
children: e.path
|
|
66
66
|
}),
|
|
67
67
|
/* @__PURE__ */ v("div", {
|
|
68
|
-
className: "mt-
|
|
68
|
+
className: "mt-4 flex items-center gap-2 justify-end border-t border-border-subtle pt-4",
|
|
69
69
|
children: [
|
|
70
70
|
a && e.status !== "ACTIVE" && /* @__PURE__ */ _("button", {
|
|
71
71
|
type: "button",
|
|
@@ -111,7 +111,7 @@ function y({ vibe: e, onOpen: t, onActivate: a, onOpenInEditor: u, onArchive: f,
|
|
|
111
111
|
function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivate: b, onOpenInEditor: x, selected: S, onToggleSelect: C }) {
|
|
112
112
|
let [w, T] = a(!1), E = i[e.type] || c;
|
|
113
113
|
return /* @__PURE__ */ v("tr", {
|
|
114
|
-
className: `border-b border-border-
|
|
114
|
+
className: `border-b border-border-subtle hover:bg-bg-sunken cursor-pointer transition-colors ${S ? "bg-[var(--color-accent-soft)]" : ""}`,
|
|
115
115
|
onClick: () => t?.(e),
|
|
116
116
|
children: [
|
|
117
117
|
/* @__PURE__ */ _("td", {
|
|
@@ -195,17 +195,21 @@ function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivat
|
|
|
195
195
|
onClick: (e) => {
|
|
196
196
|
e.stopPropagation(), T(!w);
|
|
197
197
|
},
|
|
198
|
-
className: "
|
|
199
|
-
|
|
198
|
+
className: "inline-flex size-8 items-center justify-center rounded-button text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
199
|
+
"aria-label": "Vibe actions",
|
|
200
|
+
children: /* @__PURE__ */ _(u, {
|
|
201
|
+
className: "size-3.5",
|
|
202
|
+
"aria-hidden": "true"
|
|
203
|
+
})
|
|
200
204
|
}), w && /* @__PURE__ */ v("div", {
|
|
201
|
-
className: "absolute right-0 mt-1 w-
|
|
205
|
+
className: "absolute right-0 mt-1.5 w-40 bg-bg-elevated border border-border-subtle rounded-card shadow-elevation-3 z-10 overflow-hidden py-1",
|
|
202
206
|
children: [
|
|
203
207
|
b && e.status !== "ACTIVE" && /* @__PURE__ */ v("button", {
|
|
204
208
|
type: "button",
|
|
205
209
|
onClick: (t) => {
|
|
206
210
|
t.stopPropagation(), b(e), T(!1);
|
|
207
211
|
},
|
|
208
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken
|
|
212
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
209
213
|
children: [/* @__PURE__ */ _(d, { className: "size-4" }), "Activate"]
|
|
210
214
|
}),
|
|
211
215
|
f && /* @__PURE__ */ v("button", {
|
|
@@ -213,7 +217,7 @@ function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivat
|
|
|
213
217
|
onClick: (t) => {
|
|
214
218
|
t.stopPropagation(), f(e), T(!1);
|
|
215
219
|
},
|
|
216
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
|
|
220
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
217
221
|
children: [/* @__PURE__ */ _(p, { className: "size-4" }), "Edit"]
|
|
218
222
|
}),
|
|
219
223
|
x && e.path && /* @__PURE__ */ v("button", {
|
|
@@ -221,7 +225,7 @@ function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivat
|
|
|
221
225
|
onClick: (t) => {
|
|
222
226
|
t.stopPropagation(), x(e), T(!1);
|
|
223
227
|
},
|
|
224
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken",
|
|
228
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
225
229
|
children: [/* @__PURE__ */ _(s, { className: "size-4" }), "Open in VS Code"]
|
|
226
230
|
}),
|
|
227
231
|
g && e.status !== "ARCHIVED" && /* @__PURE__ */ v("button", {
|
|
@@ -229,7 +233,7 @@ function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivat
|
|
|
229
233
|
onClick: (t) => {
|
|
230
234
|
t.stopPropagation(), g(e), T(!1);
|
|
231
235
|
},
|
|
232
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken
|
|
236
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
233
237
|
children: [/* @__PURE__ */ _(o, { className: "size-4" }), "Archive"]
|
|
234
238
|
}),
|
|
235
239
|
y && /* @__PURE__ */ v("button", {
|
|
@@ -237,7 +241,7 @@ function b({ vibe: e, onOpen: t, onEdit: f, onArchive: g, onDelete: y, onActivat
|
|
|
237
241
|
onClick: (t) => {
|
|
238
242
|
t.stopPropagation(), y(e), T(!1);
|
|
239
243
|
},
|
|
240
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-
|
|
244
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors",
|
|
241
245
|
children: [/* @__PURE__ */ _(h, { className: "size-4" }), "Delete"]
|
|
242
246
|
})
|
|
243
247
|
]
|
|
@@ -257,7 +261,7 @@ function x({ vibes: n, onOpen: i, onEdit: a, onArchive: o, onDelete: s, onActiva
|
|
|
257
261
|
action: d && /* @__PURE__ */ v("button", {
|
|
258
262
|
type: "button",
|
|
259
263
|
onClick: d,
|
|
260
|
-
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-
|
|
264
|
+
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-button hover:bg-action-primary-bgHover transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
261
265
|
children: [/* @__PURE__ */ _(f, { className: "size-4" }), w("vibecontrols.vibes.list.createVibe", "Create Vibe")]
|
|
262
266
|
})
|
|
263
267
|
}) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeList.js","names":[],"sources":["../../../src/components/vibes/VibeList.tsx"],"sourcesContent":["import type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { EmptyState } from '../shared/EmptyState';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport {\n FolderOpen,\n Plus,\n GitBranch,\n Tag,\n MoreVertical,\n Play,\n Archive,\n Settings,\n ExternalLink,\n Trash2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface VibeListProps {\n vibes: Vibe[];\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n selectedVibeIds?: Set<string>;\n onToggleSelect?: (vibe: Vibe, checked: boolean) => void;\n onToggleAllVisible?: (checked: boolean) => void;\n allVisibleSelected?: boolean;\n partiallySelected?: boolean;\n}\n\n/**\n * Mobile card view for a single vibe\n */\nfunction VibeListCard({\n vibe,\n onOpen,\n onActivate,\n onOpenInEditor,\n onArchive,\n onDelete,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => onOpen?.(vibe))();\n }\n }}\n className=\"p-4 border border-border-default rounded-lg bg-bg-surface hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(vibe)}\n >\n {/* Header: Icon, Name, Status */}\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n <Icon className=\"size-5 text-action-primary-bg flex-shrink-0 mt-0.5\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate mt-0.5\">{vibe.description}</p>\n )}\n </div>\n </div>\n <StatusBadge status={vibe.status} />\n </div>\n\n {/* Meta info row */}\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n {vibe.gitBranch && (\n <span className=\"flex items-center gap-1\">\n <GitBranch className=\"size-3\" />\n {vibe.gitBranch}\n </span>\n )}\n {vibe.tags && vibe.tags.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Tag className=\"size-3\" />\n {vibe.tags.length} tag{vibe.tags.length !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Path (if exists) */}\n {vibe.path && (\n <div className=\"mt-2 text-xs font-mono text-text-muted truncate\">{vibe.path}</div>\n )}\n\n {/* Actions */}\n <div className=\"mt-3 flex items-center gap-2 justify-end border-t border-border-default pt-3\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Activate\"\n >\n <Play className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open in VS Code\"\n >\n <ExternalLink className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Archive\"\n >\n <Archive className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Delete\"\n >\n <Trash2 className=\"size-4 text-status-error-text\" />\n </button>\n )}\n </div>\n </div>\n );\n}\n\nfunction VibeRow({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onDelete,\n onActivate,\n onOpenInEditor,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <tr\n className={`border-b border-border-default hover:bg-bg-sunken/50 cursor-pointer transition-colors ${\n selected ? 'bg-bg-sunken/40' : ''\n }`}\n onClick={() => onOpen?.(vibe)}\n >\n <td className=\"px-4 py-3\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Icon className=\"size-4 text-action-primary-bg shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate max-w-[250px]\">{vibe.description}</p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={vibe.status} />\n </td>\n <td className=\"px-4 py-3\">\n {vibe.path ? (\n <span className=\"text-xs font-mono text-text-muted truncate block max-w-[180px]\">\n {vibe.path}\n </span>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.gitBranch ? (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <GitBranch className=\"size-3\" />\n <span className=\"truncate max-w-[100px]\">{vibe.gitBranch}</span>\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.tags && vibe.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onArchive || onDelete || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Play className=\"size-4\" />\n Activate\n </button>\n )}\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Settings className=\"size-4\" />\n Edit\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <ExternalLink className=\"size-4\" />\n Open in VS Code\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"size-4\" />\n Archive\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function VibeList({\n vibes,\n onOpen,\n onEdit,\n onArchive,\n onDelete,\n onActivate,\n onOpenInEditor,\n onCreateNew,\n isLoading,\n selectedVibeIds = new Set<string>(),\n onToggleSelect,\n onToggleAllVisible,\n allVisibleSelected = false,\n partiallySelected = false,\n}: VibeListProps) {\n const tr = useTr();\n\n if (!isLoading && vibes.length === 0) {\n return (\n <EmptyState\n icon={<FolderOpen className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.vibes.list.emptyTitle', 'No vibes yet')}\n description={tr(\n 'vibecontrols.vibes.list.emptyDescription',\n 'Vibes are your development projects and environments. Create your first vibe to organize your work.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.vibes.list.createVibe', 'Create Vibe')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <>\n {/* Mobile: Card view */}\n <div className=\"sm:hidden space-y-3\">\n {vibes.map((vibe) => (\n <VibeListCard\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n onArchive={onArchive}\n onDelete={onDelete}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined}\n />\n ))}\n </div>\n\n {/* Desktop: Table view */}\n <div className=\"hidden sm:block border border-border-default rounded-lg overflow-visible\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider w-12\">\n {onToggleAllVisible ? (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible vibes\"\n />\n ) : null}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Name\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Status\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Path\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Branch\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Tags\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody>\n {vibes.map((vibe) => (\n <VibeRow\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onEdit={onEdit}\n onArchive={onArchive}\n onDelete={onDelete}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={\n onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeList.js","names":[],"sources":["../../../src/components/vibes/VibeList.tsx"],"sourcesContent":["import type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { EmptyState } from '../shared/EmptyState';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport {\n FolderOpen,\n Plus,\n GitBranch,\n Tag,\n MoreVertical,\n Play,\n Archive,\n Settings,\n ExternalLink,\n Trash2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface VibeListProps {\n vibes: Vibe[];\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n selectedVibeIds?: Set<string>;\n onToggleSelect?: (vibe: Vibe, checked: boolean) => void;\n onToggleAllVisible?: (checked: boolean) => void;\n allVisibleSelected?: boolean;\n partiallySelected?: boolean;\n}\n\n/**\n * Mobile card view for a single vibe\n */\nfunction VibeListCard({\n vibe,\n onOpen,\n onActivate,\n onOpenInEditor,\n onArchive,\n onDelete,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => onOpen?.(vibe))();\n }\n }}\n className=\"p-5 border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 hover:border-border-strong hover:shadow-elevation-2 cursor-pointer transition-all duration-200\"\n onClick={() => onOpen?.(vibe)}\n >\n {/* Header: Icon, Name, Status */}\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n <Icon className=\"size-5 text-action-primary-bg flex-shrink-0 mt-0.5\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate mt-0.5\">{vibe.description}</p>\n )}\n </div>\n </div>\n <StatusBadge status={vibe.status} />\n </div>\n\n {/* Meta info row */}\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n {vibe.gitBranch && (\n <span className=\"flex items-center gap-1\">\n <GitBranch className=\"size-3\" />\n {vibe.gitBranch}\n </span>\n )}\n {vibe.tags && vibe.tags.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Tag className=\"size-3\" />\n {vibe.tags.length} tag{vibe.tags.length !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Path (if exists) */}\n {vibe.path && (\n <div className=\"mt-2 text-xs font-mono text-text-muted truncate\">{vibe.path}</div>\n )}\n\n {/* Actions */}\n <div className=\"mt-4 flex items-center gap-2 justify-end border-t border-border-subtle pt-4\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Activate\"\n >\n <Play className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open in VS Code\"\n >\n <ExternalLink className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Archive\"\n >\n <Archive className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Delete\"\n >\n <Trash2 className=\"size-4 text-status-error-text\" />\n </button>\n )}\n </div>\n </div>\n );\n}\n\nfunction VibeRow({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onDelete,\n onActivate,\n onOpenInEditor,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onDelete?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <tr\n className={`border-b border-border-subtle hover:bg-bg-sunken cursor-pointer transition-colors ${\n selected ? 'bg-[var(--color-accent-soft)]' : ''\n }`}\n onClick={() => onOpen?.(vibe)}\n >\n <td className=\"px-4 py-3\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Icon className=\"size-4 text-action-primary-bg shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate max-w-[250px]\">{vibe.description}</p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={vibe.status} />\n </td>\n <td className=\"px-4 py-3\">\n {vibe.path ? (\n <span className=\"text-xs font-mono text-text-muted truncate block max-w-[180px]\">\n {vibe.path}\n </span>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.gitBranch ? (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <GitBranch className=\"size-3\" />\n <span className=\"truncate max-w-[100px]\">{vibe.gitBranch}</span>\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.tags && vibe.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onArchive || onDelete || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"inline-flex size-8 items-center justify-center rounded-button text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n aria-label=\"Vibe actions\"\n >\n <MoreVertical className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1.5 w-40 bg-bg-elevated border border-border-subtle rounded-card shadow-elevation-3 z-10 overflow-hidden py-1\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Play className=\"size-4\" />\n Activate\n </button>\n )}\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Settings className=\"size-4\" />\n Edit\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <ExternalLink className=\"size-4\" />\n Open in VS Code\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Archive className=\"size-4\" />\n Archive\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function VibeList({\n vibes,\n onOpen,\n onEdit,\n onArchive,\n onDelete,\n onActivate,\n onOpenInEditor,\n onCreateNew,\n isLoading,\n selectedVibeIds = new Set<string>(),\n onToggleSelect,\n onToggleAllVisible,\n allVisibleSelected = false,\n partiallySelected = false,\n}: VibeListProps) {\n const tr = useTr();\n\n if (!isLoading && vibes.length === 0) {\n return (\n <EmptyState\n icon={<FolderOpen className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.vibes.list.emptyTitle', 'No vibes yet')}\n description={tr(\n 'vibecontrols.vibes.list.emptyDescription',\n 'Vibes are your development projects and environments. Create your first vibe to organize your work.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-button hover:bg-action-primary-bgHover transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.vibes.list.createVibe', 'Create Vibe')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <>\n {/* Mobile: Card view */}\n <div className=\"sm:hidden space-y-3\">\n {vibes.map((vibe) => (\n <VibeListCard\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n onArchive={onArchive}\n onDelete={onDelete}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined}\n />\n ))}\n </div>\n\n {/* Desktop: Table view */}\n <div className=\"hidden sm:block border border-border-default rounded-lg overflow-visible\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider w-12\">\n {onToggleAllVisible ? (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible vibes\"\n />\n ) : null}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Name\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Status\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Path\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Branch\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Tags\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody>\n {vibes.map((vibe) => (\n <VibeRow\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onEdit={onEdit}\n onArchive={onArchive}\n onDelete={onDelete}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={\n onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -385,7 +385,7 @@ function _() {
|
|
|
385
385
|
message: ft.message,
|
|
386
386
|
onRetry: () => U()
|
|
387
387
|
}) }) : /* @__PURE__ */ h(g, {
|
|
388
|
-
className: "
|
|
388
|
+
className: "px-6 lg:px-8 py-6 space-y-6",
|
|
389
389
|
children: [
|
|
390
390
|
/* @__PURE__ */ m(oe, {
|
|
391
391
|
title: x("nav.actions", "Actions"),
|
|
@@ -395,8 +395,9 @@ function _() {
|
|
|
395
395
|
children: [/* @__PURE__ */ m("button", {
|
|
396
396
|
type: "button",
|
|
397
397
|
onClick: () => U(),
|
|
398
|
-
className: "p-2 rounded-
|
|
398
|
+
className: "p-2 rounded-button hover:bg-bg-sunken text-text-secondary hover:text-text-primary transition-colors",
|
|
399
399
|
title: "Refresh",
|
|
400
|
+
"aria-label": "Refresh",
|
|
400
401
|
children: /* @__PURE__ */ m(Ne, { size: 16 })
|
|
401
402
|
}), Ge && /* @__PURE__ */ h("button", {
|
|
402
403
|
type: "button",
|
|
@@ -582,7 +583,7 @@ function _() {
|
|
|
582
583
|
onKeyDown: (t) => {
|
|
583
584
|
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), lt(e.id));
|
|
584
585
|
},
|
|
585
|
-
className: `p-4 rounded-xl shadow-lg border cursor-pointer ${e.variant === "success" ? "bg-status-success-bg
|
|
586
|
+
className: `p-4 rounded-xl shadow-lg border cursor-pointer ${e.variant === "success" ? "bg-status-success-bg-subtle border-status-success-border text-status-success-text" : "bg-status-error-bg-subtle border-status-error-border text-status-error-text"}`,
|
|
586
587
|
onClick: () => lt(e.id),
|
|
587
588
|
children: [/* @__PURE__ */ m("div", {
|
|
588
589
|
className: "font-medium text-sm",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionsPage.js","names":[],"sources":["../../src/pages/ActionsPage.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useMemo } from 'react';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport { Copy, Play, Plus, RefreshCw, Trash2 } from 'lucide-react';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport { AnimatePresence } from 'framer-motion';\nimport {\n PageHeader,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n EnableRemoteTaskDialog,\n SearchInput,\n FilterDropdown,\n SelectionCheckbox,\n GetHelpButton,\n LinkToVibePanel,\n LINK_TO_VIBE_DEFAULT,\n linkToVibeInput,\n type LinkToVibeValue,\n type LinkToVibeVisibility,\n} from '@/components/shared';\nimport {\n ActionCard,\n ActionForm,\n ActionSchedulesList,\n ExecutionHistory,\n} from '@/components/actions';\nimport type { ActionFormData } from '@/components/actions';\nimport {\n useListActionsQuery,\n useGetActionQuery,\n useListAgentsQuery,\n useCreateActionMutation,\n useUpdateActionMutation,\n useDeleteActionMutation,\n useExecuteActionMutation,\n useDuplicateActionMutation,\n} from '@/generated/wspace-operations';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n isQuotaExhaustedError,\n markQuotaHandledLocally,\n getQuotaDialogContent,\n} from '@/utils/quotaUtils';\nimport { QuotaExhaustedDialog } from '@/components/shared/QuotaExhaustedDialog';\nimport {\n enableRemoteTaskExecution,\n isRemoteTaskDeniedError,\n} from '@/services/agentRemoteTaskGates';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\n\ntype ModalState =\n | { type: 'none' }\n | { type: 'create' }\n | { type: 'edit'; actionId: string }\n | { type: 'confirmDelete'; id: string; name: string }\n | { type: 'confirmExecute'; actionId: string; name: string; agentId?: string };\n\ninterface ErrorToast {\n message: string;\n variant: 'success' | 'error';\n detail?: string | null;\n id: number;\n}\n\nconst ACTION_TYPE_OPTIONS = [\n { value: 'COMMAND', label: 'Command' },\n { value: 'SCRIPT', label: 'Script' },\n { value: 'WEBHOOK', label: 'Webhook' },\n { value: 'WORKFLOW', label: 'Workflow' },\n];\n\nconst TRIGGER_TYPE_OPTIONS = [\n { value: 'MANUAL', label: 'Manual' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'EVENT', label: 'Event' },\n { value: 'ON_DEMAND', label: 'On Demand' },\n];\n\nexport function ActionsPage() {\n const navigate = useNavigate();\n const [searchParams, setSearchParams] = useSearchParams();\n const { workspaceId } = useVibeControls();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const tr = (\n (i18n) =>\n (key: string, fallback: string): string => {\n const v = i18n.t(key);\n return v === key ? fallback : v;\n }\n )(useI18n());\n // Default to true when action permissions haven't been registered in RBAC yet\n const actionPermsRegistered = (\n Array.isArray(permissions) ? permissions : permissions?.permissionStrings\n )?.some?.((p: string) => p.startsWith('action:'));\n const canList = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_LIST) : true;\n const canCreate = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_CREATE) : true;\n const canUpdate = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_UPDATE) : true;\n const canDelete = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_DELETE) : true;\n const canExecute = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_EXECUTE) : true;\n const shouldSkipQueries = permissionsLoading;\n\n const [modal, setModal] = useState<ModalState>({ type: 'none' });\n const [toasts, setToasts] = useState<ErrorToast[]>([]);\n const [searchQuery, setSearchQuery] = useState('');\n const [actionTypeFilter, setActionTypeFilter] = useState<string | null>(null);\n const [triggerTypeFilter, setTriggerTypeFilter] = useState<string | null>(null);\n const [selectedActionId, setSelectedActionId] = useState<string | null>(null);\n const [selectedActionIds, setSelectedActionIds] = useState<Set<string>>(new Set());\n const [executingActionId, setExecutingActionId] = useState<string | null>(null);\n const [bulkModal, setBulkModal] = useState<'delete' | 'execute' | null>(null);\n const [bulkBusy, setBulkBusy] = useState<'delete' | 'execute' | 'duplicate' | null>(null);\n const [quotaKind, setQuotaKind] = useState<'action' | 'command-execution' | null>(null);\n // Reactive \"enable remote execution\" prompt: set when a run is denied because\n // the agent's remote-task gate is off. Captures which action + agent to retry.\n const [remoteTaskPrompt, setRemoteTaskPrompt] = useState<{\n actionId: string;\n agentId: string;\n } | null>(null);\n const [enablingRemoteTask, setEnablingRemoteTask] = useState(false);\n const { profiles: deniedAgentProfiles } = useActiveAgentProfile(\n remoteTaskPrompt?.agentId ?? null\n );\n // The action runner always targets the agent's DEFAULT profile (the backend\n // resolves getDefaultProfileName when no profile is passed), so the gate must\n // be written to that profile — NOT the UI's \"active\" profile, which can differ\n // on multi-profile agents and would unlock the wrong daemon.\n const deniedAgentExecProfile = deniedAgentProfiles.find((p) => p.isDefault)?.name ?? 'default';\n\n // G7: Optional link to a Vibe + visibility for the create / edit forms.\n // Threaded into the create/update mutation input as `vibeId` + `visibility`.\n const [createActionLink, setCreateActionLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n const [editActionLink, setEditActionLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n\n const showToast = useCallback(\n (message: string, variant: 'success' | 'error', detail?: string | null, duration = 10000) => {\n const id = Date.now() + Math.random();\n setToasts((prev) => [...prev, { message, variant, detail, id }]);\n if (variant === 'success') {\n setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), duration);\n }\n },\n []\n );\n\n const dismissToast = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n // Queries\n const {\n data: actionsData,\n loading: actionsLoading,\n error: actionsError,\n refetch: refetchActions,\n } = useListActionsQuery({\n variables: {\n filter: {\n ...(actionTypeFilter && actionTypeFilter !== 'all' ? { actionType: actionTypeFilter } : {}),\n ...(triggerTypeFilter && triggerTypeFilter !== 'all'\n ? { triggerType: triggerTypeFilter }\n : {}),\n ...(searchQuery ? { search: searchQuery } : {}),\n },\n pagination: { limit: 50 },\n },\n skip: shouldSkipQueries,\n });\n\n const actions = useMemo(() => actionsData?.actions?.items || [], [actionsData]);\n\n // Fetch selected action details (with executions)\n const { data: selectedActionData } = useGetActionQuery({\n variables: { id: selectedActionId! },\n skip: !selectedActionId || shouldSkipQueries,\n });\n\n const selectedAction = selectedActionData?.action;\n const recentExecutions = selectedAction?.recentExecutions || [];\n\n // Agents for form\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n skip: shouldSkipQueries,\n });\n const agents = useMemo(\n () =>\n (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string; isActive: boolean }) => ({\n id: a.id,\n name: a.name,\n isActive: a.isActive,\n })\n ),\n [agentsData]\n );\n\n // Mutations\n const [createAction, { loading: createLoading }] = useCreateActionMutation({\n refetchQueries: ['ListActions'],\n });\n const { setDraftTagIds: setActionDraftTagIds, flushTags: flushActionTags } =\n useDraftEntityTags('VIBECONTROLS_ACTION');\n const [updateAction, { loading: updateLoading }] = useUpdateActionMutation({\n refetchQueries: ['ListActions', 'GetAction'],\n });\n const [deleteAction] = useDeleteActionMutation({\n refetchQueries: ['ListActions'],\n });\n const [executeAction] = useExecuteActionMutation({\n refetchQueries: ['GetAction'],\n });\n const [duplicateAction] = useDuplicateActionMutation({\n refetchQueries: ['ListActions'],\n });\n\n // Handlers\n const handleCreate = useCallback(\n async (data: ActionFormData) => {\n try {\n const result = await createAction({\n variables: {\n input: {\n name: data.name,\n displayName: data.displayName || null,\n description: data.description || null,\n actionType: data.actionType,\n triggerType: data.triggerType,\n schedule: data.triggerType === 'SCHEDULED' ? data.schedule || null : null,\n category: data.category || null,\n tags: data.tags.length > 0 ? data.tags : null,\n command: data.actionType === 'COMMAND' ? data.command || null : null,\n workingDirectory:\n data.actionType !== 'WEBHOOK' ? data.workingDirectory || null : null,\n targetAgentId: data.actionType !== 'WEBHOOK' ? data.targetAgentId || null : null,\n script: data.actionType === 'SCRIPT' ? data.script || null : null,\n scriptInterpreter:\n data.actionType === 'SCRIPT' ? data.scriptInterpreter || 'bash' : null,\n webhookUrl: data.actionType === 'WEBHOOK' ? data.webhookUrl || null : null,\n webhookMethod: data.actionType === 'WEBHOOK' ? data.webhookMethod || 'POST' : null,\n webhookBody: data.actionType === 'WEBHOOK' ? data.webhookBody || null : null,\n webhookAuthType: data.actionType === 'WEBHOOK' ? data.webhookAuthType || null : null,\n timeoutMs: data.timeoutMs,\n retryCount: data.retryCount,\n confirmationRequired: data.confirmationRequired,\n ...linkToVibeInput(createActionLink),\n },\n },\n });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n setModal({ type: 'none' });\n markQuotaHandledLocally();\n setQuotaKind('action');\n return;\n }\n const newActionId = result.data?.createAction?.id;\n setModal({ type: 'none' });\n showToast('Action created', 'success');\n setCreateActionLink(LINK_TO_VIBE_DEFAULT);\n if (newActionId) await flushActionTags(newActionId);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setModal({ type: 'none' });\n markQuotaHandledLocally();\n setQuotaKind('action');\n return;\n }\n showToast(err instanceof Error ? err.message : 'Failed to create action', 'error');\n }\n },\n [createAction, flushActionTags, showToast, createActionLink]\n );\n\n const handleUpdate = useCallback(\n async (data: ActionFormData) => {\n if (modal.type !== 'edit') return;\n try {\n await updateAction({\n variables: {\n id: modal.actionId,\n input: {\n displayName: data.displayName || null,\n description: data.description || null,\n actionType: data.actionType,\n triggerType: data.triggerType,\n schedule: data.triggerType === 'SCHEDULED' ? data.schedule || null : null,\n category: data.category || null,\n tags: data.tags.length > 0 ? data.tags : null,\n command: data.actionType === 'COMMAND' ? data.command || null : null,\n workingDirectory:\n data.actionType !== 'WEBHOOK' ? data.workingDirectory || null : null,\n targetAgentId: data.actionType !== 'WEBHOOK' ? data.targetAgentId || null : null,\n script: data.actionType === 'SCRIPT' ? data.script || null : null,\n scriptInterpreter:\n data.actionType === 'SCRIPT' ? data.scriptInterpreter || 'bash' : null,\n webhookUrl: data.actionType === 'WEBHOOK' ? data.webhookUrl || null : null,\n webhookMethod: data.actionType === 'WEBHOOK' ? data.webhookMethod || 'POST' : null,\n webhookBody: data.actionType === 'WEBHOOK' ? data.webhookBody || null : null,\n webhookAuthType: data.actionType === 'WEBHOOK' ? data.webhookAuthType || null : null,\n timeoutMs: data.timeoutMs,\n retryCount: data.retryCount,\n confirmationRequired: data.confirmationRequired,\n ...linkToVibeInput(editActionLink),\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Action updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update action', 'error');\n }\n },\n [updateAction, modal, showToast, editActionLink]\n );\n\n const handleDelete = useCallback(async () => {\n if (modal.type !== 'confirmDelete') return;\n try {\n await deleteAction({ variables: { id: modal.id } });\n if (selectedActionId === modal.id) setSelectedActionId(null);\n setModal({ type: 'none' });\n showToast('Action deleted', 'success');\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete action', 'error');\n if (isNative()) void nativeNotify('error');\n }\n }, [modal, deleteAction, selectedActionId, showToast]);\n\n const handleExecute = async (actionId: string) => {\n const action = actions.find((a: { id: string }) => a.id === actionId) as\n | { id: string; name: string; displayName?: string | null; confirmationRequired: boolean }\n | undefined;\n if (!action) return;\n\n if (action.confirmationRequired) {\n setModal({\n type: 'confirmExecute',\n actionId,\n name: action.displayName || action.name,\n });\n return;\n }\n\n await doExecute(actionId);\n };\n\n const doExecute = useCallback(\n async (actionId: string, allowRemotePrompt = true) => {\n setExecutingActionId(actionId);\n try {\n const result = await executeAction({ variables: { id: actionId } });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n return;\n }\n const exec = result.data?.executeAction;\n // The agent rejected the run because its remote-task gate is off — offer\n // to enable it in context (and retry) instead of a dead-end error toast.\n // allowRemotePrompt is false on the post-enable retry so a still-denied\n // run surfaces a plain error instead of re-opening the dialog forever.\n if (exec && isRemoteTaskDeniedError(exec) && exec.agentId) {\n if (allowRemotePrompt) {\n setRemoteTaskPrompt({ actionId, agentId: exec.agentId });\n } else {\n showToast(\n 'Remote execution still blocked after enabling — check the agent’s Security settings.',\n 'error',\n exec.output || exec.errorMessage\n );\n }\n return;\n }\n if (exec) {\n showToast(\n exec.status === 'SUCCESS' || exec.status === 'COMPLETED'\n ? 'Action executed successfully'\n : 'Action execution failed',\n exec.status === 'SUCCESS' || exec.status === 'COMPLETED' ? 'success' : 'error',\n exec.output || exec.errorMessage\n );\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n return;\n }\n showToast(err instanceof Error ? err.message : 'Execution failed', 'error');\n } finally {\n setExecutingActionId(null);\n }\n },\n [executeAction, showToast]\n );\n\n const handleConfirmExecute = useCallback(async () => {\n if (modal.type !== 'confirmExecute') return;\n const actionId = modal.actionId;\n setModal({ type: 'none' });\n await doExecute(actionId);\n }, [modal, doExecute]);\n\n const handleEnableRemoteTaskConfirm = useCallback(\n async ({ shell, file }: { shell: boolean; file: boolean }) => {\n if (!remoteTaskPrompt) return;\n const { actionId, agentId } = remoteTaskPrompt;\n setEnablingRemoteTask(true);\n try {\n await enableRemoteTaskExecution(\n { id: agentId, profile: deniedAgentExecProfile },\n { shell, file }\n );\n setRemoteTaskPrompt(null);\n // Retry the run ONCE (allowRemotePrompt=false) so a still-denied result\n // surfaces a plain error instead of re-opening this dialog in a loop.\n await doExecute(actionId, false);\n } catch (err) {\n showToast(\n err instanceof Error ? err.message : 'Failed to enable remote execution',\n 'error'\n );\n } finally {\n setEnablingRemoteTask(false);\n }\n },\n [remoteTaskPrompt, deniedAgentExecProfile, doExecute, showToast]\n );\n\n const handleDuplicate = useCallback(\n async (actionId: string) => {\n const action = actions.find((a: { id: string; name: string }) => a.id === actionId);\n if (!action) return;\n try {\n await duplicateAction({\n variables: { id: actionId, name: `${action.name}-copy` },\n });\n showToast('Action duplicated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to duplicate action', 'error');\n }\n },\n [actions, duplicateAction, showToast]\n );\n\n // Edit action: find the action data for the form\n const editingAction = useMemo(() => {\n if (modal.type !== 'edit') return null;\n return actions.find((a: { id: string }) => a.id === modal.actionId) || null;\n }, [modal, actions]);\n\n // Seed the edit form's Vibe-link panel from the action's persisted link, and\n // reset the create form's panel whenever the create modal opens.\n useEffect(() => {\n if (modal.type === 'edit' && editingAction) {\n const linked = editingAction as { vibeId?: string | null; visibility?: string | null };\n setEditActionLink({\n vibeId: linked.vibeId ?? null,\n visibility: (linked.visibility as LinkToVibeVisibility | null) ?? 'PRIVATE',\n });\n } else if (modal.type === 'create') {\n setCreateActionLink(LINK_TO_VIBE_DEFAULT);\n }\n }, [modal.type, editingAction]);\n\n // Deep-link support: other surfaces (e.g. the \"Set agent\" link in an action's\n // linking warning) navigate here with `?editAction=<id>` to open the edit\n // form directly on the action whose agent needs fixing. We consume the param\n // immediately so a later back-nav / refresh doesn't re-pop the modal.\n useEffect(() => {\n const editId = searchParams.get('editAction');\n if (!editId) return;\n setModal({ type: 'edit', actionId: editId });\n const next = new URLSearchParams(searchParams);\n next.delete('editAction');\n setSearchParams(next, { replace: true });\n }, [searchParams, setSearchParams]);\n\n const selectedActions = useMemo(\n () => actions.filter((action: { id: string }) => selectedActionIds.has(action.id)),\n [actions, selectedActionIds]\n );\n\n const allVisibleSelected =\n actions.length > 0 &&\n actions.every((action: { id: string }) => selectedActionIds.has(action.id));\n\n const partiallySelected =\n actions.some((action: { id: string }) => selectedActionIds.has(action.id)) &&\n !allVisibleSelected;\n\n const toggleActionSelection = useCallback((actionId: string, checked: boolean) => {\n setSelectedActionIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(actionId);\n } else {\n next.delete(actionId);\n }\n return next;\n });\n }, []);\n\n const toggleAllVisibleActions = useCallback(\n (checked: boolean) => {\n setSelectedActionIds((prev) => {\n const next = new Set(prev);\n actions.forEach((action: { id: string }) => {\n if (checked) {\n next.add(action.id);\n } else {\n next.delete(action.id);\n }\n });\n return next;\n });\n },\n [actions]\n );\n\n const clearSelection = useCallback(() => {\n setSelectedActionIds(new Set());\n }, []);\n\n const handleBulkDuplicate = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('duplicate');\n try {\n const results = await Promise.allSettled(\n selectedActions.map((action: { id: string; name: string }) =>\n duplicateAction({\n variables: { id: action.id, name: `${action.name}-copy` },\n })\n )\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n\n showToast(\n `Duplicated ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearSelection();\n await refetchActions();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to duplicate actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedActions, duplicateAction, showToast, clearSelection, refetchActions]);\n\n const handleBulkDelete = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('delete');\n try {\n const results = await Promise.allSettled(\n selectedActions.map((action: { id: string }) =>\n deleteAction({ variables: { id: action.id } })\n )\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n\n if (selectedActionId && selectedActionIds.has(selectedActionId)) {\n setSelectedActionId(null);\n }\n\n showToast(\n `Deleted ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearSelection();\n setBulkModal(null);\n await refetchActions();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [\n selectedActions,\n deleteAction,\n selectedActionId,\n selectedActionIds,\n showToast,\n clearSelection,\n refetchActions,\n ]);\n\n const handleBulkExecute = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('execute');\n let succeeded = 0;\n let failed = 0;\n let quotaHit = false;\n\n try {\n for (const action of selectedActions) {\n try {\n const result = await executeAction({ variables: { id: action.id } });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n quotaHit = true;\n break;\n }\n const exec = result.data?.executeAction;\n if (exec?.status === 'SUCCESS' || exec?.status === 'COMPLETED') {\n succeeded += 1;\n } else {\n failed += 1;\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n quotaHit = true;\n break;\n }\n failed += 1;\n }\n }\n\n // Skip summary toast when quota was hit — the quota dialog is the feedback\n if (!quotaHit) {\n showToast(\n `Executed ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n }\n clearSelection();\n setBulkModal(null);\n if (selectedActionId) {\n await refetchActions();\n }\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to execute actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedActions, executeAction, showToast, clearSelection, selectedActionId, refetchActions]);\n\n // Guard states — gate render until permissions resolve so we don't flash\n // the page before the AccessDenied check can run.\n if (permissionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Actions...\" />\n </MotionPage>\n );\n }\n\n if (permissions && permissions.permissionStrings?.length > 0 && !canList) {\n return (\n <MotionPage>\n <AccessDenied />\n </MotionPage>\n );\n }\n\n if (actionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Actions...\" />\n </MotionPage>\n );\n }\n\n if (actionsError) {\n return (\n <MotionPage>\n <ErrorState message={actionsError.message} onRetry={() => refetchActions()} />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"p-4 sm:p-6 space-y-6\">\n <PageHeader\n title={tr('nav.actions', 'Actions')}\n description=\"Automate tasks — run commands, scripts, or trigger webhooks on your agents\"\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => refetchActions()}\n className=\"p-2 rounded-lg hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n >\n <RefreshCw size={16} />\n </button>\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'create' })}\n className=\"inline-flex items-center gap-1.5 px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium transition-opacity\"\n >\n <Plus size={16} />\n Create Action\n </button>\n )}\n </div>\n }\n />\n\n {/* Filters */}\n <div data-tour=\"actions-filter-section\" className=\"flex flex-wrap items-center gap-3\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('actions.searchPlaceholder', 'Search actions...')}\n className=\"w-full sm:w-64\"\n />\n <FilterDropdown\n label=\"Type\"\n options={ACTION_TYPE_OPTIONS}\n value={actionTypeFilter}\n onChange={setActionTypeFilter}\n />\n <FilterDropdown\n label=\"Trigger\"\n options={TRIGGER_TYPE_OPTIONS}\n value={triggerTypeFilter}\n onChange={setTriggerTypeFilter}\n />\n </div>\n\n {actions.length > 0 && (\n <div\n data-tour=\"actions-selection-toolbar\"\n className=\"rounded-lg border border-border-default bg-bg-surface p-4\"\n >\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleActions}\n ariaLabel=\"Select all visible actions\"\n />\n <span className=\"text-sm font-medium text-text-primary\">Select all visible</span>\n </div>\n {selectedActionIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedActionIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={() => setBulkModal('execute')}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-success-border px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Play size={14} />\n Execute Selected{selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={handleBulkDuplicate}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Copy size={14} />\n Duplicate Selected\n {selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkModal('delete')}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected{selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Actions Grid */}\n <AnimatePresence mode=\"wait\">\n {actions.length === 0 && !actionsLoading && (\n <EmptyState\n title=\"No actions yet\"\n description=\"Create your first action to automate commands, scripts, and webhooks\"\n action={\n <div className=\"flex items-center gap-2\">\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'create' })}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium\"\n >\n Create Action\n </button>\n )}\n <GetHelpButton prompt=\"What is an Action in VibeControls and how do I create one?\" />\n </div>\n }\n />\n )}\n </AnimatePresence>\n\n {actions.length > 0 && (\n <div\n data-tour=\"actions-list-container\"\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n >\n {actions.map(\n (action: {\n id: string;\n name: string;\n displayName?: string | null;\n description?: string | null;\n actionType: string;\n sourceType?: string | null;\n triggerType: string;\n category?: string | null;\n tags?: string[] | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n confirmationRequired: boolean;\n }) => (\n <div\n key={action.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => setSelectedActionId(action.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedActionId(action.id);\n }\n }}\n aria-label={`Select action ${action.displayName || action.name}`}\n >\n <ActionCard\n action={action}\n onExecute={handleExecute}\n onEdit={(id) => setModal({ type: 'edit', actionId: id })}\n onDuplicate={handleDuplicate}\n onDelete={(id) =>\n setModal({\n type: 'confirmDelete',\n id,\n name: action.displayName || action.name,\n })\n }\n // Schedule navigates to the scheduler microfe with the\n // actionId prefilled. The scheduler Create-Job form reads\n // `?actionId=` and auto-selects the action so users don't\n // need to copy IDs across tabs.\n onSchedule={(id) => navigate(`/scheduler?actionId=${encodeURIComponent(id)}`)}\n // Add-to-Calendar navigates to the VibeCalendar page with\n // the actionId prefilled so the event-create modal can\n // bind a VibeCalendarTask to this action.\n onAddToCalendar={(id) =>\n navigate(`/vibecontrols/calendar?actionId=${encodeURIComponent(id)}`)\n }\n canUpdate={canUpdate}\n canDelete={canDelete}\n canExecute={canExecute}\n isExecuting={executingActionId === action.id}\n selected={selectedActionIds.has(action.id)}\n onToggleSelect={(checked) => toggleActionSelection(action.id, checked)}\n />\n </div>\n )\n )}\n </div>\n )}\n\n {/* Schedules + Execution History Panels for the selected action */}\n <AnimatePresence>\n {selectedActionId && selectedAction && (\n <div className=\"space-y-3\">\n {workspaceId && (\n <ActionSchedulesList\n actionId={selectedActionId}\n workspaceId={workspaceId}\n actionName={selectedAction.displayName || selectedAction.name}\n onClose={() => setSelectedActionId(null)}\n />\n )}\n <div data-tour=\"actions-execution-history\">\n <ExecutionHistory\n executions={recentExecutions}\n actionName={selectedAction.displayName || selectedAction.name}\n onClose={() => setSelectedActionId(null)}\n />\n </div>\n </div>\n )}\n </AnimatePresence>\n\n {/* Toast Notifications */}\n <AnimatePresence>\n {toasts.length > 0 && (\n <div className=\"fixed bottom-4 left-4 right-4 sm:left-auto sm:bottom-6 sm:right-6 z-50 flex flex-col gap-2 max-w-[calc(100vw-2rem)] sm:max-w-md\">\n {toasts.slice(-3).map((toast) => (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => dismissToast(toast.id))();\n }\n }}\n key={toast.id}\n className={`p-4 rounded-xl shadow-lg border cursor-pointer ${\n toast.variant === 'success'\n ? 'bg-status-success-bg/10 border-status-success-border/30 text-status-success-text'\n : 'bg-status-error-bg/10 border-status-error-border/30 text-status-error-text'\n }`}\n onClick={() => dismissToast(toast.id)}\n >\n <div className=\"font-medium text-sm\">{toast.message}</div>\n {toast.detail && (\n <pre className=\"text-xs font-mono opacity-80 mt-1 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {toast.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </AnimatePresence>\n\n {/* Modals */}\n {modal.type === 'create' && (\n <ActionForm\n title=\"Create Action\"\n agents={agents}\n onSubmit={handleCreate}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={createLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('actions.tags', 'Tags')}\n </h3>\n <EntityTagPicker\n entityType=\"VIBECONTROLS_ACTION\"\n onDraftChange={setActionDraftTagIds}\n />\n </div>\n <LinkToVibePanel\n value={createActionLink}\n onChange={setCreateActionLink}\n disabled={createLoading}\n />\n </div>\n }\n />\n )}\n\n {modal.type === 'edit' && editingAction && (\n <ActionForm\n title=\"Edit Action\"\n initialData={{\n name: editingAction.name,\n displayName: editingAction.displayName || '',\n description: editingAction.description || '',\n actionType: editingAction.actionType || 'COMMAND',\n triggerType: editingAction.triggerType || 'MANUAL',\n schedule: editingAction.schedule || '',\n category: editingAction.category || '',\n tags: editingAction.tags || [],\n command: editingAction.command || '',\n workingDirectory: editingAction.workingDirectory || '',\n targetAgentId: editingAction.targetAgentId || '',\n script: editingAction.script || '',\n scriptInterpreter: editingAction.scriptInterpreter || 'bash',\n webhookUrl: editingAction.webhookUrl || '',\n webhookMethod: editingAction.webhookMethod || 'POST',\n webhookBody: editingAction.webhookBody || '',\n webhookAuthType: editingAction.webhookAuthType || '',\n timeoutMs: editingAction.timeoutMs || 30000,\n retryCount: editingAction.retryCount || 0,\n confirmationRequired: editingAction.confirmationRequired ?? false,\n }}\n agents={agents}\n onSubmit={handleUpdate}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('actions.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_ACTION\" entityId={editingAction.id} />\n </div>\n <LinkToVibePanel\n value={editActionLink}\n onChange={setEditActionLink}\n disabled={updateLoading}\n />\n </div>\n }\n />\n )}\n\n {modal.type === 'confirmDelete' && (\n <ConfirmDialog\n isOpen={true}\n title=\"Delete Action\"\n message={`Are you sure you want to delete \"${modal.name}\"? This cannot be undone.`}\n confirmLabel=\"Delete\"\n variant=\"danger\"\n onConfirm={handleDelete}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n {modal.type === 'confirmExecute' && (\n <ConfirmDialog\n isOpen={true}\n title={`Execute: ${modal.name}`}\n message={`Are you sure you want to execute \"${modal.name}\"?`}\n confirmLabel=\"Execute\"\n variant=\"warning\"\n onConfirm={handleConfirmExecute}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <ConfirmDialog\n isOpen={bulkModal === 'delete'}\n title=\"Delete Selected Actions\"\n message={`Are you sure you want to delete ${selectedActions.length} selected action${selectedActions.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel=\"Delete Actions\"\n variant=\"danger\"\n onConfirm={handleBulkDelete}\n onClose={() => setBulkModal(null)}\n isLoading={bulkBusy === 'delete'}\n />\n\n <ConfirmDialog\n isOpen={bulkModal === 'execute'}\n title=\"Execute Selected Actions\"\n message={`Execute ${selectedActions.length} selected action${selectedActions.length === 1 ? '' : 's'}? This may trigger commands, scripts, or webhooks immediately.`}\n confirmLabel=\"Execute Actions\"\n variant=\"warning\"\n onConfirm={handleBulkExecute}\n onClose={() => setBulkModal(null)}\n isLoading={bulkBusy === 'execute'}\n />\n\n <QuotaExhaustedDialog\n isOpen={quotaKind !== null}\n onClose={() => setQuotaKind(null)}\n onConfirm={() => {\n markQuotaHandledLocally();\n setQuotaKind(null);\n navigate('/billing/plans');\n }}\n title={quotaKind ? getQuotaDialogContent(quotaKind).title : undefined}\n message={quotaKind ? getQuotaDialogContent(quotaKind).message : ''}\n />\n\n <EnableRemoteTaskDialog\n isOpen={remoteTaskPrompt !== null}\n agentName={\n remoteTaskPrompt\n ? agents.find((a: { id: string; name: string }) => a.id === remoteTaskPrompt.agentId)\n ?.name\n : undefined\n }\n isLoading={enablingRemoteTask}\n onClose={() => setRemoteTaskPrompt(null)}\n onConfirm={handleEnableRemoteTaskConfirm}\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ActionsPage.js","names":[],"sources":["../../src/pages/ActionsPage.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useMemo } from 'react';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport { Copy, Play, Plus, RefreshCw, Trash2 } from 'lucide-react';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport { AnimatePresence } from 'framer-motion';\nimport {\n PageHeader,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n EnableRemoteTaskDialog,\n SearchInput,\n FilterDropdown,\n SelectionCheckbox,\n GetHelpButton,\n LinkToVibePanel,\n LINK_TO_VIBE_DEFAULT,\n linkToVibeInput,\n type LinkToVibeValue,\n type LinkToVibeVisibility,\n} from '@/components/shared';\nimport {\n ActionCard,\n ActionForm,\n ActionSchedulesList,\n ExecutionHistory,\n} from '@/components/actions';\nimport type { ActionFormData } from '@/components/actions';\nimport {\n useListActionsQuery,\n useGetActionQuery,\n useListAgentsQuery,\n useCreateActionMutation,\n useUpdateActionMutation,\n useDeleteActionMutation,\n useExecuteActionMutation,\n useDuplicateActionMutation,\n} from '@/generated/wspace-operations';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n isQuotaExhaustedError,\n markQuotaHandledLocally,\n getQuotaDialogContent,\n} from '@/utils/quotaUtils';\nimport { QuotaExhaustedDialog } from '@/components/shared/QuotaExhaustedDialog';\nimport {\n enableRemoteTaskExecution,\n isRemoteTaskDeniedError,\n} from '@/services/agentRemoteTaskGates';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\n\ntype ModalState =\n | { type: 'none' }\n | { type: 'create' }\n | { type: 'edit'; actionId: string }\n | { type: 'confirmDelete'; id: string; name: string }\n | { type: 'confirmExecute'; actionId: string; name: string; agentId?: string };\n\ninterface ErrorToast {\n message: string;\n variant: 'success' | 'error';\n detail?: string | null;\n id: number;\n}\n\nconst ACTION_TYPE_OPTIONS = [\n { value: 'COMMAND', label: 'Command' },\n { value: 'SCRIPT', label: 'Script' },\n { value: 'WEBHOOK', label: 'Webhook' },\n { value: 'WORKFLOW', label: 'Workflow' },\n];\n\nconst TRIGGER_TYPE_OPTIONS = [\n { value: 'MANUAL', label: 'Manual' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'EVENT', label: 'Event' },\n { value: 'ON_DEMAND', label: 'On Demand' },\n];\n\nexport function ActionsPage() {\n const navigate = useNavigate();\n const [searchParams, setSearchParams] = useSearchParams();\n const { workspaceId } = useVibeControls();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const tr = (\n (i18n) =>\n (key: string, fallback: string): string => {\n const v = i18n.t(key);\n return v === key ? fallback : v;\n }\n )(useI18n());\n // Default to true when action permissions haven't been registered in RBAC yet\n const actionPermsRegistered = (\n Array.isArray(permissions) ? permissions : permissions?.permissionStrings\n )?.some?.((p: string) => p.startsWith('action:'));\n const canList = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_LIST) : true;\n const canCreate = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_CREATE) : true;\n const canUpdate = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_UPDATE) : true;\n const canDelete = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_DELETE) : true;\n const canExecute = actionPermsRegistered ? hasPermission(VIBE_PERMISSIONS.ACTION_EXECUTE) : true;\n const shouldSkipQueries = permissionsLoading;\n\n const [modal, setModal] = useState<ModalState>({ type: 'none' });\n const [toasts, setToasts] = useState<ErrorToast[]>([]);\n const [searchQuery, setSearchQuery] = useState('');\n const [actionTypeFilter, setActionTypeFilter] = useState<string | null>(null);\n const [triggerTypeFilter, setTriggerTypeFilter] = useState<string | null>(null);\n const [selectedActionId, setSelectedActionId] = useState<string | null>(null);\n const [selectedActionIds, setSelectedActionIds] = useState<Set<string>>(new Set());\n const [executingActionId, setExecutingActionId] = useState<string | null>(null);\n const [bulkModal, setBulkModal] = useState<'delete' | 'execute' | null>(null);\n const [bulkBusy, setBulkBusy] = useState<'delete' | 'execute' | 'duplicate' | null>(null);\n const [quotaKind, setQuotaKind] = useState<'action' | 'command-execution' | null>(null);\n // Reactive \"enable remote execution\" prompt: set when a run is denied because\n // the agent's remote-task gate is off. Captures which action + agent to retry.\n const [remoteTaskPrompt, setRemoteTaskPrompt] = useState<{\n actionId: string;\n agentId: string;\n } | null>(null);\n const [enablingRemoteTask, setEnablingRemoteTask] = useState(false);\n const { profiles: deniedAgentProfiles } = useActiveAgentProfile(\n remoteTaskPrompt?.agentId ?? null\n );\n // The action runner always targets the agent's DEFAULT profile (the backend\n // resolves getDefaultProfileName when no profile is passed), so the gate must\n // be written to that profile — NOT the UI's \"active\" profile, which can differ\n // on multi-profile agents and would unlock the wrong daemon.\n const deniedAgentExecProfile = deniedAgentProfiles.find((p) => p.isDefault)?.name ?? 'default';\n\n // G7: Optional link to a Vibe + visibility for the create / edit forms.\n // Threaded into the create/update mutation input as `vibeId` + `visibility`.\n const [createActionLink, setCreateActionLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n const [editActionLink, setEditActionLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n\n const showToast = useCallback(\n (message: string, variant: 'success' | 'error', detail?: string | null, duration = 10000) => {\n const id = Date.now() + Math.random();\n setToasts((prev) => [...prev, { message, variant, detail, id }]);\n if (variant === 'success') {\n setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), duration);\n }\n },\n []\n );\n\n const dismissToast = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n // Queries\n const {\n data: actionsData,\n loading: actionsLoading,\n error: actionsError,\n refetch: refetchActions,\n } = useListActionsQuery({\n variables: {\n filter: {\n ...(actionTypeFilter && actionTypeFilter !== 'all' ? { actionType: actionTypeFilter } : {}),\n ...(triggerTypeFilter && triggerTypeFilter !== 'all'\n ? { triggerType: triggerTypeFilter }\n : {}),\n ...(searchQuery ? { search: searchQuery } : {}),\n },\n pagination: { limit: 50 },\n },\n skip: shouldSkipQueries,\n });\n\n const actions = useMemo(() => actionsData?.actions?.items || [], [actionsData]);\n\n // Fetch selected action details (with executions)\n const { data: selectedActionData } = useGetActionQuery({\n variables: { id: selectedActionId! },\n skip: !selectedActionId || shouldSkipQueries,\n });\n\n const selectedAction = selectedActionData?.action;\n const recentExecutions = selectedAction?.recentExecutions || [];\n\n // Agents for form\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n skip: shouldSkipQueries,\n });\n const agents = useMemo(\n () =>\n (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string; isActive: boolean }) => ({\n id: a.id,\n name: a.name,\n isActive: a.isActive,\n })\n ),\n [agentsData]\n );\n\n // Mutations\n const [createAction, { loading: createLoading }] = useCreateActionMutation({\n refetchQueries: ['ListActions'],\n });\n const { setDraftTagIds: setActionDraftTagIds, flushTags: flushActionTags } =\n useDraftEntityTags('VIBECONTROLS_ACTION');\n const [updateAction, { loading: updateLoading }] = useUpdateActionMutation({\n refetchQueries: ['ListActions', 'GetAction'],\n });\n const [deleteAction] = useDeleteActionMutation({\n refetchQueries: ['ListActions'],\n });\n const [executeAction] = useExecuteActionMutation({\n refetchQueries: ['GetAction'],\n });\n const [duplicateAction] = useDuplicateActionMutation({\n refetchQueries: ['ListActions'],\n });\n\n // Handlers\n const handleCreate = useCallback(\n async (data: ActionFormData) => {\n try {\n const result = await createAction({\n variables: {\n input: {\n name: data.name,\n displayName: data.displayName || null,\n description: data.description || null,\n actionType: data.actionType,\n triggerType: data.triggerType,\n schedule: data.triggerType === 'SCHEDULED' ? data.schedule || null : null,\n category: data.category || null,\n tags: data.tags.length > 0 ? data.tags : null,\n command: data.actionType === 'COMMAND' ? data.command || null : null,\n workingDirectory:\n data.actionType !== 'WEBHOOK' ? data.workingDirectory || null : null,\n targetAgentId: data.actionType !== 'WEBHOOK' ? data.targetAgentId || null : null,\n script: data.actionType === 'SCRIPT' ? data.script || null : null,\n scriptInterpreter:\n data.actionType === 'SCRIPT' ? data.scriptInterpreter || 'bash' : null,\n webhookUrl: data.actionType === 'WEBHOOK' ? data.webhookUrl || null : null,\n webhookMethod: data.actionType === 'WEBHOOK' ? data.webhookMethod || 'POST' : null,\n webhookBody: data.actionType === 'WEBHOOK' ? data.webhookBody || null : null,\n webhookAuthType: data.actionType === 'WEBHOOK' ? data.webhookAuthType || null : null,\n timeoutMs: data.timeoutMs,\n retryCount: data.retryCount,\n confirmationRequired: data.confirmationRequired,\n ...linkToVibeInput(createActionLink),\n },\n },\n });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n setModal({ type: 'none' });\n markQuotaHandledLocally();\n setQuotaKind('action');\n return;\n }\n const newActionId = result.data?.createAction?.id;\n setModal({ type: 'none' });\n showToast('Action created', 'success');\n setCreateActionLink(LINK_TO_VIBE_DEFAULT);\n if (newActionId) await flushActionTags(newActionId);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setModal({ type: 'none' });\n markQuotaHandledLocally();\n setQuotaKind('action');\n return;\n }\n showToast(err instanceof Error ? err.message : 'Failed to create action', 'error');\n }\n },\n [createAction, flushActionTags, showToast, createActionLink]\n );\n\n const handleUpdate = useCallback(\n async (data: ActionFormData) => {\n if (modal.type !== 'edit') return;\n try {\n await updateAction({\n variables: {\n id: modal.actionId,\n input: {\n displayName: data.displayName || null,\n description: data.description || null,\n actionType: data.actionType,\n triggerType: data.triggerType,\n schedule: data.triggerType === 'SCHEDULED' ? data.schedule || null : null,\n category: data.category || null,\n tags: data.tags.length > 0 ? data.tags : null,\n command: data.actionType === 'COMMAND' ? data.command || null : null,\n workingDirectory:\n data.actionType !== 'WEBHOOK' ? data.workingDirectory || null : null,\n targetAgentId: data.actionType !== 'WEBHOOK' ? data.targetAgentId || null : null,\n script: data.actionType === 'SCRIPT' ? data.script || null : null,\n scriptInterpreter:\n data.actionType === 'SCRIPT' ? data.scriptInterpreter || 'bash' : null,\n webhookUrl: data.actionType === 'WEBHOOK' ? data.webhookUrl || null : null,\n webhookMethod: data.actionType === 'WEBHOOK' ? data.webhookMethod || 'POST' : null,\n webhookBody: data.actionType === 'WEBHOOK' ? data.webhookBody || null : null,\n webhookAuthType: data.actionType === 'WEBHOOK' ? data.webhookAuthType || null : null,\n timeoutMs: data.timeoutMs,\n retryCount: data.retryCount,\n confirmationRequired: data.confirmationRequired,\n ...linkToVibeInput(editActionLink),\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Action updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update action', 'error');\n }\n },\n [updateAction, modal, showToast, editActionLink]\n );\n\n const handleDelete = useCallback(async () => {\n if (modal.type !== 'confirmDelete') return;\n try {\n await deleteAction({ variables: { id: modal.id } });\n if (selectedActionId === modal.id) setSelectedActionId(null);\n setModal({ type: 'none' });\n showToast('Action deleted', 'success');\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete action', 'error');\n if (isNative()) void nativeNotify('error');\n }\n }, [modal, deleteAction, selectedActionId, showToast]);\n\n const handleExecute = async (actionId: string) => {\n const action = actions.find((a: { id: string }) => a.id === actionId) as\n | { id: string; name: string; displayName?: string | null; confirmationRequired: boolean }\n | undefined;\n if (!action) return;\n\n if (action.confirmationRequired) {\n setModal({\n type: 'confirmExecute',\n actionId,\n name: action.displayName || action.name,\n });\n return;\n }\n\n await doExecute(actionId);\n };\n\n const doExecute = useCallback(\n async (actionId: string, allowRemotePrompt = true) => {\n setExecutingActionId(actionId);\n try {\n const result = await executeAction({ variables: { id: actionId } });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n return;\n }\n const exec = result.data?.executeAction;\n // The agent rejected the run because its remote-task gate is off — offer\n // to enable it in context (and retry) instead of a dead-end error toast.\n // allowRemotePrompt is false on the post-enable retry so a still-denied\n // run surfaces a plain error instead of re-opening the dialog forever.\n if (exec && isRemoteTaskDeniedError(exec) && exec.agentId) {\n if (allowRemotePrompt) {\n setRemoteTaskPrompt({ actionId, agentId: exec.agentId });\n } else {\n showToast(\n 'Remote execution still blocked after enabling — check the agent’s Security settings.',\n 'error',\n exec.output || exec.errorMessage\n );\n }\n return;\n }\n if (exec) {\n showToast(\n exec.status === 'SUCCESS' || exec.status === 'COMPLETED'\n ? 'Action executed successfully'\n : 'Action execution failed',\n exec.status === 'SUCCESS' || exec.status === 'COMPLETED' ? 'success' : 'error',\n exec.output || exec.errorMessage\n );\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n return;\n }\n showToast(err instanceof Error ? err.message : 'Execution failed', 'error');\n } finally {\n setExecutingActionId(null);\n }\n },\n [executeAction, showToast]\n );\n\n const handleConfirmExecute = useCallback(async () => {\n if (modal.type !== 'confirmExecute') return;\n const actionId = modal.actionId;\n setModal({ type: 'none' });\n await doExecute(actionId);\n }, [modal, doExecute]);\n\n const handleEnableRemoteTaskConfirm = useCallback(\n async ({ shell, file }: { shell: boolean; file: boolean }) => {\n if (!remoteTaskPrompt) return;\n const { actionId, agentId } = remoteTaskPrompt;\n setEnablingRemoteTask(true);\n try {\n await enableRemoteTaskExecution(\n { id: agentId, profile: deniedAgentExecProfile },\n { shell, file }\n );\n setRemoteTaskPrompt(null);\n // Retry the run ONCE (allowRemotePrompt=false) so a still-denied result\n // surfaces a plain error instead of re-opening this dialog in a loop.\n await doExecute(actionId, false);\n } catch (err) {\n showToast(\n err instanceof Error ? err.message : 'Failed to enable remote execution',\n 'error'\n );\n } finally {\n setEnablingRemoteTask(false);\n }\n },\n [remoteTaskPrompt, deniedAgentExecProfile, doExecute, showToast]\n );\n\n const handleDuplicate = useCallback(\n async (actionId: string) => {\n const action = actions.find((a: { id: string; name: string }) => a.id === actionId);\n if (!action) return;\n try {\n await duplicateAction({\n variables: { id: actionId, name: `${action.name}-copy` },\n });\n showToast('Action duplicated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to duplicate action', 'error');\n }\n },\n [actions, duplicateAction, showToast]\n );\n\n // Edit action: find the action data for the form\n const editingAction = useMemo(() => {\n if (modal.type !== 'edit') return null;\n return actions.find((a: { id: string }) => a.id === modal.actionId) || null;\n }, [modal, actions]);\n\n // Seed the edit form's Vibe-link panel from the action's persisted link, and\n // reset the create form's panel whenever the create modal opens.\n useEffect(() => {\n if (modal.type === 'edit' && editingAction) {\n const linked = editingAction as { vibeId?: string | null; visibility?: string | null };\n setEditActionLink({\n vibeId: linked.vibeId ?? null,\n visibility: (linked.visibility as LinkToVibeVisibility | null) ?? 'PRIVATE',\n });\n } else if (modal.type === 'create') {\n setCreateActionLink(LINK_TO_VIBE_DEFAULT);\n }\n }, [modal.type, editingAction]);\n\n // Deep-link support: other surfaces (e.g. the \"Set agent\" link in an action's\n // linking warning) navigate here with `?editAction=<id>` to open the edit\n // form directly on the action whose agent needs fixing. We consume the param\n // immediately so a later back-nav / refresh doesn't re-pop the modal.\n useEffect(() => {\n const editId = searchParams.get('editAction');\n if (!editId) return;\n setModal({ type: 'edit', actionId: editId });\n const next = new URLSearchParams(searchParams);\n next.delete('editAction');\n setSearchParams(next, { replace: true });\n }, [searchParams, setSearchParams]);\n\n const selectedActions = useMemo(\n () => actions.filter((action: { id: string }) => selectedActionIds.has(action.id)),\n [actions, selectedActionIds]\n );\n\n const allVisibleSelected =\n actions.length > 0 &&\n actions.every((action: { id: string }) => selectedActionIds.has(action.id));\n\n const partiallySelected =\n actions.some((action: { id: string }) => selectedActionIds.has(action.id)) &&\n !allVisibleSelected;\n\n const toggleActionSelection = useCallback((actionId: string, checked: boolean) => {\n setSelectedActionIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(actionId);\n } else {\n next.delete(actionId);\n }\n return next;\n });\n }, []);\n\n const toggleAllVisibleActions = useCallback(\n (checked: boolean) => {\n setSelectedActionIds((prev) => {\n const next = new Set(prev);\n actions.forEach((action: { id: string }) => {\n if (checked) {\n next.add(action.id);\n } else {\n next.delete(action.id);\n }\n });\n return next;\n });\n },\n [actions]\n );\n\n const clearSelection = useCallback(() => {\n setSelectedActionIds(new Set());\n }, []);\n\n const handleBulkDuplicate = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('duplicate');\n try {\n const results = await Promise.allSettled(\n selectedActions.map((action: { id: string; name: string }) =>\n duplicateAction({\n variables: { id: action.id, name: `${action.name}-copy` },\n })\n )\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n\n showToast(\n `Duplicated ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearSelection();\n await refetchActions();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to duplicate actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedActions, duplicateAction, showToast, clearSelection, refetchActions]);\n\n const handleBulkDelete = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('delete');\n try {\n const results = await Promise.allSettled(\n selectedActions.map((action: { id: string }) =>\n deleteAction({ variables: { id: action.id } })\n )\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n\n if (selectedActionId && selectedActionIds.has(selectedActionId)) {\n setSelectedActionId(null);\n }\n\n showToast(\n `Deleted ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearSelection();\n setBulkModal(null);\n await refetchActions();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [\n selectedActions,\n deleteAction,\n selectedActionId,\n selectedActionIds,\n showToast,\n clearSelection,\n refetchActions,\n ]);\n\n const handleBulkExecute = useCallback(async () => {\n if (selectedActions.length === 0) return;\n setBulkBusy('execute');\n let succeeded = 0;\n let failed = 0;\n let quotaHit = false;\n\n try {\n for (const action of selectedActions) {\n try {\n const result = await executeAction({ variables: { id: action.id } });\n // With errorPolicy:'all', quota errors resolve on result.error instead of throwing\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n quotaHit = true;\n break;\n }\n const exec = result.data?.executeAction;\n if (exec?.status === 'SUCCESS' || exec?.status === 'COMPLETED') {\n succeeded += 1;\n } else {\n failed += 1;\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setQuotaKind('command-execution');\n quotaHit = true;\n break;\n }\n failed += 1;\n }\n }\n\n // Skip summary toast when quota was hit — the quota dialog is the feedback\n if (!quotaHit) {\n showToast(\n `Executed ${succeeded} action${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n }\n clearSelection();\n setBulkModal(null);\n if (selectedActionId) {\n await refetchActions();\n }\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to execute actions', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedActions, executeAction, showToast, clearSelection, selectedActionId, refetchActions]);\n\n // Guard states — gate render until permissions resolve so we don't flash\n // the page before the AccessDenied check can run.\n if (permissionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Actions...\" />\n </MotionPage>\n );\n }\n\n if (permissions && permissions.permissionStrings?.length > 0 && !canList) {\n return (\n <MotionPage>\n <AccessDenied />\n </MotionPage>\n );\n }\n\n if (actionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Actions...\" />\n </MotionPage>\n );\n }\n\n if (actionsError) {\n return (\n <MotionPage>\n <ErrorState message={actionsError.message} onRetry={() => refetchActions()} />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"px-6 lg:px-8 py-6 space-y-6\">\n <PageHeader\n title={tr('nav.actions', 'Actions')}\n description=\"Automate tasks — run commands, scripts, or trigger webhooks on your agents\"\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => refetchActions()}\n className=\"p-2 rounded-button hover:bg-bg-sunken text-text-secondary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n aria-label=\"Refresh\"\n >\n <RefreshCw size={16} />\n </button>\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'create' })}\n className=\"inline-flex items-center gap-1.5 px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium transition-opacity\"\n >\n <Plus size={16} />\n Create Action\n </button>\n )}\n </div>\n }\n />\n\n {/* Filters */}\n <div data-tour=\"actions-filter-section\" className=\"flex flex-wrap items-center gap-3\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('actions.searchPlaceholder', 'Search actions...')}\n className=\"w-full sm:w-64\"\n />\n <FilterDropdown\n label=\"Type\"\n options={ACTION_TYPE_OPTIONS}\n value={actionTypeFilter}\n onChange={setActionTypeFilter}\n />\n <FilterDropdown\n label=\"Trigger\"\n options={TRIGGER_TYPE_OPTIONS}\n value={triggerTypeFilter}\n onChange={setTriggerTypeFilter}\n />\n </div>\n\n {actions.length > 0 && (\n <div\n data-tour=\"actions-selection-toolbar\"\n className=\"rounded-lg border border-border-default bg-bg-surface p-4\"\n >\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleActions}\n ariaLabel=\"Select all visible actions\"\n />\n <span className=\"text-sm font-medium text-text-primary\">Select all visible</span>\n </div>\n {selectedActionIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedActionIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={() => setBulkModal('execute')}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-success-border px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Play size={14} />\n Execute Selected{selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={handleBulkDuplicate}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Copy size={14} />\n Duplicate Selected\n {selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkModal('delete')}\n disabled={selectedActions.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected{selectedActions.length > 0 ? ` (${selectedActions.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Actions Grid */}\n <AnimatePresence mode=\"wait\">\n {actions.length === 0 && !actionsLoading && (\n <EmptyState\n title=\"No actions yet\"\n description=\"Create your first action to automate commands, scripts, and webhooks\"\n action={\n <div className=\"flex items-center gap-2\">\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'create' })}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium\"\n >\n Create Action\n </button>\n )}\n <GetHelpButton prompt=\"What is an Action in VibeControls and how do I create one?\" />\n </div>\n }\n />\n )}\n </AnimatePresence>\n\n {actions.length > 0 && (\n <div\n data-tour=\"actions-list-container\"\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n >\n {actions.map(\n (action: {\n id: string;\n name: string;\n displayName?: string | null;\n description?: string | null;\n actionType: string;\n sourceType?: string | null;\n triggerType: string;\n category?: string | null;\n tags?: string[] | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n confirmationRequired: boolean;\n }) => (\n <div\n key={action.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => setSelectedActionId(action.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedActionId(action.id);\n }\n }}\n aria-label={`Select action ${action.displayName || action.name}`}\n >\n <ActionCard\n action={action}\n onExecute={handleExecute}\n onEdit={(id) => setModal({ type: 'edit', actionId: id })}\n onDuplicate={handleDuplicate}\n onDelete={(id) =>\n setModal({\n type: 'confirmDelete',\n id,\n name: action.displayName || action.name,\n })\n }\n // Schedule navigates to the scheduler microfe with the\n // actionId prefilled. The scheduler Create-Job form reads\n // `?actionId=` and auto-selects the action so users don't\n // need to copy IDs across tabs.\n onSchedule={(id) => navigate(`/scheduler?actionId=${encodeURIComponent(id)}`)}\n // Add-to-Calendar navigates to the VibeCalendar page with\n // the actionId prefilled so the event-create modal can\n // bind a VibeCalendarTask to this action.\n onAddToCalendar={(id) =>\n navigate(`/vibecontrols/calendar?actionId=${encodeURIComponent(id)}`)\n }\n canUpdate={canUpdate}\n canDelete={canDelete}\n canExecute={canExecute}\n isExecuting={executingActionId === action.id}\n selected={selectedActionIds.has(action.id)}\n onToggleSelect={(checked) => toggleActionSelection(action.id, checked)}\n />\n </div>\n )\n )}\n </div>\n )}\n\n {/* Schedules + Execution History Panels for the selected action */}\n <AnimatePresence>\n {selectedActionId && selectedAction && (\n <div className=\"space-y-3\">\n {workspaceId && (\n <ActionSchedulesList\n actionId={selectedActionId}\n workspaceId={workspaceId}\n actionName={selectedAction.displayName || selectedAction.name}\n onClose={() => setSelectedActionId(null)}\n />\n )}\n <div data-tour=\"actions-execution-history\">\n <ExecutionHistory\n executions={recentExecutions}\n actionName={selectedAction.displayName || selectedAction.name}\n onClose={() => setSelectedActionId(null)}\n />\n </div>\n </div>\n )}\n </AnimatePresence>\n\n {/* Toast Notifications */}\n <AnimatePresence>\n {toasts.length > 0 && (\n <div className=\"fixed bottom-4 left-4 right-4 sm:left-auto sm:bottom-6 sm:right-6 z-50 flex flex-col gap-2 max-w-[calc(100vw-2rem)] sm:max-w-md\">\n {toasts.slice(-3).map((toast) => (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => dismissToast(toast.id))();\n }\n }}\n key={toast.id}\n className={`p-4 rounded-xl shadow-lg border cursor-pointer ${\n toast.variant === 'success'\n ? 'bg-status-success-bg-subtle border-status-success-border text-status-success-text'\n : 'bg-status-error-bg-subtle border-status-error-border text-status-error-text'\n }`}\n onClick={() => dismissToast(toast.id)}\n >\n <div className=\"font-medium text-sm\">{toast.message}</div>\n {toast.detail && (\n <pre className=\"text-xs font-mono opacity-80 mt-1 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {toast.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </AnimatePresence>\n\n {/* Modals */}\n {modal.type === 'create' && (\n <ActionForm\n title=\"Create Action\"\n agents={agents}\n onSubmit={handleCreate}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={createLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('actions.tags', 'Tags')}\n </h3>\n <EntityTagPicker\n entityType=\"VIBECONTROLS_ACTION\"\n onDraftChange={setActionDraftTagIds}\n />\n </div>\n <LinkToVibePanel\n value={createActionLink}\n onChange={setCreateActionLink}\n disabled={createLoading}\n />\n </div>\n }\n />\n )}\n\n {modal.type === 'edit' && editingAction && (\n <ActionForm\n title=\"Edit Action\"\n initialData={{\n name: editingAction.name,\n displayName: editingAction.displayName || '',\n description: editingAction.description || '',\n actionType: editingAction.actionType || 'COMMAND',\n triggerType: editingAction.triggerType || 'MANUAL',\n schedule: editingAction.schedule || '',\n category: editingAction.category || '',\n tags: editingAction.tags || [],\n command: editingAction.command || '',\n workingDirectory: editingAction.workingDirectory || '',\n targetAgentId: editingAction.targetAgentId || '',\n script: editingAction.script || '',\n scriptInterpreter: editingAction.scriptInterpreter || 'bash',\n webhookUrl: editingAction.webhookUrl || '',\n webhookMethod: editingAction.webhookMethod || 'POST',\n webhookBody: editingAction.webhookBody || '',\n webhookAuthType: editingAction.webhookAuthType || '',\n timeoutMs: editingAction.timeoutMs || 30000,\n retryCount: editingAction.retryCount || 0,\n confirmationRequired: editingAction.confirmationRequired ?? false,\n }}\n agents={agents}\n onSubmit={handleUpdate}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('actions.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_ACTION\" entityId={editingAction.id} />\n </div>\n <LinkToVibePanel\n value={editActionLink}\n onChange={setEditActionLink}\n disabled={updateLoading}\n />\n </div>\n }\n />\n )}\n\n {modal.type === 'confirmDelete' && (\n <ConfirmDialog\n isOpen={true}\n title=\"Delete Action\"\n message={`Are you sure you want to delete \"${modal.name}\"? This cannot be undone.`}\n confirmLabel=\"Delete\"\n variant=\"danger\"\n onConfirm={handleDelete}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n {modal.type === 'confirmExecute' && (\n <ConfirmDialog\n isOpen={true}\n title={`Execute: ${modal.name}`}\n message={`Are you sure you want to execute \"${modal.name}\"?`}\n confirmLabel=\"Execute\"\n variant=\"warning\"\n onConfirm={handleConfirmExecute}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <ConfirmDialog\n isOpen={bulkModal === 'delete'}\n title=\"Delete Selected Actions\"\n message={`Are you sure you want to delete ${selectedActions.length} selected action${selectedActions.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel=\"Delete Actions\"\n variant=\"danger\"\n onConfirm={handleBulkDelete}\n onClose={() => setBulkModal(null)}\n isLoading={bulkBusy === 'delete'}\n />\n\n <ConfirmDialog\n isOpen={bulkModal === 'execute'}\n title=\"Execute Selected Actions\"\n message={`Execute ${selectedActions.length} selected action${selectedActions.length === 1 ? '' : 's'}? This may trigger commands, scripts, or webhooks immediately.`}\n confirmLabel=\"Execute Actions\"\n variant=\"warning\"\n onConfirm={handleBulkExecute}\n onClose={() => setBulkModal(null)}\n isLoading={bulkBusy === 'execute'}\n />\n\n <QuotaExhaustedDialog\n isOpen={quotaKind !== null}\n onClose={() => setQuotaKind(null)}\n onConfirm={() => {\n markQuotaHandledLocally();\n setQuotaKind(null);\n navigate('/billing/plans');\n }}\n title={quotaKind ? getQuotaDialogContent(quotaKind).title : undefined}\n message={quotaKind ? getQuotaDialogContent(quotaKind).message : ''}\n />\n\n <EnableRemoteTaskDialog\n isOpen={remoteTaskPrompt !== null}\n agentName={\n remoteTaskPrompt\n ? agents.find((a: { id: string; name: string }) => a.id === remoteTaskPrompt.agentId)\n ?.name\n : undefined\n }\n isLoading={enablingRemoteTask}\n onClose={() => setRemoteTaskPrompt(null)}\n onConfirm={handleEnableRemoteTaskConfirm}\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|