@burdenoff/microfe-vibecontrols 2026.613.1 → 2026.618.1

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 (62) hide show
  1. package/dist/components/agents/AgentConnectionRecovery.js +100 -94
  2. package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
  3. package/dist/components/agents/AgentMaintenanceTab.js +177 -160
  4. package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
  5. package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
  6. package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
  7. package/dist/components/assistant/AssistantChatArea.js +1 -0
  8. package/dist/components/assistant/AssistantChatArea.js.map +1 -1
  9. package/dist/components/assistant/AssistantModeSelector.js +20 -19
  10. package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
  11. package/dist/components/tunnels/TunnelCard.js +3 -3
  12. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  13. package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
  14. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  15. package/dist/config/assistantUsecases.js +11 -0
  16. package/dist/config/assistantUsecases.js.map +1 -1
  17. package/dist/constants/permissions.js +38 -6
  18. package/dist/constants/permissions.js.map +1 -1
  19. package/dist/index.js +4 -3
  20. package/dist/pages/CatalogDetailPage.js +155 -155
  21. package/dist/pages/CatalogDetailPage.js.map +1 -1
  22. package/dist/pages/CatalogPage.js +110 -109
  23. package/dist/pages/CatalogPage.js.map +1 -1
  24. package/dist/pages/ComponentDetailPage.js +338 -338
  25. package/dist/pages/ComponentDetailPage.js.map +1 -1
  26. package/dist/pages/ComponentsPage.js +104 -103
  27. package/dist/pages/ComponentsPage.js.map +1 -1
  28. package/dist/pages/TargetDetailsPage.js +140 -132
  29. package/dist/pages/TargetDetailsPage.js.map +1 -1
  30. package/dist/pages/TemplateDetailPage.js +201 -199
  31. package/dist/pages/TemplateDetailPage.js.map +1 -1
  32. package/dist/pages/TemplatesPage.js +62 -61
  33. package/dist/pages/TemplatesPage.js.map +1 -1
  34. package/dist/pages/VibeDetailsPage.js +568 -555
  35. package/dist/pages/VibeDetailsPage.js.map +1 -1
  36. package/dist/pages/ai/AIBookmarksPage.js +104 -89
  37. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  38. package/dist/pages/ai/AIPage.js +116 -107
  39. package/dist/pages/ai/AIPage.js.map +1 -1
  40. package/dist/pages/ai/AISessionDetailPage.js +46 -34
  41. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  42. package/dist/pages/ai/AgentManagerPage.js +112 -100
  43. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  44. package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
  45. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  46. package/dist/pages/tunnels/TunnelsTab.js +119 -111
  47. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  48. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
  49. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  50. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
  51. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  52. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
  53. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  54. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
  55. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  56. package/dist/services/assistantApi.js +9 -3
  57. package/dist/services/assistantApi.js.map +1 -1
  58. package/dist/services/createSandboxAssistantTransport.js +120 -0
  59. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  60. package/dist/store/assistantStore.js +1 -1
  61. package/dist/store/assistantStore.js.map +1 -1
  62. package/package.json +5 -1
@@ -2,33 +2,33 @@ import { useCreateCatalogMutation as e, useListCatalogsQuery as t } from "../gen
2
2
  import { QuotaExhaustedDialog as n } from "../components/shared/QuotaExhaustedDialog.js";
3
3
  import { isQuotaExhaustedError as r } from "../utils/quotaUtils.js";
4
4
  import { useVibeNavigate as i } from "../providers/VibeControlsProvider.js";
5
- import { PageHeader as a } from "../components/shared/PageHeader.js";
6
- import { ErrorState as ee } from "../components/shared/ErrorState.js";
7
- import { EntityTagPicker as o } from "../components/shared/EntityTagPicker.js";
8
- import { useDraftEntityTags as te } from "../hooks/useDraftEntityTags.js";
9
- import { EmptyState as s } from "../components/shared/EmptyState.js";
10
- import { SearchInput as c } from "../components/shared/SearchInput.js";
11
- import { FilterDropdown as l } from "../components/shared/FilterDropdown.js";
12
- import { GetHelpButton as u } from "../components/shared/GetHelpButton.js";
5
+ import { PageHeader as ee } from "../components/shared/PageHeader.js";
6
+ import { ErrorState as te } from "../components/shared/ErrorState.js";
7
+ import { EntityTagPicker as a } from "../components/shared/EntityTagPicker.js";
8
+ import { useDraftEntityTags as ne } from "../hooks/useDraftEntityTags.js";
9
+ import { EmptyState as re } from "../components/shared/EmptyState.js";
10
+ import { SearchInput as o } from "../components/shared/SearchInput.js";
11
+ import { FilterDropdown as s } from "../components/shared/FilterDropdown.js";
12
+ import { GetHelpButton as c } from "../components/shared/GetHelpButton.js";
13
13
  import "../components/shared/index.js";
14
- import { VIBE_PERMISSIONS as d } from "../constants/permissions.js";
15
- import { PageSkeleton as f } from "../components/shared/PageSkeleton.js";
16
- import { CatalogCard as p } from "../components/catalog/CatalogCard.js";
17
- import { CatalogForm as m } from "../components/catalog/CatalogForm.js";
14
+ import { VIBE_PERMISSIONS as l } from "../constants/permissions.js";
15
+ import { PageSkeleton as u } from "../components/shared/PageSkeleton.js";
16
+ import { CatalogCard as ie } from "../components/catalog/CatalogCard.js";
17
+ import { CatalogForm as ae } from "../components/catalog/CatalogForm.js";
18
18
  import "../components/catalog/index.js";
19
- import { useCallback as h, useEffect as g, useState as _ } from "react";
20
- import { useI18n as ne } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
21
- import { BookOpen as re, Plus as v, RefreshCw as ie } from "lucide-react";
22
- import { usePermissions as y } from "@burdenoff/fe-libs/shared/providers/shell";
23
- import { AnimatePresence as b } from "framer-motion";
24
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
25
- import { MotionItem as C, MotionList as w, MotionPage as T } from "@burdenoff/fe-libs/shared/motion";
19
+ import { useCallback as d, useEffect as f, useState as p } from "react";
20
+ import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
21
+ import { BookOpen as h, Plus as g, RefreshCw as oe } from "lucide-react";
22
+ import { usePermissions as se } from "@burdenoff/fe-libs/shared/providers/shell";
23
+ import { AnimatePresence as ce } from "framer-motion";
24
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
25
+ import { MotionItem as y, MotionList as b, MotionPage as x } from "@burdenoff/fe-libs/shared/motion";
26
26
  //#region src/pages/CatalogPage.tsx
