@burdenoff/microfe-vibecontrols 2026.601.23 → 2026.602.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,89 +1,141 @@
1
- import { useGetTunnelQuery as e } from "../../generated/wspace-operations.js";
2
- import { useTr as t } from "../../shared/hooks/useTr.js";
3
- import { PageHeader as n } from "../../components/shared/PageHeader.js";
4
- import { LoadingState as r } from "../../components/shared/LoadingState.js";
5
- import { ErrorState as i } from "../../components/shared/ErrorState.js";
6
- import { EntityTagPicker as a } from "../../components/shared/EntityTagPicker.js";
7
- import { EntityShareButton as o } from "../../components/sharing/EntityShareButton.js";
1
+ import { useGetTunnelQuery as e, useStartTunnelMutation as t, useStopTunnelMutation as n } from "../../generated/wspace-operations.js";
2
+ import { useTr as r } from "../../shared/hooks/useTr.js";
3
+ import { ConfirmDialog as i } from "../../components/shared/ConfirmDialog.js";
4
+ import { QuotaExhaustedDialog as a } from "../../components/shared/QuotaExhaustedDialog.js";
5
+ import { getQuotaDialogContent as o, isQuotaExhaustedError as s, markQuotaHandledLocally as c } from "../../utils/quotaUtils.js";
6
+ import { useVibeControls as l } from "../../providers/VibeControlsProvider.js";
7
+ import { PageHeader as u } from "../../components/shared/PageHeader.js";
8
+ import { LoadingState as d } from "../../components/shared/LoadingState.js";
9
+ import { ErrorState as f } from "../../components/shared/ErrorState.js";
10
+ import { EntityTagPicker as ee } from "../../components/shared/EntityTagPicker.js";
11
+ import { EntityShareButton as te } from "../../components/sharing/EntityShareButton.js";
8
12
  import "../../components/sharing/index.js";
9
- import { TunnelStatusBadge as s } from "../../components/tunnels/TunnelStatusBadge.js";
10
- import { ProviderBadge as c } from "../../components/tunnels/ProviderBadge.js";
11
- import { TunnelOverviewTab as l } from "./tabs/TunnelOverviewTab.js";
12
- import { TunnelEndpointsTab as u } from "./tabs/TunnelEndpointsTab.js";
13
- import { TunnelSessionsTab as d } from "./tabs/TunnelSessionsTab.js";
14
- import { TunnelDomainsTab as f } from "./tabs/TunnelDomainsTab.js";
15
- import { TunnelUsageTab as p } from "./tabs/TunnelUsageTab.js";
16
- import { TunnelCliTab as m } from "./tabs/TunnelCliTab.js";
17
- import { TunnelAuditTab as h } from "./tabs/TunnelAuditTab.js";
18
- import { TunnelSettingsTab as g } from "./tabs/TunnelSettingsTab.js";
19
- import { useEffect as _, useMemo as v } from "react";
20
- import { ArrowLeft as y, Tag as b } from "lucide-react";
21
- import { useNavigate as x, useParams as S, useSearchParams as C } from "react-router-dom";
13
+ import { TunnelStatusBadge as ne } from "../../components/tunnels/TunnelStatusBadge.js";
14
+ import { ProviderBadge as re } from "../../components/tunnels/ProviderBadge.js";
15
+ import { TunnelOverviewTab as ie } from "./tabs/TunnelOverviewTab.js";
16
+ import { TunnelEndpointsTab as ae } from "./tabs/TunnelEndpointsTab.js";
17
+ import { TunnelSessionsTab as oe } from "./tabs/TunnelSessionsTab.js";
18
+ import { TunnelDomainsTab as se } from "./tabs/TunnelDomainsTab.js";
19
+ import { TunnelUsageTab as ce } from "./tabs/TunnelUsageTab.js";
20
+ import { TunnelCliTab as p } from "./tabs/TunnelCliTab.js";
21
+ import { TunnelAuditTab as m } from "./tabs/TunnelAuditTab.js";
22
+ import { TunnelSettingsTab as h } from "./tabs/TunnelSettingsTab.js";
23
+ import { useEffect as g, useMemo as _, useState as v } from "react";
24
+ import { AlertCircle as y, ArrowLeft as le, Loader2 as ue, Play as de, Square as fe, Tag as pe } from "lucide-react";
25
+ import { useLocation as b, useNavigate as x, useParams as S, useSearchParams as C } from "react-router-dom";
22
26
  import { jsx as w, jsxs as T } from "react/jsx-runtime";
23
- import { Tabs as E } from "@burdenoff/fe-libs/chrome";
27
+ import { useEventBus as E } from "@burdenoff/fe-libs/shared/events";
28
+ import { Tabs as D } from "@burdenoff/fe-libs/chrome";
24
29
  //#region src/pages/tunnels/TunnelDetailsPage.tsx
