@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.
Files changed (33) hide show
  1. package/dist/components/actions/ActionCard.js +87 -74
  2. package/dist/components/actions/ActionCard.js.map +1 -1
  3. package/dist/components/ai/InstructionFilesManager.js +149 -141
  4. package/dist/components/ai/InstructionFilesManager.js.map +1 -1
  5. package/dist/components/sessions/SessionShareDialog.js +24 -462
  6. package/dist/components/sessions/SessionShareDialog.js.map +1 -1
  7. package/dist/components/shared/EntityVibeLinkControl.js +204 -0
  8. package/dist/components/shared/EntityVibeLinkControl.js.map +1 -0
  9. package/dist/components/shared/index.js +1 -0
  10. package/dist/components/sharing/entityShareOps.js +106 -0
  11. package/dist/components/sharing/entityShareOps.js.map +1 -1
  12. package/dist/components/sharing/shareRegistry.js +3 -3
  13. package/dist/components/sharing/shareRegistry.js.map +1 -1
  14. package/dist/components/tunnels/TunnelCard.js +51 -43
  15. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  16. package/dist/components/vibe/VibeLinkedEntitiesPanel.js +117 -89
  17. package/dist/components/vibe/VibeLinkedEntitiesPanel.js.map +1 -1
  18. package/dist/components/vibedeck/VibeDeckShareDialog.js +19 -335
  19. package/dist/components/vibedeck/VibeDeckShareDialog.js.map +1 -1
  20. package/dist/constants/permissions.js +1 -0
  21. package/dist/constants/permissions.js.map +1 -1
  22. package/dist/generated/wspace-operations.js +1618 -1593
  23. package/dist/generated/wspace-operations.js.map +1 -1
  24. package/dist/generated/wspace-types.js +10 -10
  25. package/dist/generated/wspace-types.js.map +1 -1
  26. package/dist/index.js +10 -10
  27. package/dist/pages/SessionsPage.js +1011 -1007
  28. package/dist/pages/SessionsPage.js.map +1 -1
  29. package/dist/pages/VibeDeckPage.js +218 -210
  30. package/dist/pages/VibeDeckPage.js.map +1 -1
  31. package/package.json +1 -1
  32. package/dist/utils/shareUrl.js +0 -41
  33. 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 { TunnelStatusBadge as n } from "./TunnelStatusBadge.js";
