@burdenoff/microfe-vibecontrols 2026.531.11 → 2026.531.13

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,39 +1,40 @@
1
1
  import { useCreateSessionShareLinkMutation as e, useGetSessionShareLinksQuery as t, useGetSessionSharesQuery as n, useRevokeSessionShareLinkMutation as r, useRevokeSessionShareMutation as i, useShareSessionMutation as a } from "../../generated/wspace-operations.js";
2
- import { useTr as o } from "../../shared/hooks/useTr.js";
3
- import { SessionSharePermission as s, ShareStatus as c } from "../../generated/wspace-types.js";
4
- import { useEffect as ee, useRef as l, useState as u } from "react";
5
- import { Check as te, Clock as d, Copy as f, Eye as p, Gamepad2 as m, Link2 as h, Lock as g, RefreshCw as ne, Share2 as re, Trash2 as _, Users as v, X as ie } from "lucide-react";
2
+ import { useTr as ee } from "../../shared/hooks/useTr.js";
3
+ import { SessionSharePermission as o, ShareStatus as s } from "../../generated/wspace-types.js";
4
+ import { copyTextToClipboard as te, normalizeShareUrl as c } from "../../utils/shareUrl.js";
5
+ import { useEffect as ne, useRef as re, useState as l } from "react";
6
+ import { Check as ie, Clock as u, Copy as d, Eye as f, Gamepad2 as p, Link2 as m, Lock as ae, RefreshCw as h, Share2 as oe, Trash2 as g, Users as _, X as v } from "lucide-react";
6
7
  import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
7
8
  //#region src/components/sessions/SessionShareDialog.tsx
