@burdenoff/microfe-vibecontrols 2026.610.6 → 2026.610.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/sessions/SessionPublicLinkPanel.js +232 -0
- package/dist/components/sessions/SessionPublicLinkPanel.js.map +1 -0
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +232 -0
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -0
- package/dist/components/vibedeck/index.js +1 -0
- package/dist/generated/wspace-types.js +5 -3
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +307 -291
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +184 -167
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { useCreateSessionShareLinkMutation as e, useGetSessionShareLinksQuery as t, useRevokeSessionShareLinkMutation as n } from "../../generated/wspace-operations.js";
|
|
2
|
+
import { LoadingState as r } from "../shared/LoadingState.js";
|
|
3
|
+
import { ErrorState as i } from "../shared/ErrorState.js";
|
|
4
|
+
import { SessionSharePermission as a } from "../../generated/wspace-types.js";
|
|
5
|
+
import "../shared/index.js";
|
|
6
|
+
import { notify as o } from "../../lib/toast.js";
|
|
7
|
+
import { useState as s } from "react";
|
|
8
|
+
import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
|
+
import { Check as l, Copy as u, Eye as d, Keyboard as f, Link2 as p, Lock as m, Plus as h, Trash2 as g, X as _ } from "lucide-react";
|
|
10
|
+
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
11
|
+
//#region src/components/sessions/SessionPublicLinkPanel.tsx
|
|
12
|
+
var x = [
|
|
13
|
+
{
|
|
14
|
+
label: "1 hour",
|
|
15
|
+
hours: 1
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "4 hours",
|
|
19
|
+
hours: 4
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "24 hours",
|
|
23
|
+
hours: 24
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: "No expiry",
|
|
27
|
+
hours: 0
|
|
28
|
+
}
|
|
29
|
+
], S = ({ sessionId: S, sessionName: w, onClose: T }) => {
|
|
30
|
+
let { t: E } = c(), D = (e, t) => {
|
|
31
|
+
let n = E(e);
|
|
32
|
+
return n === e ? t : n;
|
|
33
|
+
}, { data: O, loading: k, error: A, refetch: j } = t({
|
|
34
|
+
variables: { sessionId: S },
|
|
35
|
+
fetchPolicy: "cache-and-network"
|
|
36
|
+
}), [M, { loading: N }] = e(), [P] = n(), [F, I] = s(!1), [L, R] = s(4), [z, B] = s(""), [V, H] = s(""), [U, W] = s(null), G = O?.sessionShareLinks ?? [], K = G.filter((e) => e.status === "ACTIVE"), q = async (e, t) => {
|
|
37
|
+
try {
|
|
38
|
+
await navigator.clipboard.writeText(e), W(t), o.success(D("sessLink.copied", "Link copied")), window.setTimeout(() => W(null), 1500);
|
|
39
|
+
} catch {
|
|
40
|
+
o.error(D("sessLink.copyFailed", "Could not copy — copy it manually"), e);
|
|
41
|
+
}
|
|
42
|
+
}, J = async (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
let t = V.trim() ? Number.parseInt(V.trim(), 10) : null;
|
|
45
|
+
if (t !== null && (!Number.isFinite(t) || t < 1)) {
|
|
46
|
+
o.error(D("sessLink.badMax", "Max uses must be a positive number"));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
let e = await M({ variables: { input: {
|
|
51
|
+
sessionId: S,
|
|
52
|
+
permission: F ? a.Interact : a.View,
|
|
53
|
+
expiresInHours: L > 0 ? L : null,
|
|
54
|
+
password: z.trim() ? z.trim() : null,
|
|
55
|
+
maxUses: t
|
|
56
|
+
} } });
|
|
57
|
+
await j();
|
|
58
|
+
let n = e.data?.createSessionShareLink.shareUrl;
|
|
59
|
+
n && await q(n, e.data?.createSessionShareLink.id ?? "new"), o.success(D("sessLink.created", "Share link created"), F ? D("sessLink.createdInteract", "Recipient can request keyboard control") : D("sessLink.createdView", "Recipient can watch the terminal (view-only)")), B(""), H("");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
o.error(D("sessLink.createFailed", "Could not create link"), e.message);
|
|
62
|
+
}
|
|
63
|
+
}, Y = async (e) => {
|
|
64
|
+
try {
|
|
65
|
+
await P({ variables: { id: e } }), await j(), o.success(D("sessLink.revoked", "Link revoked — it no longer works"));
|
|
66
|
+
} catch (e) {
|
|
67
|
+
o.error(D("sessLink.revokeFailed", "Could not revoke"), e.message);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
return /* @__PURE__ */ y("div", {
|
|
71
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
72
|
+
onClick: T,
|
|
73
|
+
children: /* @__PURE__ */ b("div", {
|
|
74
|
+
className: "w-full max-w-lg rounded-lg border border-border-default bg-bg-surface p-5 shadow-lg",
|
|
75
|
+
onClick: (e) => e.stopPropagation(),
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ b("div", {
|
|
78
|
+
className: "mb-4 flex items-start justify-between",
|
|
79
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("h3", {
|
|
80
|
+
className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
|
|
81
|
+
children: [/* @__PURE__ */ y(p, { className: "size-5" }), D("sessLink.title", "Share link")]
|
|
82
|
+
}), /* @__PURE__ */ y("p", {
|
|
83
|
+
className: "mt-0.5 text-sm text-text-secondary",
|
|
84
|
+
children: w
|
|
85
|
+
})] }), /* @__PURE__ */ y("button", {
|
|
86
|
+
type: "button",
|
|
87
|
+
onClick: T,
|
|
88
|
+
className: "p-1 text-text-tertiary hover:text-text-primary",
|
|
89
|
+
"aria-label": D("common.close", "Close"),
|
|
90
|
+
children: /* @__PURE__ */ y(_, { className: "size-5" })
|
|
91
|
+
})]
|
|
92
|
+
}),
|
|
93
|
+
/* @__PURE__ */ y("div", {
|
|
94
|
+
className: "mb-4 space-y-2",
|
|
95
|
+
children: k && G.length === 0 ? /* @__PURE__ */ y(r, {}) : A ? /* @__PURE__ */ y(i, {
|
|
96
|
+
message: A.message,
|
|
97
|
+
onRetry: () => void j()
|
|
98
|
+
}) : K.length === 0 ? /* @__PURE__ */ y("p", {
|
|
99
|
+
className: "text-sm text-text-secondary",
|
|
100
|
+
children: D("sessLink.none", "No share links yet. Create one below.")
|
|
101
|
+
}) : /* @__PURE__ */ y("ul", {
|
|
102
|
+
className: "space-y-2",
|
|
103
|
+
children: K.map((e) => /* @__PURE__ */ b("li", {
|
|
104
|
+
className: "flex items-center gap-2 rounded-md border border-border-default px-3 py-2",
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ y(C, { children: e.permission === a.Interact ? /* @__PURE__ */ b(v, { children: [
|
|
107
|
+
/* @__PURE__ */ y(f, { className: "size-3" }),
|
|
108
|
+
" ",
|
|
109
|
+
D("sessLink.interact", "Interactive")
|
|
110
|
+
] }) : /* @__PURE__ */ b(v, { children: [
|
|
111
|
+
/* @__PURE__ */ y(d, { className: "size-3" }),
|
|
112
|
+
" ",
|
|
113
|
+
D("sessLink.view", "View")
|
|
114
|
+
] }) }),
|
|
115
|
+
e.hasPassword && /* @__PURE__ */ y(m, {
|
|
116
|
+
className: "size-3.5 text-text-tertiary",
|
|
117
|
+
"aria-label": "password"
|
|
118
|
+
}),
|
|
119
|
+
/* @__PURE__ */ y("span", {
|
|
120
|
+
className: "flex-1 truncate font-mono text-xs text-text-secondary",
|
|
121
|
+
children: e.shareUrl
|
|
122
|
+
}),
|
|
123
|
+
/* @__PURE__ */ b("span", {
|
|
124
|
+
className: "shrink-0 text-xs text-text-tertiary",
|
|
125
|
+
children: [
|
|
126
|
+
e.useCount,
|
|
127
|
+
e.maxUses ? `/${e.maxUses}` : "",
|
|
128
|
+
" ",
|
|
129
|
+
D("sessLink.uses", "uses")
|
|
130
|
+
]
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ y("button", {
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => void q(e.shareUrl, e.id),
|
|
135
|
+
className: "p-1 text-text-secondary hover:text-text-primary",
|
|
136
|
+
"aria-label": D("common.copy", "Copy"),
|
|
137
|
+
children: U === e.id ? /* @__PURE__ */ y(l, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ y(u, { className: "size-4" })
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ y("button", {
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: () => void Y(e.id),
|
|
142
|
+
className: "p-1 text-text-secondary hover:text-action-danger-text",
|
|
143
|
+
"aria-label": D("common.revoke", "Revoke"),
|
|
144
|
+
children: /* @__PURE__ */ y(g, { className: "size-4" })
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
}, e.id))
|
|
148
|
+
})
|
|
149
|
+
}),
|
|
150
|
+
/* @__PURE__ */ b("form", {
|
|
151
|
+
onSubmit: (e) => void J(e),
|
|
152
|
+
className: "space-y-3 border-t border-border-default pt-4",
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ b("label", {
|
|
155
|
+
className: "flex cursor-pointer items-center gap-2 text-sm text-text-primary",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ y("input", {
|
|
158
|
+
type: "checkbox",
|
|
159
|
+
checked: F,
|
|
160
|
+
onChange: (e) => I(e.target.checked),
|
|
161
|
+
className: "rounded border-border-default"
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ y(f, { className: "size-3.5" }),
|
|
164
|
+
D("sessLink.allowInteract", "Allow interactive control (recipient can request the keyboard)")
|
|
165
|
+
]
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ b("div", {
|
|
168
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
169
|
+
children: [/* @__PURE__ */ b("label", {
|
|
170
|
+
className: "flex-1",
|
|
171
|
+
children: [/* @__PURE__ */ y("span", {
|
|
172
|
+
className: "text-sm text-text-secondary",
|
|
173
|
+
children: D("sessLink.expiry", "Expires")
|
|
174
|
+
}), /* @__PURE__ */ y("select", {
|
|
175
|
+
value: L,
|
|
176
|
+
onChange: (e) => R(Number(e.target.value)),
|
|
177
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary",
|
|
178
|
+
children: x.map((e) => /* @__PURE__ */ y("option", {
|
|
179
|
+
value: e.hours,
|
|
180
|
+
children: e.label
|
|
181
|
+
}, e.label))
|
|
182
|
+
})]
|
|
183
|
+
}), /* @__PURE__ */ b("label", {
|
|
184
|
+
className: "flex-1",
|
|
185
|
+
children: [/* @__PURE__ */ y("span", {
|
|
186
|
+
className: "text-sm text-text-secondary",
|
|
187
|
+
children: D("sessLink.maxUses", "Max uses (optional)")
|
|
188
|
+
}), /* @__PURE__ */ y("input", {
|
|
189
|
+
value: V,
|
|
190
|
+
onChange: (e) => H(e.target.value),
|
|
191
|
+
inputMode: "numeric",
|
|
192
|
+
placeholder: D("sessLink.unlimited", "unlimited"),
|
|
193
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
194
|
+
})]
|
|
195
|
+
})]
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ b("label", {
|
|
198
|
+
className: "block",
|
|
199
|
+
children: [/* @__PURE__ */ y("span", {
|
|
200
|
+
className: "text-sm text-text-secondary",
|
|
201
|
+
children: D("sessLink.password", "Password (optional)")
|
|
202
|
+
}), /* @__PURE__ */ y("input", {
|
|
203
|
+
value: z,
|
|
204
|
+
onChange: (e) => B(e.target.value),
|
|
205
|
+
type: "password",
|
|
206
|
+
autoComplete: "new-password",
|
|
207
|
+
placeholder: D("sessLink.noPassword", "no password"),
|
|
208
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
209
|
+
})]
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ y("div", {
|
|
212
|
+
className: "flex justify-end",
|
|
213
|
+
children: /* @__PURE__ */ b("button", {
|
|
214
|
+
type: "submit",
|
|
215
|
+
disabled: N,
|
|
216
|
+
className: "flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50",
|
|
217
|
+
children: [/* @__PURE__ */ y(h, { className: "size-4" }), D("sessLink.create", "Create share link")]
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
]
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
})
|
|
224
|
+
});
|
|
225
|
+
}, C = ({ children: e }) => /* @__PURE__ */ y("span", {
|
|
226
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-primary",
|
|
227
|
+
children: e
|
|
228
|
+
});
|
|
229
|
+
//#endregion
|
|
230
|
+
export { S as SessionPublicLinkPanel };
|
|
231
|
+
|
|
232
|
+
//# sourceMappingURL=SessionPublicLinkPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionPublicLinkPanel.js","names":[],"sources":["../../../src/components/sessions/SessionPublicLinkPanel.tsx"],"sourcesContent":["import type { FC, FormEvent, ReactNode } from 'react';\nimport { useState } from 'react';\nimport { Link2, Keyboard, Eye, Lock, Copy, Trash2, Plus, X, Check } from 'lucide-react';\n\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { notify } from '@/lib/toast';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useGetSessionShareLinksQuery,\n useCreateSessionShareLinkMutation,\n useRevokeSessionShareLinkMutation,\n type SessionShareLinkFieldsFragment,\n} from '@/generated/wspace-operations';\nimport { SessionSharePermission } from '@/generated/wspace-types';\n\ninterface SessionPublicLinkPanelProps {\n sessionId: string;\n sessionName: string;\n onClose: () => void;\n}\n\nconst EXPIRY_OPTIONS = [\n { label: '1 hour', hours: 1 },\n { label: '4 hours', hours: 4 },\n { label: '24 hours', hours: 24 },\n { label: 'No expiry', hours: 0 },\n];\n\n/**\n * SessionPublicLinkPanel — create and manage expiring share links to a live terminal session, with\n * the controls the live-session-share story promises but the generic member-share dialog dropped:\n * viewer vs interactive permission, an **expiry**, an optional **password**, and an optional\n * **usage limit**. Links point at the live `share/:token` page (the real collaborative terminal,\n * not an auth'd accept page). Backed by the existing `createSessionShareLink` mutation — no backend\n * change.\n */\nexport const SessionPublicLinkPanel: FC<SessionPublicLinkPanelProps> = ({\n sessionId,\n sessionName,\n onClose,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const { data, loading, error, refetch } = useGetSessionShareLinksQuery({\n variables: { sessionId },\n fetchPolicy: 'cache-and-network',\n });\n const [createLink, { loading: creating }] = useCreateSessionShareLinkMutation();\n const [revokeLink] = useRevokeSessionShareLinkMutation();\n\n const [interactive, setInteractive] = useState(false);\n const [expiryHours, setExpiryHours] = useState(4);\n const [password, setPassword] = useState('');\n const [maxUses, setMaxUses] = useState('');\n const [copiedId, setCopiedId] = useState<string | null>(null);\n\n const links: SessionShareLinkFieldsFragment[] = data?.sessionShareLinks ?? [];\n const activeLinks = links.filter((l) => l.status === 'ACTIVE');\n\n const copy = async (url: string, id: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(url);\n setCopiedId(id);\n notify.success(tr('sessLink.copied', 'Link copied'));\n window.setTimeout(() => setCopiedId(null), 1500);\n } catch {\n notify.error(tr('sessLink.copyFailed', 'Could not copy — copy it manually'), url);\n }\n };\n\n const handleCreate = async (e: FormEvent): Promise<void> => {\n e.preventDefault();\n const parsedMax = maxUses.trim() ? Number.parseInt(maxUses.trim(), 10) : null;\n if (parsedMax !== null && (!Number.isFinite(parsedMax) || parsedMax < 1)) {\n notify.error(tr('sessLink.badMax', 'Max uses must be a positive number'));\n return;\n }\n try {\n const res = await createLink({\n variables: {\n input: {\n sessionId,\n permission: interactive ? SessionSharePermission.Interact : SessionSharePermission.View,\n expiresInHours: expiryHours > 0 ? expiryHours : null,\n password: password.trim() ? password.trim() : null,\n maxUses: parsedMax,\n },\n },\n });\n await refetch();\n const url = res.data?.createSessionShareLink.shareUrl;\n if (url) await copy(url, res.data?.createSessionShareLink.id ?? 'new');\n notify.success(\n tr('sessLink.created', 'Share link created'),\n interactive\n ? tr('sessLink.createdInteract', 'Recipient can request keyboard control')\n : tr('sessLink.createdView', 'Recipient can watch the terminal (view-only)')\n );\n setPassword('');\n setMaxUses('');\n } catch (err) {\n notify.error(tr('sessLink.createFailed', 'Could not create link'), (err as Error).message);\n }\n };\n\n const handleRevoke = async (id: string): Promise<void> => {\n try {\n await revokeLink({ variables: { id } });\n await refetch();\n notify.success(tr('sessLink.revoked', 'Link revoked — it no longer works'));\n } catch (err) {\n notify.error(tr('sessLink.revokeFailed', 'Could not revoke'), (err as Error).message);\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n onClick={onClose}\n >\n <div\n className=\"w-full max-w-lg rounded-lg border border-border-default bg-bg-surface p-5 shadow-lg\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between\">\n <div>\n <h3 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Link2 className=\"size-5\" />\n {tr('sessLink.title', 'Share link')}\n </h3>\n <p className=\"mt-0.5 text-sm text-text-secondary\">{sessionName}</p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 text-text-tertiary hover:text-text-primary\"\n aria-label={tr('common.close', 'Close')}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"mb-4 space-y-2\">\n {loading && links.length === 0 ? (\n <LoadingState />\n ) : error ? (\n <ErrorState message={error.message} onRetry={() => void refetch()} />\n ) : activeLinks.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {tr('sessLink.none', 'No share links yet. Create one below.')}\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {activeLinks.map((l) => (\n <li\n key={l.id}\n className=\"flex items-center gap-2 rounded-md border border-border-default px-3 py-2\"\n >\n <Badge>\n {l.permission === SessionSharePermission.Interact ? (\n <>\n <Keyboard className=\"size-3\" /> {tr('sessLink.interact', 'Interactive')}\n </>\n ) : (\n <>\n <Eye className=\"size-3\" /> {tr('sessLink.view', 'View')}\n </>\n )}\n </Badge>\n {l.hasPassword && (\n <Lock className=\"size-3.5 text-text-tertiary\" aria-label=\"password\" />\n )}\n <span className=\"flex-1 truncate font-mono text-xs text-text-secondary\">\n {l.shareUrl}\n </span>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {l.useCount}\n {l.maxUses ? `/${l.maxUses}` : ''} {tr('sessLink.uses', 'uses')}\n </span>\n <button\n type=\"button\"\n onClick={() => void copy(l.shareUrl, l.id)}\n className=\"p-1 text-text-secondary hover:text-text-primary\"\n aria-label={tr('common.copy', 'Copy')}\n >\n {copiedId === l.id ? (\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={() => void handleRevoke(l.id)}\n className=\"p-1 text-text-secondary hover:text-action-danger-text\"\n aria-label={tr('common.revoke', 'Revoke')}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <form\n onSubmit={(e) => void handleCreate(e)}\n className=\"space-y-3 border-t border-border-default pt-4\"\n >\n <label className=\"flex cursor-pointer items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={interactive}\n onChange={(e) => setInteractive(e.target.checked)}\n className=\"rounded border-border-default\"\n />\n <Keyboard className=\"size-3.5\" />\n {tr(\n 'sessLink.allowInteract',\n 'Allow interactive control (recipient can request the keyboard)'\n )}\n </label>\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <label className=\"flex-1\">\n <span className=\"text-sm text-text-secondary\">\n {tr('sessLink.expiry', 'Expires')}\n </span>\n <select\n value={expiryHours}\n onChange={(e) => setExpiryHours(Number(e.target.value))}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {EXPIRY_OPTIONS.map((o) => (\n <option key={o.label} value={o.hours}>\n {o.label}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex-1\">\n <span className=\"text-sm text-text-secondary\">\n {tr('sessLink.maxUses', 'Max uses (optional)')}\n </span>\n <input\n value={maxUses}\n onChange={(e) => setMaxUses(e.target.value)}\n inputMode=\"numeric\"\n placeholder={tr('sessLink.unlimited', 'unlimited')}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </label>\n </div>\n <label className=\"block\">\n <span className=\"text-sm text-text-secondary\">\n {tr('sessLink.password', 'Password (optional)')}\n </span>\n <input\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder={tr('sessLink.noPassword', 'no password')}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </label>\n <div className=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={creating}\n className=\"flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Plus className=\"size-4\" />\n {tr('sessLink.create', 'Create share link')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nconst Badge: FC<{ children: ReactNode }> = ({ children }) => (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-primary\">\n {children}\n </span>\n);\n"],"mappings":";;;;;;;;;;;AAqBA,IAAM,IAAiB;CACrB;EAAE,OAAO;EAAU,OAAO;EAAG;CAC7B;EAAE,OAAO;EAAW,OAAO;EAAG;CAC9B;EAAE,OAAO;EAAY,OAAO;EAAI;CAChC;EAAE,OAAO;EAAa,OAAO;EAAG;CACjC,EAUY,KAA2D,EACtE,cACA,gBACA,iBACI;CACJ,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAI,EAAE,EAAI;AAChB,SAAO,MAAM,IAAM,IAAW;IAG1B,EAAE,SAAM,YAAS,UAAO,eAAY,EAA6B;EACrE,WAAW,EAAE,cAAW;EACxB,aAAa;EACd,CAAC,EACI,CAAC,GAAY,EAAE,SAAS,OAAc,GAAmC,EACzE,CAAC,KAAc,GAAmC,EAElD,CAAC,GAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAa,KAAkB,EAAS,EAAE,EAC3C,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAU,KAAe,EAAwB,KAAK,EAEvD,IAA0C,GAAM,qBAAqB,EAAE,EACvE,IAAc,EAAM,QAAQ,MAAM,EAAE,WAAW,SAAS,EAExD,IAAO,OAAO,GAAa,MAA8B;AAC7D,MAAI;AAIF,GAHA,MAAM,UAAU,UAAU,UAAU,EAAI,EACxC,EAAY,EAAG,EACf,EAAO,QAAQ,EAAG,mBAAmB,cAAc,CAAC,EACpD,OAAO,iBAAiB,EAAY,KAAK,EAAE,KAAK;UAC1C;AACN,KAAO,MAAM,EAAG,uBAAuB,oCAAoC,EAAE,EAAI;;IAI/E,IAAe,OAAO,MAAgC;AAC1D,IAAE,gBAAgB;EAClB,IAAM,IAAY,EAAQ,MAAM,GAAG,OAAO,SAAS,EAAQ,MAAM,EAAE,GAAG,GAAG;AACzE,MAAI,MAAc,SAAS,CAAC,OAAO,SAAS,EAAU,IAAI,IAAY,IAAI;AACxE,KAAO,MAAM,EAAG,mBAAmB,qCAAqC,CAAC;AACzE;;AAEF,MAAI;GACF,IAAM,IAAM,MAAM,EAAW,EAC3B,WAAW,EACT,OAAO;IACL;IACA,YAAY,IAAc,EAAuB,WAAW,EAAuB;IACnF,gBAAgB,IAAc,IAAI,IAAc;IAChD,UAAU,EAAS,MAAM,GAAG,EAAS,MAAM,GAAG;IAC9C,SAAS;IACV,EACF,EACF,CAAC;AACF,SAAM,GAAS;GACf,IAAM,IAAM,EAAI,MAAM,uBAAuB;AAS7C,GARI,KAAK,MAAM,EAAK,GAAK,EAAI,MAAM,uBAAuB,MAAM,MAAM,EACtE,EAAO,QACL,EAAG,oBAAoB,qBAAqB,EAC5C,IACI,EAAG,4BAA4B,yCAAyC,GACxE,EAAG,wBAAwB,+CAA+C,CAC/E,EACD,EAAY,GAAG,EACf,EAAW,GAAG;WACP,GAAK;AACZ,KAAO,MAAM,EAAG,yBAAyB,wBAAwB,EAAG,EAAc,QAAQ;;IAIxF,IAAe,OAAO,MAA8B;AACxD,MAAI;AAGF,GAFA,MAAM,EAAW,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EACvC,MAAM,GAAS,EACf,EAAO,QAAQ,EAAG,oBAAoB,oCAAoC,CAAC;WACpE,GAAK;AACZ,KAAO,MAAM,EAAG,yBAAyB,mBAAmB,EAAG,EAAc,QAAQ;;;AAIzF,QACE,kBAAC,OAAD;EACE,WAAU;EACV,SAAS;YAET,kBAAC,OAAD;GACE,WAAU;GACV,UAAU,MAAM,EAAE,iBAAiB;aAFrC;IAIE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAd,CACE,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA,EAC3B,EAAG,kBAAkB,aAAa,CAChC;SACL,kBAAC,KAAD;MAAG,WAAU;gBAAsC;MAAgB,CAAA,CAC/D,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;MACV,cAAY,EAAG,gBAAgB,QAAQ;gBAEvC,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;MACjB,CAAA,CACL;;IAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,KAAW,EAAM,WAAW,IAC3B,kBAAC,GAAD,EAAgB,CAAA,GACd,IACF,kBAAC,GAAD;MAAY,SAAS,EAAM;MAAS,eAAe,KAAK,GAAS;MAAI,CAAA,GACnE,EAAY,WAAW,IACzB,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iBAAiB,wCAAwC;MAC3D,CAAA,GAEJ,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAY,KAAK,MAChB,kBAAC,MAAD;OAEE,WAAU;iBAFZ;QAIE,kBAAC,GAAD,EAAA,UACG,EAAE,eAAe,EAAuB,WACvC,kBAAA,GAAA,EAAA,UAAA;SACE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;;SAAE,EAAG,qBAAqB,cAAc;SACtE,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA;SACE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA;;SAAE,EAAG,iBAAiB,OAAO;SACtD,EAAA,CAAA,EAEC,CAAA;QACP,EAAE,eACD,kBAAC,GAAD;SAAM,WAAU;SAA8B,cAAW;SAAa,CAAA;QAExE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAE;SACE,CAAA;QACP,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACG,EAAE;UACF,EAAE,UAAU,IAAI,EAAE,YAAY;UAAG;UAAE,EAAG,iBAAiB,OAAO;UAC1D;;QACP,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,KAAK,EAAK,EAAE,UAAU,EAAE,GAAG;SAC1C,WAAU;SACV,cAAY,EAAG,eAAe,OAAO;mBAEpC,MAAa,EAAE,KACd,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA,GAErD,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;SAEtB,CAAA;QACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,KAAK,EAAa,EAAE,GAAG;SACtC,WAAU;SACV,cAAY,EAAG,iBAAiB,SAAS;mBAEzC,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;SACtB,CAAA;QACN;SA5CE,EAAE,GA4CJ,CACL;MACC,CAAA;KAEH,CAAA;IAEN,kBAAC,QAAD;KACE,WAAW,MAAM,KAAK,EAAa,EAAE;KACrC,WAAU;eAFZ;MAIE,kBAAC,SAAD;OAAO,WAAU;iBAAjB;QACE,kBAAC,SAAD;SACE,MAAK;SACL,SAAS;SACT,WAAW,MAAM,EAAe,EAAE,OAAO,QAAQ;SACjD,WAAU;SACV,CAAA;QACF,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA;QAChC,EACC,0BACA,iEACD;QACK;;MACR,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAjB,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAG,mBAAmB,UAAU;SAC5B,CAAA,EACP,kBAAC,UAAD;SACE,OAAO;SACP,WAAW,MAAM,EAAe,OAAO,EAAE,OAAO,MAAM,CAAC;SACvD,WAAU;mBAET,EAAe,KAAK,MACnB,kBAAC,UAAD;UAAsB,OAAO,EAAE;oBAC5B,EAAE;UACI,EAFI,EAAE,MAEN,CACT;SACK,CAAA,CACH;WACR,kBAAC,SAAD;QAAO,WAAU;kBAAjB,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAG,oBAAoB,sBAAsB;SACzC,CAAA,EACP,kBAAC,SAAD;SACE,OAAO;SACP,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;SAC3C,WAAU;SACV,aAAa,EAAG,sBAAsB,YAAY;SAClD,WAAU;SACV,CAAA,CACI;UACJ;;MACN,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,qBAAqB,sBAAsB;QAC1C,CAAA,EACP,kBAAC,SAAD;QACE,OAAO;QACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;QAC5C,MAAK;QACL,cAAa;QACb,aAAa,EAAG,uBAAuB,cAAc;QACrD,WAAU;QACV,CAAA,CACI;;MACR,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,UAAD;QACE,MAAK;QACL,UAAU;QACV,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAC1B,EAAG,mBAAmB,oBAAoB,CACpC;;OACL,CAAA;MACD;;IACH;;EACF,CAAA;GAIJ,KAAsC,EAAE,kBAC5C,kBAAC,QAAD;CAAM,WAAU;CACb;CACI,CAAA"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { useCreateVibeDeckShareLinkMutation as e, useListVibeDeckShareLinksQuery as t, useRevokeVibeDeckShareLinkMutation as n } from "../../generated/wspace-operations.js";
|
|
2
|
+
import { LoadingState as r } from "../shared/LoadingState.js";
|
|
3
|
+
import { ErrorState as i } from "../shared/ErrorState.js";
|
|
4
|
+
import { VibeDeckSharePermission as a } from "../../generated/wspace-types.js";
|
|
5
|
+
import "../shared/index.js";
|
|
6
|
+
import { notify as o } from "../../lib/toast.js";
|
|
7
|
+
import { useState as s } from "react";
|
|
8
|
+
import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
|
+
import { Check as l, Copy as u, Eye as d, Link2 as f, Lock as p, Play as m, Plus as h, Trash2 as g, X as _ } from "lucide-react";
|
|
10
|
+
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
11
|
+
//#region src/components/vibedeck/VibeDeckPublicLinkPanel.tsx
|
|
12
|
+
var x = [
|
|
13
|
+
{
|
|
14
|
+
label: "4 hours",
|
|
15
|
+
hours: 4
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "24 hours",
|
|
19
|
+
hours: 24
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "7 days",
|
|
23
|
+
hours: 168
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: "No expiry",
|
|
27
|
+
hours: 0
|
|
28
|
+
}
|
|
29
|
+
], S = ({ vibeDeckId: S, vibeDeckName: w, onClose: T }) => {
|
|
30
|
+
let { t: E } = c(), D = (e, t) => {
|
|
31
|
+
let n = E(e);
|
|
32
|
+
return n === e ? t : n;
|
|
33
|
+
}, { data: O, loading: k, error: A, refetch: j } = t({
|
|
34
|
+
variables: { vibeDeckId: S },
|
|
35
|
+
fetchPolicy: "cache-and-network"
|
|
36
|
+
}), [M, { loading: N }] = e(), [P] = n(), [F, I] = s(!0), [L, R] = s(4), [z, B] = s(""), [V, H] = s(""), [U, W] = s(null), G = O?.vibeDeckShareLinks ?? [], K = G.filter((e) => e.status === "ACTIVE"), q = async (e, t) => {
|
|
37
|
+
try {
|
|
38
|
+
await navigator.clipboard.writeText(e), W(t), o.success(D("deckLink.copied", "Link copied")), window.setTimeout(() => W(null), 1500);
|
|
39
|
+
} catch {
|
|
40
|
+
o.error(D("deckLink.copyFailed", "Could not copy — copy it manually"), e);
|
|
41
|
+
}
|
|
42
|
+
}, J = async (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
let t = V.trim() ? Number.parseInt(V.trim(), 10) : null;
|
|
45
|
+
if (t !== null && (!Number.isFinite(t) || t < 1)) {
|
|
46
|
+
o.error(D("deckLink.badMax", "Max uses must be a positive number"));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
let e = await M({ variables: { input: {
|
|
51
|
+
vibeDeckId: S,
|
|
52
|
+
permission: F ? a.Execute : a.View,
|
|
53
|
+
expiresInHours: L > 0 ? L : null,
|
|
54
|
+
password: z.trim() ? z.trim() : null,
|
|
55
|
+
maxUses: t
|
|
56
|
+
} } });
|
|
57
|
+
await j();
|
|
58
|
+
let n = e.data?.createVibeDeckShareLink.shareUrl;
|
|
59
|
+
n && await q(n, e.data?.createVibeDeckShareLink.id ?? "new"), o.success(D("deckLink.created", "Public link created"), F ? D("deckLink.createdExec", "Anyone with the link can run the deck tiles") : D("deckLink.createdView", "Anyone with the link can view the deck")), B(""), H("");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
o.error(D("deckLink.createFailed", "Could not create link"), e.message);
|
|
62
|
+
}
|
|
63
|
+
}, Y = async (e) => {
|
|
64
|
+
try {
|
|
65
|
+
await P({ variables: { id: e } }), await j(), o.success(D("deckLink.revoked", "Link revoked — it no longer works"));
|
|
66
|
+
} catch (e) {
|
|
67
|
+
o.error(D("deckLink.revokeFailed", "Could not revoke"), e.message);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
return /* @__PURE__ */ y("div", {
|
|
71
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
72
|
+
onClick: T,
|
|
73
|
+
children: /* @__PURE__ */ b("div", {
|
|
74
|
+
className: "w-full max-w-lg rounded-lg border border-border-default bg-bg-surface p-5 shadow-lg",
|
|
75
|
+
onClick: (e) => e.stopPropagation(),
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ b("div", {
|
|
78
|
+
className: "mb-4 flex items-start justify-between",
|
|
79
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("h3", {
|
|
80
|
+
className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
|
|
81
|
+
children: [/* @__PURE__ */ y(f, { className: "size-5" }), D("deckLink.title", "Public links")]
|
|
82
|
+
}), /* @__PURE__ */ y("p", {
|
|
83
|
+
className: "mt-0.5 text-sm text-text-secondary",
|
|
84
|
+
children: w
|
|
85
|
+
})] }), /* @__PURE__ */ y("button", {
|
|
86
|
+
type: "button",
|
|
87
|
+
onClick: T,
|
|
88
|
+
className: "p-1 text-text-tertiary hover:text-text-primary",
|
|
89
|
+
"aria-label": D("common.close", "Close"),
|
|
90
|
+
children: /* @__PURE__ */ y(_, { className: "size-5" })
|
|
91
|
+
})]
|
|
92
|
+
}),
|
|
93
|
+
/* @__PURE__ */ y("div", {
|
|
94
|
+
className: "mb-4 space-y-2",
|
|
95
|
+
children: k && G.length === 0 ? /* @__PURE__ */ y(r, {}) : A ? /* @__PURE__ */ y(i, {
|
|
96
|
+
message: A.message,
|
|
97
|
+
onRetry: () => void j()
|
|
98
|
+
}) : K.length === 0 ? /* @__PURE__ */ y("p", {
|
|
99
|
+
className: "text-sm text-text-secondary",
|
|
100
|
+
children: D("deckLink.none", "No public links yet. Create one below.")
|
|
101
|
+
}) : /* @__PURE__ */ y("ul", {
|
|
102
|
+
className: "space-y-2",
|
|
103
|
+
children: K.map((e) => /* @__PURE__ */ b("li", {
|
|
104
|
+
className: "flex items-center gap-2 rounded-md border border-border-default px-3 py-2",
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ y(C, { children: e.permission === a.Execute ? /* @__PURE__ */ b(v, { children: [
|
|
107
|
+
/* @__PURE__ */ y(m, { className: "size-3" }),
|
|
108
|
+
" ",
|
|
109
|
+
D("deckLink.execute", "Execute")
|
|
110
|
+
] }) : /* @__PURE__ */ b(v, { children: [
|
|
111
|
+
/* @__PURE__ */ y(d, { className: "size-3" }),
|
|
112
|
+
" ",
|
|
113
|
+
D("deckLink.view", "View")
|
|
114
|
+
] }) }),
|
|
115
|
+
e.hasPassword && /* @__PURE__ */ y(p, {
|
|
116
|
+
className: "size-3.5 text-text-tertiary",
|
|
117
|
+
"aria-label": "password"
|
|
118
|
+
}),
|
|
119
|
+
/* @__PURE__ */ y("span", {
|
|
120
|
+
className: "flex-1 truncate font-mono text-xs text-text-secondary",
|
|
121
|
+
children: e.shareUrl
|
|
122
|
+
}),
|
|
123
|
+
/* @__PURE__ */ b("span", {
|
|
124
|
+
className: "shrink-0 text-xs text-text-tertiary",
|
|
125
|
+
children: [
|
|
126
|
+
e.useCount,
|
|
127
|
+
e.maxUses ? `/${e.maxUses}` : "",
|
|
128
|
+
" ",
|
|
129
|
+
D("deckLink.uses", "uses")
|
|
130
|
+
]
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ y("button", {
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => void q(e.shareUrl, e.id),
|
|
135
|
+
className: "p-1 text-text-secondary hover:text-text-primary",
|
|
136
|
+
"aria-label": D("common.copy", "Copy"),
|
|
137
|
+
children: U === e.id ? /* @__PURE__ */ y(l, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ y(u, { className: "size-4" })
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ y("button", {
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: () => void Y(e.id),
|
|
142
|
+
className: "p-1 text-text-secondary hover:text-action-danger-text",
|
|
143
|
+
"aria-label": D("common.revoke", "Revoke"),
|
|
144
|
+
children: /* @__PURE__ */ y(g, { className: "size-4" })
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
}, e.id))
|
|
148
|
+
})
|
|
149
|
+
}),
|
|
150
|
+
/* @__PURE__ */ b("form", {
|
|
151
|
+
onSubmit: (e) => void J(e),
|
|
152
|
+
className: "space-y-3 border-t border-border-default pt-4",
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ b("label", {
|
|
155
|
+
className: "flex cursor-pointer items-center gap-2 text-sm text-text-primary",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ y("input", {
|
|
158
|
+
type: "checkbox",
|
|
159
|
+
checked: F,
|
|
160
|
+
onChange: (e) => I(e.target.checked),
|
|
161
|
+
className: "rounded border-border-default"
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ y(m, { className: "size-3.5" }),
|
|
164
|
+
D("deckLink.allowExecution", "Allow execution (anyone with the link can run tiles)")
|
|
165
|
+
]
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ b("div", {
|
|
168
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
169
|
+
children: [/* @__PURE__ */ b("label", {
|
|
170
|
+
className: "flex-1",
|
|
171
|
+
children: [/* @__PURE__ */ y("span", {
|
|
172
|
+
className: "text-sm text-text-secondary",
|
|
173
|
+
children: D("deckLink.expiry", "Expires")
|
|
174
|
+
}), /* @__PURE__ */ y("select", {
|
|
175
|
+
value: L,
|
|
176
|
+
onChange: (e) => R(Number(e.target.value)),
|
|
177
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary",
|
|
178
|
+
children: x.map((e) => /* @__PURE__ */ y("option", {
|
|
179
|
+
value: e.hours,
|
|
180
|
+
children: e.label
|
|
181
|
+
}, e.label))
|
|
182
|
+
})]
|
|
183
|
+
}), /* @__PURE__ */ b("label", {
|
|
184
|
+
className: "flex-1",
|
|
185
|
+
children: [/* @__PURE__ */ y("span", {
|
|
186
|
+
className: "text-sm text-text-secondary",
|
|
187
|
+
children: D("deckLink.maxUses", "Max uses (optional)")
|
|
188
|
+
}), /* @__PURE__ */ y("input", {
|
|
189
|
+
value: V,
|
|
190
|
+
onChange: (e) => H(e.target.value),
|
|
191
|
+
inputMode: "numeric",
|
|
192
|
+
placeholder: D("deckLink.unlimited", "unlimited"),
|
|
193
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
194
|
+
})]
|
|
195
|
+
})]
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ b("label", {
|
|
198
|
+
className: "block",
|
|
199
|
+
children: [/* @__PURE__ */ y("span", {
|
|
200
|
+
className: "text-sm text-text-secondary",
|
|
201
|
+
children: D("deckLink.password", "Password (optional)")
|
|
202
|
+
}), /* @__PURE__ */ y("input", {
|
|
203
|
+
value: z,
|
|
204
|
+
onChange: (e) => B(e.target.value),
|
|
205
|
+
type: "password",
|
|
206
|
+
autoComplete: "new-password",
|
|
207
|
+
placeholder: D("deckLink.noPassword", "no password"),
|
|
208
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
209
|
+
})]
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ y("div", {
|
|
212
|
+
className: "flex justify-end",
|
|
213
|
+
children: /* @__PURE__ */ b("button", {
|
|
214
|
+
type: "submit",
|
|
215
|
+
disabled: N,
|
|
216
|
+
className: "flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50",
|
|
217
|
+
children: [/* @__PURE__ */ y(h, { className: "size-4" }), D("deckLink.create", "Create public link")]
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
]
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
})
|
|
224
|
+
});
|
|
225
|
+
}, C = ({ children: e }) => /* @__PURE__ */ y("span", {
|
|
226
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-primary",
|
|
227
|
+
children: e
|
|
228
|
+
});
|
|
229
|
+
//#endregion
|
|
230
|
+
export { S as VibeDeckPublicLinkPanel };
|
|
231
|
+
|
|
232
|
+
//# sourceMappingURL=VibeDeckPublicLinkPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VibeDeckPublicLinkPanel.js","names":[],"sources":["../../../src/components/vibedeck/VibeDeckPublicLinkPanel.tsx"],"sourcesContent":["import type { FC, FormEvent, ReactNode } from 'react';\nimport { useState } from 'react';\nimport { Link2, Play, Eye, Lock, Copy, Trash2, Plus, X, Check } from 'lucide-react';\n\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { notify } from '@/lib/toast';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useListVibeDeckShareLinksQuery,\n useCreateVibeDeckShareLinkMutation,\n useRevokeVibeDeckShareLinkMutation,\n type VibeDeckShareLinkFieldsFragment,\n} from '@/generated/wspace-operations';\nimport { VibeDeckSharePermission } from '@/generated/wspace-types';\n\ninterface VibeDeckPublicLinkPanelProps {\n vibeDeckId: string;\n vibeDeckName: string;\n onClose: () => void;\n}\n\nconst EXPIRY_OPTIONS = [\n { label: '4 hours', hours: 4 },\n { label: '24 hours', hours: 24 },\n { label: '7 days', hours: 168 },\n { label: 'No expiry', hours: 0 },\n];\n\n/**\n * VibeDeckPublicLinkPanel — create and manage public links to a VibeDeck with explicit\n * **execution** control. Unlike the generic member-share dialog, this exposes the deck story's\n * promised controls: \"Public access + Allow execution + optional password + expiry + usage limit\".\n * Links carry a `VibeDeckSharePermission` (VIEW or EXECUTE); the URL points at the live\n * `deck/:token` page (not an auth'd accept page). Backed by the existing `createVibeDeckShareLink`\n * mutation — no backend change.\n */\nexport const VibeDeckPublicLinkPanel: FC<VibeDeckPublicLinkPanelProps> = ({\n vibeDeckId,\n vibeDeckName,\n onClose,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const { data, loading, error, refetch } = useListVibeDeckShareLinksQuery({\n variables: { vibeDeckId },\n fetchPolicy: 'cache-and-network',\n });\n const [createLink, { loading: creating }] = useCreateVibeDeckShareLinkMutation();\n const [revokeLink] = useRevokeVibeDeckShareLinkMutation();\n\n const [allowExecution, setAllowExecution] = useState(true);\n const [expiryHours, setExpiryHours] = useState(4);\n const [password, setPassword] = useState('');\n const [maxUses, setMaxUses] = useState('');\n const [copiedId, setCopiedId] = useState<string | null>(null);\n\n const links: VibeDeckShareLinkFieldsFragment[] = data?.vibeDeckShareLinks ?? [];\n const activeLinks = links.filter((l) => l.status === 'ACTIVE');\n\n const copy = async (url: string, id: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(url);\n setCopiedId(id);\n notify.success(tr('deckLink.copied', 'Link copied'));\n window.setTimeout(() => setCopiedId(null), 1500);\n } catch {\n notify.error(tr('deckLink.copyFailed', 'Could not copy — copy it manually'), url);\n }\n };\n\n const handleCreate = async (e: FormEvent): Promise<void> => {\n e.preventDefault();\n const parsedMax = maxUses.trim() ? Number.parseInt(maxUses.trim(), 10) : null;\n if (parsedMax !== null && (!Number.isFinite(parsedMax) || parsedMax < 1)) {\n notify.error(tr('deckLink.badMax', 'Max uses must be a positive number'));\n return;\n }\n try {\n const res = await createLink({\n variables: {\n input: {\n vibeDeckId,\n permission: allowExecution\n ? VibeDeckSharePermission.Execute\n : VibeDeckSharePermission.View,\n expiresInHours: expiryHours > 0 ? expiryHours : null,\n password: password.trim() ? password.trim() : null,\n maxUses: parsedMax,\n },\n },\n });\n await refetch();\n const url = res.data?.createVibeDeckShareLink.shareUrl;\n if (url) await copy(url, res.data?.createVibeDeckShareLink.id ?? 'new');\n notify.success(\n tr('deckLink.created', 'Public link created'),\n allowExecution\n ? tr('deckLink.createdExec', 'Anyone with the link can run the deck tiles')\n : tr('deckLink.createdView', 'Anyone with the link can view the deck')\n );\n setPassword('');\n setMaxUses('');\n } catch (err) {\n notify.error(tr('deckLink.createFailed', 'Could not create link'), (err as Error).message);\n }\n };\n\n const handleRevoke = async (id: string): Promise<void> => {\n try {\n await revokeLink({ variables: { id } });\n await refetch();\n notify.success(tr('deckLink.revoked', 'Link revoked — it no longer works'));\n } catch (err) {\n notify.error(tr('deckLink.revokeFailed', 'Could not revoke'), (err as Error).message);\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n onClick={onClose}\n >\n <div\n className=\"w-full max-w-lg rounded-lg border border-border-default bg-bg-surface p-5 shadow-lg\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between\">\n <div>\n <h3 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Link2 className=\"size-5\" />\n {tr('deckLink.title', 'Public links')}\n </h3>\n <p className=\"mt-0.5 text-sm text-text-secondary\">{vibeDeckName}</p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 text-text-tertiary hover:text-text-primary\"\n aria-label={tr('common.close', 'Close')}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Existing links */}\n <div className=\"mb-4 space-y-2\">\n {loading && links.length === 0 ? (\n <LoadingState />\n ) : error ? (\n <ErrorState message={error.message} onRetry={() => void refetch()} />\n ) : activeLinks.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {tr('deckLink.none', 'No public links yet. Create one below.')}\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {activeLinks.map((l) => (\n <li\n key={l.id}\n className=\"flex items-center gap-2 rounded-md border border-border-default px-3 py-2\"\n >\n <Badge>\n {l.permission === VibeDeckSharePermission.Execute ? (\n <>\n <Play className=\"size-3\" /> {tr('deckLink.execute', 'Execute')}\n </>\n ) : (\n <>\n <Eye className=\"size-3\" /> {tr('deckLink.view', 'View')}\n </>\n )}\n </Badge>\n {l.hasPassword && (\n <Lock className=\"size-3.5 text-text-tertiary\" aria-label=\"password\" />\n )}\n <span className=\"flex-1 truncate font-mono text-xs text-text-secondary\">\n {l.shareUrl}\n </span>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {l.useCount}\n {l.maxUses ? `/${l.maxUses}` : ''} {tr('deckLink.uses', 'uses')}\n </span>\n <button\n type=\"button\"\n onClick={() => void copy(l.shareUrl, l.id)}\n className=\"p-1 text-text-secondary hover:text-text-primary\"\n aria-label={tr('common.copy', 'Copy')}\n >\n {copiedId === l.id ? (\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={() => void handleRevoke(l.id)}\n className=\"p-1 text-text-secondary hover:text-action-danger-text\"\n aria-label={tr('common.revoke', 'Revoke')}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {/* Create form */}\n <form\n onSubmit={(e) => void handleCreate(e)}\n className=\"space-y-3 border-t border-border-default pt-4\"\n >\n <label className=\"flex cursor-pointer items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={allowExecution}\n onChange={(e) => setAllowExecution(e.target.checked)}\n className=\"rounded border-border-default\"\n />\n <Play className=\"size-3.5\" />\n {tr('deckLink.allowExecution', 'Allow execution (anyone with the link can run tiles)')}\n </label>\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <label className=\"flex-1\">\n <span className=\"text-sm text-text-secondary\">\n {tr('deckLink.expiry', 'Expires')}\n </span>\n <select\n value={expiryHours}\n onChange={(e) => setExpiryHours(Number(e.target.value))}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {EXPIRY_OPTIONS.map((o) => (\n <option key={o.label} value={o.hours}>\n {o.label}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex-1\">\n <span className=\"text-sm text-text-secondary\">\n {tr('deckLink.maxUses', 'Max uses (optional)')}\n </span>\n <input\n value={maxUses}\n onChange={(e) => setMaxUses(e.target.value)}\n inputMode=\"numeric\"\n placeholder={tr('deckLink.unlimited', 'unlimited')}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </label>\n </div>\n <label className=\"block\">\n <span className=\"text-sm text-text-secondary\">\n {tr('deckLink.password', 'Password (optional)')}\n </span>\n <input\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder={tr('deckLink.noPassword', 'no password')}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </label>\n <div className=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={creating}\n className=\"flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Plus className=\"size-4\" />\n {tr('deckLink.create', 'Create public link')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nconst Badge: FC<{ children: ReactNode }> = ({ children }) => (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-primary\">\n {children}\n </span>\n);\n"],"mappings":"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"}
|
|
@@ -34,13 +34,15 @@ var e = /* @__PURE__ */ function(e) {
|
|
|
34
34
|
}({}), g = /* @__PURE__ */ function(e) {
|
|
35
35
|
return e.Csv = "CSV", e.Json = "JSON", e;
|
|
36
36
|
}({}), _ = /* @__PURE__ */ function(e) {
|
|
37
|
-
return e.
|
|
37
|
+
return e.Execute = "EXECUTE", e.View = "VIEW", e;
|
|
38
38
|
}({}), v = /* @__PURE__ */ function(e) {
|
|
39
|
-
return e.
|
|
39
|
+
return e.Action = "ACTION", e.AiContext = "AI_CONTEXT", e.AiPrompt = "AI_PROMPT", e.InstructionFile = "INSTRUCTION_FILE", e.Sandbox = "SANDBOX", e.ScheduledJob = "SCHEDULED_JOB", e.Tunnel = "TUNNEL", e.VibeDeck = "VIBE_DECK", e;
|
|
40
40
|
}({}), y = /* @__PURE__ */ function(e) {
|
|
41
|
+
return e.Private = "PRIVATE", e.SharedWithVibe = "SHARED_WITH_VIBE", e;
|
|
42
|
+
}({}), b = /* @__PURE__ */ function(e) {
|
|
41
43
|
return e.Custom = "CUSTOM", e.Script = "SCRIPT", e.Ssh = "SSH", e.Terminal = "TERMINAL", e.Tmux = "TMUX", e.Wezterm = "WEZTERM", e.Zellij = "ZELLIJ", e;
|
|
42
44
|
}({});
|
|
43
45
|
//#endregion
|
|
44
|
-
export { e as AgentCapabilityScope, t as AnalyticsEntityType, n as CollaboratorRole, r as DeploymentEnvironment, i as InstructionFilename, a as InstructionScope, o as MeshSessionKind, s as NoteVisibility, c as SessionSharePermission, l as TunnelDomainType, u as TunnelDomainVerificationStatus, d as TunnelEnvironment, f as TunnelProtocol, p as TunnelProviderKey, m as TunnelSessionStatus, h as TunnelStatus, g as VibeAuditExportFormat, _ as
|
|
46
|
+
export { e as AgentCapabilityScope, t as AnalyticsEntityType, n as CollaboratorRole, r as DeploymentEnvironment, i as InstructionFilename, a as InstructionScope, o as MeshSessionKind, s as NoteVisibility, c as SessionSharePermission, l as TunnelDomainType, u as TunnelDomainVerificationStatus, d as TunnelEnvironment, f as TunnelProtocol, p as TunnelProviderKey, m as TunnelSessionStatus, h as TunnelStatus, g as VibeAuditExportFormat, _ as VibeDeckSharePermission, v as VibeEntityType, y as VibeVisibility, b as VibecontrolsSessionType };
|
|
45
47
|
|
|
46
48
|
//# sourceMappingURL=wspace-types.js.map
|