@burdenoff/microfe-vibecontrols 2026.602.2 → 2026.602.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/ActionCard.js +87 -74
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/ai/InstructionFilesManager.js +149 -141
- package/dist/components/ai/InstructionFilesManager.js.map +1 -1
- package/dist/components/sessions/SessionShareDialog.js +24 -462
- package/dist/components/sessions/SessionShareDialog.js.map +1 -1
- package/dist/components/shared/EntityVibeLinkControl.js +204 -0
- package/dist/components/shared/EntityVibeLinkControl.js.map +1 -0
- package/dist/components/shared/index.js +1 -0
- package/dist/components/sharing/entityShareOps.js +106 -0
- package/dist/components/sharing/entityShareOps.js.map +1 -1
- package/dist/components/sharing/shareRegistry.js +3 -3
- package/dist/components/sharing/shareRegistry.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +51 -43
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/vibe/VibeLinkedEntitiesPanel.js +117 -89
- package/dist/components/vibe/VibeLinkedEntitiesPanel.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckShareDialog.js +19 -335
- package/dist/components/vibedeck/VibeDeckShareDialog.js.map +1 -1
- package/dist/constants/permissions.js +1 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/generated/wspace-operations.js +1618 -1593
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js +10 -10
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/pages/SessionsPage.js +1011 -1007
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +218 -210
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/shareUrl.js +0 -41
- package/dist/utils/shareUrl.js.map +0 -1
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import { TunnelStatus as t } from "../../generated/wspace-types.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { TunnelStatus as t, VibeEntityType as n } from "../../generated/wspace-types.js";
|
|
3
|
+
import { EntityVibeLinkControl as r } from "../shared/EntityVibeLinkControl.js";
|
|
4
|
+
import { TunnelStatusBadge as i } from "./TunnelStatusBadge.js";
|
|
5
|
+
import { ProviderBadge as a } from "./ProviderBadge.js";
|
|
6
|
+
import { ExternalLink as o, Loader2 as s, Play as c, Square as l, Trash2 as u } from "lucide-react";
|
|
7
|
+
import { motion as d } from "framer-motion";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
8
9
|
//#region src/components/tunnels/TunnelCard.tsx
|
|
9
|
-
function
|
|
10
|
-
let
|
|
11
|
-
return /* @__PURE__ */ d
|
|
10
|
+
function m({ tunnel: m, isPending: h = !1, onOpen: g, onStart: _, onStop: v, onDelete: y }) {
|
|
11
|
+
let b = e(), x = !h && m.status !== t.Active && m.status !== t.Provisioning, S = !h && m.status === t.Active, C = m.primaryDomain?.hostname, w = C ? `${m.protocol.toLowerCase() === "tcp" ? "tcp" : "https"}://${C}` : null;
|
|
12
|
+
return /* @__PURE__ */ p(d.div, {
|
|
12
13
|
initial: {
|
|
13
14
|
opacity: 0,
|
|
14
15
|
y: 4
|
|
@@ -18,85 +19,92 @@ function f({ tunnel: f, isPending: p = !1, onOpen: m, onStart: h, onStop: g, onD
|
|
|
18
19
|
y: 0
|
|
19
20
|
},
|
|
20
21
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4 hover:border-border-default transition-colors",
|
|
21
|
-
children: [/* @__PURE__ */
|
|
22
|
+
children: [/* @__PURE__ */ p("div", {
|
|
22
23
|
className: "flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3",
|
|
23
|
-
children: [/* @__PURE__ */
|
|
24
|
+
children: [/* @__PURE__ */ p("button", {
|
|
24
25
|
type: "button",
|
|
25
|
-
onClick: () => m
|
|
26
|
+
onClick: () => g(m.id),
|
|
26
27
|
className: "flex-1 text-left min-w-0",
|
|
27
28
|
children: [
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
+
/* @__PURE__ */ p("div", {
|
|
29
30
|
className: "flex flex-wrap items-center gap-2 mb-1",
|
|
30
31
|
children: [
|
|
31
|
-
/* @__PURE__ */
|
|
32
|
+
/* @__PURE__ */ f("h3", {
|
|
32
33
|
className: "text-base font-semibold text-text-primary truncate",
|
|
33
|
-
children:
|
|
34
|
+
children: m.name
|
|
34
35
|
}),
|
|
35
|
-
/* @__PURE__ */
|
|
36
|
-
/* @__PURE__ */
|
|
36
|
+
/* @__PURE__ */ f(i, { status: m.status }),
|
|
37
|
+
/* @__PURE__ */ f(a, { providerKey: m.providerKey })
|
|
37
38
|
]
|
|
38
39
|
}),
|
|
39
|
-
|
|
40
|
+
w ? /* @__PURE__ */ f("p", {
|
|
40
41
|
className: "text-sm text-text-secondary truncate",
|
|
41
|
-
children:
|
|
42
|
-
}) : /* @__PURE__ */
|
|
42
|
+
children: w
|
|
43
|
+
}) : /* @__PURE__ */ f("p", {
|
|
43
44
|
className: "text-sm text-text-muted",
|
|
44
|
-
children:
|
|
45
|
+
children: b("vibecontrols.tunnels.noDomain", "No domain attached")
|
|
45
46
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
47
|
+
/* @__PURE__ */ p("p", {
|
|
47
48
|
className: "text-xs text-text-muted mt-1",
|
|
48
49
|
children: [
|
|
49
|
-
|
|
50
|
+
m.protocol,
|
|
50
51
|
":",
|
|
51
|
-
|
|
52
|
+
m.localPort,
|
|
52
53
|
" on ",
|
|
53
|
-
|
|
54
|
+
m.localHost
|
|
54
55
|
]
|
|
55
56
|
})
|
|
56
57
|
]
|
|
57
|
-
}), /* @__PURE__ */
|
|
58
|
+
}), /* @__PURE__ */ p("div", {
|
|
58
59
|
className: "flex items-center gap-2 flex-shrink-0 flex-wrap",
|
|
59
60
|
children: [
|
|
60
|
-
|
|
61
|
-
href:
|
|
61
|
+
w && /* @__PURE__ */ p("a", {
|
|
62
|
+
href: w,
|
|
62
63
|
target: "_blank",
|
|
63
64
|
rel: "noreferrer",
|
|
64
65
|
className: "inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated",
|
|
65
66
|
onClick: (e) => e.stopPropagation(),
|
|
66
|
-
children: [/* @__PURE__ */
|
|
67
|
+
children: [/* @__PURE__ */ f(o, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.open", "Open")]
|
|
67
68
|
}),
|
|
68
|
-
|
|
69
|
+
h && /* @__PURE__ */ p("span", {
|
|
69
70
|
className: "inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-muted",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
71
|
+
children: [/* @__PURE__ */ f(s, { className: "size-3.5 mr-1 animate-spin" }), m.status === "ACTIVE" ? b("vibecontrols.tunnels.stopping", "Stopping…") : b("vibecontrols.tunnels.starting", "Starting…")]
|
|
71
72
|
}),
|
|
72
|
-
|
|
73
|
+
x && /* @__PURE__ */ p("button", {
|
|
73
74
|
type: "button",
|
|
74
|
-
onClick: () =>
|
|
75
|
+
onClick: () => _(m.id),
|
|
75
76
|
className: "inline-flex items-center rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg hover:bg-action-primary-bg-hover",
|
|
76
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ f(c, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.start", "Start")]
|
|
77
78
|
}),
|
|
78
|
-
|
|
79
|
+
S && /* @__PURE__ */ p("button", {
|
|
79
80
|
type: "button",
|
|
80
|
-
onClick: () =>
|
|
81
|
+
onClick: () => v(m.id),
|
|
81
82
|
className: "inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ f(l, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.stop", "Stop")]
|
|
83
84
|
}),
|
|
84
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ f(r, {
|
|
86
|
+
entityType: n.Tunnel,
|
|
87
|
+
entityId: m.id,
|
|
88
|
+
currentVibeId: m.vibeId ?? null,
|
|
89
|
+
currentVisibility: m.visibility ?? null,
|
|
90
|
+
refetchQueries: ["ListTunnels"]
|
|
91
|
+
}),
|
|
92
|
+
/* @__PURE__ */ f("button", {
|
|
85
93
|
type: "button",
|
|
86
|
-
onClick: () =>
|
|
94
|
+
onClick: () => y(m.id, m.name),
|
|
87
95
|
className: "inline-flex items-center rounded-md border border-border-default px-2 py-1.5 text-xs text-status-error-fg hover:bg-status-error-bg",
|
|
88
96
|
"aria-label": "Delete tunnel",
|
|
89
|
-
children: /* @__PURE__ */ u
|
|
97
|
+
children: /* @__PURE__ */ f(u, { className: "size-3.5" })
|
|
90
98
|
})
|
|
91
99
|
]
|
|
92
100
|
})]
|
|
93
|
-
}),
|
|
101
|
+
}), m.lastError && /* @__PURE__ */ f("div", {
|
|
94
102
|
className: "mt-3 rounded-md bg-status-error-bg px-3 py-2 text-xs text-status-error-fg",
|
|
95
|
-
children:
|
|
103
|
+
children: m.lastError
|
|
96
104
|
})]
|
|
97
105
|
});
|
|
98
106
|
}
|
|
99
107
|
//#endregion
|
|
100
|
-
export {
|
|
108
|
+
export { m as TunnelCard };
|
|
101
109
|
|
|
102
110
|
//# sourceMappingURL=TunnelCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n onStart: (id: string) => void;\n onStop: (id: string) => void;\n onDelete: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 hover:border-border-default transition-colors\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1\">\n <h3 className=\"text-base font-semibold text-text-primary truncate\">{tunnel.name}</h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs text-text-muted mt-1\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg hover:bg-action-primary-bg-hover\"\n >\n <Play className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n >\n <Square className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-md border border-border-default px-2 py-1.5 text-xs text-status-error-fg hover:bg-status-error-bg\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-3 rounded-md bg-status-error-bg px-3 py-2 text-xs text-status-error-fg\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n onStart: (id: string) => void;\n onStop: (id: string) => void;\n onDelete: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 hover:border-border-default transition-colors\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1\">\n <h3 className=\"text-base font-semibold text-text-primary truncate\">{tunnel.name}</h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs text-text-muted mt-1\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg hover:bg-action-primary-bg-hover\"\n >\n <Play className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n >\n <Square className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-md border border-border-default px-2 py-1.5 text-xs text-status-error-fg hover:bg-status-error-bg\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-3 rounded-md bg-status-error-bg px-3 py-2 text-xs text-status-error-fg\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBAAsD,EAAO;QAAU,CAAA;OACrF,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,iBAAkB,CAAA,EACzC,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,8BAA+B,CAAA,EACjD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,iBAAkB,CAAA,EACjC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,iBAAkB,CAAA,EACnC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACF,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KACL;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useGetVibeLinkedEntitiesQuery as e, useGetVibeLinkedSandboxesQuery as t, useGetVibeLinkedScheduledJobsQuery as n } from "../../generated/wspace-operations.js";
|
|
2
2
|
import { useTr as r } from "../../shared/hooks/useTr.js";
|
|
3
|
-
import { useVibeControls as i } from "../../providers/VibeControlsProvider.js";
|
|
4
|
-
import { LoadingState as
|
|
5
|
-
import { ErrorState as
|
|
6
|
-
import { EmptyState as
|
|
3
|
+
import { useVibeControls as i, useVibeNavigate as a } from "../../providers/VibeControlsProvider.js";
|
|
4
|
+
import { LoadingState as o } from "../shared/LoadingState.js";
|
|
5
|
+
import { ErrorState as s } from "../shared/ErrorState.js";
|
|
6
|
+
import { EmptyState as c } from "../shared/EmptyState.js";
|
|
7
7
|
import "../shared/index.js";
|
|
8
|
-
import { Link2 as
|
|
9
|
-
import { jsx as
|
|
8
|
+
import { ArrowUpRight as l, Link2 as u } from "lucide-react";
|
|
9
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
10
|
//#region src/components/vibe/VibeLinkedEntitiesPanel.tsx
|
|
11
|
-
var
|
|
11
|
+
var p = {
|
|
12
12
|
vibedecks: {
|
|
13
13
|
singular: "Vibe Deck",
|
|
14
14
|
plural: "Vibe Decks"
|
|
@@ -41,152 +41,179 @@ var d = {
|
|
|
41
41
|
singular: "Tunnel",
|
|
42
42
|
plural: "Tunnels"
|
|
43
43
|
}
|
|
44
|
-
},
|
|
44
|
+
}, m = new Set([
|
|
45
45
|
"vibedecks",
|
|
46
46
|
"actions",
|
|
47
47
|
"aiPrompts",
|
|
48
48
|
"aiContexts",
|
|
49
49
|
"instructionFiles",
|
|
50
50
|
"tunnels"
|
|
51
|
-
])
|
|
52
|
-
|
|
51
|
+
]), h = {
|
|
52
|
+
vibedecks: "/vibedeck",
|
|
53
|
+
actions: "/actions",
|
|
54
|
+
scheduledJobs: "/calendar",
|
|
55
|
+
sandboxes: "/sandbox",
|
|
56
|
+
aiPrompts: "/ai-tools/ai/prompts",
|
|
57
|
+
aiContexts: "/ai-tools/ai/contexts",
|
|
58
|
+
instructionFiles: "/ai-tools/ai/instructions",
|
|
59
|
+
tunnels: "/tunnels"
|
|
60
|
+
};
|
|
61
|
+
function g(e) {
|
|
53
62
|
return e === "SHARED_WITH_VIBE" ? "Shared" : "Private";
|
|
54
63
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
className: "
|
|
58
|
-
children: /* @__PURE__ */
|
|
59
|
-
}) :
|
|
60
|
-
className: "
|
|
61
|
-
children: /* @__PURE__ */
|
|
64
|
+
function _({ labels: e, loading: t, hasData: n, error: i, rows: a, emptyDescription: p, onOpenPage: m }) {
|
|
65
|
+
let h = r(), _ = t && !n ? /* @__PURE__ */ d("div", {
|
|
66
|
+
className: "p-6",
|
|
67
|
+
children: /* @__PURE__ */ d(o, { message: `Loading ${e.plural.toLowerCase()}…` })
|
|
68
|
+
}) : i ? /* @__PURE__ */ d("div", {
|
|
69
|
+
className: "p-6",
|
|
70
|
+
children: /* @__PURE__ */ d(s, {
|
|
62
71
|
title: `Failed to load ${e.plural.toLowerCase()}`,
|
|
63
|
-
message:
|
|
72
|
+
message: i.message
|
|
64
73
|
})
|
|
65
|
-
}) :
|
|
66
|
-
className: "
|
|
67
|
-
children: /* @__PURE__ */
|
|
68
|
-
icon: /* @__PURE__ */
|
|
74
|
+
}) : a.length === 0 ? /* @__PURE__ */ d("div", {
|
|
75
|
+
className: "p-6",
|
|
76
|
+
children: /* @__PURE__ */ d(c, {
|
|
77
|
+
icon: /* @__PURE__ */ d(u, {
|
|
69
78
|
size: 48,
|
|
70
79
|
className: "text-text-secondary"
|
|
71
80
|
}),
|
|
72
81
|
title: `No ${e.plural.toLowerCase()} linked yet`,
|
|
73
|
-
description:
|
|
82
|
+
description: p
|
|
74
83
|
})
|
|
75
|
-
}) : /* @__PURE__ */
|
|
76
|
-
className: "
|
|
84
|
+
}) : /* @__PURE__ */ d("ul", {
|
|
85
|
+
className: "divide-y divide-border-default",
|
|
77
86
|
"data-testid": "vibe-linked-entities",
|
|
78
|
-
children: /* @__PURE__ */
|
|
79
|
-
className: "
|
|
80
|
-
children:
|
|
81
|
-
className: "flex items-center
|
|
82
|
-
children: [/* @__PURE__ */
|
|
83
|
-
className: "
|
|
84
|
-
children:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
className: "flex-shrink-0 rounded bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
|
|
89
|
-
children: e.badge
|
|
90
|
-
})]
|
|
91
|
-
}), /* @__PURE__ */ l("span", {
|
|
92
|
-
className: `flex-shrink-0 rounded px-2 py-0.5 text-xs ${e.visibility === "SHARED_WITH_VIBE" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-tertiary"}`,
|
|
93
|
-
children: p(e.visibility)
|
|
87
|
+
children: a.map((e) => /* @__PURE__ */ f("li", {
|
|
88
|
+
className: "flex items-center justify-between gap-3 px-4 py-3",
|
|
89
|
+
children: [/* @__PURE__ */ f("div", {
|
|
90
|
+
className: "flex min-w-0 items-center gap-2",
|
|
91
|
+
children: [/* @__PURE__ */ d("span", {
|
|
92
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
93
|
+
children: e.label
|
|
94
|
+
}), /* @__PURE__ */ d("span", {
|
|
95
|
+
className: "flex-shrink-0 rounded bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
|
|
96
|
+
children: e.badge
|
|
94
97
|
})]
|
|
95
|
-
},
|
|
96
|
-
|
|
98
|
+
}), /* @__PURE__ */ d("span", {
|
|
99
|
+
className: `flex-shrink-0 rounded px-2 py-0.5 text-xs ${e.visibility === "SHARED_WITH_VIBE" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-tertiary"}`,
|
|
100
|
+
children: g(e.visibility)
|
|
101
|
+
})]
|
|
102
|
+
}, e.id))
|
|
103
|
+
});
|
|
104
|
+
return /* @__PURE__ */ f("div", {
|
|
105
|
+
className: "rounded-lg border border-border-default bg-bg-surface",
|
|
106
|
+
children: [/* @__PURE__ */ f("div", {
|
|
107
|
+
className: "flex items-center justify-between gap-3 border-b border-border-default px-4 py-3",
|
|
108
|
+
children: [/* @__PURE__ */ d("h3", {
|
|
109
|
+
className: "text-sm font-semibold text-text-primary",
|
|
110
|
+
children: e.plural
|
|
111
|
+
}), m && /* @__PURE__ */ f("button", {
|
|
112
|
+
type: "button",
|
|
113
|
+
onClick: m,
|
|
114
|
+
"data-testid": "vibe-linked-open-page",
|
|
115
|
+
className: "inline-flex flex-shrink-0 items-center gap-1.5 rounded-md border border-border-default px-2.5 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-bg-elevated",
|
|
116
|
+
title: h("vibeDetails.linked.openPageTitle", `Open the ${e.plural} page`),
|
|
117
|
+
children: [h("vibeDetails.linked.openPage", `Open ${e.plural} page`), /* @__PURE__ */ d(l, { size: 14 })]
|
|
118
|
+
})]
|
|
119
|
+
}), _]
|
|
97
120
|
});
|
|
98
121
|
}
|
|
99
|
-
function
|
|
100
|
-
let n = r(), a =
|
|
122
|
+
function v({ vibeId: e }) {
|
|
123
|
+
let n = r(), o = a(), s = p.sandboxes, { workspaceId: c, projectId: l, navigate: u } = i(), f = () => {
|
|
124
|
+
u ? u(h.sandboxes) : o(h.sandboxes);
|
|
125
|
+
}, { data: m, loading: g, error: v } = t({
|
|
101
126
|
variables: {
|
|
102
127
|
context: {
|
|
103
|
-
workspaceId:
|
|
104
|
-
projectId:
|
|
128
|
+
workspaceId: c ?? void 0,
|
|
129
|
+
projectId: l ?? void 0
|
|
105
130
|
},
|
|
106
131
|
vibeId: e
|
|
107
132
|
},
|
|
108
|
-
skip: !
|
|
133
|
+
skip: !c,
|
|
109
134
|
fetchPolicy: "cache-and-network"
|
|
110
|
-
}),
|
|
135
|
+
}), y = (m?.listSandboxes?.items ?? []).map((e) => ({
|
|
111
136
|
id: e.id,
|
|
112
137
|
label: e.name,
|
|
113
138
|
badge: String(e.status),
|
|
114
139
|
visibility: e.visibility
|
|
115
140
|
}));
|
|
116
|
-
return /* @__PURE__ */
|
|
117
|
-
labels:
|
|
118
|
-
loading:
|
|
119
|
-
hasData: !!
|
|
120
|
-
error:
|
|
121
|
-
rows:
|
|
122
|
-
|
|
141
|
+
return /* @__PURE__ */ d(_, {
|
|
142
|
+
labels: s,
|
|
143
|
+
loading: g,
|
|
144
|
+
hasData: !!m,
|
|
145
|
+
error: v,
|
|
146
|
+
rows: y,
|
|
147
|
+
onOpenPage: f,
|
|
148
|
+
emptyDescription: n("vibeDetails.linked.empty", `Link a ${s.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
|
|
123
149
|
});
|
|
124
150
|
}
|
|
125
|
-
function
|
|
126
|
-
let t = r(), a =
|
|
151
|
+
function y({ vibeId: e }) {
|
|
152
|
+
let t = r(), o = a(), s = p.scheduledJobs, { workspaceId: c } = i(), { data: l, loading: u, error: f } = n({
|
|
127
153
|
variables: {
|
|
128
|
-
workspaceId:
|
|
154
|
+
workspaceId: c ?? "",
|
|
129
155
|
vibeId: e
|
|
130
156
|
},
|
|
131
|
-
skip: !
|
|
157
|
+
skip: !c,
|
|
132
158
|
fetchPolicy: "cache-and-network"
|
|
133
|
-
}),
|
|
159
|
+
}), m = (l?.scheduledJobs?.jobs ?? []).map((e) => ({
|
|
134
160
|
id: e.id,
|
|
135
161
|
label: e.name ?? e.id,
|
|
136
162
|
badge: String(e.status),
|
|
137
163
|
visibility: e.visibility
|
|
138
164
|
}));
|
|
139
|
-
return /* @__PURE__ */
|
|
140
|
-
labels:
|
|
141
|
-
loading:
|
|
142
|
-
hasData: !!
|
|
143
|
-
error:
|
|
144
|
-
rows:
|
|
145
|
-
|
|
165
|
+
return /* @__PURE__ */ d(_, {
|
|
166
|
+
labels: s,
|
|
167
|
+
loading: u,
|
|
168
|
+
hasData: !!l,
|
|
169
|
+
error: f,
|
|
170
|
+
rows: m,
|
|
171
|
+
onOpenPage: () => o(h.scheduledJobs),
|
|
172
|
+
emptyDescription: t("vibeDetails.linked.empty", `Link a ${s.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
|
|
146
173
|
});
|
|
147
174
|
}
|
|
148
|
-
function
|
|
149
|
-
let i = r(), a =
|
|
175
|
+
function b({ vibeId: t, kind: n }) {
|
|
176
|
+
let i = r(), o = a(), s = p[n], c = m.has(n), { data: l, loading: u, error: f } = e({
|
|
150
177
|
variables: { id: t },
|
|
151
|
-
skip: !
|
|
178
|
+
skip: !c,
|
|
152
179
|
fetchPolicy: "cache-and-network"
|
|
153
180
|
});
|
|
154
|
-
if (n === "sandboxes") return /* @__PURE__ */
|
|
155
|
-
if (n === "scheduledJobs") return /* @__PURE__ */
|
|
156
|
-
let
|
|
157
|
-
if (!
|
|
181
|
+
if (n === "sandboxes") return /* @__PURE__ */ d(v, { vibeId: t });
|
|
182
|
+
if (n === "scheduledJobs") return /* @__PURE__ */ d(y, { vibeId: t });
|
|
183
|
+
let g = l?.vibe?.linkedEntities ?? void 0, b = (() => {
|
|
184
|
+
if (!g) return [];
|
|
158
185
|
switch (n) {
|
|
159
|
-
case "vibedecks": return
|
|
186
|
+
case "vibedecks": return g.vibeDecks.map((e) => ({
|
|
160
187
|
id: e.id,
|
|
161
188
|
label: e.name,
|
|
162
189
|
badge: "Deck",
|
|
163
190
|
visibility: e.visibility
|
|
164
191
|
}));
|
|
165
|
-
case "actions": return
|
|
192
|
+
case "actions": return g.actions.map((e) => ({
|
|
166
193
|
id: e.id,
|
|
167
194
|
label: e.name,
|
|
168
195
|
badge: "Action",
|
|
169
196
|
visibility: e.visibility
|
|
170
197
|
}));
|
|
171
|
-
case "aiPrompts": return
|
|
198
|
+
case "aiPrompts": return g.aiPrompts.map((e) => ({
|
|
172
199
|
id: e.id,
|
|
173
200
|
label: e.name,
|
|
174
201
|
badge: String(e.category),
|
|
175
202
|
visibility: e.visibility
|
|
176
203
|
}));
|
|
177
|
-
case "aiContexts": return
|
|
204
|
+
case "aiContexts": return g.aiContexts.map((e) => ({
|
|
178
205
|
id: e.id,
|
|
179
206
|
label: e.name,
|
|
180
207
|
badge: String(e.type),
|
|
181
208
|
visibility: e.visibility
|
|
182
209
|
}));
|
|
183
|
-
case "instructionFiles": return
|
|
210
|
+
case "instructionFiles": return g.instructionFiles.map((e) => ({
|
|
184
211
|
id: e.id,
|
|
185
212
|
label: e.effectiveFilename,
|
|
186
213
|
badge: String(e.scope),
|
|
187
214
|
visibility: e.visibility
|
|
188
215
|
}));
|
|
189
|
-
case "tunnels": return
|
|
216
|
+
case "tunnels": return g.tunnels.map((e) => ({
|
|
190
217
|
id: e.id,
|
|
191
218
|
label: e.name,
|
|
192
219
|
badge: "Tunnel",
|
|
@@ -195,16 +222,17 @@ function _({ vibeId: t, kind: n }) {
|
|
|
195
222
|
default: return [];
|
|
196
223
|
}
|
|
197
224
|
})();
|
|
198
|
-
return /* @__PURE__ */
|
|
199
|
-
labels:
|
|
200
|
-
loading:
|
|
201
|
-
hasData: !!
|
|
202
|
-
error:
|
|
203
|
-
rows:
|
|
204
|
-
|
|
225
|
+
return /* @__PURE__ */ d(_, {
|
|
226
|
+
labels: s,
|
|
227
|
+
loading: u,
|
|
228
|
+
hasData: !!l,
|
|
229
|
+
error: f,
|
|
230
|
+
rows: b,
|
|
231
|
+
onOpenPage: () => o(h[n]),
|
|
232
|
+
emptyDescription: i("vibeDetails.linked.empty", `Link a ${s.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
|
|
205
233
|
});
|
|
206
234
|
}
|
|
207
235
|
//#endregion
|
|
208
|
-
export {
|
|
236
|
+
export { b as VibeLinkedEntitiesPanel };
|
|
209
237
|
|
|
210
238
|
//# sourceMappingURL=VibeLinkedEntitiesPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeLinkedEntitiesPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLinkedEntitiesPanel.tsx"],"sourcesContent":["import { Link2 } from 'lucide-react';\nimport { EmptyState, LoadingState, ErrorState } from '@/components/shared';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport {\n useGetVibeLinkedEntitiesQuery,\n useGetVibeLinkedSandboxesQuery,\n useGetVibeLinkedScheduledJobsQuery,\n type GetVibeLinkedEntitiesQuery,\n type GetVibeLinkedSandboxesQuery,\n type GetVibeLinkedScheduledJobsQuery,\n} from '@/generated/wspace-operations';\n\ntype LinkedSandbox = GetVibeLinkedSandboxesQuery['listSandboxes']['items'][number];\ntype LinkedScheduledJob = GetVibeLinkedScheduledJobsQuery['scheduledJobs']['jobs'][number];\n\ntype LinkedEntities = NonNullable<\n NonNullable<GetVibeLinkedEntitiesQuery['vibe']>['linkedEntities']\n>;\n\nexport type LinkedEntityKind =\n | 'vibedecks'\n | 'actions'\n | 'scheduledJobs'\n | 'sandboxes'\n | 'aiPrompts'\n | 'aiContexts'\n | 'instructionFiles'\n | 'tunnels';\n\ninterface VibeLinkedEntitiesPanelProps {\n vibeId: string;\n kind: LinkedEntityKind;\n}\n\nconst KIND_LABELS: Record<LinkedEntityKind, { singular: string; plural: string }> = {\n vibedecks: { singular: 'Vibe Deck', plural: 'Vibe Decks' },\n actions: { singular: 'Action', plural: 'Actions' },\n scheduledJobs: { singular: 'Scheduled Job', plural: 'Scheduled Jobs' },\n sandboxes: { singular: 'Sandbox', plural: 'Sandboxes' },\n aiPrompts: { singular: 'AI Prompt', plural: 'AI Prompts' },\n aiContexts: { singular: 'AI Context', plural: 'AI Contexts' },\n instructionFiles: { singular: 'Instruction File', plural: 'Instruction Files' },\n tunnels: { singular: 'Tunnel', plural: 'Tunnels' },\n};\n\n// Kinds backed by Vibe.linkedEntities on wspace-vibecontrols-svc. scheduledJobs +\n// sandboxes live in other subgraphs and are rendered by the dedicated\n// sub-panels below (listSandboxes / scheduledJobs filtered by vibeId).\nconst LOCAL_KINDS = new Set<LinkedEntityKind>([\n 'vibedecks',\n 'actions',\n 'aiPrompts',\n 'aiContexts',\n 'instructionFiles',\n 'tunnels',\n]);\n\ninterface LinkedRow {\n id: string;\n label: string;\n badge: string;\n visibility: string;\n}\n\nfunction visibilityLabel(visibility: string): string {\n return visibility === 'SHARED_WITH_VIBE' ? 'Shared' : 'Private';\n}\n\n/**\n * Shared presentational shell for a list of linked rows: handles loading,\n * error, empty, and the populated list. Keeps the three data sources\n * (linkedEntities, sandboxes, scheduledJobs) rendering identically.\n */\nfunction LinkedRowsView({\n labels,\n loading,\n hasData,\n error,\n rows,\n emptyDescription,\n}: {\n labels: { singular: string; plural: string };\n loading: boolean;\n hasData: boolean;\n error?: { message: string };\n rows: LinkedRow[];\n emptyDescription: string;\n}) {\n if (loading && !hasData) {\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-6\">\n <LoadingState message={`Loading ${labels.plural.toLowerCase()}…`} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-6\">\n <ErrorState\n title={`Failed to load ${labels.plural.toLowerCase()}`}\n message={error.message}\n />\n </div>\n );\n }\n\n if (rows.length === 0) {\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-6\">\n <EmptyState\n icon={<Link2 size={48} className=\"text-text-secondary\" />}\n title={`No ${labels.plural.toLowerCase()} linked yet`}\n description={emptyDescription}\n />\n </div>\n );\n }\n\n return (\n <div\n className=\"rounded-lg border border-border-default bg-bg-surface\"\n data-testid=\"vibe-linked-entities\"\n >\n <ul className=\"divide-y divide-border-default\">\n {rows.map((row) => (\n <li key={row.id} className=\"flex items-center justify-between gap-3 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{row.label}</span>\n <span className=\"flex-shrink-0 rounded bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {row.badge}\n </span>\n </div>\n <span\n className={`flex-shrink-0 rounded px-2 py-0.5 text-xs ${\n row.visibility === 'SHARED_WITH_VIBE'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-tertiary'\n }`}\n >\n {visibilityLabel(row.visibility)}\n </span>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\n/** Sandboxes linked to the vibe — fetched from the sandbox subgraph. */\nfunction VibeLinkedSandboxes({ vibeId }: { vibeId: string }) {\n const tr = useTr();\n const labels = KIND_LABELS.sandboxes;\n const { workspaceId, projectId } = useVibeControls();\n\n const { data, loading, error } = useGetVibeLinkedSandboxesQuery({\n variables: {\n context: { workspaceId: workspaceId ?? undefined, projectId: projectId ?? undefined },\n vibeId,\n },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const rows: LinkedRow[] = (data?.listSandboxes?.items ?? []).map((s: LinkedSandbox) => ({\n id: s.id,\n label: s.name,\n badge: String(s.status),\n visibility: s.visibility,\n }));\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n\n/** Scheduled jobs linked to the vibe — fetched from the scheduler subgraph. */\nfunction VibeLinkedScheduledJobs({ vibeId }: { vibeId: string }) {\n const tr = useTr();\n const labels = KIND_LABELS.scheduledJobs;\n const { workspaceId } = useVibeControls();\n\n const { data, loading, error } = useGetVibeLinkedScheduledJobsQuery({\n variables: { workspaceId: workspaceId ?? '', vibeId },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const rows: LinkedRow[] = (data?.scheduledJobs?.jobs ?? []).map((j: LinkedScheduledJob) => ({\n id: j.id,\n label: j.name ?? j.id,\n badge: String(j.status),\n visibility: j.visibility,\n }));\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n\n/**\n * Renders the entities linked to a vibe (visibility-filtered server-side) for a\n * given kind. Local kinds come from `Vibe.linkedEntities`; sandboxes +\n * scheduledJobs are fetched from their own subgraphs via dedicated vibeId\n * filters. SHARED_WITH_VIBE entities are visible to every member with access to\n * the vibe; PRIVATE only to their owner.\n */\nexport function VibeLinkedEntitiesPanel({ vibeId, kind }: VibeLinkedEntitiesPanelProps) {\n const tr = useTr();\n const labels = KIND_LABELS[kind];\n const isLocal = LOCAL_KINDS.has(kind);\n\n const { data, loading, error } = useGetVibeLinkedEntitiesQuery({\n variables: { id: vibeId },\n skip: !isLocal,\n fetchPolicy: 'cache-and-network',\n });\n\n if (kind === 'sandboxes') {\n return <VibeLinkedSandboxes vibeId={vibeId} />;\n }\n if (kind === 'scheduledJobs') {\n return <VibeLinkedScheduledJobs vibeId={vibeId} />;\n }\n\n const linked: LinkedEntities | undefined = data?.vibe?.linkedEntities ?? undefined;\n const rows: LinkedRow[] = (() => {\n if (!linked) return [];\n switch (kind) {\n case 'vibedecks':\n return linked.vibeDecks.map((d) => ({\n id: d.id,\n label: d.name,\n badge: 'Deck',\n visibility: d.visibility,\n }));\n case 'actions':\n return linked.actions.map((a) => ({\n id: a.id,\n label: a.name,\n badge: 'Action',\n visibility: a.visibility,\n }));\n case 'aiPrompts':\n return linked.aiPrompts.map((p) => ({\n id: p.id,\n label: p.name,\n badge: String(p.category),\n visibility: p.visibility,\n }));\n case 'aiContexts':\n return linked.aiContexts.map((c) => ({\n id: c.id,\n label: c.name,\n badge: String(c.type),\n visibility: c.visibility,\n }));\n case 'instructionFiles':\n return linked.instructionFiles.map((f) => ({\n id: f.id,\n label: f.effectiveFilename,\n badge: String(f.scope),\n visibility: f.visibility,\n }));\n case 'tunnels':\n return linked.tunnels.map((t) => ({\n id: t.id,\n label: t.name,\n badge: 'Tunnel',\n visibility: t.visibility,\n }));\n default:\n return [];\n }\n })();\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeLinkedEntitiesPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLinkedEntitiesPanel.tsx"],"sourcesContent":["import { Link2, ArrowUpRight } from 'lucide-react';\nimport { EmptyState, LoadingState, ErrorState } from '@/components/shared';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport {\n useGetVibeLinkedEntitiesQuery,\n useGetVibeLinkedSandboxesQuery,\n useGetVibeLinkedScheduledJobsQuery,\n type GetVibeLinkedEntitiesQuery,\n type GetVibeLinkedSandboxesQuery,\n type GetVibeLinkedScheduledJobsQuery,\n} from '@/generated/wspace-operations';\n\ntype LinkedSandbox = GetVibeLinkedSandboxesQuery['listSandboxes']['items'][number];\ntype LinkedScheduledJob = GetVibeLinkedScheduledJobsQuery['scheduledJobs']['jobs'][number];\n\ntype LinkedEntities = NonNullable<\n NonNullable<GetVibeLinkedEntitiesQuery['vibe']>['linkedEntities']\n>;\n\nexport type LinkedEntityKind =\n | 'vibedecks'\n | 'actions'\n | 'scheduledJobs'\n | 'sandboxes'\n | 'aiPrompts'\n | 'aiContexts'\n | 'instructionFiles'\n | 'tunnels';\n\ninterface VibeLinkedEntitiesPanelProps {\n vibeId: string;\n kind: LinkedEntityKind;\n}\n\nconst KIND_LABELS: Record<LinkedEntityKind, { singular: string; plural: string }> = {\n vibedecks: { singular: 'Vibe Deck', plural: 'Vibe Decks' },\n actions: { singular: 'Action', plural: 'Actions' },\n scheduledJobs: { singular: 'Scheduled Job', plural: 'Scheduled Jobs' },\n sandboxes: { singular: 'Sandbox', plural: 'Sandboxes' },\n aiPrompts: { singular: 'AI Prompt', plural: 'AI Prompts' },\n aiContexts: { singular: 'AI Context', plural: 'AI Contexts' },\n instructionFiles: { singular: 'Instruction File', plural: 'Instruction Files' },\n tunnels: { singular: 'Tunnel', plural: 'Tunnels' },\n};\n\n// Kinds backed by Vibe.linkedEntities on wspace-vibecontrols-svc. scheduledJobs +\n// sandboxes live in other subgraphs and are rendered by the dedicated\n// sub-panels below (listSandboxes / scheduledJobs filtered by vibeId).\nconst LOCAL_KINDS = new Set<LinkedEntityKind>([\n 'vibedecks',\n 'actions',\n 'aiPrompts',\n 'aiContexts',\n 'instructionFiles',\n 'tunnels',\n]);\n\n// In-app destination for each linked-entity kind's main management page. Lets\n// users jump straight from a vibe's linked-entity tab to the full entity surface\n// without hunting through the side navigation. All paths are relative to the\n// vibecontrols basePath and go through useVibeNavigate (which prepends it) —\n// EXCEPT `sandboxes`, which is served by a sibling host-shell MFE mounted at the\n// app-absolute `/sandbox` route and must be navigated via the host shell (see\n// VibeLinkedSandboxes below).\nconst KIND_ROUTES: Record<LinkedEntityKind, string> = {\n vibedecks: '/vibedeck',\n actions: '/actions',\n scheduledJobs: '/calendar',\n sandboxes: '/sandbox',\n aiPrompts: '/ai-tools/ai/prompts',\n aiContexts: '/ai-tools/ai/contexts',\n instructionFiles: '/ai-tools/ai/instructions',\n tunnels: '/tunnels',\n};\n\ninterface LinkedRow {\n id: string;\n label: string;\n badge: string;\n visibility: string;\n}\n\nfunction visibilityLabel(visibility: string): string {\n return visibility === 'SHARED_WITH_VIBE' ? 'Shared' : 'Private';\n}\n\n/**\n * Shared presentational shell for a list of linked rows: handles loading,\n * error, empty, and the populated list. Keeps the three data sources\n * (linkedEntities, sandboxes, scheduledJobs) rendering identically.\n */\nfunction LinkedRowsView({\n labels,\n loading,\n hasData,\n error,\n rows,\n emptyDescription,\n onOpenPage,\n}: {\n labels: { singular: string; plural: string };\n loading: boolean;\n hasData: boolean;\n error?: { message: string };\n rows: LinkedRow[];\n emptyDescription: string;\n /** Navigate to this kind's full management page (Part 1 deep-link). */\n onOpenPage?: () => void;\n}) {\n const tr = useTr();\n\n const body = (() => {\n if (loading && !hasData) {\n return (\n <div className=\"p-6\">\n <LoadingState message={`Loading ${labels.plural.toLowerCase()}…`} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"p-6\">\n <ErrorState\n title={`Failed to load ${labels.plural.toLowerCase()}`}\n message={error.message}\n />\n </div>\n );\n }\n\n if (rows.length === 0) {\n return (\n <div className=\"p-6\">\n <EmptyState\n icon={<Link2 size={48} className=\"text-text-secondary\" />}\n title={`No ${labels.plural.toLowerCase()} linked yet`}\n description={emptyDescription}\n />\n </div>\n );\n }\n\n return (\n <ul className=\"divide-y divide-border-default\" data-testid=\"vibe-linked-entities\">\n {rows.map((row) => (\n <li key={row.id} className=\"flex items-center justify-between gap-3 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{row.label}</span>\n <span className=\"flex-shrink-0 rounded bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {row.badge}\n </span>\n </div>\n <span\n className={`flex-shrink-0 rounded px-2 py-0.5 text-xs ${\n row.visibility === 'SHARED_WITH_VIBE'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-tertiary'\n }`}\n >\n {visibilityLabel(row.visibility)}\n </span>\n </li>\n ))}\n </ul>\n );\n })();\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface\">\n <div className=\"flex items-center justify-between gap-3 border-b border-border-default px-4 py-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">{labels.plural}</h3>\n {onOpenPage && (\n <button\n type=\"button\"\n onClick={onOpenPage}\n data-testid=\"vibe-linked-open-page\"\n className=\"inline-flex flex-shrink-0 items-center gap-1.5 rounded-md border border-border-default px-2.5 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-bg-elevated\"\n title={tr('vibeDetails.linked.openPageTitle', `Open the ${labels.plural} page`)}\n >\n {tr('vibeDetails.linked.openPage', `Open ${labels.plural} page`)}\n <ArrowUpRight size={14} />\n </button>\n )}\n </div>\n {body}\n </div>\n );\n}\n\n/** Sandboxes linked to the vibe — fetched from the sandbox subgraph. */\nfunction VibeLinkedSandboxes({ vibeId }: { vibeId: string }) {\n const tr = useTr();\n const navigate = useVibeNavigate();\n const labels = KIND_LABELS.sandboxes;\n const { workspaceId, projectId, navigate: shellNavigate } = useVibeControls();\n\n // Sandboxes mount at the app-absolute `/sandbox` route, OUTSIDE the\n // vibecontrols basePath. Use the host shell navigate directly so we don't get\n // basePath-prefixed into a dead end; fall back to the in-MFE navigate when\n // running standalone (no shell, basePath empty → path passes through as-is).\n const openSandboxes = () => {\n if (shellNavigate) shellNavigate(KIND_ROUTES.sandboxes);\n else navigate(KIND_ROUTES.sandboxes);\n };\n\n const { data, loading, error } = useGetVibeLinkedSandboxesQuery({\n variables: {\n context: { workspaceId: workspaceId ?? undefined, projectId: projectId ?? undefined },\n vibeId,\n },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const rows: LinkedRow[] = (data?.listSandboxes?.items ?? []).map((s: LinkedSandbox) => ({\n id: s.id,\n label: s.name,\n badge: String(s.status),\n visibility: s.visibility,\n }));\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n onOpenPage={openSandboxes}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n\n/** Scheduled jobs linked to the vibe — fetched from the scheduler subgraph. */\nfunction VibeLinkedScheduledJobs({ vibeId }: { vibeId: string }) {\n const tr = useTr();\n const navigate = useVibeNavigate();\n const labels = KIND_LABELS.scheduledJobs;\n const { workspaceId } = useVibeControls();\n\n const { data, loading, error } = useGetVibeLinkedScheduledJobsQuery({\n variables: { workspaceId: workspaceId ?? '', vibeId },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const rows: LinkedRow[] = (data?.scheduledJobs?.jobs ?? []).map((j: LinkedScheduledJob) => ({\n id: j.id,\n label: j.name ?? j.id,\n badge: String(j.status),\n visibility: j.visibility,\n }));\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n onOpenPage={() => navigate(KIND_ROUTES.scheduledJobs)}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n\n/**\n * Renders the entities linked to a vibe (visibility-filtered server-side) for a\n * given kind. Local kinds come from `Vibe.linkedEntities`; sandboxes +\n * scheduledJobs are fetched from their own subgraphs via dedicated vibeId\n * filters. SHARED_WITH_VIBE entities are visible to every member with access to\n * the vibe; PRIVATE only to their owner.\n */\nexport function VibeLinkedEntitiesPanel({ vibeId, kind }: VibeLinkedEntitiesPanelProps) {\n const tr = useTr();\n const navigate = useVibeNavigate();\n const labels = KIND_LABELS[kind];\n const isLocal = LOCAL_KINDS.has(kind);\n\n const { data, loading, error } = useGetVibeLinkedEntitiesQuery({\n variables: { id: vibeId },\n skip: !isLocal,\n fetchPolicy: 'cache-and-network',\n });\n\n if (kind === 'sandboxes') {\n return <VibeLinkedSandboxes vibeId={vibeId} />;\n }\n if (kind === 'scheduledJobs') {\n return <VibeLinkedScheduledJobs vibeId={vibeId} />;\n }\n\n const linked: LinkedEntities | undefined = data?.vibe?.linkedEntities ?? undefined;\n const rows: LinkedRow[] = (() => {\n if (!linked) return [];\n switch (kind) {\n case 'vibedecks':\n return linked.vibeDecks.map((d) => ({\n id: d.id,\n label: d.name,\n badge: 'Deck',\n visibility: d.visibility,\n }));\n case 'actions':\n return linked.actions.map((a) => ({\n id: a.id,\n label: a.name,\n badge: 'Action',\n visibility: a.visibility,\n }));\n case 'aiPrompts':\n return linked.aiPrompts.map((p) => ({\n id: p.id,\n label: p.name,\n badge: String(p.category),\n visibility: p.visibility,\n }));\n case 'aiContexts':\n return linked.aiContexts.map((c) => ({\n id: c.id,\n label: c.name,\n badge: String(c.type),\n visibility: c.visibility,\n }));\n case 'instructionFiles':\n return linked.instructionFiles.map((f) => ({\n id: f.id,\n label: f.effectiveFilename,\n badge: String(f.scope),\n visibility: f.visibility,\n }));\n case 'tunnels':\n return linked.tunnels.map((t) => ({\n id: t.id,\n label: t.name,\n badge: 'Tunnel',\n visibility: t.visibility,\n }));\n default:\n return [];\n }\n })();\n\n return (\n <LinkedRowsView\n labels={labels}\n loading={loading}\n hasData={!!data}\n error={error}\n rows={rows}\n onOpenPage={() => navigate(KIND_ROUTES[kind])}\n emptyDescription={tr(\n 'vibeDetails.linked.empty',\n `Link a ${labels.singular.toLowerCase()} to this vibe and set it to \"Shared with vibe\" to make it visible to everyone with access.`\n )}\n />\n );\n}\n"],"mappings":"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"}
|