8
9
  var S = ({ session: S, isOpen: C, onClose: w }) => {
9
- let T = o(), E = l(null), [D, O] = u("users"), [ae, k] = u(!1), [A, j] = u(""), [M, N] = u(s.View), [P, F] = u(""), [I, oe] = u(24), [L, R] = u(""), [z, B] = u(s.View), [V, H] = u(1), [U, W] = u(""), [G, K] = u(null), { data: se, refetch: q } = n({
10
+ let T = ee(), E = re(null), [D, O] = l("users"), [se, k] = l(null), [ce, A] = l(null), [j, M] = l(""), [N, le] = l(o.View), [P, F] = l(""), [I, ue] = l(24), [L, R] = l(""), [z, B] = l(o.View), [V, H] = l(1), [U, W] = l(""), [G, K] = l(null), { data: de, refetch: q } = n({
10
11
  variables: { sessionId: S.id },
11
12
  skip: !C
12
- }), { data: ce, refetch: J } = t({
13
+ }), { data: fe, refetch: J } = t({
13
14
  variables: { sessionId: S.id },
14
15
  skip: !C
15
- }), [le, { loading: Y }] = a(), [ue, { loading: X }] = e(), [de, { loading: fe }] = i(), [pe, { loading: me }] = r(), Z = se?.sessionShares?.filter((e) => e.status === c.Active) || [], Q = ce?.sessionShareLinks?.filter((e) => e.status === c.Active) || [];
16
- ee(() => {
16
+ }), [pe, { loading: Y }] = a(), [me, { loading: X }] = e(), [he, { loading: ge }] = i(), [_e, { loading: ve }] = r(), Z = de?.sessionShares?.filter((e) => e.status === s.Active) || [], Q = fe?.sessionShareLinks?.filter((e) => e.status === s.Active) || [];
17
+ ne(() => {
17
18
  let e = E.current;
18
19
  e && (C ? e.showModal() : e.close());
19
20
  }, [C]);
20
- let he = async (e) => {
21
- if (e.preventDefault(), A.trim()) try {
21
+ let ye = async (e) => {
22
+ if (e.preventDefault(), j.trim()) try {
22
23
  let e = new Date(Date.now() + I * 60 * 60 * 1e3).toISOString();
23
- await le({ variables: { input: {
24
+ await pe({ variables: { input: {
24
25
  sessionId: S.id,
25
- sharedWithEmail: A.trim(),
26
- permission: M,
26
+ sharedWithEmail: j.trim(),
27
+ permission: N,
27
28
  expiresAt: e,
28
29
  message: P.trim() || void 0
29
- } } }), j(""), F(""), q();
30
+ } } }), M(""), F(""), q();
30
31
  } catch (e) {
31
32
  console.error("Failed to share session:", e);
32
33
  }
33
- }, ge = async (e) => {
34
+ }, be = async (e) => {
34
35
  e.preventDefault();
35
36
  try {
36
- await ue({ variables: { input: {
37
+ await me({ variables: { input: {
37
38
  sessionId: S.id,
38
39
  name: L.trim() || void 0,
39
40
  permission: z,
@@ -44,26 +45,23 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
44
45
  } catch (e) {
45
46
  console.error("Failed to create share link:", e);
46
47
  }
47
- }, _e = async (e) => {
48
+ }, xe = async (e) => {
48
49
  try {
49
- await de({ variables: { id: e } }), q();
50
+ await he({ variables: { id: e } }), q();
50
51
  } catch (e) {
51
52
  console.error("Failed to revoke share:", e);
52
53
  }
53
- }, ve = async (e) => {
54
+ }, Se = async (e) => {
54
55
  try {
55
- await pe({ variables: { id: e } }), J();
56
+ await _e({ variables: { id: e } }), J();
56
57
  } catch (e) {
57
58
  console.error("Failed to revoke link:", e);
58
59
  }
59
- }, ye = async (e) => {
60
- try {
61
- await navigator.clipboard.writeText(e);
62
- } catch {
63
- let t = document.createElement("textarea");
64
- t.value = e, t.style.position = "fixed", t.style.opacity = "0", document.body.appendChild(t), t.select(), document.execCommand("copy"), document.body.removeChild(t);
65
- }
66
- k(!0), setTimeout(() => k(!1), 2e3);
60
+ }, Ce = async (e, t) => {
61
+ let n = await te(c(t)).then(() => !0, (e) => (console.warn("Failed to copy session share link:", e), !1));
62
+ k(n ? e : null), A(n ? null : e), setTimeout(() => {
63
+ k((t) => t === e ? null : t), A((t) => t === e ? null : t);
64
+ }, 2e3);
67
65
  }, $ = (e) => {
68
66
  let t = new Date(e), n = /* @__PURE__ */ new Date(), r = t.getTime() - n.getTime(), i = Math.floor(r / (1e3 * 60 * 60)), a = Math.floor(r % (1e3 * 60 * 60) / (1e3 * 60));
69
67
  return r < 0 ? "Expired" : i > 24 ? `${Math.floor(i / 24)}d` : i > 0 ? `${i}h ${a}m` : `${a}m`;
@@ -81,7 +79,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
81
79
  className: "flex items-center gap-3",
82
80
  children: [/* @__PURE__ */ b("div", {
83
81
  className: "p-2 bg-action-primary-bg/10 rounded-lg",
84
- children: /* @__PURE__ */ b(re, { className: "size-5 text-action-primary-bg" })
82
+ children: /* @__PURE__ */ b(oe, { className: "size-5 text-action-primary-bg" })
85
83
  }), /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("h2", {
86
84
  className: "text-lg font-semibold text-text-primary",
87
85
  children: T("vibecontrols.sessions.share.title", "Share Session")
@@ -93,7 +91,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
93
91
  type: "button",
94
92
  onClick: w,
95
93
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
96
- children: /* @__PURE__ */ b(ie, { className: "size-5 text-text-secondary" })
94
+ children: /* @__PURE__ */ b(v, { className: "size-5 text-text-secondary" })
97
95
  })]
98
96
  }),
99
97
  /* @__PURE__ */ x("div", {
@@ -103,7 +101,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
103
101
  onClick: () => O("users"),
104
102
  className: `flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${D === "users" ? "text-action-primary-bg border-b-2 border-action-primary-bg" : "text-text-secondary hover:text-text-primary"}`,
105
103
  children: [
106
- /* @__PURE__ */ b(v, { className: "size-4" }),
104
+ /* @__PURE__ */ b(_, { className: "size-4" }),
107
105
  T("vibecontrols.sessions.share.shareWithUser", "Share with User"),
108
106
  Z.length > 0 && /* @__PURE__ */ b("span", {
109
107
  className: "ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full",
@@ -115,7 +113,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
115
113
  onClick: () => O("links"),
116
114
  className: `flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${D === "links" ? "text-action-primary-bg border-b-2 border-action-primary-bg" : "text-text-secondary hover:text-text-primary"}`,
117
115
  children: [
118
- /* @__PURE__ */ b(h, { className: "size-4" }),
116
+ /* @__PURE__ */ b(m, { className: "size-4" }),
119
117
  T("vibecontrols.sessions.share.createLink", "Create Link"),
120
118
  Q.length > 0 && /* @__PURE__ */ b("span", {
121
119
  className: "ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full",
@@ -129,7 +127,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
129
127
  children: D === "users" ? /* @__PURE__ */ x("div", {
130
128
  className: "space-y-6",
131
129
  children: [/* @__PURE__ */ x("form", {
132
- onSubmit: he,
130
+ onSubmit: ye,
133
131
  className: "space-y-4",
134
132
  children: [
135
133
  /* @__PURE__ */ x("div", { children: [
@@ -140,8 +138,8 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
140
138
  /* @__PURE__ */ b("input", {
141
139
  "aria-label": "teammate@company.com",
142
140
  type: "email",
143
- value: A,
144
- onChange: (e) => j(e.target.value),
141
+ value: j,
142
+ onChange: (e) => M(e.target.value),
145
143
  placeholder: "teammate@company.com",
146
144
  required: !0,
147
145
  className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg"
@@ -157,14 +155,14 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
157
155
  className: "block text-sm font-medium text-text-primary mb-1",
158
156
  children: T("vibecontrols.sessions.share.permission", "Permission")
159
157
  }), /* @__PURE__ */ x("select", {
160
- value: M,
161
- onChange: (e) => N(e.target.value),
158
+ value: N,
159
+ onChange: (e) => le(e.target.value),
162
160
  className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
163
161
  children: [/* @__PURE__ */ b("option", {
164
- value: s.View,
162
+ value: o.View,
165
163
  children: T("vibecontrols.sessions.share.viewOnly", "View Only")
166
164
  }), /* @__PURE__ */ b("option", {
167
- value: s.Interact,
165
+ value: o.Interact,
168
166
  children: T("vibecontrols.sessions.share.canControl", "Can Control")
169
167
  })]
170
168
  })] }), /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("label", {
@@ -172,7 +170,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
172
170
  children: T("vibecontrols.sessions.share.expiresIn", "Expires In")
173
171
  }), /* @__PURE__ */ x("select", {
174
172
  value: I,
175
- onChange: (e) => oe(Number(e.target.value)),
173
+ onChange: (e) => ue(Number(e.target.value)),
176
174
  className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
177
175
  children: [
178
176
  /* @__PURE__ */ b("option", {
@@ -215,17 +213,17 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
215
213
  })] }),
216
214
  /* @__PURE__ */ b("div", {
217
215
  className: "flex items-center gap-2 p-3 bg-bg-sunken rounded-lg text-sm",
218
- children: M === s.View ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(p, { className: "size-4 text-text-secondary" }), /* @__PURE__ */ b("span", {
216
+ children: N === o.View ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(f, { className: "size-4 text-text-secondary" }), /* @__PURE__ */ b("span", {
219
217
  className: "text-text-secondary",
220
218
  children: T("vibecontrols.sessions.share.viewOnlyHint", "User can watch the terminal but cannot type")
221
- })] }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(m, { className: "size-4 text-text-secondary" }), /* @__PURE__ */ b("span", {
219
+ })] }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(p, { className: "size-4 text-text-secondary" }), /* @__PURE__ */ b("span", {
222
220
  className: "text-text-secondary",
223
221
  children: T("vibecontrols.sessions.share.controlHint", "User can request control to type (turn-based)")
224
222
  })] })
225
223
  }),
226
224
  /* @__PURE__ */ b("button", {
227
225
  type: "submit",
228
- disabled: Y || !A.trim(),
226
+ disabled: Y || !j.trim(),
229
227
  className: "w-full px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50",
230
228
  children: Y ? T("vibecontrols.sessions.share.sharing", "Sharing...") : T("vibecontrols.sessions.share.shareSession", "Share Session")
231
229
  })
@@ -241,7 +239,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
241
239
  className: "flex items-center gap-3",
242
240
  children: [/* @__PURE__ */ b("div", {
243
241
  className: "size-8 rounded-full bg-action-primary-bg/20 flex items-center justify-center",
244
- children: /* @__PURE__ */ b(v, { className: "size-4 text-action-primary-bg" })
242
+ children: /* @__PURE__ */ b(_, { className: "size-4 text-action-primary-bg" })
245
243
  }), /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ x("p", {
246
244
  className: "text-sm font-medium text-text-primary",
247
245
  children: [
@@ -252,29 +250,29 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
252
250
  }), /* @__PURE__ */ x("div", {
253
251
  className: "flex items-center gap-2 text-xs text-text-secondary",
254
252
  children: [
255
- e.permission === s.View ? /* @__PURE__ */ b(p, { className: "size-3" }) : /* @__PURE__ */ b(m, { className: "size-3" }),
253
+ e.permission === o.View ? /* @__PURE__ */ b(f, { className: "size-3" }) : /* @__PURE__ */ b(p, { className: "size-3" }),
256
254
  /* @__PURE__ */ b("span", { children: e.permission }),
257
255
  e.expiresAt && /* @__PURE__ */ x(y, { children: [
258
256
  /* @__PURE__ */ b("span", { children: "·" }),
259
- /* @__PURE__ */ b(d, { className: "size-3" }),
257
+ /* @__PURE__ */ b(u, { className: "size-3" }),
260
258
  /* @__PURE__ */ b("span", { children: $(e.expiresAt) })
261
259
  ] })
262
260
  ]
263
261
  })] })]
264
262
  }), /* @__PURE__ */ b("button", {
265
263
  type: "button",
266
- onClick: () => _e(e.id),
267
- disabled: fe,
264
+ onClick: () => xe(e.id),
265
+ disabled: ge,
268
266
  className: "p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors",
269
267
  title: "Revoke access",
270
- children: /* @__PURE__ */ b(_, { className: "size-4" })
268
+ children: /* @__PURE__ */ b(g, { className: "size-4" })
271
269
  })]
272
270
  }, e.id))
273
271
  })] })]
274
272
  }) : /* @__PURE__ */ x("div", {
275
273
  className: "space-y-6",
276
274
  children: [/* @__PURE__ */ x("form", {
277
- onSubmit: ge,
275
+ onSubmit: be,
278
276
  className: "space-y-4",
279
277
  children: [
280
278
  /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("label", {
@@ -298,10 +296,10 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
298
296
  onChange: (e) => B(e.target.value),
299
297
  className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
300
298
  children: [/* @__PURE__ */ b("option", {
301
- value: s.View,
299
+ value: o.View,
302
300
  children: T("vibecontrols.sessions.share.viewOnly", "View Only")
303
301
  }), /* @__PURE__ */ b("option", {
304
- value: s.Interact,
302
+ value: o.Interact,
305
303
  children: T("vibecontrols.sessions.share.canControl", "Can Control")
306
304
  })]
307
305
  })] }), /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("label", {
@@ -380,46 +378,46 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
380
378
  children: [/* @__PURE__ */ x("div", {
381
379
  className: "flex items-center gap-2",
382
380
  children: [
383
- /* @__PURE__ */ b(h, { className: "size-4 text-action-primary-bg" }),
381
+ /* @__PURE__ */ b(m, { className: "size-4 text-action-primary-bg" }),
384
382
  /* @__PURE__ */ b("span", {
385
383
  className: "text-sm font-medium text-text-primary",
386
384
  children: e.name || "Unnamed Link"
387
385
  }),
388
- e.hasPassword && /* @__PURE__ */ b(g, { className: "size-3 text-text-secondary" })
386
+ e.hasPassword && /* @__PURE__ */ b(ae, { className: "size-3 text-text-secondary" })
389
387
  ]
390
388
  }), /* @__PURE__ */ x("div", {
391
389
  className: "flex items-center gap-1",
392
390
  children: [/* @__PURE__ */ b("button", {
393
391
  type: "button",
394
- onClick: () => ye(e.shareUrl),
392
+ onClick: () => Ce(e.id, e.shareUrl),
395
393
  className: "p-1.5 text-text-secondary hover:text-action-primary-bg hover:bg-action-primary-bg/10 rounded transition-colors",
396
394
  title: "Copy link",
397
- children: ae ? /* @__PURE__ */ b(te, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ b(f, { className: "size-4" })
395
+ children: se === e.id ? /* @__PURE__ */ b(ie, { className: "size-4 text-status-success-text" }) : ce === e.id ? /* @__PURE__ */ b(v, { className: "size-4 text-status-error-text" }) : /* @__PURE__ */ b(d, { className: "size-4" })
398
396
  }), /* @__PURE__ */ b("button", {
399
397
  type: "button",
400
- onClick: () => ve(e.id),
401
- disabled: me,
398
+ onClick: () => Se(e.id),
399
+ disabled: ve,
402
400
  className: "p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors",
403
401
  title: "Revoke link",
404
- children: /* @__PURE__ */ b(_, { className: "size-4" })
402
+ children: /* @__PURE__ */ b(g, { className: "size-4" })
405
403
  })]
406
404
  })]
407
405
  }),
408
406
  /* @__PURE__ */ x("div", {
409
407
  className: "flex items-center gap-3 text-xs text-text-secondary",
410
408
  children: [
411
- e.permission === s.View ? /* @__PURE__ */ x("span", {
409
+ e.permission === o.View ? /* @__PURE__ */ x("span", {
412
410
  className: "flex items-center gap-1",
413
- children: [/* @__PURE__ */ b(p, { className: "size-3" }), " View"]
411
+ children: [/* @__PURE__ */ b(f, { className: "size-3" }), " View"]
414
412
  }) : /* @__PURE__ */ x("span", {
415
413
  className: "flex items-center gap-1",
416
- children: [/* @__PURE__ */ b(m, { className: "size-3" }), " Control"]
414
+ children: [/* @__PURE__ */ b(p, { className: "size-3" }), " Control"]
417
415
  }),
418
416
  /* @__PURE__ */ b("span", { children: "·" }),
419
417
  /* @__PURE__ */ x("span", {
420
418
  className: "flex items-center gap-1",
421
419
  children: [
422
- /* @__PURE__ */ b(d, { className: "size-3" }),
420
+ /* @__PURE__ */ b(u, { className: "size-3" }),
423
421
  " ",
424
422
  $(e.expiresAt)
425
423
  ]
@@ -428,7 +426,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
428
426
  /* @__PURE__ */ x("span", {
429
427
  className: "flex items-center gap-1",
430
428
  children: [
431
- /* @__PURE__ */ b(ne, { className: "size-3" }),
429
+ /* @__PURE__ */ b(h, { className: "size-3" }),
432
430
  " ",
433
431
  e.useCount,
434
432
  e.maxUses ? `/${e.maxUses}` : "",
@@ -442,7 +440,7 @@ var S = ({ session: S, isOpen: C, onClose: w }) => {
442
440
  children: /* @__PURE__ */ b("input", {
443
441
  "aria-label": "control",
444
442
  type: "text",
445
- value: e.shareUrl,
443
+ value: c(e.shareUrl),
446
444
  readOnly: !0,
447
445
  className: "flex-1 px-2 py-1 text-xs font-mono bg-bg-surface border border-border-default rounded text-text-secondary truncate"
448
446
  })
@@ -1 +1 @@
1
- {"version":3,"file":"SessionShareDialog.js","names":[],"sources":["../../../src/components/sessions/SessionShareDialog.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState, useEffect, useRef } from 'react';\nimport {\n X,\n Share2,\n Link2,\n Users,\n Copy,\n Check,\n Eye,\n Gamepad2,\n Clock,\n Lock,\n Trash2,\n RefreshCw,\n} from 'lucide-react';\nimport type { Session } from './types';\nimport {\n useShareSessionMutation,\n useCreateSessionShareLinkMutation,\n useRevokeSessionShareMutation,\n useRevokeSessionShareLinkMutation,\n useGetSessionSharesQuery,\n useGetSessionShareLinksQuery,\n type SessionShareFieldsFragment,\n type SessionShareLinkFieldsFragment,\n} from '../../generated/wspace-operations';\nimport { SessionSharePermission, ShareStatus } from '../../generated/wspace-types';\nimport { useTr } from '../../shared/hooks/useTr';\n\ntype TabType = 'users' | 'links';\n\ninterface SessionShareDialogProps {\n session: Session;\n isOpen: boolean;\n onClose: () => void;\n}\n\n/**\n * SessionShareDialog - Modal for sharing terminal sessions\n * Supports sharing with specific users or creating shareable links\n */\nexport const SessionShareDialog: FC<SessionShareDialogProps> = ({ session, isOpen, onClose }) => {\n const tr = useTr();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const [activeTab, setActiveTab] = useState<TabType>('users');\n const [copied, setCopied] = useState(false);\n\n // Share with user form state\n const [email, setEmail] = useState('');\n const [permission, setPermission] = useState<SessionSharePermission>(SessionSharePermission.View);\n const [message, setMessage] = useState('');\n const [expiresInHours, setExpiresInHours] = useState(24);\n\n // Link form state\n const [linkName, setLinkName] = useState('');\n const [linkPermission, setLinkPermission] = useState<SessionSharePermission>(\n SessionSharePermission.View\n );\n const [linkExpiresInHours, setLinkExpiresInHours] = useState(1);\n const [linkPassword, setLinkPassword] = useState('');\n const [maxUses, setMaxUses] = useState<number | null>(null);\n\n // Queries for existing shares\n const { data: sharesData, refetch: refetchShares } = useGetSessionSharesQuery({\n variables: { sessionId: session.id },\n skip: !isOpen,\n });\n\n const { data: linksData, refetch: refetchLinks } = useGetSessionShareLinksQuery({\n variables: { sessionId: session.id },\n skip: !isOpen,\n });\n\n // Mutations\n const [shareSession, { loading: sharingUser }] = useShareSessionMutation();\n const [createLink, { loading: creatingLink }] = useCreateSessionShareLinkMutation();\n const [revokeShare, { loading: revokingShare }] = useRevokeSessionShareMutation();\n const [revokeLink, { loading: revokingLink }] = useRevokeSessionShareLinkMutation();\n\n const existingShares: SessionShareFieldsFragment[] =\n sharesData?.sessionShares?.filter(\n (s: SessionShareFieldsFragment) => s.status === ShareStatus.Active\n ) || [];\n const existingLinks: SessionShareLinkFieldsFragment[] =\n linksData?.sessionShareLinks?.filter(\n (l: SessionShareLinkFieldsFragment) => l.status === ShareStatus.Active\n ) || [];\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (isOpen) {\n dialog.showModal();\n } else {\n dialog.close();\n }\n }, [isOpen]);\n\n const handleShareWithUser = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!email.trim()) return;\n\n try {\n const expiresAt = new Date(Date.now() + expiresInHours * 60 * 60 * 1000).toISOString();\n await shareSession({\n variables: {\n input: {\n sessionId: session.id,\n sharedWithEmail: email.trim(),\n permission,\n expiresAt,\n message: message.trim() || undefined,\n },\n },\n });\n setEmail('');\n setMessage('');\n refetchShares();\n } catch (error) {\n console.error('Failed to share session:', error);\n }\n };\n\n const handleCreateLink = async (e: React.FormEvent) => {\n e.preventDefault();\n\n try {\n await createLink({\n variables: {\n input: {\n sessionId: session.id,\n name: linkName.trim() || undefined,\n permission: linkPermission,\n expiresInHours: linkExpiresInHours,\n maxUses: maxUses || undefined,\n password: linkPassword.trim() || undefined,\n },\n },\n });\n setLinkName('');\n setLinkPassword('');\n setMaxUses(null);\n refetchLinks();\n } catch (error) {\n console.error('Failed to create share link:', error);\n }\n };\n\n const handleRevokeShare = async (shareId: string) => {\n try {\n await revokeShare({ variables: { id: shareId } });\n refetchShares();\n } catch (error) {\n console.error('Failed to revoke share:', error);\n }\n };\n\n const handleRevokeLink = async (linkId: string) => {\n try {\n await revokeLink({ variables: { id: linkId } });\n refetchLinks();\n } catch (error) {\n console.error('Failed to revoke link:', error);\n }\n };\n\n const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n // Fallback for non-secure contexts (HTTP dev/staging)\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const formatExpiry = (expiresAt: string) => {\n const expiry = new Date(expiresAt);\n const now = new Date();\n const diffMs = expiry.getTime() - now.getTime();\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n const diffMins = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));\n\n if (diffMs < 0) return 'Expired';\n if (diffHours > 24) return `${Math.floor(diffHours / 24)}d`;\n if (diffHours > 0) return `${diffHours}h ${diffMins}m`;\n return `${diffMins}m`;\n };\n\n if (!isOpen) return null;\n\n return (\n <dialog\n ref={dialogRef}\n className=\"fixed inset-0 z-50 m-auto bg-bg-overlay/0 p-0 backdrop:bg-bg-overlay\"\n onClose={onClose}\n >\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[85vh] flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-lg\">\n <Share2 className=\"size-5 text-action-primary-bg\" />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.sessions.share.title', 'Share Session')}\n </h2>\n <p className=\"text-sm text-text-secondary truncate max-w-[300px]\">{session.name}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"flex border-b border-border-default\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('users')}\n className={`flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${\n activeTab === 'users'\n ? 'text-action-primary-bg border-b-2 border-action-primary-bg'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n <Users className=\"size-4\" />\n {tr('vibecontrols.sessions.share.shareWithUser', 'Share with User')}\n {existingShares.length > 0 && (\n <span className=\"ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full\">\n {existingShares.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('links')}\n className={`flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${\n activeTab === 'links'\n ? 'text-action-primary-bg border-b-2 border-action-primary-bg'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n <Link2 className=\"size-4\" />\n {tr('vibecontrols.sessions.share.createLink', 'Create Link')}\n {existingLinks.length > 0 && (\n <span className=\"ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full\">\n {existingLinks.length}\n </span>\n )}\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6\">\n {activeTab === 'users' ? (\n <div className=\"space-y-6\">\n {/* Share form */}\n <form onSubmit={handleShareWithUser} className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.emailAddress', 'Email Address')}\n </label>\n <input\n aria-label=\"teammate@company.com\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"teammate@company.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.mustBeWorkspaceMember',\n 'Must be an existing workspace member'\n )}\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.permission', 'Permission')}\n </label>\n <select\n value={permission}\n onChange={(e) => setPermission(e.target.value as SessionSharePermission)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={SessionSharePermission.View}>\n {tr('vibecontrols.sessions.share.viewOnly', 'View Only')}\n </option>\n <option value={SessionSharePermission.Interact}>\n {tr('vibecontrols.sessions.share.canControl', 'Can Control')}\n </option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.expiresIn', 'Expires In')}\n </label>\n <select\n value={expiresInHours}\n onChange={(e) => setExpiresInHours(Number(e.target.value))}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={1}>1 hour</option>\n <option value={4}>4 hours</option>\n <option value={8}>8 hours</option>\n <option value={24}>24 hours</option>\n <option value={72}>3 days</option>\n <option value={168}>1 week</option>\n </select>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.messageOptional', 'Message (optional)')}\n </label>\n <textarea\n aria-label=\"Let me show you this issue...\"\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n placeholder=\"Let me show you this issue...\"\n rows={2}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n />\n </div>\n\n <div className=\"flex items-center gap-2 p-3 bg-bg-sunken rounded-lg text-sm\">\n {permission === SessionSharePermission.View ? (\n <>\n <Eye className=\"size-4 text-text-secondary\" />\n <span className=\"text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.viewOnlyHint',\n 'User can watch the terminal but cannot type'\n )}\n </span>\n </>\n ) : (\n <>\n <Gamepad2 className=\"size-4 text-text-secondary\" />\n <span className=\"text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.controlHint',\n 'User can request control to type (turn-based)'\n )}\n </span>\n </>\n )}\n </div>\n\n <button\n type=\"submit\"\n disabled={sharingUser || !email.trim()}\n className=\"w-full px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {sharingUser\n ? tr('vibecontrols.sessions.share.sharing', 'Sharing...')\n : tr('vibecontrols.sessions.share.shareSession', 'Share Session')}\n </button>\n </form>\n\n {/* Existing shares */}\n {existingShares.length > 0 && (\n <div>\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">\n {tr('vibecontrols.sessions.share.currentlySharedWith', 'Currently Shared With')}\n </h3>\n <div className=\"space-y-2\">\n {existingShares.map((share) => (\n <div\n key={share.id}\n className=\"flex items-center justify-between p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"size-8 rounded-full bg-action-primary-bg/20 flex items-center justify-center\">\n <Users className=\"size-4 text-action-primary-bg\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n User: {share.sharedWithId.slice(0, 8)}...\n </p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n {share.permission === SessionSharePermission.View ? (\n <Eye className=\"size-3\" />\n ) : (\n <Gamepad2 className=\"size-3\" />\n )}\n <span>{share.permission}</span>\n {share.expiresAt && (\n <>\n <span>·</span>\n <Clock className=\"size-3\" />\n <span>{formatExpiry(share.expiresAt)}</span>\n </>\n )}\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => handleRevokeShare(share.id)}\n disabled={revokingShare}\n className=\"p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors\"\n title=\"Revoke access\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {/* Create link form */}\n <form onSubmit={handleCreateLink} className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.linkNameOptional', 'Link Name (optional)')}\n </label>\n <input\n aria-label=\"Debug session link\"\n type=\"text\"\n value={linkName}\n onChange={(e) => setLinkName(e.target.value)}\n placeholder=\"Debug session link\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.permission', 'Permission')}\n </label>\n <select\n value={linkPermission}\n onChange={(e) => setLinkPermission(e.target.value as SessionSharePermission)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={SessionSharePermission.View}>\n {tr('vibecontrols.sessions.share.viewOnly', 'View Only')}\n </option>\n <option value={SessionSharePermission.Interact}>\n {tr('vibecontrols.sessions.share.canControl', 'Can Control')}\n </option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.expiresIn', 'Expires In')}\n </label>\n <select\n value={linkExpiresInHours}\n onChange={(e) => setLinkExpiresInHours(Number(e.target.value))}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={1}>1 hour</option>\n <option value={4}>4 hours</option>\n <option value={8}>8 hours</option>\n <option value={24}>24 hours</option>\n <option value={72}>3 days</option>\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.passwordOptional', 'Password (optional)')}\n </label>\n <input\n aria-label=\"••••••••\"\n type=\"password\"\n value={linkPassword}\n onChange={(e) => setLinkPassword(e.target.value)}\n placeholder=\"••••••••\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.maxUses', 'Max Uses')}\n </label>\n <input\n aria-label=\"Unlimited\"\n type=\"number\"\n value={maxUses ?? ''}\n onChange={(e) => setMaxUses(e.target.value ? Number(e.target.value) : null)}\n placeholder=\"Unlimited\"\n min={1}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n </div>\n\n <button\n type=\"submit\"\n disabled={creatingLink}\n className=\"w-full px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creatingLink\n ? tr('vibecontrols.sessions.share.creating', 'Creating...')\n : tr('vibecontrols.sessions.share.createShareLink', 'Create Share Link')}\n </button>\n </form>\n\n {/* Existing links */}\n {existingLinks.length > 0 && (\n <div>\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">\n {tr('vibecontrols.sessions.share.activeLinks', 'Active Links')}\n </h3>\n <div className=\"space-y-2\">\n {existingLinks.map((link) => (\n <div key={link.id} className=\"p-3 bg-bg-sunken rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Link2 className=\"size-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {link.name || 'Unnamed Link'}\n </span>\n {link.hasPassword && <Lock className=\"size-3 text-text-secondary\" />}\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => copyToClipboard(link.shareUrl)}\n className=\"p-1.5 text-text-secondary hover:text-action-primary-bg hover:bg-action-primary-bg/10 rounded transition-colors\"\n title=\"Copy link\"\n >\n {copied ? (\n <Check className=\"size-4 text-status-success-text\" />\n ) : (\n <Copy className=\"size-4\" />\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => handleRevokeLink(link.id)}\n disabled={revokingLink}\n className=\"p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors\"\n title=\"Revoke link\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n </div>\n <div className=\"flex items-center gap-3 text-xs text-text-secondary\">\n {link.permission === SessionSharePermission.View ? (\n <span className=\"flex items-center gap-1\">\n <Eye className=\"size-3\" /> View\n </span>\n ) : (\n <span className=\"flex items-center gap-1\">\n <Gamepad2 className=\"size-3\" /> Control\n </span>\n )}\n <span>·</span>\n <span className=\"flex items-center gap-1\">\n <Clock className=\"size-3\" /> {formatExpiry(link.expiresAt)}\n </span>\n <span>·</span>\n <span className=\"flex items-center gap-1\">\n <RefreshCw className=\"size-3\" /> {link.useCount}\n {link.maxUses ? `/${link.maxUses}` : ''} uses\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={link.shareUrl}\n readOnly\n className=\"flex-1 px-2 py-1 text-xs font-mono bg-bg-surface border border-border-default rounded text-text-secondary truncate\"\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"px-6 py-4 bg-bg-sunken border-t border-border-default rounded-b-lg\">\n <p className=\"text-xs text-text-secondary text-center\">\n {tr(\n 'vibecontrols.sessions.share.footerNote',\n 'Shared users must be logged in to access the session'\n )}\n </p>\n </div>\n </div>\n </dialog>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"SessionShareDialog.js","names":[],"sources":["../../../src/components/sessions/SessionShareDialog.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState, useEffect, useRef } from 'react';\nimport {\n X,\n Share2,\n Link2,\n Users,\n Copy,\n Check,\n Eye,\n Gamepad2,\n Clock,\n Lock,\n Trash2,\n RefreshCw,\n} from 'lucide-react';\nimport type { Session } from './types';\nimport {\n useShareSessionMutation,\n useCreateSessionShareLinkMutation,\n useRevokeSessionShareMutation,\n useRevokeSessionShareLinkMutation,\n useGetSessionSharesQuery,\n useGetSessionShareLinksQuery,\n type SessionShareFieldsFragment,\n type SessionShareLinkFieldsFragment,\n} from '../../generated/wspace-operations';\nimport { SessionSharePermission, ShareStatus } from '../../generated/wspace-types';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { copyTextToClipboard, normalizeShareUrl } from '../../utils/shareUrl';\n\ntype TabType = 'users' | 'links';\n\ninterface SessionShareDialogProps {\n session: Session;\n isOpen: boolean;\n onClose: () => void;\n}\n\n/**\n * SessionShareDialog - Modal for sharing terminal sessions\n * Supports sharing with specific users or creating shareable links\n */\nexport const SessionShareDialog: FC<SessionShareDialogProps> = ({ session, isOpen, onClose }) => {\n const tr = useTr();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const [activeTab, setActiveTab] = useState<TabType>('users');\n const [copied, setCopied] = useState<string | null>(null);\n const [copyFailed, setCopyFailed] = useState<string | null>(null);\n\n // Share with user form state\n const [email, setEmail] = useState('');\n const [permission, setPermission] = useState<SessionSharePermission>(SessionSharePermission.View);\n const [message, setMessage] = useState('');\n const [expiresInHours, setExpiresInHours] = useState(24);\n\n // Link form state\n const [linkName, setLinkName] = useState('');\n const [linkPermission, setLinkPermission] = useState<SessionSharePermission>(\n SessionSharePermission.View\n );\n const [linkExpiresInHours, setLinkExpiresInHours] = useState(1);\n const [linkPassword, setLinkPassword] = useState('');\n const [maxUses, setMaxUses] = useState<number | null>(null);\n\n // Queries for existing shares\n const { data: sharesData, refetch: refetchShares } = useGetSessionSharesQuery({\n variables: { sessionId: session.id },\n skip: !isOpen,\n });\n\n const { data: linksData, refetch: refetchLinks } = useGetSessionShareLinksQuery({\n variables: { sessionId: session.id },\n skip: !isOpen,\n });\n\n // Mutations\n const [shareSession, { loading: sharingUser }] = useShareSessionMutation();\n const [createLink, { loading: creatingLink }] = useCreateSessionShareLinkMutation();\n const [revokeShare, { loading: revokingShare }] = useRevokeSessionShareMutation();\n const [revokeLink, { loading: revokingLink }] = useRevokeSessionShareLinkMutation();\n\n const existingShares: SessionShareFieldsFragment[] =\n sharesData?.sessionShares?.filter(\n (s: SessionShareFieldsFragment) => s.status === ShareStatus.Active\n ) || [];\n const existingLinks: SessionShareLinkFieldsFragment[] =\n linksData?.sessionShareLinks?.filter(\n (l: SessionShareLinkFieldsFragment) => l.status === ShareStatus.Active\n ) || [];\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (isOpen) {\n dialog.showModal();\n } else {\n dialog.close();\n }\n }, [isOpen]);\n\n const handleShareWithUser = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!email.trim()) return;\n\n try {\n const expiresAt = new Date(Date.now() + expiresInHours * 60 * 60 * 1000).toISOString();\n await shareSession({\n variables: {\n input: {\n sessionId: session.id,\n sharedWithEmail: email.trim(),\n permission,\n expiresAt,\n message: message.trim() || undefined,\n },\n },\n });\n setEmail('');\n setMessage('');\n refetchShares();\n } catch (error) {\n console.error('Failed to share session:', error);\n }\n };\n\n const handleCreateLink = async (e: React.FormEvent) => {\n e.preventDefault();\n\n try {\n await createLink({\n variables: {\n input: {\n sessionId: session.id,\n name: linkName.trim() || undefined,\n permission: linkPermission,\n expiresInHours: linkExpiresInHours,\n maxUses: maxUses || undefined,\n password: linkPassword.trim() || undefined,\n },\n },\n });\n setLinkName('');\n setLinkPassword('');\n setMaxUses(null);\n refetchLinks();\n } catch (error) {\n console.error('Failed to create share link:', error);\n }\n };\n\n const handleRevokeShare = async (shareId: string) => {\n try {\n await revokeShare({ variables: { id: shareId } });\n refetchShares();\n } catch (error) {\n console.error('Failed to revoke share:', error);\n }\n };\n\n const handleRevokeLink = async (linkId: string) => {\n try {\n await revokeLink({ variables: { id: linkId } });\n refetchLinks();\n } catch (error) {\n console.error('Failed to revoke link:', error);\n }\n };\n\n const copyToClipboard = async (id: string, text: string) => {\n const shareUrl = normalizeShareUrl(text);\n const ok = await copyTextToClipboard(shareUrl).then(\n () => true,\n (error) => {\n console.warn('Failed to copy session share link:', error);\n return false;\n }\n );\n setCopied(ok ? id : null);\n setCopyFailed(ok ? null : id);\n setTimeout(() => {\n setCopied((current) => (current === id ? null : current));\n setCopyFailed((current) => (current === id ? null : current));\n }, 2000);\n };\n\n const formatExpiry = (expiresAt: string) => {\n const expiry = new Date(expiresAt);\n const now = new Date();\n const diffMs = expiry.getTime() - now.getTime();\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n const diffMins = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));\n\n if (diffMs < 0) return 'Expired';\n if (diffHours > 24) return `${Math.floor(diffHours / 24)}d`;\n if (diffHours > 0) return `${diffHours}h ${diffMins}m`;\n return `${diffMins}m`;\n };\n\n if (!isOpen) return null;\n\n return (\n <dialog\n ref={dialogRef}\n className=\"fixed inset-0 z-50 m-auto bg-bg-overlay/0 p-0 backdrop:bg-bg-overlay\"\n onClose={onClose}\n >\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[85vh] flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-lg\">\n <Share2 className=\"size-5 text-action-primary-bg\" />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.sessions.share.title', 'Share Session')}\n </h2>\n <p className=\"text-sm text-text-secondary truncate max-w-[300px]\">{session.name}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"flex border-b border-border-default\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('users')}\n className={`flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${\n activeTab === 'users'\n ? 'text-action-primary-bg border-b-2 border-action-primary-bg'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n <Users className=\"size-4\" />\n {tr('vibecontrols.sessions.share.shareWithUser', 'Share with User')}\n {existingShares.length > 0 && (\n <span className=\"ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full\">\n {existingShares.length}\n </span>\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('links')}\n className={`flex items-center gap-2 px-6 py-3 text-sm font-medium transition-colors ${\n activeTab === 'links'\n ? 'text-action-primary-bg border-b-2 border-action-primary-bg'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n <Link2 className=\"size-4\" />\n {tr('vibecontrols.sessions.share.createLink', 'Create Link')}\n {existingLinks.length > 0 && (\n <span className=\"ml-1 px-1.5 py-0.5 text-xs bg-bg-sunken rounded-full\">\n {existingLinks.length}\n </span>\n )}\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6\">\n {activeTab === 'users' ? (\n <div className=\"space-y-6\">\n {/* Share form */}\n <form onSubmit={handleShareWithUser} className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.emailAddress', 'Email Address')}\n </label>\n <input\n aria-label=\"teammate@company.com\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"teammate@company.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.mustBeWorkspaceMember',\n 'Must be an existing workspace member'\n )}\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.permission', 'Permission')}\n </label>\n <select\n value={permission}\n onChange={(e) => setPermission(e.target.value as SessionSharePermission)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={SessionSharePermission.View}>\n {tr('vibecontrols.sessions.share.viewOnly', 'View Only')}\n </option>\n <option value={SessionSharePermission.Interact}>\n {tr('vibecontrols.sessions.share.canControl', 'Can Control')}\n </option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.expiresIn', 'Expires In')}\n </label>\n <select\n value={expiresInHours}\n onChange={(e) => setExpiresInHours(Number(e.target.value))}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={1}>1 hour</option>\n <option value={4}>4 hours</option>\n <option value={8}>8 hours</option>\n <option value={24}>24 hours</option>\n <option value={72}>3 days</option>\n <option value={168}>1 week</option>\n </select>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.messageOptional', 'Message (optional)')}\n </label>\n <textarea\n aria-label=\"Let me show you this issue...\"\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n placeholder=\"Let me show you this issue...\"\n rows={2}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg resize-none\"\n />\n </div>\n\n <div className=\"flex items-center gap-2 p-3 bg-bg-sunken rounded-lg text-sm\">\n {permission === SessionSharePermission.View ? (\n <>\n <Eye className=\"size-4 text-text-secondary\" />\n <span className=\"text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.viewOnlyHint',\n 'User can watch the terminal but cannot type'\n )}\n </span>\n </>\n ) : (\n <>\n <Gamepad2 className=\"size-4 text-text-secondary\" />\n <span className=\"text-text-secondary\">\n {tr(\n 'vibecontrols.sessions.share.controlHint',\n 'User can request control to type (turn-based)'\n )}\n </span>\n </>\n )}\n </div>\n\n <button\n type=\"submit\"\n disabled={sharingUser || !email.trim()}\n className=\"w-full px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {sharingUser\n ? tr('vibecontrols.sessions.share.sharing', 'Sharing...')\n : tr('vibecontrols.sessions.share.shareSession', 'Share Session')}\n </button>\n </form>\n\n {/* Existing shares */}\n {existingShares.length > 0 && (\n <div>\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">\n {tr('vibecontrols.sessions.share.currentlySharedWith', 'Currently Shared With')}\n </h3>\n <div className=\"space-y-2\">\n {existingShares.map((share) => (\n <div\n key={share.id}\n className=\"flex items-center justify-between p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"size-8 rounded-full bg-action-primary-bg/20 flex items-center justify-center\">\n <Users className=\"size-4 text-action-primary-bg\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n User: {share.sharedWithId.slice(0, 8)}...\n </p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n {share.permission === SessionSharePermission.View ? (\n <Eye className=\"size-3\" />\n ) : (\n <Gamepad2 className=\"size-3\" />\n )}\n <span>{share.permission}</span>\n {share.expiresAt && (\n <>\n <span>·</span>\n <Clock className=\"size-3\" />\n <span>{formatExpiry(share.expiresAt)}</span>\n </>\n )}\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => handleRevokeShare(share.id)}\n disabled={revokingShare}\n className=\"p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors\"\n title=\"Revoke access\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {/* Create link form */}\n <form onSubmit={handleCreateLink} className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.linkNameOptional', 'Link Name (optional)')}\n </label>\n <input\n aria-label=\"Debug session link\"\n type=\"text\"\n value={linkName}\n onChange={(e) => setLinkName(e.target.value)}\n placeholder=\"Debug session link\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.permission', 'Permission')}\n </label>\n <select\n value={linkPermission}\n onChange={(e) => setLinkPermission(e.target.value as SessionSharePermission)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={SessionSharePermission.View}>\n {tr('vibecontrols.sessions.share.viewOnly', 'View Only')}\n </option>\n <option value={SessionSharePermission.Interact}>\n {tr('vibecontrols.sessions.share.canControl', 'Can Control')}\n </option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.expiresIn', 'Expires In')}\n </label>\n <select\n value={linkExpiresInHours}\n onChange={(e) => setLinkExpiresInHours(Number(e.target.value))}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value={1}>1 hour</option>\n <option value={4}>4 hours</option>\n <option value={8}>8 hours</option>\n <option value={24}>24 hours</option>\n <option value={72}>3 days</option>\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.passwordOptional', 'Password (optional)')}\n </label>\n <input\n aria-label=\"••••••••\"\n type=\"password\"\n value={linkPassword}\n onChange={(e) => setLinkPassword(e.target.value)}\n placeholder=\"••••••••\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.sessions.share.maxUses', 'Max Uses')}\n </label>\n <input\n aria-label=\"Unlimited\"\n type=\"number\"\n value={maxUses ?? ''}\n onChange={(e) => setMaxUses(e.target.value ? Number(e.target.value) : null)}\n placeholder=\"Unlimited\"\n min={1}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n </div>\n\n <button\n type=\"submit\"\n disabled={creatingLink}\n className=\"w-full px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creatingLink\n ? tr('vibecontrols.sessions.share.creating', 'Creating...')\n : tr('vibecontrols.sessions.share.createShareLink', 'Create Share Link')}\n </button>\n </form>\n\n {/* Existing links */}\n {existingLinks.length > 0 && (\n <div>\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">\n {tr('vibecontrols.sessions.share.activeLinks', 'Active Links')}\n </h3>\n <div className=\"space-y-2\">\n {existingLinks.map((link) => (\n <div key={link.id} className=\"p-3 bg-bg-sunken rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Link2 className=\"size-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {link.name || 'Unnamed Link'}\n </span>\n {link.hasPassword && <Lock className=\"size-3 text-text-secondary\" />}\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => copyToClipboard(link.id, link.shareUrl)}\n className=\"p-1.5 text-text-secondary hover:text-action-primary-bg hover:bg-action-primary-bg/10 rounded transition-colors\"\n title=\"Copy link\"\n >\n {copied === link.id ? (\n <Check className=\"size-4 text-status-success-text\" />\n ) : copyFailed === link.id ? (\n <X className=\"size-4 text-status-error-text\" />\n ) : (\n <Copy className=\"size-4\" />\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => handleRevokeLink(link.id)}\n disabled={revokingLink}\n className=\"p-1.5 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 rounded transition-colors\"\n title=\"Revoke link\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n </div>\n <div className=\"flex items-center gap-3 text-xs text-text-secondary\">\n {link.permission === SessionSharePermission.View ? (\n <span className=\"flex items-center gap-1\">\n <Eye className=\"size-3\" /> View\n </span>\n ) : (\n <span className=\"flex items-center gap-1\">\n <Gamepad2 className=\"size-3\" /> Control\n </span>\n )}\n <span>·</span>\n <span className=\"flex items-center gap-1\">\n <Clock className=\"size-3\" /> {formatExpiry(link.expiresAt)}\n </span>\n <span>·</span>\n <span className=\"flex items-center gap-1\">\n <RefreshCw className=\"size-3\" /> {link.useCount}\n {link.maxUses ? `/${link.maxUses}` : ''} uses\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={normalizeShareUrl(link.shareUrl)}\n readOnly\n className=\"flex-1 px-2 py-1 text-xs font-mono bg-bg-surface border border-border-default rounded text-text-secondary truncate\"\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"px-6 py-4 bg-bg-sunken border-t border-border-default rounded-b-lg\">\n <p className=\"text-xs text-text-secondary text-center\">\n {tr(\n 'vibecontrols.sessions.share.footerNote',\n 'Shared users must be logged in to access the session'\n )}\n </p>\n </div>\n </div>\n </dialog>\n );\n};\n"],"mappings":"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"}