@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.
- package/dist/components/actions/ActionCard.js +77 -66
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +186 -173
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AITemplatesTab.js +135 -125
- package/dist/components/ai/AITemplatesTab.js.map +1 -1
- package/dist/components/ai/InstructionFilesManager.js +151 -137
- package/dist/components/ai/InstructionFilesManager.js.map +1 -1
- package/dist/components/docs/DocsEditPanel.js +17 -16
- package/dist/components/docs/DocsEditPanel.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +25 -24
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +110 -94
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +8 -8
- package/dist/components/scorecard/ScorecardPanel.js +271 -257
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/sharing/EntityShareButton.js +58 -0
- package/dist/components/sharing/EntityShareButton.js.map +1 -0
- package/dist/components/sharing/entityShareOps.js +603 -0
- package/dist/components/sharing/entityShareOps.js.map +1 -0
- package/dist/components/sharing/index.js +3 -0
- package/dist/components/sharing/shareRegistry.js +37 -12
- package/dist/components/sharing/shareRegistry.js.map +1 -1
- package/dist/components/sharing/useEntityShareController.js +88 -0
- package/dist/components/sharing/useEntityShareController.js.map +1 -0
- package/dist/constants/permissions.js +11 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/pages/ActionsPage.js +162 -162
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +264 -250
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +124 -113
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +139 -126
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +78 -67
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +1 -1
- package/dist/pages/VibeDetailsPage.js +484 -484
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +91 -77
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- 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 {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
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
|
|
18
|
-
let { id:
|
|
19
|
-
let n =
|
|
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:
|
|
22
|
-
variables: { id:
|
|
23
|
-
skip: !
|
|
23
|
+
}, { data: k, loading: A, error: j, refetch: M } = e({
|
|
24
|
+
variables: { id: T ?? "" },
|
|
25
|
+
skip: !T,
|
|
24
26
|
fetchPolicy: "cache-and-network"
|
|
25
|
-
}),
|
|
26
|
-
if (!
|
|
27
|
-
title:
|
|
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 (
|
|
31
|
-
if (
|
|
32
|
-
title:
|
|
33
|
-
message:
|
|
34
|
-
onRetry: () => void
|
|
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 (!
|
|
37
|
-
icon: /* @__PURE__ */
|
|
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:
|
|
42
|
-
description:
|
|
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
|
|
45
|
-
return /* @__PURE__ */
|
|
46
|
-
/* @__PURE__ */
|
|
47
|
-
title:
|
|
48
|
-
description: `${
|
|
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:
|
|
53
|
+
label: O("breadcrumbs.targetsAgents", "Targets & Agents"),
|
|
52
54
|
path: "../agents"
|
|
53
55
|
},
|
|
54
56
|
{
|
|
55
|
-
label:
|
|
57
|
+
label: O("breadcrumbs.targets", "Targets"),
|
|
56
58
|
path: "../agents?tab=targets"
|
|
57
59
|
},
|
|
58
|
-
{ label:
|
|
60
|
+
{ label: N.name }
|
|
59
61
|
],
|
|
60
|
-
actions: /* @__PURE__ */
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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__ */
|
|
80
|
+
/* @__PURE__ */ C(o, {
|
|
68
81
|
className: "mt-4",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
82
|
+
children: [/* @__PURE__ */ C("div", {
|
|
70
83
|
className: "p-4 border-b border-border-default flex items-center gap-2",
|
|
71
|
-
children: [/* @__PURE__ */
|
|
84
|
+
children: [/* @__PURE__ */ S(_, { className: "size-5" }), /* @__PURE__ */ S("h3", {
|
|
72
85
|
className: "font-semibold text-text-primary",
|
|
73
|
-
children:
|
|
86
|
+
children: O("targetDetails.identity", "Identity")
|
|
74
87
|
})]
|
|
75
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
91
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
79
92
|
className: "text-text-tertiary",
|
|
80
|
-
children:
|
|
81
|
-
}), /* @__PURE__ */
|
|
93
|
+
children: O("targetDetails.name", "Name")
|
|
94
|
+
}), /* @__PURE__ */ S("p", {
|
|
82
95
|
className: "text-text-primary font-medium",
|
|
83
|
-
children:
|
|
96
|
+
children: N.name
|
|
84
97
|
})] }),
|
|
85
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
86
99
|
className: "text-text-tertiary",
|
|
87
|
-
children:
|
|
88
|
-
}), /* @__PURE__ */
|
|
100
|
+
children: O("targetDetails.type", "Type")
|
|
101
|
+
}), /* @__PURE__ */ S("p", {
|
|
89
102
|
className: "text-text-primary font-medium",
|
|
90
|
-
children:
|
|
103
|
+
children: N.type
|
|
91
104
|
})] }),
|
|
92
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
93
106
|
className: "text-text-tertiary",
|
|
94
|
-
children:
|
|
95
|
-
}), /* @__PURE__ */
|
|
96
|
-
/* @__PURE__ */
|
|
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:
|
|
99
|
-
}), /* @__PURE__ */
|
|
111
|
+
children: O("targetDetails.host", "Host")
|
|
112
|
+
}), /* @__PURE__ */ S("p", {
|
|
100
113
|
className: "text-text-primary font-mono text-xs",
|
|
101
|
-
children:
|
|
114
|
+
children: N.host ?? "—"
|
|
102
115
|
})] }),
|
|
103
|
-
|
|
116
|
+
N.username && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
104
117
|
className: "text-text-tertiary",
|
|
105
|
-
children:
|
|
106
|
-
}), /* @__PURE__ */
|
|
118
|
+
children: O("targetDetails.username", "Username")
|
|
119
|
+
}), /* @__PURE__ */ S("p", {
|
|
107
120
|
className: "text-text-primary font-mono text-xs",
|
|
108
|
-
children:
|
|
121
|
+
children: N.username
|
|
109
122
|
})] }),
|
|
110
|
-
|
|
123
|
+
N.port != null && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
111
124
|
className: "text-text-tertiary",
|
|
112
|
-
children:
|
|
113
|
-
}), /* @__PURE__ */
|
|
125
|
+
children: O("targetDetails.port", "Port")
|
|
126
|
+
}), /* @__PURE__ */ S("p", {
|
|
114
127
|
className: "text-text-primary font-mono text-xs",
|
|
115
|
-
children:
|
|
128
|
+
children: N.port
|
|
116
129
|
})] }),
|
|
117
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
118
131
|
className: "text-text-tertiary",
|
|
119
|
-
children:
|
|
120
|
-
}), /* @__PURE__ */
|
|
132
|
+
children: O("targetDetails.updatedAt", "Last updated")
|
|
133
|
+
}), /* @__PURE__ */ S("p", {
|
|
121
134
|
className: "text-text-primary text-xs",
|
|
122
|
-
children:
|
|
135
|
+
children: I
|
|
123
136
|
})] }),
|
|
124
|
-
|
|
137
|
+
N.tags && N.tags.length > 0 && /* @__PURE__ */ C("div", {
|
|
125
138
|
className: "sm:col-span-2",
|
|
126
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ S("p", {
|
|
127
140
|
className: "text-text-tertiary mb-1",
|
|
128
|
-
children:
|
|
129
|
-
}), /* @__PURE__ */
|
|
141
|
+
children: O("targetDetails.tags", "Tags")
|
|
142
|
+
}), /* @__PURE__ */ S("div", {
|
|
130
143
|
className: "flex flex-wrap gap-1",
|
|
131
|
-
children:
|
|
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__ */
|
|
153
|
+
/* @__PURE__ */ C(o, {
|
|
141
154
|
className: "mt-4",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
155
|
+
children: [/* @__PURE__ */ C("div", {
|
|
143
156
|
className: "p-4 border-b border-border-default flex items-center gap-2",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
157
|
+
children: [/* @__PURE__ */ S(v, { className: "size-5" }), /* @__PURE__ */ S("h3", {
|
|
145
158
|
className: "font-semibold text-text-primary",
|
|
146
|
-
children:
|
|
159
|
+
children: O("targetDetails.tags", "Tags")
|
|
147
160
|
})]
|
|
148
|
-
}), /* @__PURE__ */
|
|
161
|
+
}), /* @__PURE__ */ S("div", {
|
|
149
162
|
className: "p-4",
|
|
150
|
-
children: /* @__PURE__ */
|
|
163
|
+
children: /* @__PURE__ */ S(r, {
|
|
151
164
|
entityType: "VIBECONTROLS_TARGET",
|
|
152
|
-
entityId:
|
|
165
|
+
entityId: N.id
|
|
153
166
|
})
|
|
154
167
|
})]
|
|
155
168
|
}),
|
|
156
|
-
/* @__PURE__ */
|
|
169
|
+
/* @__PURE__ */ C(o, {
|
|
157
170
|
className: "mt-4",
|
|
158
|
-
children: [/* @__PURE__ */
|
|
171
|
+
children: [/* @__PURE__ */ C("div", {
|
|
159
172
|
className: "p-4 border-b border-border-default flex items-center justify-between",
|
|
160
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ C("div", {
|
|
161
174
|
className: "flex items-center gap-2",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
175
|
+
children: [/* @__PURE__ */ S(h, { className: "size-5" }), /* @__PURE__ */ C("h3", {
|
|
163
176
|
className: "font-semibold text-text-primary",
|
|
164
177
|
children: [
|
|
165
|
-
|
|
178
|
+
O("targetDetails.agents", "Agents on this target"),
|
|
166
179
|
" (",
|
|
167
|
-
|
|
180
|
+
P.length,
|
|
168
181
|
")"
|
|
169
182
|
]
|
|
170
183
|
})]
|
|
171
|
-
}), /* @__PURE__ */
|
|
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: [
|
|
187
|
+
children: [O("targetDetails.allAgents", "All agents"), /* @__PURE__ */ S(g, { size: 12 })]
|
|
175
188
|
})]
|
|
176
|
-
}),
|
|
189
|
+
}), P.length === 0 ? /* @__PURE__ */ S("div", {
|
|
177
190
|
className: "p-6",
|
|
178
|
-
children: /* @__PURE__ */
|
|
179
|
-
icon: /* @__PURE__ */
|
|
191
|
+
children: /* @__PURE__ */ S(i, {
|
|
192
|
+
icon: /* @__PURE__ */ S(h, {
|
|
180
193
|
size: 40,
|
|
181
194
|
className: "text-text-tertiary"
|
|
182
195
|
}),
|
|
183
|
-
title:
|
|
184
|
-
description:
|
|
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__ */
|
|
199
|
+
}) : /* @__PURE__ */ S("div", {
|
|
187
200
|
className: "p-4 space-y-2",
|
|
188
|
-
children:
|
|
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__ */
|
|
204
|
+
children: [/* @__PURE__ */ C("div", {
|
|
192
205
|
className: "flex items-center gap-3 min-w-0",
|
|
193
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
196
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
211
|
+
children: [/* @__PURE__ */ S("p", {
|
|
199
212
|
className: "text-sm font-medium text-text-primary truncate",
|
|
200
213
|
children: e.name
|
|
201
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
223
|
+
}), /* @__PURE__ */ C("div", {
|
|
211
224
|
className: "flex items-center gap-2",
|
|
212
|
-
children: [/* @__PURE__ */
|
|
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 ?
|
|
215
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
236
|
+
/* @__PURE__ */ C(o, {
|
|
224
237
|
className: "mt-4",
|
|
225
|
-
children: [/* @__PURE__ */
|
|
238
|
+
children: [/* @__PURE__ */ C("div", {
|
|
226
239
|
className: "p-4 border-b border-border-default flex items-center gap-2",
|
|
227
|
-
children: [/* @__PURE__ */
|
|
240
|
+
children: [/* @__PURE__ */ S(d, { className: "size-5" }), /* @__PURE__ */ C("h3", {
|
|
228
241
|
className: "font-semibold text-text-primary",
|
|
229
242
|
children: [
|
|
230
|
-
|
|
243
|
+
O("targetDetails.connections", "Inbound connections"),
|
|
231
244
|
" (",
|
|
232
|
-
|
|
245
|
+
F.length,
|
|
233
246
|
")"
|
|
234
247
|
]
|
|
235
248
|
})]
|
|
236
|
-
}),
|
|
249
|
+
}), F.length === 0 ? /* @__PURE__ */ S("div", {
|
|
237
250
|
className: "p-6",
|
|
238
|
-
children: /* @__PURE__ */
|
|
239
|
-
icon: /* @__PURE__ */
|
|
251
|
+
children: /* @__PURE__ */ S(i, {
|
|
252
|
+
icon: /* @__PURE__ */ S(d, {
|
|
240
253
|
size: 40,
|
|
241
254
|
className: "text-text-tertiary"
|
|
242
255
|
}),
|
|
243
|
-
title:
|
|
244
|
-
description:
|
|
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__ */
|
|
259
|
+
}) : /* @__PURE__ */ S("div", {
|
|
247
260
|
className: "p-4 space-y-2",
|
|
248
|
-
children:
|
|
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__ */
|
|
263
|
+
children: [/* @__PURE__ */ C("div", {
|
|
251
264
|
className: "min-w-0",
|
|
252
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
268
|
+
}), /* @__PURE__ */ C("p", {
|
|
256
269
|
className: "text-xs text-text-tertiary truncate",
|
|
257
270
|
children: [
|
|
258
|
-
|
|
271
|
+
O("targetDetails.from", "From"),
|
|
259
272
|
" ",
|
|
260
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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 {
|
|
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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"}
|