27
- function E() {
28
- let E = i(), { t: D } = ne(), { hasPermission: ae, isLoading: oe } = y(), O = h((e, t, n) => {
29
- let r = D(e, n), i = r === e ? t : r;
27
+ function S() {
28
+ let S = i(), { t: C } = m(), { hasPermission: w, isLoading: T } = se(), E = w(l.CATALOG_CREATE), D = w(l.CATALOG_READ), O = d((e, t, n) => {
29
+ let r = C(e, n), i = r === e ? t : r;
30
30
  return n ? Object.entries(n).reduce((e, [t, n]) => e.replace(`{{${t}}}`, String(n)), i) : i;
31
- }, [D]), k = [
31
+ }, [C]), le = [
32
32
  {
33
33
  value: "all",
34
34
  label: O("catalog.allVisibility", "All Visibility")
@@ -45,20 +45,21 @@ function E() {
45
45
  value: "PUBLIC",
46
46
  label: O("catalog.visibilityPublic", "Public")
47
47
  }
48
- ], [A, j] = _(""), [M, N] = _("all"), [P, F] = _(!1), [I, L] = _(!1), [R, z] = _(null), [B, V] = _([]), [H, U] = _(!1), { data: W, loading: G, error: K, refetch: q, fetchMore: J } = t({
48
+ ], [k, A] = p(""), [j, M] = p("all"), [N, P] = p(!1), [F, I] = p(!1), [L, R] = p(null), [z, B] = p([]), [V, H] = p(!1), { data: U, loading: W, error: G, refetch: K, fetchMore: q } = t({
49
49
  variables: {
50
50
  filter: {
51
- visibility: M === "all" ? void 0 : M,
52
- search: A || void 0
51
+ visibility: j === "all" ? void 0 : j,
52
+ search: k || void 0
53
53
  },
54
54
  pagination: {
55
55
  limit: 50,
56
56
  offset: 0
57
57
  }
58
58
  },
59
+ skip: T || !D,
59
60
  fetchPolicy: "cache-and-network",
60
61
  notifyOnNetworkStatusChange: !0
61
- }), [se] = e({ refetchQueries: ["ListCatalogs"] }), { setDraftTagIds: ce, flushTags: le } = te("VIBECONTROLS_CATALOG"), Y = h((e) => e.map((e) => ({
62
+ }), [ue] = e({ refetchQueries: ["ListCatalogs"] }), { setDraftTagIds: J, flushTags: de } = ne("VIBECONTROLS_CATALOG"), Y = d((e) => e.map((e) => ({
62
63
  id: e.id,
63
64
  name: e.name,
64
65
  description: e.description || null,
@@ -69,17 +70,17 @@ function E() {
69
70
  createdAt: e.createdAt,
70
71
  updatedAt: e.updatedAt
71
72
  })), []);
72
- g(() => {
73
- V(Y(W?.vibecontrolsCatalogs?.items ?? []));
74
- }, [W?.vibecontrolsCatalogs?.items, Y]);
75
- let X = W?.vibecontrolsCatalogs?.total ?? 0, Z = B.length < X, Q = B, $ = B, ue = h(async () => {
76
- if (!(H || !Z)) {
77
- U(!0);
73
+ f(() => {
74
+ B(Y(U?.vibecontrolsCatalogs?.items ?? []));
75
+ }, [U?.vibecontrolsCatalogs?.items, Y]);
76
+ let X = U?.vibecontrolsCatalogs?.total ?? 0, Z = z.length < X, Q = z, $ = z, fe = d(async () => {
77
+ if (!(V || !Z)) {
78
+ H(!0);
78
79
  try {
79
- await J({
80
+ await q({
80
81
  variables: { pagination: {
81
82
  limit: 50,
82
- offset: B.length
83
+ offset: z.length
83
84
  } },
84
85
  updateQuery: (e, { fetchMoreResult: t }) => {
85
86
  if (!t?.vibecontrolsCatalogs) return e;
@@ -96,156 +97,156 @@ function E() {
96
97
  }
97
98
  });
98
99
  } finally {
99
- U(!1);
100
+ H(!1);
100
101
  }
101
102
  }
102
103
  }, [
103
- J,
104
- B.length,
105
- H,
104
+ q,
105
+ z.length,
106
+ V,
106
107
  Z
107
108
  ]);
108
- if (oe) return /* @__PURE__ */ x("div", {
109
+ if (T) return /* @__PURE__ */ _("div", {
109
110
  className: "flex items-center justify-center min-h-[400px]",
110
- children: /* @__PURE__ */ x("p", {
111
+ children: /* @__PURE__ */ _("p", {
111
112
  className: "text-text-secondary",
112
113
  children: "Loading permissions…"
113
114
  })
114
115
  });
115
- if (!ae(d.VIBE_LIST)) return /* @__PURE__ */ x("div", {
116
+ if (!D) return /* @__PURE__ */ _("div", {
116
117
  className: "flex items-center justify-center min-h-[400px]",
117
- children: /* @__PURE__ */ S("div", {
118
+ children: /* @__PURE__ */ v("div", {
118
119
  className: "text-center space-y-2",
119
- children: [/* @__PURE__ */ x("h2", {
120
+ children: [/* @__PURE__ */ _("h2", {
120
121
  className: "text-lg font-semibold text-foreground",
121
122
  children: "Access Denied"
122
- }), /* @__PURE__ */ x("p", {
123
+ }), /* @__PURE__ */ _("p", {
123
124
  className: "text-sm text-text-secondary",
124
125
  children: "You don't have permission to access this page."
125
126
  })]
126
127
  })
127
128
  });
128
- let de = (e) => {
129
- E(`/catalogs/${e.id}`);
129
+ let pe = (e) => {
130
+ S(`/catalogs/${e.id}`);
130
131
  };
131
- return K && $.length === 0 ? /* @__PURE__ */ x(T, {
132
+ return G && $.length === 0 ? /* @__PURE__ */ _(x, {
132
133
  className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
133
- children: /* @__PURE__ */ x(ee, {
134
+ children: /* @__PURE__ */ _(te, {
134
135
  title: O("catalog.failedLoad", "Failed to load catalogs"),
135
- message: K.message,
136
- onRetry: () => q()
136
+ message: G.message,
137
+ onRetry: () => K()
137
138
  })
138
- }) : /* @__PURE__ */ S(T, {
139
+ }) : /* @__PURE__ */ v(x, {
139
140
  className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
140
141
  children: [
141
- /* @__PURE__ */ x(a, {
142
+ /* @__PURE__ */ _(ee, {
142
143
  title: O("catalog.title", "Catalogs"),
143
144
  description: O("catalog.description", "{{total}} catalogs", { total: $.length }),
144
- actions: /* @__PURE__ */ S("div", {
145
+ actions: /* @__PURE__ */ v("div", {
145
146
  className: "flex items-center gap-2",
146
- children: [/* @__PURE__ */ x("button", {
147
+ children: [/* @__PURE__ */ _("button", {
147
148
  type: "button",
148
- onClick: () => q(),
149
- disabled: G,
149
+ onClick: () => K(),
150
+ disabled: W,
150
151
  className: "flex items-center gap-2 px-3 py-2 text-text-secondary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50",
151
152
  title: O("common.refresh", "Refresh"),
152
- children: /* @__PURE__ */ x(ie, { className: `size-4 ${G ? "animate-spin" : ""}` })
153
- }), /* @__PURE__ */ S("button", {
153
+ children: /* @__PURE__ */ _(oe, { className: `size-4 ${W ? "animate-spin" : ""}` })
154
+ }), E && /* @__PURE__ */ v("button", {
154
155
  type: "button",
155
- onClick: () => F(!0),
156
+ onClick: () => P(!0),
156
157
  className: "flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors",
157
- children: [/* @__PURE__ */ x(v, { className: "size-4" }), O("catalog.createCatalog", "Create Catalog")]
158
+ children: [/* @__PURE__ */ _(g, { className: "size-4" }), O("catalog.createCatalog", "Create Catalog")]
158
159
  })]
159
160
  })
160
161
  }),
161
- /* @__PURE__ */ S("div", {
162
+ /* @__PURE__ */ v("div", {
162
163
  className: "flex items-center gap-2 sm:gap-3 flex-wrap",
163
- children: [/* @__PURE__ */ x("div", {
164
+ children: [/* @__PURE__ */ _("div", {
164
165
  "data-tour": "vibecontrols-catalog-search",
165
166
  className: "flex-1 sm:w-64 sm:flex-none",
166
- children: /* @__PURE__ */ x(c, {
167
- value: A,
168
- onChange: j,
167
+ children: /* @__PURE__ */ _(o, {
168
+ value: k,
169
+ onChange: A,
169
170
  placeholder: O("catalog.searchPlaceholder", "Search catalogs..."),
170
171
  className: "w-full"
171
172
  })
172
- }), /* @__PURE__ */ x("div", {
173
+ }), /* @__PURE__ */ _("div", {
173
174
  "data-tour": "vibecontrols-catalog-visibility-filter",
174
- children: /* @__PURE__ */ x(l, {
175
+ children: /* @__PURE__ */ _(s, {
175
176
  label: O("catalog.filterVisibility", "Visibility"),
176
- value: M,
177
- options: k,
178
- onChange: N
177
+ value: j,
178
+ options: le,
179
+ onChange: M
179
180
  })
180
181
  })]
181
182
  }),
182
- /* @__PURE__ */ S("p", {
183
+ /* @__PURE__ */ v("p", {
183
184
  className: "text-sm text-text-secondary",
184
185
  children: [O("catalog.showingResults", "Showing {{filtered}} of {{total}} catalogs", {
185
186
  filtered: Q.length,
186
187
  total: X
187
- }), G && /* @__PURE__ */ x("span", {
188
+ }), W && /* @__PURE__ */ _("span", {
188
189
  className: "ml-2 text-text-muted",
189
190
  children: O("common.refreshing", "(refreshing...)")
190
191
  })]
191
192
  }),
192
- G && $.length === 0 ? /* @__PURE__ */ x(f, {
193
+ W && $.length === 0 ? /* @__PURE__ */ _(u, {
193
194
  variant: "cards",
194
195
  count: 6
195
- }) : Q.length > 0 ? /* @__PURE__ */ x(b, {
196
+ }) : Q.length > 0 ? /* @__PURE__ */ _(ce, {
196
197
  mode: "wait",
197
- children: /* @__PURE__ */ x(w, {
198
+ children: /* @__PURE__ */ _(b, {
198
199
  stagger: .04,
199
200
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
200
201
  "data-tour": "vibecontrols-catalog-grid",
201
- children: Q.map((e) => /* @__PURE__ */ x(C, { children: /* @__PURE__ */ x(p, {
202
+ children: Q.map((e) => /* @__PURE__ */ _(y, { children: /* @__PURE__ */ _(ie, {
202
203
  catalog: e,
203
- onOpen: de
204
+ onOpen: pe
204
205
  }) }, e.id))
205
206
  }, "catalog-grid")
206
- }) : /* @__PURE__ */ x(s, {
207
- icon: /* @__PURE__ */ x(re, { className: "size-8 text-text-secondary" }),
208
- title: A || M !== "all" ? O("catalog.emptyNoResults", "No catalogs found") : O("catalog.emptyNoCatalogs", "No catalogs yet"),
209
- description: A || M !== "all" ? O("catalog.emptyAdjustSearch", "Try adjusting your search or filters") : O("catalog.emptyCreate", "Create your first catalog to organize components"),
210
- action: !A && M === "all" ? /* @__PURE__ */ S("div", {
207
+ }) : /* @__PURE__ */ _(re, {
208
+ icon: /* @__PURE__ */ _(h, { className: "size-8 text-text-secondary" }),
209
+ title: k || j !== "all" ? O("catalog.emptyNoResults", "No catalogs found") : O("catalog.emptyNoCatalogs", "No catalogs yet"),
210
+ description: k || j !== "all" ? O("catalog.emptyAdjustSearch", "Try adjusting your search or filters") : O("catalog.emptyCreate", "Create your first catalog to organize components"),
211
+ action: !k && j === "all" ? /* @__PURE__ */ v("div", {
211
212
  className: "flex items-center gap-2",
212
- children: [/* @__PURE__ */ S("button", {
213
+ children: [E && /* @__PURE__ */ v("button", {
213
214
  type: "button",
214
- onClick: () => F(!0),
215
+ onClick: () => P(!0),
215
216
  className: "flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors",
216
- children: [/* @__PURE__ */ x(v, { className: "size-4" }), O("catalog.createCatalog", "Create Catalog")]
217
- }), /* @__PURE__ */ x(u, { prompt: "What is a Catalog in VibeControls and how do I create one?" })]
217
+ children: [/* @__PURE__ */ _(g, { className: "size-4" }), O("catalog.createCatalog", "Create Catalog")]
218
+ }), /* @__PURE__ */ _(c, { prompt: "What is a Catalog in VibeControls and how do I create one?" })]
218
219
  }) : void 0
219
220
  }),
220
- Z && Q.length > 0 && /* @__PURE__ */ x("div", {
221
+ Z && Q.length > 0 && /* @__PURE__ */ _("div", {
221
222
  className: "flex justify-center pt-2",
222
- children: /* @__PURE__ */ x("button", {
223
+ children: /* @__PURE__ */ _("button", {
223
224
  type: "button",
224
- onClick: ue,
225
- disabled: H,
225
+ onClick: fe,
226
+ disabled: V,
226
227
  className: "flex items-center gap-2 px-4 py-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken-hover transition-colors disabled:opacity-50",
227
- children: H ? O("common.loading", "Loading...") : O("common.loadMore", "Load more")
228
+ children: V ? O("common.loading", "Loading...") : O("common.loadMore", "Load more")
228
229
  })
229
230
  }),
230
- R && /* @__PURE__ */ x("div", {
231
+ L && /* @__PURE__ */ _("div", {
231
232
  className: "fixed bottom-4 right-4 z-50 px-4 py-3 bg-status-success-bg text-status-success-text rounded-md shadow-lg text-sm",
232
- children: R
233
+ children: L
233
234
  }),
234
- /* @__PURE__ */ x(n, {
235
- isOpen: I,
236
- onClose: () => L(!1),
235
+ /* @__PURE__ */ _(n, {
236
+ isOpen: F,
237
+ onClose: () => I(!1),
237
238
  onConfirm: () => {
238
- L(!1), E("/billing/plans");
239
+ I(!1), S("/billing/plans");
239
240
  },
240
241
  title: "Catalog Quota Reached",
241
242
  message: "You've reached the maximum number of catalogs on your current plan. Upgrade your plan or purchase an add-on to create more catalogs."
242
243
  }),
243
- /* @__PURE__ */ x(m, {
244
- isOpen: P,
245
- onClose: () => F(!1),
244
+ /* @__PURE__ */ _(ae, {
245
+ isOpen: N,
246
+ onClose: () => P(!1),
246
247
  onSubmit: async (e) => {
247
248
  try {
248
- let t = await se({ variables: { input: {
249
+ let t = await ue({ variables: { input: {
249
250
  name: e.name,
250
251
  description: e.description || void 0,
251
252
  visibility: e.visibility,
@@ -253,32 +254,32 @@ function E() {
253
254
  tags: e.tags.length > 0 ? e.tags : void 0
254
255
  } } });
255
256
  if (t.error && r(t.error)) {
256
- F(!1), L(!0);
257
+ P(!1), I(!0);
257
258
  return;
258
259
  }
259
260
  let n = t.data?.createVibecontrolsCatalog?.id;
260
261
  if (!n) throw Error(O("catalog.failedCreate", "Failed to create catalog"));
261
- await le(n), F(!1), z(O("catalog.createdSuccess", "Catalog created successfully")), await q(), setTimeout(() => z(null), 3e3);
262
+ await de(n), P(!1), R(O("catalog.createdSuccess", "Catalog created successfully")), await K(), setTimeout(() => R(null), 3e3);
262
263
  } catch (e) {
263
264
  if (r(e)) {
264
- F(!1), L(!0);
265
+ P(!1), I(!0);
265
266
  return;
266
267
  }
267
268
  throw e;
268
269
  }
269
270
  },
270
- extraSection: /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("h3", {
271
+ extraSection: /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h3", {
271
272
  className: "text-sm font-medium text-text-secondary mb-2",
272
273
  children: O("catalog.tags", "Tags")
273
- }), /* @__PURE__ */ x(o, {
274
+ }), /* @__PURE__ */ _(a, {
274
275
  entityType: "VIBECONTROLS_CATALOG",
275
- onDraftChange: ce
276
+ onDraftChange: J
276
277
  })] })
277
278
  })
278
279
  ]
279
280
  });
280
281
  }
281
282
  //#endregion
282
- export { E as CatalogPage };
283
+ export { S as CatalogPage };
283
284
 
284
285
  //# sourceMappingURL=CatalogPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogPage.js","names":[],"sources":["../../src/pages/CatalogPage.tsx"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { Plus, BookOpen, RefreshCw } from 'lucide-react';\nimport { CatalogCard } from '@/components/catalog';\nimport type { CatalogCardData } from '@/components/catalog';\nimport { CatalogForm } from '@/components/catalog';\nimport type { CatalogFormData } from '@/components/catalog';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport {\n PageHeader,\n SearchInput,\n FilterDropdown,\n EmptyState,\n ErrorState,\n GetHelpButton,\n QuotaExhaustedDialog,\n} from '@/components/shared';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { AnimatePresence } from 'framer-motion';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useListCatalogsQuery, useCreateCatalogMutation } from '@/generated/wspace-operations';\n\nexport function CatalogPage() {\n const navigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n\n const tr = useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n if (!params) return template;\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n },\n [t]\n );\n\n const visibilityOptions = [\n { value: 'all', label: tr('catalog.allVisibility', 'All Visibility') },\n { value: 'PRIVATE', label: tr('catalog.visibilityPrivate', 'Private') },\n { value: 'INTERNAL', label: tr('catalog.visibilityInternal', 'Internal') },\n { value: 'PUBLIC', label: tr('catalog.visibilityPublic', 'Public') },\n ];\n\n const PAGE_SIZE = 50;\n const [searchQuery, setSearchQuery] = useState('');\n const [visibilityFilter, setVisibilityFilter] = useState('all');\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [accumulated, setAccumulated] = useState<CatalogCardData[]>([]);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const { data, loading, error, refetch, fetchMore } = useListCatalogsQuery({\n variables: {\n filter: {\n visibility:\n visibilityFilter !== 'all'\n ? (visibilityFilter as 'PRIVATE' | 'INTERNAL' | 'PUBLIC')\n : undefined,\n search: searchQuery || undefined,\n },\n pagination: { limit: PAGE_SIZE, offset: 0 },\n },\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n });\n\n const [createCatalog] = useCreateCatalogMutation({ refetchQueries: ['ListCatalogs'] });\n const { setDraftTagIds, flushTags } = useDraftEntityTags('VIBECONTROLS_CATALOG');\n\n const mapItems = useCallback(\n (items: ReadonlyArray<Record<string, unknown>>): CatalogCardData[] =>\n items.map((item) => ({\n id: item.id as string,\n name: item.name as string,\n description: (item.description as string) || null,\n visibility: item.visibility as CatalogCardData['visibility'],\n componentCount: (item.componentCount as number) || 0,\n vibeCount: (item.vibeCount as number) || 0,\n tags: (item.tags as string[]) || [],\n createdAt: item.createdAt as string,\n updatedAt: item.updatedAt as string,\n })),\n []\n );\n\n // Mirror the watched query's items into local state. fetchMore below uses\n // updateQuery to append new pages into the watched data, so this single\n // effect handles both the initial load and load-more cases.\n useEffect(() => {\n const items = data?.vibecontrolsCatalogs?.items ?? [];\n setAccumulated(mapItems(items as ReadonlyArray<Record<string, unknown>>));\n }, [data?.vibecontrolsCatalogs?.items, mapItems]);\n\n const total = data?.vibecontrolsCatalogs?.total ?? 0;\n const hasMore = accumulated.length < total;\n const filteredCatalogs = accumulated;\n const catalogs = accumulated;\n\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { limit: PAGE_SIZE, offset: accumulated.length } },\n updateQuery: (prev, { fetchMoreResult }) => {\n if (!fetchMoreResult?.vibecontrolsCatalogs) return prev;\n const prevList = prev.vibecontrolsCatalogs;\n const nextList = fetchMoreResult.vibecontrolsCatalogs;\n return {\n ...prev,\n vibecontrolsCatalogs: {\n ...nextList,\n items: [...(prevList?.items ?? []), ...nextList.items],\n total: nextList.total,\n hasMore: nextList.hasMore,\n },\n };\n },\n });\n } finally {\n setLoadingMore(false);\n }\n }, [fetchMore, accumulated.length, loadingMore, hasMore]);\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!hasPermission(VIBE_PERMISSIONS.VIBE_LIST))\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleCatalogSelect = (catalog: CatalogCardData) => {\n navigate(`/catalogs/${catalog.id}`);\n };\n\n const handleCreateCatalog = async (formData: CatalogFormData) => {\n try {\n const res = await createCatalog({\n variables: {\n input: {\n name: formData.name,\n description: formData.description || undefined,\n visibility: formData.visibility,\n ownerName: formData.owner || undefined,\n tags: formData.tags.length > 0 ? formData.tags : undefined,\n },\n },\n });\n if (res.error && isQuotaExhaustedError(res.error)) {\n setShowCreateForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n const newCatalogId = res.data?.createVibecontrolsCatalog?.id;\n if (!newCatalogId) throw new Error(tr('catalog.failedCreate', 'Failed to create catalog'));\n await flushTags(newCatalogId);\n setShowCreateForm(false);\n setSuccessMessage(tr('catalog.createdSuccess', 'Catalog created successfully'));\n await refetch();\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setShowCreateForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n if (error && catalogs.length === 0) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <ErrorState\n title={tr('catalog.failedLoad', 'Failed to load catalogs')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <PageHeader\n title={tr('catalog.title', 'Catalogs')}\n description={tr('catalog.description', '{{total}} catalogs', {\n total: catalogs.length,\n })}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center gap-2 px-3 py-2 text-text-secondary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n </div>\n }\n />\n\n {/* Filters — SearchInput / FilterDropdown are custom components that don't\n forward rest props onto a DOM node, so the tour anchors live on\n wrapper <div>s. */}\n <div className=\"flex items-center gap-2 sm:gap-3 flex-wrap\">\n <div data-tour=\"vibecontrols-catalog-search\" className=\"flex-1 sm:w-64 sm:flex-none\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('catalog.searchPlaceholder', 'Search catalogs...')}\n className=\"w-full\"\n />\n </div>\n <div data-tour=\"vibecontrols-catalog-visibility-filter\">\n <FilterDropdown\n label={tr('catalog.filterVisibility', 'Visibility')}\n value={visibilityFilter}\n options={visibilityOptions}\n onChange={setVisibilityFilter}\n />\n </div>\n </div>\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {tr('catalog.showingResults', 'Showing {{filtered}} of {{total}} catalogs', {\n filtered: filteredCatalogs.length,\n total,\n })}\n {loading && (\n <span className=\"ml-2 text-text-muted\">{tr('common.refreshing', '(refreshing...)')}</span>\n )}\n </p>\n\n {/* Grid */}\n {loading && catalogs.length === 0 ? (\n <PageSkeleton variant=\"cards\" count={6} />\n ) : filteredCatalogs.length > 0 ? (\n <AnimatePresence mode=\"wait\">\n <MotionList\n key=\"catalog-grid\"\n stagger={0.04}\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n data-tour=\"vibecontrols-catalog-grid\"\n >\n {filteredCatalogs.map((catalog) => (\n <MotionItem key={catalog.id}>\n <CatalogCard catalog={catalog} onOpen={handleCatalogSelect} />\n </MotionItem>\n ))}\n </MotionList>\n </AnimatePresence>\n ) : (\n <EmptyState\n icon={<BookOpen className=\"size-8 text-text-secondary\" />}\n title={\n searchQuery || visibilityFilter !== 'all'\n ? tr('catalog.emptyNoResults', 'No catalogs found')\n : tr('catalog.emptyNoCatalogs', 'No catalogs yet')\n }\n description={\n searchQuery || visibilityFilter !== 'all'\n ? tr('catalog.emptyAdjustSearch', 'Try adjusting your search or filters')\n : tr('catalog.emptyCreate', 'Create your first catalog to organize components')\n }\n action={\n !searchQuery && visibilityFilter === 'all' ? (\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n <GetHelpButton prompt=\"What is a Catalog in VibeControls and how do I create one?\" />\n </div>\n ) : undefined\n }\n />\n )}\n\n {/* Load more */}\n {hasMore && filteredCatalogs.length > 0 && (\n <div className=\"flex justify-center pt-2\">\n <button\n type=\"button\"\n onClick={handleLoadMore}\n disabled={loadingMore}\n className=\"flex items-center gap-2 px-4 py-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken-hover transition-colors disabled:opacity-50\"\n >\n {loadingMore ? tr('common.loading', 'Loading...') : tr('common.loadMore', 'Load more')}\n </button>\n </div>\n )}\n\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed bottom-4 right-4 z-50 px-4 py-3 bg-status-success-bg text-status-success-text rounded-md shadow-lg text-sm\">\n {successMessage}\n </div>\n )}\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Catalog Quota Reached\"\n message=\"You've reached the maximum number of catalogs on your current plan. Upgrade your plan or purchase an add-on to create more catalogs.\"\n />\n\n {/* Create Form */}\n <CatalogForm\n isOpen={showCreateForm}\n onClose={() => setShowCreateForm(false)}\n onSubmit={handleCreateCatalog}\n extraSection={\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('catalog.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_CATALOG\" onDraftChange={setDraftTagIds} />\n </div>\n }\n />\n </MotionPage>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,IAAc;CAC5B,IAAM,IAAW,GAAiB,EAC5B,EAAE,SAAM,IAAS,EACjB,EAAE,mBAAe,WAAW,OAAuB,GAAgB,EAEnE,IAAK,GACR,GAAa,GAAkB,MAAqD;EACnF,IAAM,IAAa,EAAE,GAAK,EAAO,EAC3B,IAAW,MAAe,IAAM,IAAW;AAEjD,SADK,IACE,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAU,OAAgB,EAAI,QAAQ,KAAK,EAAS,KAAK,OAAO,EAAW,CAAC,EACnF,EACD,GAJmB;IAMtB,CAAC,EAAE,CACJ,EAEK,IAAoB;EACxB;GAAE,OAAO;GAAO,OAAO,EAAG,yBAAyB,iBAAiB;GAAE;EACtE;GAAE,OAAO;GAAW,OAAO,EAAG,6BAA6B,UAAU;GAAE;EACvE;GAAE,OAAO;GAAY,OAAO,EAAG,8BAA8B,WAAW;GAAE;EAC1E;GAAE,OAAO;GAAU,OAAO,EAAG,4BAA4B,SAAS;GAAE;EACrE,EAGK,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAkB,KAAuB,EAAS,MAAM,EACzD,CAAC,GAAgB,KAAqB,EAAS,GAAM,EACrD,CAAC,GAAoB,KAAyB,EAAS,GAAM,EAC7D,CAAC,GAAgB,KAAqB,EAAwB,KAAK,EACnE,CAAC,GAAa,KAAkB,EAA4B,EAAE,CAAC,EAC/D,CAAC,GAAa,KAAkB,EAAS,GAAM,EAE/C,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAAqB;EACxE,WAAW;GACT,QAAQ;IACN,YACE,MAAqB,QAEjB,KAAA,IADC;IAEP,QAAQ,KAAe,KAAA;IACxB;GACD,YAAY;IAAE,OAAO;IAAW,QAAQ;IAAG;GAC5C;EACD,aAAa;EACb,6BAA6B;EAC9B,CAAC,EAEI,CAAC,MAAiB,EAAyB,EAAE,gBAAgB,CAAC,eAAe,EAAE,CAAC,EAChF,EAAE,oBAAgB,kBAAc,GAAmB,uBAAuB,EAE1E,IAAW,GACd,MACC,EAAM,KAAK,OAAU;EACnB,IAAI,EAAK;EACT,MAAM,EAAK;EACX,aAAc,EAAK,eAA0B;EAC7C,YAAY,EAAK;EACjB,gBAAiB,EAAK,kBAA6B;EACnD,WAAY,EAAK,aAAwB;EACzC,MAAO,EAAK,QAAqB,EAAE;EACnC,WAAW,EAAK;EAChB,WAAW,EAAK;EACjB,EAAE,EACL,EAAE,CACH;AAKD,SAAgB;AAEd,IAAe,EADD,GAAM,sBAAsB,SAAS,EAAE,CACmB,CAAC;IACxE,CAAC,GAAM,sBAAsB,OAAO,EAAS,CAAC;CAEjD,IAAM,IAAQ,GAAM,sBAAsB,SAAS,GAC7C,IAAU,EAAY,SAAS,GAC/B,IAAmB,GACnB,IAAW,GAEX,KAAiB,EAAY,YAAY;AACzC,aAAe,CAAC,IACpB;KAAe,GAAK;AACpB,OAAI;AACF,UAAM,EAAU;KACd,WAAW,EAAE,YAAY;MAAE,OAAO;MAAW,QAAQ,EAAY;MAAQ,EAAE;KAC3E,cAAc,GAAM,EAAE,yBAAsB;AAC1C,UAAI,CAAC,GAAiB,qBAAsB,QAAO;MACnD,IAAM,IAAW,EAAK,sBAChB,IAAW,EAAgB;AACjC,aAAO;OACL,GAAG;OACH,sBAAsB;QACpB,GAAG;QACH,OAAO,CAAC,GAAI,GAAU,SAAS,EAAE,EAAG,GAAG,EAAS,MAAM;QACtD,OAAO,EAAS;QAChB,SAAS,EAAS;QACnB;OACF;;KAEJ,CAAC;aACM;AACR,MAAe,GAAM;;;IAEtB;EAAC;EAAW,EAAY;EAAQ;EAAa;EAAQ,CAAC;AAEzD,KAAI,GACF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aAAsB;GAAwB,CAAA;EACvD,CAAA;AAEV,KAAI,CAAC,GAAc,EAAiB,UAAU,CAC5C,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAAwC;IAAkB,CAAA,EACxE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAEvC,CAAA,CACA;;EACF,CAAA;CAGV,IAAM,MAAuB,MAA6B;AACxD,IAAS,aAAa,EAAQ,KAAK;;AAkDrC,QAZI,KAAS,EAAS,WAAW,IAE7B,kBAAC,GAAD;EAAY,WAAU;YACpB,kBAAC,IAAD;GACE,OAAO,EAAG,sBAAsB,0BAA0B;GAC1D,SAAS,EAAM;GACf,eAAe,GAAS;GACxB,CAAA;EACS,CAAA,GAKf,kBAAC,GAAD;EAAY,WAAU;YAAtB;GACE,kBAAC,GAAD;IACE,OAAO,EAAG,iBAAiB,WAAW;IACtC,aAAa,EAAG,uBAAuB,sBAAsB,EAC3D,OAAO,EAAS,QACjB,CAAC;IACF,SACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAS;MACxB,UAAU;MACV,WAAU;MACV,OAAO,EAAG,kBAAkB,UAAU;gBAEtC,kBAAC,IAAD,EAAW,WAAW,UAAU,IAAU,iBAAiB,MAAQ,CAAA;MAC5D,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAkB,GAAK;MACtC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAC1B,EAAG,yBAAyB,iBAAiB,CACvC;QACL;;IAER,CAAA;GAKF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,aAAU;KAA8B,WAAU;eACrD,kBAAC,GAAD;MACE,OAAO;MACP,UAAU;MACV,aAAa,EAAG,6BAA6B,qBAAqB;MAClE,WAAU;MACV,CAAA;KACE,CAAA,EACN,kBAAC,OAAD;KAAK,aAAU;eACb,kBAAC,GAAD;MACE,OAAO,EAAG,4BAA4B,aAAa;MACnD,OAAO;MACP,SAAS;MACT,UAAU;MACV,CAAA;KACE,CAAA,CACF;;GAGN,kBAAC,KAAD;IAAG,WAAU;cAAb,CACG,EAAG,0BAA0B,8CAA8C;KAC1E,UAAU,EAAiB;KAC3B;KACD,CAAC,EACD,KACC,kBAAC,QAAD;KAAM,WAAU;eAAwB,EAAG,qBAAqB,kBAAkB;KAAQ,CAAA,CAE1F;;GAGH,KAAW,EAAS,WAAW,IAC9B,kBAAC,GAAD;IAAc,SAAQ;IAAQ,OAAO;IAAK,CAAA,GACxC,EAAiB,SAAS,IAC5B,kBAAC,GAAD;IAAiB,MAAK;cACpB,kBAAC,GAAD;KAEE,SAAS;KACT,WAAU;KACV,aAAU;eAET,EAAiB,KAAK,MACrB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAsB;MAAS,QAAQ;MAAuB,CAAA,EACnD,EAFI,EAAQ,GAEZ,CACb;KACS,EAVP,eAUO;IACG,CAAA,GAElB,kBAAC,GAAD;IACE,MAAM,kBAAC,IAAD,EAAU,WAAU,8BAA+B,CAAA;IACzD,OACE,KAAe,MAAqB,QAChC,EAAG,0BAA0B,oBAAoB,GACjD,EAAG,2BAA2B,kBAAkB;IAEtD,aACE,KAAe,MAAqB,QAChC,EAAG,6BAA6B,uCAAuC,GACvE,EAAG,uBAAuB,mDAAmD;IAEnF,QACE,CAAC,KAAe,MAAqB,QACnC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAkB,GAAK;MACtC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAC1B,EAAG,yBAAyB,iBAAiB,CACvC;SACT,kBAAC,GAAD,EAAe,QAAO,8DAA+D,CAAA,CACjF;SACJ,KAAA;IAEN,CAAA;GAIH,KAAW,EAAiB,SAAS,KACpC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAU;eAET,IAAc,EAAG,kBAAkB,aAAa,GAAG,EAAG,mBAAmB,YAAY;KAC/E,CAAA;IACL,CAAA;GAIP,KACC,kBAAC,OAAD;IAAK,WAAU;cACZ;IACG,CAAA;GAGR,kBAAC,GAAD;IACE,QAAQ;IACR,eAAe,EAAsB,GAAM;IAC3C,iBAAiB;AAEf,KADA,EAAsB,GAAM,EAC5B,EAAS,iBAAiB;;IAE5B,OAAM;IACN,SAAQ;IACR,CAAA;GAGF,kBAAC,GAAD;IACE,QAAQ;IACR,eAAe,EAAkB,GAAM;IACvC,UAnMsB,OAAO,MAA8B;AAC/D,SAAI;MACF,IAAM,IAAM,MAAM,GAAc,EAC9B,WAAW,EACT,OAAO;OACL,MAAM,EAAS;OACf,aAAa,EAAS,eAAe,KAAA;OACrC,YAAY,EAAS;OACrB,WAAW,EAAS,SAAS,KAAA;OAC7B,MAAM,EAAS,KAAK,SAAS,IAAI,EAAS,OAAO,KAAA;OAClD,EACF,EACF,CAAC;AACF,UAAI,EAAI,SAAS,EAAsB,EAAI,MAAM,EAAE;AAEjD,OADA,EAAkB,GAAM,EACxB,EAAsB,GAAK;AAC3B;;MAEF,IAAM,IAAe,EAAI,MAAM,2BAA2B;AAC1D,UAAI,CAAC,EAAc,OAAU,MAAM,EAAG,wBAAwB,2BAA2B,CAAC;AAK1F,MAJA,MAAM,GAAU,EAAa,EAC7B,EAAkB,GAAM,EACxB,EAAkB,EAAG,0BAA0B,+BAA+B,CAAC,EAC/E,MAAM,GAAS,EACf,iBAAiB,EAAkB,KAAK,EAAE,IAAK;cACxC,GAAK;AACZ,UAAI,EAAsB,EAAI,EAAE;AAE9B,OADA,EAAkB,GAAM,EACxB,EAAsB,GAAK;AAC3B;;AAEF,YAAM;;;IAqKJ,cACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,gBAAgB,OAAO;KACxB,CAAA,EACL,kBAAC,GAAD;KAAiB,YAAW;KAAuB,eAAe;KAAkB,CAAA,CAChF,EAAA,CAAA;IAER,CAAA;GACS"}
1
+ {"version":3,"file":"CatalogPage.js","names":[],"sources":["../../src/pages/CatalogPage.tsx"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { Plus, BookOpen, RefreshCw } from 'lucide-react';\nimport { CatalogCard } from '@/components/catalog';\nimport type { CatalogCardData } from '@/components/catalog';\nimport { CatalogForm } from '@/components/catalog';\nimport type { CatalogFormData } from '@/components/catalog';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport {\n PageHeader,\n SearchInput,\n FilterDropdown,\n EmptyState,\n ErrorState,\n GetHelpButton,\n QuotaExhaustedDialog,\n} from '@/components/shared';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { AnimatePresence } from 'framer-motion';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useListCatalogsQuery, useCreateCatalogMutation } from '@/generated/wspace-operations';\n\nexport function CatalogPage() {\n const navigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canCreateCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_CREATE);\n const canReadCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_READ);\n\n const tr = useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n if (!params) return template;\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n },\n [t]\n );\n\n const visibilityOptions = [\n { value: 'all', label: tr('catalog.allVisibility', 'All Visibility') },\n { value: 'PRIVATE', label: tr('catalog.visibilityPrivate', 'Private') },\n { value: 'INTERNAL', label: tr('catalog.visibilityInternal', 'Internal') },\n { value: 'PUBLIC', label: tr('catalog.visibilityPublic', 'Public') },\n ];\n\n const PAGE_SIZE = 50;\n const [searchQuery, setSearchQuery] = useState('');\n const [visibilityFilter, setVisibilityFilter] = useState('all');\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [accumulated, setAccumulated] = useState<CatalogCardData[]>([]);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const { data, loading, error, refetch, fetchMore } = useListCatalogsQuery({\n variables: {\n filter: {\n visibility:\n visibilityFilter !== 'all'\n ? (visibilityFilter as 'PRIVATE' | 'INTERNAL' | 'PUBLIC')\n : undefined,\n search: searchQuery || undefined,\n },\n pagination: { limit: PAGE_SIZE, offset: 0 },\n },\n skip: permissionsLoading || !canReadCatalog,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n });\n\n const [createCatalog] = useCreateCatalogMutation({ refetchQueries: ['ListCatalogs'] });\n const { setDraftTagIds, flushTags } = useDraftEntityTags('VIBECONTROLS_CATALOG');\n\n const mapItems = useCallback(\n (items: ReadonlyArray<Record<string, unknown>>): CatalogCardData[] =>\n items.map((item) => ({\n id: item.id as string,\n name: item.name as string,\n description: (item.description as string) || null,\n visibility: item.visibility as CatalogCardData['visibility'],\n componentCount: (item.componentCount as number) || 0,\n vibeCount: (item.vibeCount as number) || 0,\n tags: (item.tags as string[]) || [],\n createdAt: item.createdAt as string,\n updatedAt: item.updatedAt as string,\n })),\n []\n );\n\n // Mirror the watched query's items into local state. fetchMore below uses\n // updateQuery to append new pages into the watched data, so this single\n // effect handles both the initial load and load-more cases.\n useEffect(() => {\n const items = data?.vibecontrolsCatalogs?.items ?? [];\n setAccumulated(mapItems(items as ReadonlyArray<Record<string, unknown>>));\n }, [data?.vibecontrolsCatalogs?.items, mapItems]);\n\n const total = data?.vibecontrolsCatalogs?.total ?? 0;\n const hasMore = accumulated.length < total;\n const filteredCatalogs = accumulated;\n const catalogs = accumulated;\n\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { limit: PAGE_SIZE, offset: accumulated.length } },\n updateQuery: (prev, { fetchMoreResult }) => {\n if (!fetchMoreResult?.vibecontrolsCatalogs) return prev;\n const prevList = prev.vibecontrolsCatalogs;\n const nextList = fetchMoreResult.vibecontrolsCatalogs;\n return {\n ...prev,\n vibecontrolsCatalogs: {\n ...nextList,\n items: [...(prevList?.items ?? []), ...nextList.items],\n total: nextList.total,\n hasMore: nextList.hasMore,\n },\n };\n },\n });\n } finally {\n setLoadingMore(false);\n }\n }, [fetchMore, accumulated.length, loadingMore, hasMore]);\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!canReadCatalog)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleCatalogSelect = (catalog: CatalogCardData) => {\n navigate(`/catalogs/${catalog.id}`);\n };\n\n const handleCreateCatalog = async (formData: CatalogFormData) => {\n try {\n const res = await createCatalog({\n variables: {\n input: {\n name: formData.name,\n description: formData.description || undefined,\n visibility: formData.visibility,\n ownerName: formData.owner || undefined,\n tags: formData.tags.length > 0 ? formData.tags : undefined,\n },\n },\n });\n if (res.error && isQuotaExhaustedError(res.error)) {\n setShowCreateForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n const newCatalogId = res.data?.createVibecontrolsCatalog?.id;\n if (!newCatalogId) throw new Error(tr('catalog.failedCreate', 'Failed to create catalog'));\n await flushTags(newCatalogId);\n setShowCreateForm(false);\n setSuccessMessage(tr('catalog.createdSuccess', 'Catalog created successfully'));\n await refetch();\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setShowCreateForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n if (error && catalogs.length === 0) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <ErrorState\n title={tr('catalog.failedLoad', 'Failed to load catalogs')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <PageHeader\n title={tr('catalog.title', 'Catalogs')}\n description={tr('catalog.description', '{{total}} catalogs', {\n total: catalogs.length,\n })}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center gap-2 px-3 py-2 text-text-secondary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n {canCreateCatalog && (\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n )}\n </div>\n }\n />\n\n {/* Filters — SearchInput / FilterDropdown are custom components that don't\n forward rest props onto a DOM node, so the tour anchors live on\n wrapper <div>s. */}\n <div className=\"flex items-center gap-2 sm:gap-3 flex-wrap\">\n <div data-tour=\"vibecontrols-catalog-search\" className=\"flex-1 sm:w-64 sm:flex-none\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('catalog.searchPlaceholder', 'Search catalogs...')}\n className=\"w-full\"\n />\n </div>\n <div data-tour=\"vibecontrols-catalog-visibility-filter\">\n <FilterDropdown\n label={tr('catalog.filterVisibility', 'Visibility')}\n value={visibilityFilter}\n options={visibilityOptions}\n onChange={setVisibilityFilter}\n />\n </div>\n </div>\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {tr('catalog.showingResults', 'Showing {{filtered}} of {{total}} catalogs', {\n filtered: filteredCatalogs.length,\n total,\n })}\n {loading && (\n <span className=\"ml-2 text-text-muted\">{tr('common.refreshing', '(refreshing...)')}</span>\n )}\n </p>\n\n {/* Grid */}\n {loading && catalogs.length === 0 ? (\n <PageSkeleton variant=\"cards\" count={6} />\n ) : filteredCatalogs.length > 0 ? (\n <AnimatePresence mode=\"wait\">\n <MotionList\n key=\"catalog-grid\"\n stagger={0.04}\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n data-tour=\"vibecontrols-catalog-grid\"\n >\n {filteredCatalogs.map((catalog) => (\n <MotionItem key={catalog.id}>\n <CatalogCard catalog={catalog} onOpen={handleCatalogSelect} />\n </MotionItem>\n ))}\n </MotionList>\n </AnimatePresence>\n ) : (\n <EmptyState\n icon={<BookOpen className=\"size-8 text-text-secondary\" />}\n title={\n searchQuery || visibilityFilter !== 'all'\n ? tr('catalog.emptyNoResults', 'No catalogs found')\n : tr('catalog.emptyNoCatalogs', 'No catalogs yet')\n }\n description={\n searchQuery || visibilityFilter !== 'all'\n ? tr('catalog.emptyAdjustSearch', 'Try adjusting your search or filters')\n : tr('catalog.emptyCreate', 'Create your first catalog to organize components')\n }\n action={\n !searchQuery && visibilityFilter === 'all' ? (\n <div className=\"flex items-center gap-2\">\n {canCreateCatalog && (\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n )}\n <GetHelpButton prompt=\"What is a Catalog in VibeControls and how do I create one?\" />\n </div>\n ) : undefined\n }\n />\n )}\n\n {/* Load more */}\n {hasMore && filteredCatalogs.length > 0 && (\n <div className=\"flex justify-center pt-2\">\n <button\n type=\"button\"\n onClick={handleLoadMore}\n disabled={loadingMore}\n className=\"flex items-center gap-2 px-4 py-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken-hover transition-colors disabled:opacity-50\"\n >\n {loadingMore ? tr('common.loading', 'Loading...') : tr('common.loadMore', 'Load more')}\n </button>\n </div>\n )}\n\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed bottom-4 right-4 z-50 px-4 py-3 bg-status-success-bg text-status-success-text rounded-md shadow-lg text-sm\">\n {successMessage}\n </div>\n )}\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Catalog Quota Reached\"\n message=\"You've reached the maximum number of catalogs on your current plan. Upgrade your plan or purchase an add-on to create more catalogs.\"\n />\n\n {/* Create Form */}\n <CatalogForm\n isOpen={showCreateForm}\n onClose={() => setShowCreateForm(false)}\n onSubmit={handleCreateCatalog}\n extraSection={\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('catalog.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_CATALOG\" onDraftChange={setDraftTagIds} />\n </div>\n }\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}