@burdenoff/microfe-vibecontrols 2026.826.1 → 2026.829.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/ActionCard.js +99 -84
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/actions/ActionWebhookEndpoint.js +57 -0
- package/dist/components/actions/ActionWebhookEndpoint.js.map +1 -0
- package/dist/components/actions/index.js +1 -0
- package/dist/components/agent-manager/BridleConfigPanel.js +10 -10
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/FilePickerModal.js +71 -65
- package/dist/components/agent-manager/FilePickerModal.js.map +1 -1
- package/dist/components/ai/AIQueueTab.js +5 -5
- package/dist/components/components/ComponentHealthCell.js +62 -0
- package/dist/components/components/ComponentHealthCell.js.map +1 -0
- package/dist/components/components/ComponentTierBadge.js +42 -0
- package/dist/components/components/ComponentTierBadge.js.map +1 -0
- package/dist/components/components/ComponentsTable.js +192 -0
- package/dist/components/components/ComponentsTable.js.map +1 -0
- package/dist/components/components/index.js +3 -0
- package/dist/components/graph/MeshAgentNode.js +39 -38
- package/dist/components/graph/MeshAgentNode.js.map +1 -1
- package/dist/components/sessions/SessionPublicLinkPanel.js +10 -10
- package/dist/components/shared/DiffView.js +7 -0
- package/dist/components/shared/index.js +1 -0
- package/dist/components/tunnels/TunnelConnectionCard.js +38 -0
- package/dist/components/tunnels/TunnelConnectionCard.js.map +1 -0
- package/dist/components/tunnels/TunnelCopyButton.js +34 -0
- package/dist/components/tunnels/TunnelCopyButton.js.map +1 -0
- package/dist/components/tunnels/TunnelMetricTiles.js +132 -0
- package/dist/components/tunnels/TunnelMetricTiles.js.map +1 -0
- package/dist/components/tunnels/TunnelSparkline.js +28 -0
- package/dist/components/tunnels/TunnelSparkline.js.map +1 -0
- package/dist/components/tunnels/tunnelEndpoints.js +34 -0
- package/dist/components/tunnels/tunnelEndpoints.js.map +1 -0
- package/dist/components/tunnels/tunnelMetrics.js +43 -0
- package/dist/components/tunnels/tunnelMetrics.js.map +1 -0
- package/dist/components/vibe/VibeEnvVarsPanel.js +8 -8
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +10 -10
- package/dist/components/vibes/VibeList.js +88 -93
- package/dist/components/vibes/VibeList.js.map +1 -1
- package/dist/generated/wspace-operations.js +5 -0
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +11 -11
- package/dist/pages/AgentGraphPage.js +1 -1
- package/dist/pages/AgentsPage.js +15 -15
- package/dist/pages/ComponentsPage.js +205 -167
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/EnvTopologyPage.js +7 -7
- package/dist/pages/HealthPage.js +1 -1
- package/dist/pages/TargetsPage.js +478 -478
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelEndpointsTab.js +26 -38
- package/dist/pages/tunnels/tabs/TunnelEndpointsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +136 -122
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelUsageTab.js +37 -39
- package/dist/pages/tunnels/tabs/TunnelUsageTab.js.map +1 -1
- package/dist/translations/en.js +119 -2
- package/dist/translations/en.js.map +1 -1
- package/dist/utils/shareUrl.js +18 -0
- package/dist/utils/shareUrl.js.map +1 -0
- package/package.json +1 -1
|
@@ -3,168 +3,183 @@ import { VibeEntityType as t } from "../../generated/wspace-types.js";
|
|
|
3
3
|
import { EntityVibeLinkControl as n } from "../shared/EntityVibeLinkControl.js";
|
|
4
4
|
import { SelectionCheckbox as r } from "../shared/SelectionCheckbox.js";
|
|
5
5
|
import { ActionTypeBadge as i, SourceTypeBadge as a, TriggerTypeBadge as o } from "./ActionTypeBadge.js";
|
|
6
|
-
import {
|
|
6
|
+
import { ActionWebhookEndpoint as s } from "./ActionWebhookEndpoint.js";
|
|
7
|
+
import { EntityShareButton as c } from "../sharing/EntityShareButton.js";
|
|
7
8
|
import "../sharing/index.js";
|
|
8
|
-
import { AlarmClock as
|
|
9
|
-
import { motion as
|
|
10
|
-
import { jsx as
|
|
9
|
+
import { AlarmClock as l, AlertTriangle as u, CalendarClock as d, Clock as f, Copy as p, Hash as m, Pencil as h, Play as g, Trash2 as _ } from "lucide-react";
|
|
10
|
+
import { motion as v, useReducedMotion as y } from "framer-motion";
|
|
11
|
+
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
11
12
|
//#region src/components/actions/ActionCard.tsx
|
|
12
|
-
function
|
|
13
|
-
let
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
-
className: `bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${
|
|
16
|
-
whileHover:
|
|
13
|
+
function S({ action: S, onExecute: C, onEdit: w, onDuplicate: T, onDelete: E, onSchedule: D, onAddToCalendar: O, canUpdate: k, canDelete: A, canExecute: j, isExecuting: M = !1, selected: N = !1, onToggleSelect: P }) {
|
|
14
|
+
let F = y(), I = e();
|
|
15
|
+
return /* @__PURE__ */ x(v.div, {
|
|
16
|
+
className: `bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${N ? "border-action-primary-bg ring-1 ring-action-primary-bg/25" : "border-border-default"}`,
|
|
17
|
+
whileHover: F ? void 0 : {
|
|
17
18
|
y: -2,
|
|
18
19
|
boxShadow: "0 4px 12px var(--color-border-default)"
|
|
19
20
|
},
|
|
20
21
|
transition: { duration: .15 },
|
|
21
22
|
layout: !0,
|
|
22
23
|
role: "group",
|
|
23
|
-
"aria-label": `Action: ${
|
|
24
|
+
"aria-label": `Action: ${S.displayName || S.name}`,
|
|
24
25
|
children: [
|
|
25
|
-
/* @__PURE__ */
|
|
26
|
+
/* @__PURE__ */ x("div", {
|
|
26
27
|
className: "flex items-start justify-between gap-3 mb-3",
|
|
27
|
-
children: [/* @__PURE__ */
|
|
28
|
+
children: [/* @__PURE__ */ x("div", {
|
|
28
29
|
className: "flex items-start gap-3 min-w-0 flex-1",
|
|
29
|
-
children: [
|
|
30
|
+
children: [P && /* @__PURE__ */ b("div", {
|
|
30
31
|
onClick: (e) => e.stopPropagation(),
|
|
31
|
-
children: /* @__PURE__ */
|
|
32
|
-
checked:
|
|
33
|
-
onChange:
|
|
34
|
-
ariaLabel: `Select action ${
|
|
32
|
+
children: /* @__PURE__ */ b(r, {
|
|
33
|
+
checked: N,
|
|
34
|
+
onChange: P,
|
|
35
|
+
ariaLabel: `Select action ${S.displayName || S.name}`
|
|
35
36
|
})
|
|
36
|
-
}), /* @__PURE__ */
|
|
37
|
+
}), /* @__PURE__ */ x("div", {
|
|
37
38
|
className: "min-w-0 flex-1",
|
|
38
|
-
children: [/* @__PURE__ */
|
|
39
|
+
children: [/* @__PURE__ */ b("h3", {
|
|
39
40
|
className: "font-semibold text-text-primary truncate",
|
|
40
|
-
children:
|
|
41
|
-
}),
|
|
41
|
+
children: S.displayName || S.name
|
|
42
|
+
}), S.description && /* @__PURE__ */ b("p", {
|
|
42
43
|
className: "text-sm text-text-secondary mt-0.5 line-clamp-2",
|
|
43
|
-
children:
|
|
44
|
+
children: S.description
|
|
44
45
|
})]
|
|
45
46
|
})]
|
|
46
|
-
}), /* @__PURE__ */
|
|
47
|
+
}), /* @__PURE__ */ x("div", {
|
|
47
48
|
className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0",
|
|
48
49
|
children: [
|
|
49
|
-
|
|
50
|
+
j && /* @__PURE__ */ b("button", {
|
|
50
51
|
type: "button",
|
|
51
52
|
onClick: (e) => {
|
|
52
|
-
e.stopPropagation(),
|
|
53
|
+
e.stopPropagation(), C(S.id);
|
|
53
54
|
},
|
|
54
|
-
disabled:
|
|
55
|
+
disabled: M,
|
|
55
56
|
className: "p-1.5 rounded-md hover:bg-status-success-bg-subtle text-status-success-text transition-colors disabled:opacity-50",
|
|
56
|
-
title:
|
|
57
|
-
children: /* @__PURE__ */
|
|
57
|
+
title: I("vibecontrols.actions.card.execute", "Execute"),
|
|
58
|
+
children: /* @__PURE__ */ b(g, { size: 14 })
|
|
58
59
|
}),
|
|
59
|
-
|
|
60
|
+
k && /* @__PURE__ */ b("button", {
|
|
60
61
|
type: "button",
|
|
61
62
|
onClick: (e) => {
|
|
62
|
-
e.stopPropagation(), S
|
|
63
|
+
e.stopPropagation(), w(S.id);
|
|
63
64
|
},
|
|
64
65
|
className: "p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors",
|
|
65
|
-
title:
|
|
66
|
-
children: /* @__PURE__ */
|
|
66
|
+
title: I("vibecontrols.actions.card.edit", "Edit"),
|
|
67
|
+
children: /* @__PURE__ */ b(h, { size: 14 })
|
|
67
68
|
}),
|
|
68
|
-
|
|
69
|
+
D && /* @__PURE__ */ b("button", {
|
|
69
70
|
type: "button",
|
|
70
71
|
onClick: (e) => {
|
|
71
|
-
e.stopPropagation(),
|
|
72
|
+
e.stopPropagation(), D(S.id);
|
|
72
73
|
},
|
|
73
74
|
className: "p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors",
|
|
74
|
-
title:
|
|
75
|
-
children: /* @__PURE__ */
|
|
75
|
+
title: I("vibecontrols.actions.card.schedule", "Schedule this action"),
|
|
76
|
+
children: /* @__PURE__ */ b(l, { size: 14 })
|
|
76
77
|
}),
|
|
77
|
-
|
|
78
|
+
O && /* @__PURE__ */ b("button", {
|
|
78
79
|
type: "button",
|
|
79
80
|
onClick: (e) => {
|
|
80
|
-
e.stopPropagation(),
|
|
81
|
+
e.stopPropagation(), O(S.id);
|
|
81
82
|
},
|
|
82
83
|
className: "p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors",
|
|
83
|
-
title:
|
|
84
|
-
children: /* @__PURE__ */
|
|
84
|
+
title: I("vibecontrols.actions.card.addToCalendar", "Add to calendar"),
|
|
85
|
+
children: /* @__PURE__ */ b(d, { size: 14 })
|
|
85
86
|
}),
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
+
/* @__PURE__ */ b("button", {
|
|
87
88
|
type: "button",
|
|
88
89
|
onClick: (e) => {
|
|
89
|
-
e.stopPropagation(),
|
|
90
|
+
e.stopPropagation(), T(S.id);
|
|
90
91
|
},
|
|
91
92
|
className: "p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors",
|
|
92
|
-
title:
|
|
93
|
-
children: /* @__PURE__ */
|
|
93
|
+
title: I("vibecontrols.actions.card.duplicate", "Duplicate"),
|
|
94
|
+
children: /* @__PURE__ */ b(p, { size: 14 })
|
|
94
95
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ b(c, {
|
|
96
97
|
entity: "action",
|
|
97
98
|
resource: {
|
|
98
|
-
id:
|
|
99
|
-
name:
|
|
100
|
-
vibeId:
|
|
99
|
+
id: S.id,
|
|
100
|
+
name: S.displayName || S.name,
|
|
101
|
+
vibeId: S.vibeId ?? null
|
|
101
102
|
},
|
|
102
|
-
label:
|
|
103
|
+
label: I("vibecontrols.actions.card.share", "Share")
|
|
103
104
|
}),
|
|
104
|
-
|
|
105
|
+
A && /* @__PURE__ */ b("button", {
|
|
105
106
|
type: "button",
|
|
106
107
|
onClick: (e) => {
|
|
107
|
-
e.stopPropagation(),
|
|
108
|
+
e.stopPropagation(), E(S.id);
|
|
108
109
|
},
|
|
109
110
|
className: "p-1.5 rounded-md hover:bg-status-error-bg-subtle text-status-error-text transition-colors",
|
|
110
|
-
title:
|
|
111
|
-
children: /* @__PURE__ */
|
|
111
|
+
title: I("vibecontrols.actions.card.delete", "Delete"),
|
|
112
|
+
children: /* @__PURE__ */ b(_, { size: 14 })
|
|
112
113
|
})
|
|
113
114
|
]
|
|
114
115
|
})]
|
|
115
116
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ x("div", {
|
|
117
118
|
className: "flex flex-wrap items-center gap-1.5 mb-3",
|
|
118
119
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
-
/* @__PURE__ */
|
|
121
|
-
|
|
120
|
+
/* @__PURE__ */ b(i, { type: S.actionType }),
|
|
121
|
+
/* @__PURE__ */ b(o, { type: S.triggerType }),
|
|
122
|
+
S.sourceType && /* @__PURE__ */ b(a, { type: S.sourceType })
|
|
122
123
|
]
|
|
123
124
|
}),
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
+
S.actionType === "WEBHOOK" && S.webhookUrl && /* @__PURE__ */ b("div", {
|
|
126
|
+
className: "mb-3",
|
|
127
|
+
children: /* @__PURE__ */ b(s, {
|
|
128
|
+
url: S.webhookUrl,
|
|
129
|
+
method: S.webhookMethod
|
|
130
|
+
})
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ b("div", {
|
|
125
133
|
className: "mb-3",
|
|
126
134
|
onClick: (e) => e.stopPropagation(),
|
|
127
|
-
children: /* @__PURE__ */
|
|
135
|
+
children: /* @__PURE__ */ b(n, {
|
|
128
136
|
entityType: t.Action,
|
|
129
|
-
entityId:
|
|
130
|
-
currentVibeId:
|
|
131
|
-
currentVisibility:
|
|
137
|
+
entityId: S.id,
|
|
138
|
+
currentVibeId: S.vibeId ?? null,
|
|
139
|
+
currentVisibility: S.visibility ?? null,
|
|
132
140
|
refetchQueries: ["ListActions"]
|
|
133
141
|
})
|
|
134
142
|
}),
|
|
135
|
-
(
|
|
143
|
+
(S.category || S.tags && S.tags.length > 0) && /* @__PURE__ */ x("div", {
|
|
136
144
|
className: "flex flex-wrap items-center gap-1.5 mb-3",
|
|
137
|
-
children: [
|
|
145
|
+
children: [S.category && /* @__PURE__ */ b("span", {
|
|
138
146
|
className: "text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary",
|
|
139
|
-
children:
|
|
140
|
-
}),
|
|
147
|
+
children: S.category
|
|
148
|
+
}), S.tags?.map((e) => /* @__PURE__ */ x("span", {
|
|
141
149
|
className: "text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-placeholder",
|
|
142
150
|
children: ["#", e]
|
|
143
151
|
}, e))]
|
|
144
152
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ x("div", {
|
|
146
154
|
className: "flex items-center gap-4 text-xs text-text-placeholder",
|
|
147
|
-
children: [
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
children: [
|
|
156
|
+
S.confirmationRequired && /* @__PURE__ */ x("span", {
|
|
157
|
+
className: "inline-flex items-center gap-1 text-status-warning-text",
|
|
158
|
+
children: [/* @__PURE__ */ b(u, { size: 12 }), I("vibecontrols.actions.card.confirmationRequired", "Confirmation required")]
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ x("span", {
|
|
161
|
+
className: "inline-flex items-center gap-1",
|
|
162
|
+
children: [/* @__PURE__ */ b(m, { size: 12 }), I("vibecontrols.actions.card.executionRuns", "{{count}} runs", { count: S.executionCount ?? 0 })]
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ x("span", {
|
|
165
|
+
className: "inline-flex items-center gap-1",
|
|
166
|
+
children: [/* @__PURE__ */ b(f, { size: 12 }), ((e) => {
|
|
167
|
+
if (!e) return I("vibecontrols.actions.card.never", "Never");
|
|
168
|
+
let t = new Date(e), n = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), r = Math.floor(n / 6e4);
|
|
169
|
+
if (r < 1) return I("vibecontrols.actions.card.justNow", "Just now");
|
|
170
|
+
if (r < 60) return I("vibecontrols.actions.card.minutesAgo", "{{count}}m ago", { count: r });
|
|
171
|
+
let i = Math.floor(r / 60);
|
|
172
|
+
if (i < 24) return I("vibecontrols.actions.card.hoursAgo", "{{count}}h ago", { count: i });
|
|
173
|
+
let a = Math.floor(i / 24);
|
|
174
|
+
return a < 7 ? `${a}d ago` : t.toLocaleDateString();
|
|
175
|
+
})(S.lastExecutedAt)]
|
|
176
|
+
})
|
|
177
|
+
]
|
|
163
178
|
})
|
|
164
179
|
]
|
|
165
180
|
});
|
|
166
181
|
}
|
|
167
182
|
//#endregion
|
|
168
|
-
export {
|
|
183
|
+
export { S as ActionCard };
|
|
169
184
|
|
|
170
185
|
//# sourceMappingURL=ActionCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionCard.js","names":[],"sources":["../../../src/components/actions/ActionCard.tsx"],"sourcesContent":["import { Play, Pencil, Copy, Trash2, Clock, Hash, CalendarClock, AlarmClock } from 'lucide-react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { ActionTypeBadge, TriggerTypeBadge, SourceTypeBadge } from './ActionTypeBadge';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\nimport { EntityShareButton } from '../sharing';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { VibeEntityType, VibeVisibility } from '@/generated/wspace-types';\n\ninterface ActionCardAction {\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 vibeId?: string | null;\n visibility?: VibeVisibility | null;\n}\n\ninterface ActionCardProps {\n action: ActionCardAction;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n onSchedule?: (id: string) => void;\n onAddToCalendar?: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n isExecuting?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\nexport function ActionCard({\n action,\n onExecute,\n onEdit,\n onDuplicate,\n onDelete,\n onSchedule,\n onAddToCalendar,\n canUpdate,\n canDelete,\n canExecute,\n isExecuting = false,\n selected = false,\n onToggleSelect,\n}: ActionCardProps) {\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n const formatDate = (dateStr: string | null | undefined) => {\n if (!dateStr) return tr('vibecontrols.actions.card.never', 'Never');\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return tr('vibecontrols.actions.card.justNow', 'Just now');\n if (diffMin < 60)\n return tr('vibecontrols.actions.card.minutesAgo', '{{count}}m ago', { count: diffMin });\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24)\n return tr('vibecontrols.actions.card.hoursAgo', '{{count}}h ago', { count: diffHr });\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n };\n\n return (\n <motion.div\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n }`}\n whileHover={\n shouldReduceMotion\n ? undefined\n : { y: -2, boxShadow: '0 4px 12px var(--color-border-default)' }\n }\n transition={{ duration: 0.15 }}\n layout\n role=\"group\"\n aria-label={`Action: ${action.displayName || action.name}`}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between gap-3 mb-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 action ${action.displayName || action.name}`}\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate\">\n {action.displayName || action.name}\n </h3>\n {action.description && (\n <p className=\"text-sm text-text-secondary mt-0.5 line-clamp-2\">\n {action.description}\n </p>\n )}\n </div>\n </div>\n {/* Action buttons */}\n <div className=\"flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\">\n {canExecute && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onExecute(action.id);\n }}\n disabled={isExecuting}\n className=\"p-1.5 rounded-md hover:bg-status-success-bg-subtle text-status-success-text transition-colors disabled:opacity-50\"\n title={tr('vibecontrols.actions.card.execute', 'Execute')}\n >\n <Play size={14} />\n </button>\n )}\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.edit', 'Edit')}\n >\n <Pencil size={14} />\n </button>\n )}\n {onSchedule && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onSchedule(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.schedule', 'Schedule this action')}\n >\n <AlarmClock size={14} />\n </button>\n )}\n {onAddToCalendar && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onAddToCalendar(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.addToCalendar', 'Add to calendar')}\n >\n <CalendarClock size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDuplicate(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.duplicate', 'Duplicate')}\n >\n <Copy size={14} />\n </button>\n <EntityShareButton\n entity=\"action\"\n resource={{\n id: action.id,\n name: action.displayName || action.name,\n vibeId: action.vibeId ?? null,\n }}\n label={tr('vibecontrols.actions.card.share', 'Share')}\n />\n {canDelete && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-status-error-bg-subtle text-status-error-text transition-colors\"\n title={tr('vibecontrols.actions.card.delete', 'Delete')}\n >\n <Trash2 size={14} />\n </button>\n )}\n </div>\n </div>\n\n {/* Badges */}\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n <ActionTypeBadge type={action.actionType} />\n <TriggerTypeBadge type={action.triggerType} />\n {action.sourceType && <SourceTypeBadge type={action.sourceType} />}\n </div>\n\n {/* Linked vibe — map / unmap this action to a vibe */}\n <div className=\"mb-3\" onClick={(event) => event.stopPropagation()}>\n <EntityVibeLinkControl\n entityType={VibeEntityType.Action}\n entityId={action.id}\n currentVibeId={action.vibeId ?? null}\n currentVisibility={action.visibility ?? null}\n refetchQueries={['ListActions']}\n />\n </div>\n\n {/* Category and Tags */}\n {(action.category || (action.tags && action.tags.length > 0)) && (\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n {action.category && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary\">\n {action.category}\n </span>\n )}\n {action.tags?.map((tag) => (\n <span\n key={tag}\n className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-placeholder\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex items-center gap-4 text-xs text-text-placeholder\">\n <span className=\"inline-flex items-center gap-1\">\n <Hash size={12} />\n {tr('vibecontrols.actions.card.executionRuns', '{{count}} runs', {\n count: action.executionCount ?? 0,\n })}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={12} />\n {formatDate(action.lastExecutedAt)}\n </span>\n </div>\n </motion.div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ActionCard.js","names":[],"sources":["../../../src/components/actions/ActionCard.tsx"],"sourcesContent":["import {\n Play,\n Pencil,\n Copy,\n Trash2,\n Clock,\n Hash,\n CalendarClock,\n AlarmClock,\n AlertTriangle,\n} from 'lucide-react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { ActionTypeBadge, TriggerTypeBadge, SourceTypeBadge } from './ActionTypeBadge';\nimport { ActionWebhookEndpoint } from './ActionWebhookEndpoint';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\nimport { EntityShareButton } from '../sharing';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { VibeEntityType, VibeVisibility } from '@/generated/wspace-types';\n\ninterface ActionCardAction {\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 webhookUrl?: string | null;\n webhookMethod?: string | null;\n vibeId?: string | null;\n visibility?: VibeVisibility | null;\n}\n\ninterface ActionCardProps {\n action: ActionCardAction;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n onSchedule?: (id: string) => void;\n onAddToCalendar?: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n isExecuting?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\nexport function ActionCard({\n action,\n onExecute,\n onEdit,\n onDuplicate,\n onDelete,\n onSchedule,\n onAddToCalendar,\n canUpdate,\n canDelete,\n canExecute,\n isExecuting = false,\n selected = false,\n onToggleSelect,\n}: ActionCardProps) {\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n const formatDate = (dateStr: string | null | undefined) => {\n if (!dateStr) return tr('vibecontrols.actions.card.never', 'Never');\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return tr('vibecontrols.actions.card.justNow', 'Just now');\n if (diffMin < 60)\n return tr('vibecontrols.actions.card.minutesAgo', '{{count}}m ago', { count: diffMin });\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24)\n return tr('vibecontrols.actions.card.hoursAgo', '{{count}}h ago', { count: diffHr });\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n };\n\n return (\n <motion.div\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n }`}\n whileHover={\n shouldReduceMotion\n ? undefined\n : { y: -2, boxShadow: '0 4px 12px var(--color-border-default)' }\n }\n transition={{ duration: 0.15 }}\n layout\n role=\"group\"\n aria-label={`Action: ${action.displayName || action.name}`}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between gap-3 mb-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 action ${action.displayName || action.name}`}\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate\">\n {action.displayName || action.name}\n </h3>\n {action.description && (\n <p className=\"text-sm text-text-secondary mt-0.5 line-clamp-2\">\n {action.description}\n </p>\n )}\n </div>\n </div>\n {/* Action buttons */}\n <div className=\"flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\">\n {canExecute && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onExecute(action.id);\n }}\n disabled={isExecuting}\n className=\"p-1.5 rounded-md hover:bg-status-success-bg-subtle text-status-success-text transition-colors disabled:opacity-50\"\n title={tr('vibecontrols.actions.card.execute', 'Execute')}\n >\n <Play size={14} />\n </button>\n )}\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.edit', 'Edit')}\n >\n <Pencil size={14} />\n </button>\n )}\n {onSchedule && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onSchedule(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.schedule', 'Schedule this action')}\n >\n <AlarmClock size={14} />\n </button>\n )}\n {onAddToCalendar && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onAddToCalendar(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.addToCalendar', 'Add to calendar')}\n >\n <CalendarClock size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDuplicate(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.duplicate', 'Duplicate')}\n >\n <Copy size={14} />\n </button>\n <EntityShareButton\n entity=\"action\"\n resource={{\n id: action.id,\n name: action.displayName || action.name,\n vibeId: action.vibeId ?? null,\n }}\n label={tr('vibecontrols.actions.card.share', 'Share')}\n />\n {canDelete && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-status-error-bg-subtle text-status-error-text transition-colors\"\n title={tr('vibecontrols.actions.card.delete', 'Delete')}\n >\n <Trash2 size={14} />\n </button>\n )}\n </div>\n </div>\n\n {/* Badges */}\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n <ActionTypeBadge type={action.actionType} />\n <TriggerTypeBadge type={action.triggerType} />\n {action.sourceType && <SourceTypeBadge type={action.sourceType} />}\n </div>\n\n {/* Webhook target — only webhook actions have one to show. */}\n {action.actionType === 'WEBHOOK' && action.webhookUrl && (\n <div className=\"mb-3\">\n <ActionWebhookEndpoint url={action.webhookUrl} method={action.webhookMethod} />\n </div>\n )}\n\n {/* Linked vibe — map / unmap this action to a vibe */}\n <div className=\"mb-3\" onClick={(event) => event.stopPropagation()}>\n <EntityVibeLinkControl\n entityType={VibeEntityType.Action}\n entityId={action.id}\n currentVibeId={action.vibeId ?? null}\n currentVisibility={action.visibility ?? null}\n refetchQueries={['ListActions']}\n />\n </div>\n\n {/* Category and Tags */}\n {(action.category || (action.tags && action.tags.length > 0)) && (\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n {action.category && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary\">\n {action.category}\n </span>\n )}\n {action.tags?.map((tag) => (\n <span\n key={tag}\n className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-placeholder\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex items-center gap-4 text-xs text-text-placeholder\">\n {/* This action prompts before it runs — worth knowing before you hit\n Execute, and the only place the flag is visible outside the form. */}\n {action.confirmationRequired && (\n <span className=\"inline-flex items-center gap-1 text-status-warning-text\">\n <AlertTriangle size={12} />\n {tr('vibecontrols.actions.card.confirmationRequired', 'Confirmation required')}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <Hash size={12} />\n {tr('vibecontrols.actions.card.executionRuns', '{{count}} runs', {\n count: action.executionCount ?? 0,\n })}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={12} />\n {formatDate(action.lastExecutedAt)}\n </span>\n </div>\n </motion.div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { notify as t } from "../../lib/toast.js";
|
|
3
|
+
import { copyTextToClipboard as n } from "../../utils/shareUrl.js";
|
|
4
|
+
import { useState as r } from "react";
|
|
5
|
+
import { Check as i, Copy as a } from "lucide-react";
|
|
6
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/actions/ActionWebhookEndpoint.tsx
|
|
8
|
+
var c = 34, l = "POST";
|
|
9
|
+
function u(e) {
|
|
10
|
+
let t;
|
|
11
|
+
try {
|
|
12
|
+
let n = new URL(e);
|
|
13
|
+
t = n.pathname === "/" ? n.host : `${n.host}${n.pathname}`;
|
|
14
|
+
} catch {
|
|
15
|
+
t = e.replace(/^[a-zA-Z][a-zA-Z\d+.-]*:\/\//, "");
|
|
16
|
+
}
|
|
17
|
+
return t.length <= c ? t : `${t.slice(0, c - 1)}…`;
|
|
18
|
+
}
|
|
19
|
+
function d({ url: c, method: d }) {
|
|
20
|
+
let f = e(), [p, m] = r(!1), h = (d ?? l).toUpperCase(), g = u(c), _ = async () => {
|
|
21
|
+
try {
|
|
22
|
+
await n(c), m(!0), t.success(f("vibecontrols.actions.card.endpointCopied", "Webhook URL copied")), window.setTimeout(() => m(!1), 1500);
|
|
23
|
+
} catch {
|
|
24
|
+
t.error(f("vibecontrols.actions.card.endpointCopyFailed", "Could not copy — copy it manually"));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return /* @__PURE__ */ s("div", {
|
|
28
|
+
className: "flex items-center gap-2 rounded-md border border-border-default bg-bg-sunken px-2 py-1.5",
|
|
29
|
+
onClick: (e) => e.stopPropagation(),
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ o("span", {
|
|
32
|
+
className: "font-mono text-xs font-semibold text-text-secondary flex-shrink-0",
|
|
33
|
+
children: h
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ o("span", {
|
|
36
|
+
className: "flex-1 truncate font-mono text-xs text-text-placeholder",
|
|
37
|
+
title: g,
|
|
38
|
+
children: g
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ o("button", {
|
|
41
|
+
type: "button",
|
|
42
|
+
onClick: () => void _(),
|
|
43
|
+
className: "p-0.5 rounded text-text-secondary hover:text-text-primary transition-colors flex-shrink-0",
|
|
44
|
+
"aria-label": f("vibecontrols.actions.card.copyEndpoint", "Copy webhook URL"),
|
|
45
|
+
title: f("vibecontrols.actions.card.copyEndpoint", "Copy webhook URL"),
|
|
46
|
+
children: p ? /* @__PURE__ */ o(i, {
|
|
47
|
+
size: 12,
|
|
48
|
+
className: "text-status-success-text"
|
|
49
|
+
}) : /* @__PURE__ */ o(a, { size: 12 })
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { d as ActionWebhookEndpoint };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=ActionWebhookEndpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionWebhookEndpoint.js","names":[],"sources":["../../../src/components/actions/ActionWebhookEndpoint.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Copy, Check } from 'lucide-react';\nimport { notify } from '@/lib/toast';\nimport { copyTextToClipboard } from '@/utils/shareUrl';\nimport { useTr } from '../../shared/hooks/useTr';\n\n/**\n * Longest endpoint string we render before eliding. Sized so a preview still\n * fits on one line inside a three-up action card at the narrowest grid step.\n */\nconst MAX_ENDPOINT_LENGTH = 34;\n\n/**\n * Webhook actions default to POST in ActionForm, so a row that predates an\n * explicit method (or a null from the API) reads as the same default here\n * instead of rendering a blank verb.\n */\nconst DEFAULT_METHOD = 'POST';\n\n/**\n * Build the at-a-glance form of a webhook target: host + path, no scheme.\n *\n * The query string is deliberately dropped from the *preview* — webhook URLs\n * routinely carry a token there (Slack, Discord, PagerDuty all do) and a card\n * in a shared library is exactly where that should not be shoulder-surfable.\n * The copy button still copies the untouched URL, so nothing is lost.\n */\nfunction formatEndpoint(rawUrl: string): string {\n let display: string;\n try {\n const parsed = new URL(rawUrl);\n display = parsed.pathname === '/' ? parsed.host : `${parsed.host}${parsed.pathname}`;\n } catch {\n // Not a parseable absolute URL (a template or a relative target) — strip\n // any scheme we can recognise and show the rest verbatim.\n display = rawUrl.replace(/^[a-zA-Z][a-zA-Z\\d+.-]*:\\/\\//, '');\n }\n if (display.length <= MAX_ENDPOINT_LENGTH) return display;\n return `${display.slice(0, MAX_ENDPOINT_LENGTH - 1)}…`;\n}\n\ninterface ActionWebhookEndpointProps {\n /** The full webhook target as stored on the action. */\n url: string;\n /** HTTP verb the action fires; falls back to POST when unset. */\n method?: string | null;\n}\n\n/**\n * ActionWebhookEndpoint — the `POST hooks.slack.com/…` line on a webhook action\n * card, with one-click copy of the full URL.\n *\n * Without it a webhook action is indistinguishable from every other webhook\n * action on the library screen: the card shows the name and a \"Webhook\" badge\n * but nothing about where the request actually goes. Surfacing method + host\n * makes \"which of these three alert hooks points at the on-call channel?\"\n * answerable without opening the edit form.\n */\nexport function ActionWebhookEndpoint({ url, method }: ActionWebhookEndpointProps) {\n const tr = useTr();\n const [copied, setCopied] = useState(false);\n\n const verb = (method ?? DEFAULT_METHOD).toUpperCase();\n const endpoint = formatEndpoint(url);\n\n const handleCopy = async (): Promise<void> => {\n try {\n await copyTextToClipboard(url);\n setCopied(true);\n notify.success(tr('vibecontrols.actions.card.endpointCopied', 'Webhook URL copied'));\n window.setTimeout(() => setCopied(false), 1500);\n } catch {\n notify.error(\n tr('vibecontrols.actions.card.endpointCopyFailed', 'Could not copy — copy it manually')\n );\n }\n };\n\n return (\n <div\n className=\"flex items-center gap-2 rounded-md border border-border-default bg-bg-sunken px-2 py-1.5\"\n onClick={(event) => event.stopPropagation()}\n >\n <span className=\"font-mono text-xs font-semibold text-text-secondary flex-shrink-0\">\n {verb}\n </span>\n <span className=\"flex-1 truncate font-mono text-xs text-text-placeholder\" title={endpoint}>\n {endpoint}\n </span>\n <button\n type=\"button\"\n onClick={() => void handleCopy()}\n className=\"p-0.5 rounded text-text-secondary hover:text-text-primary transition-colors flex-shrink-0\"\n aria-label={tr('vibecontrols.actions.card.copyEndpoint', 'Copy webhook URL')}\n title={tr('vibecontrols.actions.card.copyEndpoint', 'Copy webhook URL')}\n >\n {copied ? <Check size={12} className=\"text-status-success-text\" /> : <Copy size={12} />}\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAUA,IAAM,IAAsB,IAOtB,IAAiB;AAUvB,SAAS,EAAe,GAAwB;CAC9C,IAAI;AACJ,KAAI;EACF,IAAM,IAAS,IAAI,IAAI,EAAO;AAC9B,MAAU,EAAO,aAAa,MAAM,EAAO,OAAO,GAAG,EAAO,OAAO,EAAO;SACpE;AAGN,MAAU,EAAO,QAAQ,gCAAgC,GAAG;;AAG9D,QADI,EAAQ,UAAU,IAA4B,IAC3C,GAAG,EAAQ,MAAM,GAAG,IAAsB,EAAE,CAAC;;AAoBtD,SAAgB,EAAsB,EAAE,QAAK,aAAsC;CACjF,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAS,GAAM,EAErC,KAAQ,KAAU,GAAgB,aAAa,EAC/C,IAAW,EAAe,EAAI,EAE9B,IAAa,YAA2B;AAC5C,MAAI;AAIF,GAHA,MAAM,EAAoB,EAAI,EAC9B,EAAU,GAAK,EACf,EAAO,QAAQ,EAAG,4CAA4C,qBAAqB,CAAC,EACpF,OAAO,iBAAiB,EAAU,GAAM,EAAE,KAAK;UACzC;AACN,KAAO,MACL,EAAG,gDAAgD,oCAAoC,CACxF;;;AAIL,QACE,kBAAC,OAAD;EACE,WAAU;EACV,UAAU,MAAU,EAAM,iBAAiB;YAF7C;GAIE,kBAAC,QAAD;IAAM,WAAU;cACb;IACI,CAAA;GACP,kBAAC,QAAD;IAAM,WAAU;IAA0D,OAAO;cAC9E;IACI,CAAA;GACP,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,KAAK,GAAY;IAChC,WAAU;IACV,cAAY,EAAG,0CAA0C,mBAAmB;IAC5E,OAAO,EAAG,0CAA0C,mBAAmB;cAEtE,IAAS,kBAAC,GAAD;KAAO,MAAM;KAAI,WAAU;KAA6B,CAAA,GAAG,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IAChF,CAAA;GACL"}
|
|
@@ -179,11 +179,11 @@ function g({ agent: g }) {
|
|
|
179
179
|
/* @__PURE__ */ p("div", {
|
|
180
180
|
className: "flex gap-2",
|
|
181
181
|
children: /* @__PURE__ */ p("input", {
|
|
182
|
-
"aria-label": "
|
|
182
|
+
"aria-label": _("vibecontrols.agentManager.bridle.profileNameAriaLabel", "Profile name"),
|
|
183
183
|
type: "text",
|
|
184
184
|
value: S,
|
|
185
185
|
onChange: (e) => C(e.target.value),
|
|
186
|
-
placeholder: "e.g., work, personal, minimal",
|
|
186
|
+
placeholder: _("vibecontrols.agentManager.bridle.profileNamePlaceholder", "e.g., work, personal, minimal"),
|
|
187
187
|
className: "flex-1 px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
188
188
|
})
|
|
189
189
|
}),
|
|
@@ -237,11 +237,11 @@ function g({ agent: g }) {
|
|
|
237
237
|
/* @__PURE__ */ m("div", {
|
|
238
238
|
className: "flex gap-2",
|
|
239
239
|
children: [/* @__PURE__ */ p("input", {
|
|
240
|
-
"aria-label": "
|
|
240
|
+
"aria-label": _("vibecontrols.agentManager.bridle.installSourceAriaLabel", "GitHub repository or full URL"),
|
|
241
241
|
type: "text",
|
|
242
242
|
value: w,
|
|
243
243
|
onChange: (e) => T(e.target.value),
|
|
244
|
-
placeholder: "owner/repo or full GitHub URL",
|
|
244
|
+
placeholder: _("vibecontrols.agentManager.bridle.installSourcePlaceholder", "owner/repo or full GitHub URL"),
|
|
245
245
|
className: "flex-1 px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
246
246
|
}), /* @__PURE__ */ m("button", {
|
|
247
247
|
type: "button",
|
|
@@ -275,27 +275,27 @@ function g({ agent: g }) {
|
|
|
275
275
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
276
276
|
htmlFor: "bridleconfigpanel-4",
|
|
277
277
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
278
|
-
children: "Key"
|
|
278
|
+
children: _("vibecontrols.agentManager.bridle.configKeyLabel", "Key")
|
|
279
279
|
}), /* @__PURE__ */ p("input", {
|
|
280
280
|
id: "bridleconfigpanel-4",
|
|
281
|
-
"aria-label": "
|
|
281
|
+
"aria-label": _("vibecontrols.agentManager.bridle.configKeyAriaLabel", "Configuration key"),
|
|
282
282
|
type: "text",
|
|
283
283
|
value: E,
|
|
284
284
|
onChange: (e) => D(e.target.value),
|
|
285
|
-
placeholder: "e.g., editor, default_harness, profile_marker",
|
|
285
|
+
placeholder: _("vibecontrols.agentManager.bridle.configKeyPlaceholder", "e.g., editor, default_harness, profile_marker"),
|
|
286
286
|
className: "w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
287
287
|
})] }),
|
|
288
288
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
289
289
|
htmlFor: "bridleconfigpanel-3",
|
|
290
290
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
291
|
-
children: "Value"
|
|
291
|
+
children: _("vibecontrols.agentManager.bridle.configValueLabel", "Value")
|
|
292
292
|
}), /* @__PURE__ */ p("input", {
|
|
293
293
|
id: "bridleconfigpanel-3",
|
|
294
|
-
"aria-label": "value",
|
|
294
|
+
"aria-label": _("vibecontrols.agentManager.bridle.configValueAriaLabel", "Configuration value"),
|
|
295
295
|
type: "text",
|
|
296
296
|
value: O,
|
|
297
297
|
onChange: (e) => k(e.target.value),
|
|
298
|
-
placeholder: "value",
|
|
298
|
+
placeholder: _("vibecontrols.agentManager.bridle.configValuePlaceholder", "value"),
|
|
299
299
|
className: "w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
300
300
|
})] }),
|
|
301
301
|
/* @__PURE__ */ m("div", {
|