25
- function D() {
26
- let D = t(), { tunnelId: O = "" } = S(), k = x(), [A, j] = C(), { data: M, loading: N, error: P, refetch: F, startPolling: I, stopPolling: L } = e({
27
- variables: { id: O },
30
+ function O() {
31
+ let O = r(), { tunnelId: k = "" } = S(), A = x(), j = b(), M = E(), { workspaceId: N } = l(), [P, F] = C(), [I, L] = v(!1), [R, z] = v(!1), [B, V] = v(() => j.state?.autoPromptStart === !0), { data: H, loading: me, error: U, refetch: he, startPolling: W, stopPolling: G } = e({
32
+ variables: { id: k },
28
33
  fetchPolicy: "cache-and-network",
29
- skip: !O
30
- }), R = M?.tunnel?.status === "PROVISIONING" || M?.tunnel?.status === "DELETING" || M?.tunnel?.status === "ACTIVE" && !M.tunnel.primaryDomain?.hostname;
31
- _(() => {
32
- R ? I(4e3) : L();
34
+ skip: !k
35
+ });
36
+ g(() => {
37
+ j.state?.autoPromptStart && A(j.pathname + j.search, {
38
+ replace: !0,
39
+ state: {}
40
+ });
41
+ }, []);
42
+ let [ge] = t(), [_e] = n(), K = async () => {
43
+ let e = H?.tunnel;
44
+ if (!(!e || I)) {
45
+ V(!1), L(!0);
46
+ try {
47
+ let t = await ge({
48
+ variables: { id: e.id },
49
+ optimisticResponse: { startTunnel: {
50
+ ...e,
51
+ status: "PROVISIONING",
52
+ __typename: "Tunnel"
53
+ } }
54
+ });
55
+ t.error && s(t.error) ? (c(), z(!0), M.emitCustom("vibecontrols.quota.tunnel_limit_hit", { workspaceId: N ?? void 0 })) : t.error || M.emitCustom("vibecontrols.tunnel.started", {
56
+ workspaceId: N ?? void 0,
57
+ tunnelId: e.id
58
+ });
59
+ } catch (e) {
60
+ s(e) ? (c(), z(!0), M.emitCustom("vibecontrols.quota.tunnel_limit_hit", { workspaceId: N ?? void 0 })) : console.error("[TunnelDetailsPage] startTunnel failed", e);
61
+ } finally {
62
+ L(!1);
63
+ }
64
+ }
65
+ }, ve = async () => {
66
+ let e = H?.tunnel;
67
+ if (!(!e || I)) {
68
+ L(!0);
69
+ try {
70
+ await _e({
71
+ variables: { id: e.id },
72
+ optimisticResponse: { stopTunnel: {
73
+ ...e,
74
+ status: "STOPPED",
75
+ __typename: "Tunnel"
76
+ } }
77
+ });
78
+ } finally {
79
+ L(!1);
80
+ }
81
+ }
82
+ }, q = H?.tunnel?.status === "PROVISIONING" || H?.tunnel?.status === "DELETING" || H?.tunnel?.status === "ACTIVE" && !H.tunnel.primaryDomain?.hostname;
83
+ g(() => {
84
+ q ? W(4e3) : G();
33
85
  }, [
34
- R,
35
- I,
36
- L
86
+ q,
87
+ W,
88
+ G
37
89
  ]);
38
- let z = v(() => [
90
+ let J = _(() => [
39
91
  {
40
92
  id: "overview",
41
- label: D("vibecontrols.tunnels.detail.overview", "Overview")
93
+ label: O("vibecontrols.tunnels.detail.overview", "Overview")
42
94
  },
43
95
  {
44
96
  id: "endpoints",
45
- label: D("vibecontrols.tunnels.detail.endpoints", "Endpoints")
97
+ label: O("vibecontrols.tunnels.detail.endpoints", "Endpoints")
46
98
  },
47
99
  {
48
100
  id: "sessions",
49
- label: D("vibecontrols.tunnels.detail.sessions", "Sessions")
101
+ label: O("vibecontrols.tunnels.detail.sessions", "Sessions")
50
102
  },
51
103
  {
52
104
  id: "domains",
53
- label: D("vibecontrols.tunnels.detail.domains", "Domains")
105
+ label: O("vibecontrols.tunnels.detail.domains", "Domains")
54
106
  },
55
107
  {
56
108
  id: "usage",
57
- label: D("vibecontrols.tunnels.detail.usage", "Usage")
109
+ label: O("vibecontrols.tunnels.detail.usage", "Usage")
58
110
  },
59
111
  {
60
112
  id: "cli",
61
- label: D("vibecontrols.tunnels.detail.cli", "CLI")
113
+ label: O("vibecontrols.tunnels.detail.cli", "CLI")
62
114
  },
63
115
  {
64
116
  id: "audit",
65
- label: D("vibecontrols.tunnels.detail.audit", "Audit")
117
+ label: O("vibecontrols.tunnels.detail.audit", "Audit")
66
118
  },
67
119
  {
68
120
  id: "settings",
69
- label: D("vibecontrols.tunnels.detail.settings", "Settings")
121
+ label: O("vibecontrols.tunnels.detail.settings", "Settings")
70
122
  }
71
- ], [D]), B = A.get("tab") ?? z[0].id, V = (e) => {
72
- let t = new URLSearchParams(A);
73
- e === z[0].id ? t.delete("tab") : t.set("tab", e), j(t, { replace: !0 });
123
+ ], [O]), Y = P.get("tab") ?? J[0].id, ye = (e) => {
124
+ let t = new URLSearchParams(P);
125
+ e === J[0].id ? t.delete("tab") : t.set("tab", e), F(t, { replace: !0 });
74
126
  };
75
- if (N && !M) return /* @__PURE__ */ w(r, { message: "Loading tunnel" });
76
- if (P) return /* @__PURE__ */ w(i, {
127
+ if (me && !H) return /* @__PURE__ */ w(d, { message: "Loading tunnel" });
128
+ if (U) return /* @__PURE__ */ w(f, {
77
129
  title: "Failed to load tunnel",
78
- message: P.message,
79
- onRetry: () => F()
130
+ message: U.message,
131
+ onRetry: () => he()
80
132
  });
81
- if (!M?.tunnel) return /* @__PURE__ */ w(i, {
133
+ if (!H?.tunnel) return /* @__PURE__ */ w(f, {
82
134
  title: "Tunnel not found",
83
135
  message: "This tunnel may have been deleted.",
84
- onRetry: () => k("/vibecontrols/tunnels")
136
+ onRetry: () => A("/vibecontrols/tunnels")
85
137
  });
86
- let H = M.tunnel;
138
+ let X = H.tunnel, Z = I || X.status === "PROVISIONING" || X.status === "DELETING", Q = X.status === "ACTIVE", be = Q && !Z, $ = !Q && !Z;
87
139
  return /* @__PURE__ */ T("div", {
88
140
  className: "flex flex-col h-full",
89
141
  children: [
@@ -92,40 +144,81 @@ function D() {
92
144
  children: [
93
145
  /* @__PURE__ */ T("button", {
94
146
  type: "button",
95
- onClick: () => k("/vibecontrols/tunnels"),
147
+ onClick: () => A("/vibecontrols/tunnels"),
96
148
  className: "flex items-center gap-1.5 mb-4 text-sm text-text-secondary hover:text-text-primary transition-colors",
97
- children: [/* @__PURE__ */ w(y, { size: 16 }), "Back to Tunnels"]
149
+ children: [/* @__PURE__ */ w(le, { size: 16 }), "Back to Tunnels"]
98
150
  }),
99
- /* @__PURE__ */ w(n, {
151
+ /* @__PURE__ */ w(u, {
100
152
  breadcrumb: [{
101
153
  label: "Tunnels",
102
154
  path: "/vibecontrols/tunnels"
103
- }, { label: H.name }],
104
- title: H.name,
105
- description: H.description ?? `${H.protocol}:${H.localPort} on ${H.localHost}`,
155
+ }, { label: X.name }],
156
+ title: X.name,
157
+ description: X.description ?? `${X.protocol}:${X.localPort} on ${X.localHost}`,
106
158
  actions: /* @__PURE__ */ T("div", {
107
159
  className: "flex items-center gap-2",
108
160
  children: [
109
- /* @__PURE__ */ w(s, { status: H.status }),
110
- /* @__PURE__ */ w(c, { providerKey: H.providerKey }),
111
- /* @__PURE__ */ w(o, {
161
+ Z && /* @__PURE__ */ T("span", {
162
+ className: "inline-flex items-center rounded-md border border-border-default px-3 py-2 text-sm text-text-muted",
163
+ children: [/* @__PURE__ */ w(ue, { className: "size-4 mr-1.5 animate-spin" }), Q ? O("vibecontrols.tunnels.stopping", "Stopping…") : O("vibecontrols.tunnels.starting", "Starting…")]
164
+ }),
165
+ $ && /* @__PURE__ */ T("button", {
166
+ type: "button",
167
+ onClick: () => void K(),
168
+ className: "inline-flex items-center rounded-md bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-fg hover:bg-action-primary-bg-hover focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40",
169
+ children: [/* @__PURE__ */ w(de, { className: "size-4 mr-1.5" }), O("vibecontrols.tunnels.detail.startTunnel", "Start tunnel")]
170
+ }),
171
+ be && /* @__PURE__ */ T("button", {
172
+ type: "button",
173
+ onClick: () => void ve(),
174
+ className: "inline-flex items-center rounded-md border border-border-default px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-elevated focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40",
175
+ children: [/* @__PURE__ */ w(fe, { className: "size-4 mr-1.5" }), O("vibecontrols.tunnels.detail.stopTunnel", "Stop tunnel")]
176
+ }),
177
+ /* @__PURE__ */ w(ne, { status: X.status }),
178
+ /* @__PURE__ */ w(re, { providerKey: X.providerKey }),
179
+ /* @__PURE__ */ w(te, {
112
180
  entity: "tunnel",
113
181
  resource: {
114
- id: H.id,
115
- name: H.name
182
+ id: X.id,
183
+ name: X.name
116
184
  },
117
- label: D("vibecontrols.tunnels.detail.share", "Share"),
185
+ label: O("vibecontrols.tunnels.detail.share", "Share"),
118
186
  variant: "button"
119
187
  })
120
188
  ]
121
189
  })
122
190
  }),
191
+ X.status === "ERROR" && X.lastError && /* @__PURE__ */ T("div", {
192
+ className: "mt-3 flex items-start gap-2 rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-fg",
193
+ children: [
194
+ /* @__PURE__ */ w(y, {
195
+ className: "mt-0.5 size-4 flex-shrink-0",
196
+ "aria-hidden": "true"
197
+ }),
198
+ /* @__PURE__ */ T("div", {
199
+ className: "min-w-0 flex-1",
200
+ children: [/* @__PURE__ */ w("p", {
201
+ className: "font-medium",
202
+ children: O("vibecontrols.tunnels.detail.startFailed", "The tunnel failed to start")
203
+ }), /* @__PURE__ */ w("p", {
204
+ className: "mt-0.5 break-words text-status-error-fg/90",
205
+ children: X.lastError
206
+ })]
207
+ }),
208
+ $ && /* @__PURE__ */ w("button", {
209
+ type: "button",
210
+ onClick: () => void K(),
211
+ className: "flex-shrink-0 rounded-md border border-status-error-fg/30 px-2.5 py-1 text-xs font-medium hover:bg-status-error-bg/60",
212
+ children: O("vibecontrols.tunnels.detail.retry", "Retry")
213
+ })
214
+ ]
215
+ }),
123
216
  /* @__PURE__ */ w("div", {
124
217
  className: "mt-2",
125
- children: /* @__PURE__ */ w(E, {
126
- items: z,
127
- activeTabId: B,
128
- onTabChange: V,
218
+ children: /* @__PURE__ */ w(D, {
219
+ items: J,
220
+ activeTabId: Y,
221
+ onTabChange: ye,
129
222
  variant: "underline"
130
223
  })
131
224
  })
@@ -133,37 +226,56 @@ function D() {
133
226
  }),
134
227
  /* @__PURE__ */ T("div", {
135
228
  className: "flex items-start gap-2 border-b border-border-subtle bg-bg-surface px-6 py-2",
136
- children: [/* @__PURE__ */ w(b, {
229
+ children: [/* @__PURE__ */ w(pe, {
137
230
  className: "mt-1 size-4 flex-shrink-0 text-text-secondary",
138
231
  "aria-hidden": "true"
139
232
  }), /* @__PURE__ */ w("div", {
140
233
  className: "min-w-0 flex-1",
141
- children: /* @__PURE__ */ w(a, {
234
+ children: /* @__PURE__ */ w(ee, {
142
235
  entityType: "VIBECONTROLS_TUNNEL",
143
- entityId: H.id
236
+ entityId: X.id
144
237
  })
145
238
  })]
146
239
  }),
147
240
  /* @__PURE__ */ T("div", {
148
241
  className: "flex-1 min-h-0 overflow-auto p-6",
149
242
  children: [
150
- B === "overview" && /* @__PURE__ */ w(l, { tunnel: H }),
151
- B === "endpoints" && /* @__PURE__ */ w(u, { tunnel: H }),
152
- B === "sessions" && /* @__PURE__ */ w(d, { tunnelId: H.id }),
153
- B === "domains" && /* @__PURE__ */ w(f, { tunnel: H }),
154
- B === "usage" && /* @__PURE__ */ w(p, { tunnelId: H.id }),
155
- B === "cli" && /* @__PURE__ */ w(m, { tunnel: H }),
156
- B === "audit" && /* @__PURE__ */ w(h, { tunnelId: H.id }),
157
- B === "settings" && /* @__PURE__ */ w(g, {
158
- tunnel: H,
159
- onDeleted: () => k("/vibecontrols/tunnels")
243
+ Y === "overview" && /* @__PURE__ */ w(ie, { tunnel: X }),
244
+ Y === "endpoints" && /* @__PURE__ */ w(ae, { tunnel: X }),
245
+ Y === "sessions" && /* @__PURE__ */ w(oe, { tunnelId: X.id }),
246
+ Y === "domains" && /* @__PURE__ */ w(se, { tunnel: X }),
247
+ Y === "usage" && /* @__PURE__ */ w(ce, { tunnelId: X.id }),
248
+ Y === "cli" && /* @__PURE__ */ w(p, { tunnel: X }),
249
+ Y === "audit" && /* @__PURE__ */ w(m, { tunnelId: X.id }),
250
+ Y === "settings" && /* @__PURE__ */ w(h, {
251
+ tunnel: X,
252
+ onDeleted: () => A("/vibecontrols/tunnels")
160
253
  })
161
254
  ]
255
+ }),
256
+ /* @__PURE__ */ w(i, {
257
+ isOpen: B && $,
258
+ onClose: () => V(!1),
259
+ onConfirm: () => void K(),
260
+ title: O("vibecontrols.tunnels.detail.startPromptTitle", "Start this tunnel now?"),
261
+ message: O("vibecontrols.tunnels.detail.startPromptMessage", "Your tunnel was created as a draft. Start it to bring it online and get its public URL. You can stop it anytime from this page."),
262
+ confirmLabel: O("vibecontrols.tunnels.detail.startTunnel", "Start tunnel"),
263
+ cancelLabel: O("vibecontrols.tunnels.detail.startPromptLater", "Not now"),
264
+ variant: "default",
265
+ isLoading: I
266
+ }),
267
+ /* @__PURE__ */ w(a, {
268
+ isOpen: R,
269
+ onClose: () => z(!1),
270
+ onConfirm: () => {
271
+ z(!1), A("/billing/plans");
272
+ },
273
+ ...o("tunnel-start")
162
274
  })
163
275
  ]
164
276
  });
165
277
  }
166
278
  //#endregion
167
- export { D as TunnelDetailsPage };
279
+ export { O as TunnelDetailsPage };
168
280
 
169
281
  //# sourceMappingURL=TunnelDetailsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TunnelDetailsPage.js","names":[],"sources":["../../../src/pages/tunnels/TunnelDetailsPage.tsx"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport { useParams, useNavigate, useSearchParams } from 'react-router-dom';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\n\nimport { Tag, ArrowLeft } from 'lucide-react';\nimport { PageHeader } from '@/components/shared/PageHeader';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { LoadingState } from '@/components/shared/LoadingState';\nimport { ErrorState } from '@/components/shared/ErrorState';\nimport { TunnelStatusBadge } from '@/components/tunnels/TunnelStatusBadge';\nimport { ProviderBadge } from '@/components/tunnels/ProviderBadge';\nimport { EntityShareButton } from '@/components/sharing';\nimport { useGetTunnelQuery } from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport { TunnelOverviewTab } from './tabs/TunnelOverviewTab';\nimport { TunnelEndpointsTab } from './tabs/TunnelEndpointsTab';\nimport { TunnelSessionsTab } from './tabs/TunnelSessionsTab';\nimport { TunnelDomainsTab } from './tabs/TunnelDomainsTab';\nimport { TunnelUsageTab } from './tabs/TunnelUsageTab';\nimport { TunnelCliTab } from './tabs/TunnelCliTab';\nimport { TunnelAuditTab } from './tabs/TunnelAuditTab';\nimport { TunnelSettingsTab } from './tabs/TunnelSettingsTab';\n\nexport function TunnelDetailsPage() {\n const tr = useTr();\n const { tunnelId = '' } = useParams();\n const navigate = useNavigate();\n const [params, setParams] = useSearchParams();\n\n const { data, loading, error, refetch, startPolling, stopPolling } = useGetTunnelQuery({\n variables: { id: tunnelId },\n fetchPolicy: 'cache-and-network',\n skip: !tunnelId,\n });\n\n // Poll while transitioning OR ACTIVE-but-no-domain (Cloudflare URL arrives async).\n const needsPoll =\n data?.tunnel?.status === 'PROVISIONING' ||\n data?.tunnel?.status === 'DELETING' ||\n (data?.tunnel?.status === 'ACTIVE' && !data.tunnel.primaryDomain?.hostname);\n useEffect(() => {\n if (needsPoll) {\n startPolling(4000);\n } else {\n stopPolling();\n }\n }, [needsPoll, startPolling, stopPolling]);\n\n const tabs: TabItem[] = useMemo(\n () => [\n { id: 'overview', label: tr('vibecontrols.tunnels.detail.overview', 'Overview') },\n { id: 'endpoints', label: tr('vibecontrols.tunnels.detail.endpoints', 'Endpoints') },\n { id: 'sessions', label: tr('vibecontrols.tunnels.detail.sessions', 'Sessions') },\n { id: 'domains', label: tr('vibecontrols.tunnels.detail.domains', 'Domains') },\n { id: 'usage', label: tr('vibecontrols.tunnels.detail.usage', 'Usage') },\n { id: 'cli', label: tr('vibecontrols.tunnels.detail.cli', 'CLI') },\n { id: 'audit', label: tr('vibecontrols.tunnels.detail.audit', 'Audit') },\n { id: 'settings', label: tr('vibecontrols.tunnels.detail.settings', 'Settings') },\n ],\n [tr]\n );\n\n const activeId = params.get('tab') ?? tabs[0].id;\n\n const handleTabChange = (id: string) => {\n const next = new URLSearchParams(params);\n if (id === tabs[0].id) next.delete('tab');\n else next.set('tab', id);\n setParams(next, { replace: true });\n };\n\n if (loading && !data) return <LoadingState message=\"Loading tunnel\" />;\n if (error) {\n return (\n <ErrorState title=\"Failed to load tunnel\" message={error.message} onRetry={() => refetch()} />\n );\n }\n if (!data?.tunnel) {\n return (\n <ErrorState\n title=\"Tunnel not found\"\n message=\"This tunnel may have been deleted.\"\n onRetry={() => navigate('/vibecontrols/tunnels')}\n />\n );\n }\n\n const tunnel = data.tunnel;\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"px-6 pt-6 pb-2 border-b border-border-subtle\">\n <button\n type=\"button\"\n onClick={() => navigate('/vibecontrols/tunnels')}\n className=\"flex items-center gap-1.5 mb-4 text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft size={16} />\n Back to Tunnels\n </button>\n <PageHeader\n breadcrumb={[{ label: 'Tunnels', path: '/vibecontrols/tunnels' }, { label: tunnel.name }]}\n title={tunnel.name}\n description={\n tunnel.description ?? `${tunnel.protocol}:${tunnel.localPort} on ${tunnel.localHost}`\n }\n actions={\n <div className=\"flex items-center gap-2\">\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n <EntityShareButton\n entity=\"tunnel\"\n resource={{ id: tunnel.id, name: tunnel.name }}\n label={tr('vibecontrols.tunnels.detail.share', 'Share')}\n variant=\"button\"\n />\n </div>\n }\n />\n <div className=\"mt-2\">\n <Tabs\n items={tabs}\n activeTabId={activeId}\n onTabChange={handleTabChange}\n variant=\"underline\"\n />\n </div>\n </div>\n <div className=\"flex items-start gap-2 border-b border-border-subtle bg-bg-surface px-6 py-2\">\n <Tag className=\"mt-1 size-4 flex-shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <div className=\"min-w-0 flex-1\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TUNNEL\" entityId={tunnel.id} />\n </div>\n </div>\n <div className=\"flex-1 min-h-0 overflow-auto p-6\">\n {activeId === 'overview' && <TunnelOverviewTab tunnel={tunnel} />}\n {activeId === 'endpoints' && <TunnelEndpointsTab tunnel={tunnel} />}\n {activeId === 'sessions' && <TunnelSessionsTab tunnelId={tunnel.id} />}\n {activeId === 'domains' && <TunnelDomainsTab tunnel={tunnel} />}\n {activeId === 'usage' && <TunnelUsageTab tunnelId={tunnel.id} />}\n {activeId === 'cli' && <TunnelCliTab tunnel={tunnel} />}\n {activeId === 'audit' && <TunnelAuditTab tunnelId={tunnel.id} />}\n {activeId === 'settings' && (\n <TunnelSettingsTab tunnel={tunnel} onDeleted={() => navigate('/vibecontrols/tunnels')} />\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,IAAoB;CAClC,IAAM,IAAK,GAAO,EACZ,EAAE,cAAW,OAAO,GAAW,EAC/B,IAAW,GAAa,EACxB,CAAC,GAAQ,KAAa,GAAiB,EAEvC,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,mBAAgB,EAAkB;EACrF,WAAW,EAAE,IAAI,GAAU;EAC3B,aAAa;EACb,MAAM,CAAC;EACR,CAAC,EAGI,IACJ,GAAM,QAAQ,WAAW,kBACzB,GAAM,QAAQ,WAAW,cACxB,GAAM,QAAQ,WAAW,YAAY,CAAC,EAAK,OAAO,eAAe;AACpE,SAAgB;AACd,EAAI,IACF,EAAa,IAAK,GAElB,GAAa;IAEd;EAAC;EAAW;EAAc;EAAY,CAAC;CAE1C,IAAM,IAAkB,QAChB;EACJ;GAAE,IAAI;GAAY,OAAO,EAAG,wCAAwC,WAAW;GAAE;EACjF;GAAE,IAAI;GAAa,OAAO,EAAG,yCAAyC,YAAY;GAAE;EACpF;GAAE,IAAI;GAAY,OAAO,EAAG,wCAAwC,WAAW;GAAE;EACjF;GAAE,IAAI;GAAW,OAAO,EAAG,uCAAuC,UAAU;GAAE;EAC9E;GAAE,IAAI;GAAS,OAAO,EAAG,qCAAqC,QAAQ;GAAE;EACxE;GAAE,IAAI;GAAO,OAAO,EAAG,mCAAmC,MAAM;GAAE;EAClE;GAAE,IAAI;GAAS,OAAO,EAAG,qCAAqC,QAAQ;GAAE;EACxE;GAAE,IAAI;GAAY,OAAO,EAAG,wCAAwC,WAAW;GAAE;EAClF,EACD,CAAC,EAAG,CACL,EAEK,IAAW,EAAO,IAAI,MAAM,IAAI,EAAK,GAAG,IAExC,KAAmB,MAAe;EACtC,IAAM,IAAO,IAAI,gBAAgB,EAAO;AAGxC,EAFI,MAAO,EAAK,GAAG,KAAI,EAAK,OAAO,MAAM,GACpC,EAAK,IAAI,OAAO,EAAG,EACxB,EAAU,GAAM,EAAE,SAAS,IAAM,CAAC;;AAGpC,KAAI,KAAW,CAAC,EAAM,QAAO,kBAAC,GAAD,EAAc,SAAQ,kBAAmB,CAAA;AACtE,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAwB,SAAS,EAAM;EAAS,eAAe,GAAS;EAAI,CAAA;AAGlG,KAAI,CAAC,GAAM,OACT,QACE,kBAAC,GAAD;EACE,OAAM;EACN,SAAQ;EACR,eAAe,EAAS,wBAAwB;EAChD,CAAA;CAIN,IAAM,IAAS,EAAK;AAEpB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,wBAAwB;MAChD,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EAAA,kBAEhB;;KACT,kBAAC,GAAD;MACE,YAAY,CAAC;OAAE,OAAO;OAAW,MAAM;OAAyB,EAAE,EAAE,OAAO,EAAO,MAAM,CAAC;MACzF,OAAO,EAAO;MACd,aACE,EAAO,eAAe,GAAG,EAAO,SAAS,GAAG,EAAO,UAAU,MAAM,EAAO;MAE5E,SACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;QAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;QAClD,kBAAC,GAAD;SACE,QAAO;SACP,UAAU;UAAE,IAAI,EAAO;UAAI,MAAM,EAAO;UAAM;SAC9C,OAAO,EAAG,qCAAqC,QAAQ;SACvD,SAAQ;SACR,CAAA;QACE;;MAER,CAAA;KACF,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OACE,OAAO;OACP,aAAa;OACb,aAAa;OACb,SAAQ;OACR,CAAA;MACE,CAAA;KACF;;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAK,WAAU;KAAgD,eAAY;KAAS,CAAA,EACpF,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAiB,YAAW;MAAsB,UAAU,EAAO;MAAM,CAAA;KACrE,CAAA,CACF;;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,MAAa,cAAc,kBAAC,GAAD,EAA2B,WAAU,CAAA;KAChE,MAAa,eAAe,kBAAC,GAAD,EAA4B,WAAU,CAAA;KAClE,MAAa,cAAc,kBAAC,GAAD,EAAmB,UAAU,EAAO,IAAM,CAAA;KACrE,MAAa,aAAa,kBAAC,GAAD,EAA0B,WAAU,CAAA;KAC9D,MAAa,WAAW,kBAAC,GAAD,EAAgB,UAAU,EAAO,IAAM,CAAA;KAC/D,MAAa,SAAS,kBAAC,GAAD,EAAsB,WAAU,CAAA;KACtD,MAAa,WAAW,kBAAC,GAAD,EAAgB,UAAU,EAAO,IAAM,CAAA;KAC/D,MAAa,cACZ,kBAAC,GAAD;MAA2B;MAAQ,iBAAiB,EAAS,wBAAwB;MAAI,CAAA;KAEvF;;GACF"}
1
+ {"version":3,"file":"TunnelDetailsPage.js","names":[],"sources":["../../../src/pages/tunnels/TunnelDetailsPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { useParams, useNavigate, useSearchParams, useLocation } from 'react-router-dom';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\n\nimport { Tag, ArrowLeft, Play, Square, Loader2, AlertCircle } from 'lucide-react';\nimport { PageHeader } from '@/components/shared/PageHeader';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { LoadingState } from '@/components/shared/LoadingState';\nimport { ErrorState } from '@/components/shared/ErrorState';\nimport { ConfirmDialog } from '@/components/shared/ConfirmDialog';\nimport { QuotaExhaustedDialog } from '@/components/shared/QuotaExhaustedDialog';\nimport { TunnelStatusBadge } from '@/components/tunnels/TunnelStatusBadge';\nimport { ProviderBadge } from '@/components/tunnels/ProviderBadge';\nimport { EntityShareButton } from '@/components/sharing';\nimport {\n useGetTunnelQuery,\n useStartTunnelMutation,\n useStopTunnelMutation,\n} from '@/generated/wspace-operations';\nimport type { TunnelStatus } from '@/generated/wspace-types';\nimport {\n isQuotaExhaustedError,\n markQuotaHandledLocally,\n getQuotaDialogContent,\n} from '@/utils/quotaUtils';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport { TunnelOverviewTab } from './tabs/TunnelOverviewTab';\nimport { TunnelEndpointsTab } from './tabs/TunnelEndpointsTab';\nimport { TunnelSessionsTab } from './tabs/TunnelSessionsTab';\nimport { TunnelDomainsTab } from './tabs/TunnelDomainsTab';\nimport { TunnelUsageTab } from './tabs/TunnelUsageTab';\nimport { TunnelCliTab } from './tabs/TunnelCliTab';\nimport { TunnelAuditTab } from './tabs/TunnelAuditTab';\nimport { TunnelSettingsTab } from './tabs/TunnelSettingsTab';\n\nexport function TunnelDetailsPage() {\n const tr = useTr();\n const { tunnelId = '' } = useParams();\n const navigate = useNavigate();\n const location = useLocation();\n const bus = useEventBus();\n const { workspaceId } = useVibeControls();\n const [params, setParams] = useSearchParams();\n const [isPending, setIsPending] = useState(false);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n // Set by the create wizard so a freshly created tunnel offers to start\n // immediately instead of leaving the user on a DRAFT with no obvious action.\n const [showStartPrompt, setShowStartPrompt] = useState(\n () => (location.state as { autoPromptStart?: boolean } | null)?.autoPromptStart === true\n );\n\n const { data, loading, error, refetch, startPolling, stopPolling } = useGetTunnelQuery({\n variables: { id: tunnelId },\n fetchPolicy: 'cache-and-network',\n skip: !tunnelId,\n });\n\n // Clear the one-shot auto-prompt flag from history so a refresh / back-forward\n // navigation doesn't re-open the dialog.\n useEffect(() => {\n if ((location.state as { autoPromptStart?: boolean } | null)?.autoPromptStart) {\n navigate(location.pathname + location.search, { replace: true, state: {} });\n }\n // Only run once on mount — intentionally not reacting to later nav changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const [startTunnel] = useStartTunnelMutation();\n const [stopTunnel] = useStopTunnelMutation();\n\n const handleStart = async () => {\n const tunnel = data?.tunnel;\n if (!tunnel || isPending) return;\n setShowStartPrompt(false);\n setIsPending(true);\n try {\n const result = await startTunnel({\n variables: { id: tunnel.id },\n optimisticResponse: {\n startTunnel: { ...tunnel, status: 'PROVISIONING' as TunnelStatus, __typename: 'Tunnel' },\n },\n });\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n bus.emitCustom('vibecontrols.quota.tunnel_limit_hit', {\n workspaceId: workspaceId ?? undefined,\n });\n } else if (!result.error) {\n bus.emitCustom('vibecontrols.tunnel.started', {\n workspaceId: workspaceId ?? undefined,\n tunnelId: tunnel.id,\n });\n }\n } catch (err) {\n // Only the quota dialog is reserved for quota errors; everything else is\n // surfaced via the tunnel's lastError banner after the refetch.\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n bus.emitCustom('vibecontrols.quota.tunnel_limit_hit', {\n workspaceId: workspaceId ?? undefined,\n });\n } else {\n console.error('[TunnelDetailsPage] startTunnel failed', err);\n }\n } finally {\n setIsPending(false);\n }\n };\n\n const handleStop = async () => {\n const tunnel = data?.tunnel;\n if (!tunnel || isPending) return;\n setIsPending(true);\n try {\n await stopTunnel({\n variables: { id: tunnel.id },\n optimisticResponse: {\n stopTunnel: { ...tunnel, status: 'STOPPED' as TunnelStatus, __typename: 'Tunnel' },\n },\n });\n } finally {\n setIsPending(false);\n }\n };\n\n // Poll while transitioning OR ACTIVE-but-no-domain (Cloudflare URL arrives async).\n const needsPoll =\n data?.tunnel?.status === 'PROVISIONING' ||\n data?.tunnel?.status === 'DELETING' ||\n (data?.tunnel?.status === 'ACTIVE' && !data.tunnel.primaryDomain?.hostname);\n useEffect(() => {\n if (needsPoll) {\n startPolling(4000);\n } else {\n stopPolling();\n }\n }, [needsPoll, startPolling, stopPolling]);\n\n const tabs: TabItem[] = useMemo(\n () => [\n { id: 'overview', label: tr('vibecontrols.tunnels.detail.overview', 'Overview') },\n { id: 'endpoints', label: tr('vibecontrols.tunnels.detail.endpoints', 'Endpoints') },\n { id: 'sessions', label: tr('vibecontrols.tunnels.detail.sessions', 'Sessions') },\n { id: 'domains', label: tr('vibecontrols.tunnels.detail.domains', 'Domains') },\n { id: 'usage', label: tr('vibecontrols.tunnels.detail.usage', 'Usage') },\n { id: 'cli', label: tr('vibecontrols.tunnels.detail.cli', 'CLI') },\n { id: 'audit', label: tr('vibecontrols.tunnels.detail.audit', 'Audit') },\n { id: 'settings', label: tr('vibecontrols.tunnels.detail.settings', 'Settings') },\n ],\n [tr]\n );\n\n const activeId = params.get('tab') ?? tabs[0].id;\n\n const handleTabChange = (id: string) => {\n const next = new URLSearchParams(params);\n if (id === tabs[0].id) next.delete('tab');\n else next.set('tab', id);\n setParams(next, { replace: true });\n };\n\n if (loading && !data) return <LoadingState message=\"Loading tunnel\" />;\n if (error) {\n return (\n <ErrorState title=\"Failed to load tunnel\" message={error.message} onRetry={() => refetch()} />\n );\n }\n if (!data?.tunnel) {\n return (\n <ErrorState\n title=\"Tunnel not found\"\n message=\"This tunnel may have been deleted.\"\n onRetry={() => navigate('/vibecontrols/tunnels')}\n />\n );\n }\n\n const tunnel = data.tunnel;\n const isTransitioning =\n isPending || tunnel.status === 'PROVISIONING' || tunnel.status === 'DELETING';\n const isActive = tunnel.status === 'ACTIVE';\n const canStop = isActive && !isTransitioning;\n const canStart = !isActive && !isTransitioning;\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"px-6 pt-6 pb-2 border-b border-border-subtle\">\n <button\n type=\"button\"\n onClick={() => navigate('/vibecontrols/tunnels')}\n className=\"flex items-center gap-1.5 mb-4 text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft size={16} />\n Back to Tunnels\n </button>\n <PageHeader\n breadcrumb={[{ label: 'Tunnels', path: '/vibecontrols/tunnels' }, { label: tunnel.name }]}\n title={tunnel.name}\n description={\n tunnel.description ?? `${tunnel.protocol}:${tunnel.localPort} on ${tunnel.localHost}`\n }\n actions={\n <div className=\"flex items-center gap-2\">\n {isTransitioning && (\n <span className=\"inline-flex items-center rounded-md border border-border-default px-3 py-2 text-sm text-text-muted\">\n <Loader2 className=\"size-4 mr-1.5 animate-spin\" />\n {isActive\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && (\n <button\n type=\"button\"\n onClick={() => void handleStart()}\n className=\"inline-flex items-center rounded-md bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-fg hover:bg-action-primary-bg-hover focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n <Play className=\"size-4 mr-1.5\" />\n {tr('vibecontrols.tunnels.detail.startTunnel', 'Start tunnel')}\n </button>\n )}\n {canStop && (\n <button\n type=\"button\"\n onClick={() => void handleStop()}\n className=\"inline-flex items-center rounded-md border border-border-default px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-elevated focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n <Square className=\"size-4 mr-1.5\" />\n {tr('vibecontrols.tunnels.detail.stopTunnel', 'Stop tunnel')}\n </button>\n )}\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n <EntityShareButton\n entity=\"tunnel\"\n resource={{ id: tunnel.id, name: tunnel.name }}\n label={tr('vibecontrols.tunnels.detail.share', 'Share')}\n variant=\"button\"\n />\n </div>\n }\n />\n {tunnel.status === 'ERROR' && tunnel.lastError && (\n <div className=\"mt-3 flex items-start gap-2 rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-fg\">\n <AlertCircle className=\"mt-0.5 size-4 flex-shrink-0\" aria-hidden=\"true\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium\">\n {tr('vibecontrols.tunnels.detail.startFailed', 'The tunnel failed to start')}\n </p>\n <p className=\"mt-0.5 break-words text-status-error-fg/90\">{tunnel.lastError}</p>\n </div>\n {canStart && (\n <button\n type=\"button\"\n onClick={() => void handleStart()}\n className=\"flex-shrink-0 rounded-md border border-status-error-fg/30 px-2.5 py-1 text-xs font-medium hover:bg-status-error-bg/60\"\n >\n {tr('vibecontrols.tunnels.detail.retry', 'Retry')}\n </button>\n )}\n </div>\n )}\n <div className=\"mt-2\">\n <Tabs\n items={tabs}\n activeTabId={activeId}\n onTabChange={handleTabChange}\n variant=\"underline\"\n />\n </div>\n </div>\n <div className=\"flex items-start gap-2 border-b border-border-subtle bg-bg-surface px-6 py-2\">\n <Tag className=\"mt-1 size-4 flex-shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <div className=\"min-w-0 flex-1\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TUNNEL\" entityId={tunnel.id} />\n </div>\n </div>\n <div className=\"flex-1 min-h-0 overflow-auto p-6\">\n {activeId === 'overview' && <TunnelOverviewTab tunnel={tunnel} />}\n {activeId === 'endpoints' && <TunnelEndpointsTab tunnel={tunnel} />}\n {activeId === 'sessions' && <TunnelSessionsTab tunnelId={tunnel.id} />}\n {activeId === 'domains' && <TunnelDomainsTab tunnel={tunnel} />}\n {activeId === 'usage' && <TunnelUsageTab tunnelId={tunnel.id} />}\n {activeId === 'cli' && <TunnelCliTab tunnel={tunnel} />}\n {activeId === 'audit' && <TunnelAuditTab tunnelId={tunnel.id} />}\n {activeId === 'settings' && (\n <TunnelSettingsTab tunnel={tunnel} onDeleted={() => navigate('/vibecontrols/tunnels')} />\n )}\n </div>\n\n <ConfirmDialog\n isOpen={showStartPrompt && canStart}\n onClose={() => setShowStartPrompt(false)}\n onConfirm={() => void handleStart()}\n title={tr('vibecontrols.tunnels.detail.startPromptTitle', 'Start this tunnel now?')}\n message={tr(\n 'vibecontrols.tunnels.detail.startPromptMessage',\n 'Your tunnel was created as a draft. Start it to bring it online and get its public URL. You can stop it anytime from this page.'\n )}\n confirmLabel={tr('vibecontrols.tunnels.detail.startTunnel', 'Start tunnel')}\n cancelLabel={tr('vibecontrols.tunnels.detail.startPromptLater', 'Not now')}\n variant=\"default\"\n isLoading={isPending}\n />\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n {...getQuotaDialogContent('tunnel-start')}\n />\n </div>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-vibecontrols",
3
- "version": "2026.601.23",
3
+ "version": "2026.602.2",
4
4
  "description": "VibeControls microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [