@burdenoff/microfe-vibecontrols 2026.601.21 → 2026.601.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/components/actions/ActionCard.js +77 -66
  2. package/dist/components/actions/ActionCard.js.map +1 -1
  3. package/dist/components/ai/AIContextsTab.js +186 -173
  4. package/dist/components/ai/AIContextsTab.js.map +1 -1
  5. package/dist/components/ai/AITemplatesTab.js +135 -125
  6. package/dist/components/ai/AITemplatesTab.js.map +1 -1
  7. package/dist/components/ai/InstructionFilesManager.js +151 -137
  8. package/dist/components/ai/InstructionFilesManager.js.map +1 -1
  9. package/dist/components/docs/DocsEditPanel.js +17 -16
  10. package/dist/components/docs/DocsEditPanel.js.map +1 -1
  11. package/dist/components/docs/DocsPreviewPanel.js +25 -24
  12. package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
  13. package/dist/components/docs/DocsTabPanel.js +110 -94
  14. package/dist/components/docs/DocsTabPanel.js.map +1 -1
  15. package/dist/components/notes/NotesTabPanel.js +8 -8
  16. package/dist/components/scorecard/ScorecardPanel.js +271 -257
  17. package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
  18. package/dist/components/sharing/EntityShareButton.js +58 -0
  19. package/dist/components/sharing/EntityShareButton.js.map +1 -0
  20. package/dist/components/sharing/entityShareOps.js +603 -0
  21. package/dist/components/sharing/entityShareOps.js.map +1 -0
  22. package/dist/components/sharing/index.js +3 -0
  23. package/dist/components/sharing/shareRegistry.js +37 -12
  24. package/dist/components/sharing/shareRegistry.js.map +1 -1
  25. package/dist/components/sharing/useEntityShareController.js +88 -0
  26. package/dist/components/sharing/useEntityShareController.js.map +1 -0
  27. package/dist/constants/permissions.js +11 -0
  28. package/dist/constants/permissions.js.map +1 -1
  29. package/dist/pages/ActionsPage.js +162 -162
  30. package/dist/pages/ActionsPage.js.map +1 -1
  31. package/dist/pages/CatalogDetailPage.js +264 -250
  32. package/dist/pages/CatalogDetailPage.js.map +1 -1
  33. package/dist/pages/ComponentDetailPage.js +124 -113
  34. package/dist/pages/ComponentDetailPage.js.map +1 -1
  35. package/dist/pages/TargetDetailsPage.js +139 -126
  36. package/dist/pages/TargetDetailsPage.js.map +1 -1
  37. package/dist/pages/TemplateDetailPage.js +78 -67
  38. package/dist/pages/TemplateDetailPage.js.map +1 -1
  39. package/dist/pages/VibeDeckPage.js +1 -1
  40. package/dist/pages/VibeDetailsPage.js +484 -484
  41. package/dist/pages/VibeDetailsPage.js.map +1 -1
  42. package/dist/pages/tunnels/TunnelDetailsPage.js +91 -77
  43. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  44. package/package.json +1 -1
@@ -6,129 +6,142 @@ import { EmptyState as i } from "../components/shared/EmptyState.js";
6
6
  import { StatusBadge as a } from "../components/shared/StatusBadge.js";
7
7
  import { Card as o } from "../components/shared/Card.js";
8
8
  import "../components/shared/index.js";
9
- import { PageSkeleton as s } from "../components/shared/PageSkeleton.js";
10
- import { useMemo as c } from "react";
11
- import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
12
- import { Activity as u, ArrowLeft as d, CircleCheck as f, CircleX as p, Cpu as m, ExternalLink as h, Server as g, Tag as _ } from "lucide-react";
13
- import { Link as v, useNavigate as y, useParams as b } from "react-router-dom";
14
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
15
- import { MotionPage as C } from "@burdenoff/fe-libs/shared/motion";
9
+ import { EntityShareButton as s } from "../components/sharing/EntityShareButton.js";
10
+ import "../components/sharing/index.js";
11
+ import { PageSkeleton as c } from "../components/shared/PageSkeleton.js";
12
+ import { useMemo as l } from "react";
13
+ import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
+ import { Activity as d, ArrowLeft as f, CircleCheck as p, CircleX as m, Cpu as h, ExternalLink as g, Server as _, Tag as v } from "lucide-react";
15
+ import { Link as y, useNavigate as b, useParams as x } from "react-router-dom";
16
+ import { jsx as S, jsxs as C } from "react/jsx-runtime";
17
+ import { MotionPage as w } from "@burdenoff/fe-libs/shared/motion";
16
18
  //#region src/pages/TargetDetailsPage.tsx
17
- function w() {
18
- let { id: w } = b(), T = y(), { t: E } = l(), D = (e, t) => {
19
- let n = E(e);
19
+ function T() {
20
+ let { id: T } = x(), E = b(), { t: D } = u(), O = (e, t) => {
21
+ let n = D(e);
20
22
  return n === e ? t : n;
21
- }, { data: O, loading: k, error: A, refetch: j } = e({
22
- variables: { id: w ?? "" },
23
- skip: !w,
23
+ }, { data: k, loading: A, error: j, refetch: M } = e({
24
+ variables: { id: T ?? "" },
25
+ skip: !T,
24
26
  fetchPolicy: "cache-and-network"
25
- }), M = O?.target ?? null, N = c(() => M?.agents ?? [], [M]), P = c(() => M?.inboundConnections ?? [], [M]);
26
- if (!w) return /* @__PURE__ */ x(n, {
27
- title: D("targetDetails.missingId", "Target id missing from URL"),
27
+ }), N = k?.target ?? null, P = l(() => N?.agents ?? [], [N]), F = l(() => N?.inboundConnections ?? [], [N]);
28
+ if (!T) return /* @__PURE__ */ S(n, {
29
+ title: O("targetDetails.missingId", "Target id missing from URL"),
28
30
  message: ""
29
31
  });
30
- if (k && !O) return /* @__PURE__ */ x(s, { variant: "detail" });
31
- if (A && !M) return /* @__PURE__ */ x(n, {
32
- title: D("targetDetails.errorTitle", "Failed to load target"),
33
- message: A.message,
34
- onRetry: () => void j()
32
+ if (A && !k) return /* @__PURE__ */ S(c, { variant: "detail" });
33
+ if (j && !N) return /* @__PURE__ */ S(n, {
34
+ title: O("targetDetails.errorTitle", "Failed to load target"),
35
+ message: j.message,
36
+ onRetry: () => void M()
35
37
  });
36
- if (!M) return /* @__PURE__ */ x(i, {
37
- icon: /* @__PURE__ */ x(g, {
38
+ if (!N) return /* @__PURE__ */ S(i, {
39
+ icon: /* @__PURE__ */ S(_, {
38
40
  size: 48,
39
41
  className: "text-text-tertiary"
40
42
  }),
41
- title: D("targetDetails.notFoundTitle", "Target not found"),
42
- description: D("targetDetails.notFoundBody", "The target you requested may have been deleted or is in a different workspace.")
43
+ title: O("targetDetails.notFoundTitle", "Target not found"),
44
+ description: O("targetDetails.notFoundBody", "The target you requested may have been deleted or is in a different workspace.")
43
45
  });
44
- let F = M.updatedAt ? new Date(M.updatedAt).toLocaleString() : "—";
45
- return /* @__PURE__ */ S(C, { children: [
46
- /* @__PURE__ */ x(t, {
47
- title: M.name,
48
- description: `${M.type} · ${M.host ?? "no host"}`,
46
+ let I = N.updatedAt ? new Date(N.updatedAt).toLocaleString() : "—";
47
+ return /* @__PURE__ */ C(w, { children: [
48
+ /* @__PURE__ */ S(t, {
49
+ title: N.name,
50
+ description: `${N.type} · ${N.host ?? "no host"}`,
49
51
  breadcrumb: [
50
52
  {
51
- label: D("breadcrumbs.targetsAgents", "Targets & Agents"),
53
+ label: O("breadcrumbs.targetsAgents", "Targets & Agents"),
52
54
  path: "../agents"
53
55
  },
54
56
  {
55
- label: D("breadcrumbs.targets", "Targets"),
57
+ label: O("breadcrumbs.targets", "Targets"),
56
58
  path: "../agents?tab=targets"
57
59
  },
58
- { label: M.name }
60
+ { label: N.name }
59
61
  ],
60
- actions: /* @__PURE__ */ S("button", {
61
- type: "button",
62
- onClick: () => T("../agents?tab=targets"),
63
- className: "flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border-default hover:bg-bg-sunken transition-colors",
64
- children: [/* @__PURE__ */ x(d, { size: 14 }), D("common.back", "Back")]
62
+ actions: /* @__PURE__ */ C("div", {
63
+ className: "flex items-center gap-2",
64
+ children: [/* @__PURE__ */ S(s, {
65
+ entity: "target",
66
+ resource: {
67
+ id: N.id,
68
+ name: N.name
69
+ },
70
+ label: O("targetDetails.share", "Share"),
71
+ variant: "button"
72
+ }), /* @__PURE__ */ C("button", {
73
+ type: "button",
74
+ onClick: () => E("../agents?tab=targets"),
75
+ className: "flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border-default hover:bg-bg-sunken transition-colors",
76
+ children: [/* @__PURE__ */ S(f, { size: 14 }), O("common.back", "Back")]
77
+ })]
65
78
  })
66
79
  }),
67
- /* @__PURE__ */ S(o, {
80
+ /* @__PURE__ */ C(o, {
68
81
  className: "mt-4",
69
- children: [/* @__PURE__ */ S("div", {
82
+ children: [/* @__PURE__ */ C("div", {
70
83
  className: "p-4 border-b border-border-default flex items-center gap-2",
71
- children: [/* @__PURE__ */ x(g, { className: "size-5" }), /* @__PURE__ */ x("h3", {
84
+ children: [/* @__PURE__ */ S(_, { className: "size-5" }), /* @__PURE__ */ S("h3", {
72
85
  className: "font-semibold text-text-primary",
73
- children: D("targetDetails.identity", "Identity")
86
+ children: O("targetDetails.identity", "Identity")
74
87
  })]
75
- }), /* @__PURE__ */ S("div", {
88
+ }), /* @__PURE__ */ C("div", {
76
89
  className: "p-4 grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm",
77
90
  children: [
78
- /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
91
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
79
92
  className: "text-text-tertiary",
80
- children: D("targetDetails.name", "Name")
81
- }), /* @__PURE__ */ x("p", {
93
+ children: O("targetDetails.name", "Name")
94
+ }), /* @__PURE__ */ S("p", {
82
95
  className: "text-text-primary font-medium",
83
- children: M.name
96
+ children: N.name
84
97
  })] }),
85
- /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
98
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
86
99
  className: "text-text-tertiary",
87
- children: D("targetDetails.type", "Type")
88
- }), /* @__PURE__ */ x("p", {
100
+ children: O("targetDetails.type", "Type")
101
+ }), /* @__PURE__ */ S("p", {
89
102
  className: "text-text-primary font-medium",
90
- children: M.type
103
+ children: N.type
91
104
  })] }),
92
- /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
105
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
93
106
  className: "text-text-tertiary",
94
- children: D("targetDetails.status", "Status")
95
- }), /* @__PURE__ */ x(a, { status: M.status })] }),
96
- /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
107
+ children: O("targetDetails.status", "Status")
108
+ }), /* @__PURE__ */ S(a, { status: N.status })] }),
109
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
97
110
  className: "text-text-tertiary",
98
- children: D("targetDetails.host", "Host")
99
- }), /* @__PURE__ */ x("p", {
111
+ children: O("targetDetails.host", "Host")
112
+ }), /* @__PURE__ */ S("p", {
100
113
  className: "text-text-primary font-mono text-xs",
101
- children: M.host ?? "—"
114
+ children: N.host ?? "—"
102
115
  })] }),
103
- M.username && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
116
+ N.username && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
104
117
  className: "text-text-tertiary",
105
- children: D("targetDetails.username", "Username")
106
- }), /* @__PURE__ */ x("p", {
118
+ children: O("targetDetails.username", "Username")
119
+ }), /* @__PURE__ */ S("p", {
107
120
  className: "text-text-primary font-mono text-xs",
108
- children: M.username
121
+ children: N.username
109
122
  })] }),
110
- M.port != null && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
123
+ N.port != null && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
111
124
  className: "text-text-tertiary",
112
- children: D("targetDetails.port", "Port")
113
- }), /* @__PURE__ */ x("p", {
125
+ children: O("targetDetails.port", "Port")
126
+ }), /* @__PURE__ */ S("p", {
114
127
  className: "text-text-primary font-mono text-xs",
115
- children: M.port
128
+ children: N.port
116
129
  })] }),