4
- import { ProviderBadge as r } from "./ProviderBadge.js";
5
- import { ExternalLink as i, Loader2 as a, Play as o, Square as s, Trash2 as c } from "lucide-react";
6
- import { motion as l } from "framer-motion";
7
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
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 f({ tunnel: f, isPending: p = !1, onOpen: m, onStart: h, onStop: g, onDelete: _ }) {
10
- let v = e(), y = !p && f.status !== t.Active && f.status !== t.Provisioning, b = !p && f.status === t.Active, x = f.primaryDomain?.hostname, S = x ? `${f.protocol.toLowerCase() === "tcp" ? "tcp" : "https"}://${x}` : null;
11
- return /* @__PURE__ */ d(l.div, {
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__ */ d("div", {
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__ */ d("button", {
24
+ children: [/* @__PURE__ */ p("button", {
24
25
  type: "button",
25
- onClick: () => m(f.id),
26
+ onClick: () => g(m.id),
26
27
  className: "flex-1 text-left min-w-0",
27
28
  children: [
28
- /* @__PURE__ */ d("div", {
29
+ /* @__PURE__ */ p("div", {
29
30
  className: "flex flex-wrap items-center gap-2 mb-1",
30
31
  children: [
31
- /* @__PURE__ */ u("h3", {
32
+ /* @__PURE__ */ f("h3", {
32
33
  className: "text-base font-semibold text-text-primary truncate",
33
- children: f.name
34
+ children: m.name
34
35
  }),
35
- /* @__PURE__ */ u(n, { status: f.status }),
36
- /* @__PURE__ */ u(r, { providerKey: f.providerKey })
36
+ /* @__PURE__ */ f(i, { status: m.status }),
37
+ /* @__PURE__ */ f(a, { providerKey: m.providerKey })
37
38
  ]
38
39
  }),
39
- S ? /* @__PURE__ */ u("p", {
40
+ w ? /* @__PURE__ */ f("p", {
40
41
  className: "text-sm text-text-secondary truncate",
41
- children: S
42
- }) : /* @__PURE__ */ u("p", {
42
+ children: w
43
+ }) : /* @__PURE__ */ f("p", {
43
44
  className: "text-sm text-text-muted",
44
- children: v("vibecontrols.tunnels.noDomain", "No domain attached")
45
+ children: b("vibecontrols.tunnels.noDomain", "No domain attached")
45
46
  }),
46
- /* @__PURE__ */ d("p", {
47
+ /* @__PURE__ */ p("p", {
47
48
  className: "text-xs text-text-muted mt-1",
48
49
  children: [
49
- f.protocol,
50
+ m.protocol,
50
51
  ":",
51
- f.localPort,
52
+ m.localPort,
52
53
  " on ",
53
- f.localHost
54
+ m.localHost
54
55
  ]
55
56
  })
56
57
  ]
57
- }), /* @__PURE__ */ d("div", {
58
+ }), /* @__PURE__ */ p("div", {
58
59
  className: "flex items-center gap-2 flex-shrink-0 flex-wrap",
59
60
  children: [
60
- S && /* @__PURE__ */ d("a", {
61
- href: S,
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__ */ u(i, { className: "size-3.5 mr-1" }), v("vibecontrols.tunnels.open", "Open")]
67
+ children: [/* @__PURE__ */ f(o, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.open", "Open")]
67
68
  }),
68
- p && /* @__PURE__ */ d("span", {
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__ */ u(a, { className: "size-3.5 mr-1 animate-spin" }), f.status === "ACTIVE" ? v("vibecontrols.tunnels.stopping", "Stopping…") : v("vibecontrols.tunnels.starting", "Starting…")]
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
- y && /* @__PURE__ */ d("button", {
73
+ x && /* @__PURE__ */ p("button", {
73
74
  type: "button",
74
- onClick: () => h(f.id),
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__ */ u(o, { className: "size-3.5 mr-1" }), v("vibecontrols.tunnels.start", "Start")]
77
+ children: [/* @__PURE__ */ f(c, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.start", "Start")]
77
78
  }),
78
- b && /* @__PURE__ */ d("button", {
79
+ S && /* @__PURE__ */ p("button", {
79
80
  type: "button",
80
- onClick: () => g(f.id),
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__ */ u(s, { className: "size-3.5 mr-1" }), v("vibecontrols.tunnels.stop", "Stop")]
83
+ children: [/* @__PURE__ */ f(l, { className: "size-3.5 mr-1" }), b("vibecontrols.tunnels.stop", "Stop")]
83
84
  }),
84
- /* @__PURE__ */ u("button", {
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: () => _(f.id, f.name),
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(c, { className: "size-3.5" })
97
+ children: /* @__PURE__ */ f(u, { className: "size-3.5" })
90
98
  })
91
99
  ]
92
100
  })]
93
- }), f.lastError && /* @__PURE__ */ u("div", {
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: f.lastError
103
+ children: m.lastError
96
104
  })]
97
105
  });
98
106
  }
99
107
  //#endregion
100
- export { f as TunnelCard };
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":";;;;;;;;AAoBA,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,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
+ {"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 a } from "../shared/LoadingState.js";
5
- import { ErrorState as o } from "../shared/ErrorState.js";
6
- import { EmptyState as s } from "../shared/EmptyState.js";
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 c } from "lucide-react";
9
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
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 d = {
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
- }, f = new Set([
44
+ }, m = new Set([
45
45
  "vibedecks",
46
46
  "actions",
47
47
  "aiPrompts",
48
48
  "aiContexts",
49
49
  "instructionFiles",
50
50
  "tunnels"
51
- ]);
52
- function p(e) {
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 m({ labels: e, loading: t, hasData: n, error: r, rows: i, emptyDescription: d }) {
56
- return t && !n ? /* @__PURE__ */ l("div", {
57
- className: "rounded-lg border border-border-default bg-bg-surface p-6",
58
- children: /* @__PURE__ */ l(a, { message: `Loading ${e.plural.toLowerCase()}…` })
59
- }) : r ? /* @__PURE__ */ l("div", {
60
- className: "rounded-lg border border-border-default bg-bg-surface p-6",
61
- children: /* @__PURE__ */ l(o, {
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: r.message
72
+ message: i.message
64
73
  })
65
- }) : i.length === 0 ? /* @__PURE__ */ l("div", {
66
- className: "rounded-lg border border-border-default bg-bg-surface p-6",
67
- children: /* @__PURE__ */ l(s, {
68
- icon: /* @__PURE__ */ l(c, {
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: d
82
+ description: p
74
83
  })
75
- }) : /* @__PURE__ */ l("div", {
76
- className: "rounded-lg border border-border-default bg-bg-surface",
84
+ }) : /* @__PURE__ */ d("ul", {
85
+ className: "divide-y divide-border-default",
77
86
  "data-testid": "vibe-linked-entities",
78
- children: /* @__PURE__ */ l("ul", {
79
- className: "divide-y divide-border-default",
80
- children: i.map((e) => /* @__PURE__ */ u("li", {
81
- className: "flex items-center justify-between gap-3 px-4 py-3",
82
- children: [/* @__PURE__ */ u("div", {
83
- className: "flex min-w-0 items-center gap-2",
84
- children: [/* @__PURE__ */ l("span", {
85
- className: "truncate text-sm font-medium text-text-primary",
86
- children: e.label
87
- }), /* @__PURE__ */ l("span", {
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
- }, e.id))
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 h({ vibeId: e }) {
100
- let n = r(), a = d.sandboxes, { workspaceId: o, projectId: s } = i(), { data: c, loading: u, error: f } = t({
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: o ?? void 0,
104
- projectId: s ?? void 0
128
+ workspaceId: c ?? void 0,
129
+ projectId: l ?? void 0
105
130
  },
106
131
  vibeId: e
107
132
  },
108
- skip: !o,
133
+ skip: !c,
109
134
  fetchPolicy: "cache-and-network"
110
- }), p = (c?.listSandboxes?.items ?? []).map((e) => ({
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__ */ l(m, {
117
- labels: a,
118
- loading: u,
119
- hasData: !!c,
120
- error: f,
121
- rows: p,
122
- emptyDescription: n("vibeDetails.linked.empty", `Link a ${a.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
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 g({ vibeId: e }) {
126
- let t = r(), a = d.scheduledJobs, { workspaceId: o } = i(), { data: s, loading: c, error: u } = n({
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: o ?? "",
154
+ workspaceId: c ?? "",
129
155
  vibeId: e
130
156
  },
131
- skip: !o,
157
+ skip: !c,
132
158
  fetchPolicy: "cache-and-network"
133
- }), f = (s?.scheduledJobs?.jobs ?? []).map((e) => ({
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__ */ l(m, {
140
- labels: a,
141
- loading: c,
142
- hasData: !!s,
143
- error: u,
144
- rows: f,
145
- emptyDescription: t("vibeDetails.linked.empty", `Link a ${a.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
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 _({ vibeId: t, kind: n }) {
149
- let i = r(), a = d[n], o = f.has(n), { data: s, loading: c, error: u } = e({
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: !o,
178
+ skip: !c,
152
179
  fetchPolicy: "cache-and-network"
153
180
  });
154
- if (n === "sandboxes") return /* @__PURE__ */ l(h, { vibeId: t });
155
- if (n === "scheduledJobs") return /* @__PURE__ */ l(g, { vibeId: t });
156
- let p = s?.vibe?.linkedEntities ?? void 0, _ = (() => {
157
- if (!p) return [];
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 p.vibeDecks.map((e) => ({
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 p.actions.map((e) => ({
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 p.aiPrompts.map((e) => ({
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 p.aiContexts.map((e) => ({
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 p.instructionFiles.map((e) => ({
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 p.tunnels.map((e) => ({
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__ */ l(m, {
199
- labels: a,
200
- loading: c,
201
- hasData: !!s,
202
- error: u,
203
- rows: _,
204
- emptyDescription: i("vibeDetails.linked.empty", `Link a ${a.singular.toLowerCase()} to this vibe and set it to "Shared with vibe" to make it visible to everyone with access.`)
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 { _ as VibeLinkedEntitiesPanel };
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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"}