117
- /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
130
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
118
131
  className: "text-text-tertiary",
119
- children: D("targetDetails.updatedAt", "Last updated")
120
- }), /* @__PURE__ */ x("p", {
132
+ children: O("targetDetails.updatedAt", "Last updated")
133
+ }), /* @__PURE__ */ S("p", {
121
134
  className: "text-text-primary text-xs",
122
- children: F
135
+ children: I
123
136
  })] }),
124
- M.tags && M.tags.length > 0 && /* @__PURE__ */ S("div", {
137
+ N.tags && N.tags.length > 0 && /* @__PURE__ */ C("div", {
125
138
  className: "sm:col-span-2",
126
- children: [/* @__PURE__ */ x("p", {
139
+ children: [/* @__PURE__ */ S("p", {
127
140
  className: "text-text-tertiary mb-1",
128
- children: D("targetDetails.tags", "Tags")
129
- }), /* @__PURE__ */ x("div", {
141
+ children: O("targetDetails.tags", "Tags")
142
+ }), /* @__PURE__ */ S("div", {
130
143
  className: "flex flex-wrap gap-1",
131
- children: M.tags.map((e) => /* @__PURE__ */ x("span", {
144
+ children: N.tags.map((e) => /* @__PURE__ */ S("span", {
132
145
  className: "px-2 py-0.5 text-xs rounded bg-bg-sunken border border-border-default",
133
146
  children: e
134
147
  }, e))
@@ -137,68 +150,68 @@ function w() {
137
150
  ]
138
151
  })]
139
152
  }),
140
- /* @__PURE__ */ S(o, {
153
+ /* @__PURE__ */ C(o, {
141
154
  className: "mt-4",
142
- children: [/* @__PURE__ */ S("div", {
155
+ children: [/* @__PURE__ */ C("div", {
143
156
  className: "p-4 border-b border-border-default flex items-center gap-2",
144
- children: [/* @__PURE__ */ x(_, { className: "size-5" }), /* @__PURE__ */ x("h3", {
157
+ children: [/* @__PURE__ */ S(v, { className: "size-5" }), /* @__PURE__ */ S("h3", {
145
158
  className: "font-semibold text-text-primary",
146
- children: D("targetDetails.tags", "Tags")
159
+ children: O("targetDetails.tags", "Tags")
147
160
  })]
148
- }), /* @__PURE__ */ x("div", {
161
+ }), /* @__PURE__ */ S("div", {
149
162
  className: "p-4",
150
- children: /* @__PURE__ */ x(r, {
163
+ children: /* @__PURE__ */ S(r, {
151
164
  entityType: "VIBECONTROLS_TARGET",
152
- entityId: M.id
165
+ entityId: N.id
153
166
  })
154
167
  })]
155
168
  }),
156
- /* @__PURE__ */ S(o, {
169
+ /* @__PURE__ */ C(o, {
157
170
  className: "mt-4",
158
- children: [/* @__PURE__ */ S("div", {
171
+ children: [/* @__PURE__ */ C("div", {
159
172
  className: "p-4 border-b border-border-default flex items-center justify-between",
160
- children: [/* @__PURE__ */ S("div", {
173
+ children: [/* @__PURE__ */ C("div", {
161
174
  className: "flex items-center gap-2",
162
- children: [/* @__PURE__ */ x(m, { className: "size-5" }), /* @__PURE__ */ S("h3", {
175
+ children: [/* @__PURE__ */ S(h, { className: "size-5" }), /* @__PURE__ */ C("h3", {
163
176
  className: "font-semibold text-text-primary",
164
177
  children: [
165
- D("targetDetails.agents", "Agents on this target"),
178
+ O("targetDetails.agents", "Agents on this target"),
166
179
  " (",
167
- N.length,
180
+ P.length,
168
181
  ")"
169
182
  ]
170
183
  })]
171
- }), /* @__PURE__ */ S(v, {
184
+ }), /* @__PURE__ */ C(y, {
172
185
  to: "../agents?tab=agents",
173
186
  className: "text-sm text-action-primary-text hover:underline flex items-center gap-1",
174
- children: [D("targetDetails.allAgents", "All agents"), /* @__PURE__ */ x(h, { size: 12 })]
187
+ children: [O("targetDetails.allAgents", "All agents"), /* @__PURE__ */ S(g, { size: 12 })]
175
188
  })]
176
- }), N.length === 0 ? /* @__PURE__ */ x("div", {
189
+ }), P.length === 0 ? /* @__PURE__ */ S("div", {
177
190
  className: "p-6",
178
- children: /* @__PURE__ */ x(i, {
179
- icon: /* @__PURE__ */ x(m, {
191
+ children: /* @__PURE__ */ S(i, {
192
+ icon: /* @__PURE__ */ S(h, {
180
193
  size: 40,
181
194
  className: "text-text-tertiary"
182
195
  }),
183
- title: D("targetDetails.noAgents", "No agents on this target yet"),
184
- description: D("targetDetails.noAgentsBody", "Use the Agents tab to onboard an agent and select this target during setup.")
196
+ title: O("targetDetails.noAgents", "No agents on this target yet"),
197
+ description: O("targetDetails.noAgentsBody", "Use the Agents tab to onboard an agent and select this target during setup.")
185
198
  })
186
- }) : /* @__PURE__ */ x("div", {
199
+ }) : /* @__PURE__ */ S("div", {
187
200
  className: "p-4 space-y-2",
188
- children: N.map((e) => /* @__PURE__ */ S(v, {
201
+ children: P.map((e) => /* @__PURE__ */ C(y, {
189
202
  to: `../agents/${e.id}`,
190
203
  className: "flex items-center justify-between gap-3 p-3 rounded-md border border-border-default hover:bg-bg-sunken/40 transition-colors",
191
- children: [/* @__PURE__ */ S("div", {
204
+ children: [/* @__PURE__ */ C("div", {
192
205
  className: "flex items-center gap-3 min-w-0",
193
- children: [/* @__PURE__ */ x("div", {
206
+ children: [/* @__PURE__ */ S("div", {
194
207
  className: "size-8 rounded-md bg-bg-sunken flex items-center justify-center flex-shrink-0",
195
- children: e.isActive ? /* @__PURE__ */ x(f, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ x(p, { className: "size-4 text-text-tertiary" })
196
- }), /* @__PURE__ */ S("div", {
208
+ children: e.isActive ? /* @__PURE__ */ S(p, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ S(m, { className: "size-4 text-text-tertiary" })
209
+ }), /* @__PURE__ */ C("div", {
197
210
  className: "min-w-0",
198
- children: [/* @__PURE__ */ x("p", {
211
+ children: [/* @__PURE__ */ S("p", {
199
212
  className: "text-sm font-medium text-text-primary truncate",
200
213
  children: e.name
201
- }), /* @__PURE__ */ S("p", {
214
+ }), /* @__PURE__ */ C("p", {
202
215
  className: "text-xs text-text-tertiary truncate",
203
216
  children: [
204
217
  "v",
@@ -207,12 +220,12 @@ function w() {
207
220
  ]
208
221
  })]
209
222
  })]
210
- }), /* @__PURE__ */ S("div", {
223
+ }), /* @__PURE__ */ C("div", {
211
224
  className: "flex items-center gap-2",
212
- children: [/* @__PURE__ */ x("span", {
225
+ children: [/* @__PURE__ */ S("span", {
213
226
  className: `text-xs px-2 py-0.5 rounded ${e.isActive ? "bg-status-success-bg text-status-success-text" : "bg-bg-sunken text-text-tertiary"}`,
214
- children: e.isActive ? D("targetDetails.active", "Active") : D("targetDetails.offline", "Offline")
215
- }), /* @__PURE__ */ x(h, {
227
+ children: e.isActive ? O("targetDetails.active", "Active") : O("targetDetails.offline", "Offline")
228
+ }), /* @__PURE__ */ S(g, {
216
229
  size: 14,
217
230
  className: "text-text-tertiary"
218
231
  })]
@@ -220,44 +233,44 @@ function w() {
220
233
  }, e.id))
221
234
  })]
222
235
  }),
223
- /* @__PURE__ */ S(o, {
236
+ /* @__PURE__ */ C(o, {
224
237
  className: "mt-4",
225
- children: [/* @__PURE__ */ S("div", {
238
+ children: [/* @__PURE__ */ C("div", {
226
239
  className: "p-4 border-b border-border-default flex items-center gap-2",
227
- children: [/* @__PURE__ */ x(u, { className: "size-5" }), /* @__PURE__ */ S("h3", {
240
+ children: [/* @__PURE__ */ S(d, { className: "size-5" }), /* @__PURE__ */ C("h3", {
228
241
  className: "font-semibold text-text-primary",
229
242
  children: [
230
- D("targetDetails.connections", "Inbound connections"),
243
+ O("targetDetails.connections", "Inbound connections"),
231
244
  " (",
232
- P.length,
245
+ F.length,
233
246
  ")"
234
247
  ]
235
248
  })]
236
- }), P.length === 0 ? /* @__PURE__ */ x("div", {
249
+ }), F.length === 0 ? /* @__PURE__ */ S("div", {
237
250
  className: "p-6",
238
- children: /* @__PURE__ */ x(i, {
239
- icon: /* @__PURE__ */ x(u, {
251
+ children: /* @__PURE__ */ S(i, {
252
+ icon: /* @__PURE__ */ S(d, {
240
253
  size: 40,
241
254
  className: "text-text-tertiary"
242
255
  }),
243
- title: D("targetDetails.noConnections", "No inbound connections"),
244
- description: D("targetDetails.noConnectionsBody", "No agents are currently connected to this target.")
256
+ title: O("targetDetails.noConnections", "No inbound connections"),
257
+ description: O("targetDetails.noConnectionsBody", "No agents are currently connected to this target.")
245
258
  })
246
- }) : /* @__PURE__ */ x("div", {
259
+ }) : /* @__PURE__ */ S("div", {
247
260
  className: "p-4 space-y-2",
248
- children: P.map((e) => /* @__PURE__ */ S("div", {
261
+ children: F.map((e) => /* @__PURE__ */ C("div", {
249
262
  className: "flex items-center justify-between gap-3 p-3 rounded-md border border-border-default",
250
- children: [/* @__PURE__ */ S("div", {
263
+ children: [/* @__PURE__ */ C("div", {
251
264
  className: "min-w-0",
252
- children: [/* @__PURE__ */ x("p", {
265
+ children: [/* @__PURE__ */ S("p", {
253
266
  className: "text-sm font-medium text-text-primary truncate",
254
267
  children: e.label || `${e.protocol} connection`
255
- }), /* @__PURE__ */ S("p", {
268
+ }), /* @__PURE__ */ C("p", {
256
269
  className: "text-xs text-text-tertiary truncate",
257
270
  children: [
258
- D("targetDetails.from", "From"),
271
+ O("targetDetails.from", "From"),
259
272
  " ",
260
- /* @__PURE__ */ x(v, {
273
+ /* @__PURE__ */ S(y, {
261
274
  to: `../agents/${e.sourceAgent.id}`,
262
275
  className: "text-action-primary-text hover:underline",
263
276
  children: e.sourceAgent.name
@@ -269,7 +282,7 @@ function w() {
269
282
  e.status
270
283
  ]
271
284
  })]
272
- }), /* @__PURE__ */ x("span", {
285
+ }), /* @__PURE__ */ S("span", {
273
286
  className: "text-xs px-2 py-0.5 rounded bg-bg-sunken",
274
287
  children: e.status
275
288
  })]
@@ -279,6 +292,6 @@ function w() {
279
292
  ] });
280
293
  }
281
294
  //#endregion
282
- export { w as TargetDetailsPage };
295
+ export { T as TargetDetailsPage };
283
296
 
284
297
  //# sourceMappingURL=TargetDetailsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TargetDetailsPage.js","names":[],"sources":["../../src/pages/TargetDetailsPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useParams, Link, useNavigate } from 'react-router-dom';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n ArrowLeft,\n Server,\n CircleCheck,\n CircleX,\n Cpu,\n ExternalLink,\n Activity,\n Tag,\n} from 'lucide-react';\nimport { PageHeader, Card, StatusBadge, EmptyState, ErrorState } from '@/components/shared';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useGetTargetQuery } from '@/generated/wspace-operations';\nimport type { GetTargetQuery } from '@/generated/wspace-operations';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype TargetType = NonNullable<GetTargetQuery['target']>;\ntype AgentSummary = TargetType['agents'][number];\ntype ConnectionSummary = TargetType['inboundConnections'][number];\n\n/**\n * TargetDetailsPage — `/vibecontrols/targets/:id`\n *\n * Mirrors AgentDetailsPage shell. Three sections:\n * 1. Identity card (name, type, status, host, last updated)\n * 2. Agents on this target (table with link to AgentDetailsPage)\n * 3. Inbound agent connections\n *\n * Reuses the existing `GetTarget` query — no schema changes needed; the\n * `TargetFields` fragment already includes the agent list and metadata.\n */\nexport function TargetDetailsPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const { data, loading, error, refetch } = useGetTargetQuery({\n variables: { id: id ?? '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n const target = data?.target ?? null;\n const agents = useMemo(() => target?.agents ?? [], [target]);\n const connections = useMemo(() => target?.inboundConnections ?? [], [target]);\n\n if (!id) {\n return (\n <ErrorState title={tr('targetDetails.missingId', 'Target id missing from URL')} message=\"\" />\n );\n }\n\n if (loading && !data) {\n return <PageSkeleton variant=\"detail\" />;\n }\n\n if (error && !target) {\n return (\n <ErrorState\n title={tr('targetDetails.errorTitle', 'Failed to load target')}\n message={error.message}\n onRetry={() => void refetch()}\n />\n );\n }\n\n if (!target) {\n return (\n <EmptyState\n icon={<Server size={48} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.notFoundTitle', 'Target not found')}\n description={tr(\n 'targetDetails.notFoundBody',\n 'The target you requested may have been deleted or is in a different workspace.'\n )}\n />\n );\n }\n\n const lastUpdatedAt = target.updatedAt\n ? new Date(target.updatedAt as string).toLocaleString()\n : '—';\n\n return (\n <MotionPage>\n <PageHeader\n title={target.name}\n description={`${target.type} · ${target.host ?? 'no host'}`}\n breadcrumb={[\n { label: tr('breadcrumbs.targetsAgents', 'Targets & Agents'), path: '../agents' },\n { label: tr('breadcrumbs.targets', 'Targets'), path: '../agents?tab=targets' },\n { label: target.name },\n ]}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate('../agents?tab=targets')}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border-default hover:bg-bg-sunken transition-colors\"\n >\n <ArrowLeft size={14} />\n {tr('common.back', 'Back')}\n </button>\n }\n />\n\n {/* Identity */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Server className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.identity', 'Identity')}\n </h3>\n </div>\n <div className=\"p-4 grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.name', 'Name')}</p>\n <p className=\"text-text-primary font-medium\">{target.name}</p>\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.type', 'Type')}</p>\n <p className=\"text-text-primary font-medium\">{target.type}</p>\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.status', 'Status')}</p>\n <StatusBadge status={target.status} />\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.host', 'Host')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.host ?? '—'}</p>\n </div>\n {target.username && (\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.username', 'Username')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.username}</p>\n </div>\n )}\n {target.port != null && (\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.port', 'Port')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.port}</p>\n </div>\n )}\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.updatedAt', 'Last updated')}</p>\n <p className=\"text-text-primary text-xs\">{lastUpdatedAt}</p>\n </div>\n {target.tags && target.tags.length > 0 && (\n <div className=\"sm:col-span-2\">\n <p className=\"text-text-tertiary mb-1\">{tr('targetDetails.tags', 'Tags')}</p>\n <div className=\"flex flex-wrap gap-1\">\n {target.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"px-2 py-0.5 text-xs rounded bg-bg-sunken border border-border-default\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </Card>\n\n {/* Tags */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('targetDetails.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TARGET\" entityId={target.id} />\n </div>\n </Card>\n\n {/* Agents on this target */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Cpu className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.agents', 'Agents on this target')} ({agents.length})\n </h3>\n </div>\n <Link\n to=\"../agents?tab=agents\"\n className=\"text-sm text-action-primary-text hover:underline flex items-center gap-1\"\n >\n {tr('targetDetails.allAgents', 'All agents')}\n <ExternalLink size={12} />\n </Link>\n </div>\n {agents.length === 0 ? (\n <div className=\"p-6\">\n <EmptyState\n icon={<Cpu size={40} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.noAgents', 'No agents on this target yet')}\n description={tr(\n 'targetDetails.noAgentsBody',\n 'Use the Agents tab to onboard an agent and select this target during setup.'\n )}\n />\n </div>\n ) : (\n <div className=\"p-4 space-y-2\">\n {agents.map((agent: AgentSummary) => (\n <Link\n key={agent.id}\n to={`../agents/${agent.id}`}\n className=\"flex items-center justify-between gap-3 p-3 rounded-md border border-border-default hover:bg-bg-sunken/40 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"size-8 rounded-md bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n {agent.isActive ? (\n <CircleCheck className=\"size-4 text-status-success-text\" />\n ) : (\n <CircleX className=\"size-4 text-text-tertiary\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{agent.name}</p>\n <p className=\"text-xs text-text-tertiary truncate\">\n v{agent.version}\n {agent.tunnelUrl ? ` · ${agent.tunnelUrl}` : ''}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded ${\n agent.isActive\n ? 'bg-status-success-bg text-status-success-text'\n : 'bg-bg-sunken text-text-tertiary'\n }`}\n >\n {agent.isActive\n ? tr('targetDetails.active', 'Active')\n : tr('targetDetails.offline', 'Offline')}\n </span>\n <ExternalLink size={14} className=\"text-text-tertiary\" />\n </div>\n </Link>\n ))}\n </div>\n )}\n </Card>\n\n {/* Inbound connections */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Activity className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.connections', 'Inbound connections')} ({connections.length})\n </h3>\n </div>\n {connections.length === 0 ? (\n <div className=\"p-6\">\n <EmptyState\n icon={<Activity size={40} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.noConnections', 'No inbound connections')}\n description={tr(\n 'targetDetails.noConnectionsBody',\n 'No agents are currently connected to this target.'\n )}\n />\n </div>\n ) : (\n <div className=\"p-4 space-y-2\">\n {connections.map((conn: ConnectionSummary) => (\n <div\n key={conn.id}\n className=\"flex items-center justify-between gap-3 p-3 rounded-md border border-border-default\"\n >\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {conn.label || `${conn.protocol} connection`}\n </p>\n <p className=\"text-xs text-text-tertiary truncate\">\n {tr('targetDetails.from', 'From')}{' '}\n <Link\n to={`../agents/${conn.sourceAgent.id}`}\n className=\"text-action-primary-text hover:underline\"\n >\n {conn.sourceAgent.name}\n </Link>{' '}\n · {conn.protocol} · {conn.status}\n </p>\n </div>\n <span className=\"text-xs px-2 py-0.5 rounded bg-bg-sunken\">{conn.status}</span>\n </div>\n ))}\n </div>\n )}\n </Card>\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TargetDetailsPage.js","names":[],"sources":["../../src/pages/TargetDetailsPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useParams, Link, useNavigate } from 'react-router-dom';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n ArrowLeft,\n Server,\n CircleCheck,\n CircleX,\n Cpu,\n ExternalLink,\n Activity,\n Tag,\n} from 'lucide-react';\nimport { PageHeader, Card, StatusBadge, EmptyState, ErrorState } from '@/components/shared';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { EntityShareButton } from '@/components/sharing';\nimport { useGetTargetQuery } from '@/generated/wspace-operations';\nimport type { GetTargetQuery } from '@/generated/wspace-operations';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype TargetType = NonNullable<GetTargetQuery['target']>;\ntype AgentSummary = TargetType['agents'][number];\ntype ConnectionSummary = TargetType['inboundConnections'][number];\n\n/**\n * TargetDetailsPage — `/vibecontrols/targets/:id`\n *\n * Mirrors AgentDetailsPage shell. Three sections:\n * 1. Identity card (name, type, status, host, last updated)\n * 2. Agents on this target (table with link to AgentDetailsPage)\n * 3. Inbound agent connections\n *\n * Reuses the existing `GetTarget` query — no schema changes needed; the\n * `TargetFields` fragment already includes the agent list and metadata.\n */\nexport function TargetDetailsPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const { data, loading, error, refetch } = useGetTargetQuery({\n variables: { id: id ?? '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n const target = data?.target ?? null;\n const agents = useMemo(() => target?.agents ?? [], [target]);\n const connections = useMemo(() => target?.inboundConnections ?? [], [target]);\n\n if (!id) {\n return (\n <ErrorState title={tr('targetDetails.missingId', 'Target id missing from URL')} message=\"\" />\n );\n }\n\n if (loading && !data) {\n return <PageSkeleton variant=\"detail\" />;\n }\n\n if (error && !target) {\n return (\n <ErrorState\n title={tr('targetDetails.errorTitle', 'Failed to load target')}\n message={error.message}\n onRetry={() => void refetch()}\n />\n );\n }\n\n if (!target) {\n return (\n <EmptyState\n icon={<Server size={48} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.notFoundTitle', 'Target not found')}\n description={tr(\n 'targetDetails.notFoundBody',\n 'The target you requested may have been deleted or is in a different workspace.'\n )}\n />\n );\n }\n\n const lastUpdatedAt = target.updatedAt\n ? new Date(target.updatedAt as string).toLocaleString()\n : '—';\n\n return (\n <MotionPage>\n <PageHeader\n title={target.name}\n description={`${target.type} · ${target.host ?? 'no host'}`}\n breadcrumb={[\n { label: tr('breadcrumbs.targetsAgents', 'Targets & Agents'), path: '../agents' },\n { label: tr('breadcrumbs.targets', 'Targets'), path: '../agents?tab=targets' },\n { label: target.name },\n ]}\n actions={\n <div className=\"flex items-center gap-2\">\n <EntityShareButton\n entity=\"target\"\n resource={{ id: target.id, name: target.name }}\n label={tr('targetDetails.share', 'Share')}\n variant=\"button\"\n />\n <button\n type=\"button\"\n onClick={() => navigate('../agents?tab=targets')}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border-default hover:bg-bg-sunken transition-colors\"\n >\n <ArrowLeft size={14} />\n {tr('common.back', 'Back')}\n </button>\n </div>\n }\n />\n\n {/* Identity */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Server className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.identity', 'Identity')}\n </h3>\n </div>\n <div className=\"p-4 grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.name', 'Name')}</p>\n <p className=\"text-text-primary font-medium\">{target.name}</p>\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.type', 'Type')}</p>\n <p className=\"text-text-primary font-medium\">{target.type}</p>\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.status', 'Status')}</p>\n <StatusBadge status={target.status} />\n </div>\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.host', 'Host')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.host ?? '—'}</p>\n </div>\n {target.username && (\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.username', 'Username')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.username}</p>\n </div>\n )}\n {target.port != null && (\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.port', 'Port')}</p>\n <p className=\"text-text-primary font-mono text-xs\">{target.port}</p>\n </div>\n )}\n <div>\n <p className=\"text-text-tertiary\">{tr('targetDetails.updatedAt', 'Last updated')}</p>\n <p className=\"text-text-primary text-xs\">{lastUpdatedAt}</p>\n </div>\n {target.tags && target.tags.length > 0 && (\n <div className=\"sm:col-span-2\">\n <p className=\"text-text-tertiary mb-1\">{tr('targetDetails.tags', 'Tags')}</p>\n <div className=\"flex flex-wrap gap-1\">\n {target.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"px-2 py-0.5 text-xs rounded bg-bg-sunken border border-border-default\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </Card>\n\n {/* Tags */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('targetDetails.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TARGET\" entityId={target.id} />\n </div>\n </Card>\n\n {/* Agents on this target */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Cpu className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.agents', 'Agents on this target')} ({agents.length})\n </h3>\n </div>\n <Link\n to=\"../agents?tab=agents\"\n className=\"text-sm text-action-primary-text hover:underline flex items-center gap-1\"\n >\n {tr('targetDetails.allAgents', 'All agents')}\n <ExternalLink size={12} />\n </Link>\n </div>\n {agents.length === 0 ? (\n <div className=\"p-6\">\n <EmptyState\n icon={<Cpu size={40} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.noAgents', 'No agents on this target yet')}\n description={tr(\n 'targetDetails.noAgentsBody',\n 'Use the Agents tab to onboard an agent and select this target during setup.'\n )}\n />\n </div>\n ) : (\n <div className=\"p-4 space-y-2\">\n {agents.map((agent: AgentSummary) => (\n <Link\n key={agent.id}\n to={`../agents/${agent.id}`}\n className=\"flex items-center justify-between gap-3 p-3 rounded-md border border-border-default hover:bg-bg-sunken/40 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"size-8 rounded-md bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n {agent.isActive ? (\n <CircleCheck className=\"size-4 text-status-success-text\" />\n ) : (\n <CircleX className=\"size-4 text-text-tertiary\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{agent.name}</p>\n <p className=\"text-xs text-text-tertiary truncate\">\n v{agent.version}\n {agent.tunnelUrl ? ` · ${agent.tunnelUrl}` : ''}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded ${\n agent.isActive\n ? 'bg-status-success-bg text-status-success-text'\n : 'bg-bg-sunken text-text-tertiary'\n }`}\n >\n {agent.isActive\n ? tr('targetDetails.active', 'Active')\n : tr('targetDetails.offline', 'Offline')}\n </span>\n <ExternalLink size={14} className=\"text-text-tertiary\" />\n </div>\n </Link>\n ))}\n </div>\n )}\n </Card>\n\n {/* Inbound connections */}\n <Card className=\"mt-4\">\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Activity className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('targetDetails.connections', 'Inbound connections')} ({connections.length})\n </h3>\n </div>\n {connections.length === 0 ? (\n <div className=\"p-6\">\n <EmptyState\n icon={<Activity size={40} className=\"text-text-tertiary\" />}\n title={tr('targetDetails.noConnections', 'No inbound connections')}\n description={tr(\n 'targetDetails.noConnectionsBody',\n 'No agents are currently connected to this target.'\n )}\n />\n </div>\n ) : (\n <div className=\"p-4 space-y-2\">\n {connections.map((conn: ConnectionSummary) => (\n <div\n key={conn.id}\n className=\"flex items-center justify-between gap-3 p-3 rounded-md border border-border-default\"\n >\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {conn.label || `${conn.protocol} connection`}\n </p>\n <p className=\"text-xs text-text-tertiary truncate\">\n {tr('targetDetails.from', 'From')}{' '}\n <Link\n to={`../agents/${conn.sourceAgent.id}`}\n className=\"text-action-primary-text hover:underline\"\n >\n {conn.sourceAgent.name}\n </Link>{' '}\n · {conn.protocol} · {conn.status}\n </p>\n </div>\n <span className=\"text-xs px-2 py-0.5 rounded bg-bg-sunken\">{conn.status}</span>\n </div>\n ))}\n </div>\n )}\n </Card>\n </MotionPage>\n );\n}\n"],"mappings":"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"}