@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.
- package/dist/components/agents/AgentConnectionRecovery.js +100 -94
- package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
- package/dist/components/agents/AgentMaintenanceTab.js +177 -160
- package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
- package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
- package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
- package/dist/components/assistant/AssistantChatArea.js +1 -0
- package/dist/components/assistant/AssistantChatArea.js.map +1 -1
- package/dist/components/assistant/AssistantModeSelector.js +20 -19
- package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +3 -3
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
- package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
- package/dist/config/assistantUsecases.js +11 -0
- package/dist/config/assistantUsecases.js.map +1 -1
- package/dist/constants/permissions.js +38 -6
- package/dist/constants/permissions.js.map +1 -1
- package/dist/index.js +4 -3
- package/dist/pages/CatalogDetailPage.js +155 -155
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +110 -109
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +338 -338
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +104 -103
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +140 -132
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +201 -199
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +62 -61
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +568 -555
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +104 -89
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AIPage.js +116 -107
- package/dist/pages/ai/AIPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +46 -34
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +112 -100
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelsTab.js +119 -111
- package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
- package/dist/services/assistantApi.js +9 -3
- package/dist/services/assistantApi.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js +120 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/store/assistantStore.js +1 -1
- package/dist/store/assistantStore.js.map +1 -1
- 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
|
|
6
|
-
import { ErrorState as
|
|
7
|
-
import { EntityTagPicker as
|
|
8
|
-
import { useDraftEntityTags as
|
|
9
|
-
import { EmptyState as
|
|
10
|
-
import { SearchInput as
|
|
11
|
-
import { FilterDropdown as
|
|
12
|
-
import { GetHelpButton as
|
|
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
|
|
15
|
-
import { PageSkeleton as
|
|
16
|
-
import { CatalogCard as
|
|
17
|
-
import { CatalogForm as
|
|
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
|
|
20
|
-
import { useI18n as
|
|
21
|
-
import { BookOpen as
|
|
22
|
-
import { usePermissions as
|
|
23
|
-
import { AnimatePresence as
|
|
24
|
-
import { jsx as
|
|
25
|
-
import { MotionItem as
|
|
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
|
|
28
|
-
let
|
|
29
|
-
let 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
|
-
}, [
|
|
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
|
-
], [
|
|
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:
|
|
52
|
-
search:
|
|
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
|
-
}), [
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
}, [
|
|
75
|
-
let X =
|
|
76
|
-
if (!(
|
|
77
|
-
|
|
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
|
|
80
|
+
await q({
|
|
80
81
|
variables: { pagination: {
|
|
81
82
|
limit: 50,
|
|
82
|
-
offset:
|
|
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
|
-
|
|
100
|
+
H(!1);
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
}, [
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
q,
|
|
105
|
+
z.length,
|
|
106
|
+
V,
|
|
106
107
|
Z
|
|
107
108
|
]);
|
|
108
|
-
if (
|
|
109
|
+
if (T) return /* @__PURE__ */ _("div", {
|
|
109
110
|
className: "flex items-center justify-center min-h-[400px]",
|
|
110
|
-
children: /* @__PURE__ */
|
|
111
|
+
children: /* @__PURE__ */ _("p", {
|
|
111
112
|
className: "text-text-secondary",
|
|
112
113
|
children: "Loading permissions…"
|
|
113
114
|
})
|
|
114
115
|
});
|
|
115
|
-
if (!
|
|
116
|
+
if (!D) return /* @__PURE__ */ _("div", {
|
|
116
117
|
className: "flex items-center justify-center min-h-[400px]",
|
|
117
|
-
children: /* @__PURE__ */
|
|
118
|
+
children: /* @__PURE__ */ v("div", {
|
|
118
119
|
className: "text-center space-y-2",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
120
|
+
children: [/* @__PURE__ */ _("h2", {
|
|
120
121
|
className: "text-lg font-semibold text-foreground",
|
|
121
122
|
children: "Access Denied"
|
|
122
|
-
}), /* @__PURE__ */
|
|
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
|
|
129
|
-
|
|
129
|
+
let pe = (e) => {
|
|
130
|
+
S(`/catalogs/${e.id}`);
|
|
130
131
|
};
|
|
131
|
-
return
|
|
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__ */
|
|
134
|
+
children: /* @__PURE__ */ _(te, {
|
|
134
135
|
title: O("catalog.failedLoad", "Failed to load catalogs"),
|
|
135
|
-
message:
|
|
136
|
-
onRetry: () =>
|
|
136
|
+
message: G.message,
|
|
137
|
+
onRetry: () => K()
|
|
137
138
|
})
|
|
138
|
-
}) : /* @__PURE__ */
|
|
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__ */
|
|
142
|
+
/* @__PURE__ */ _(ee, {
|
|
142
143
|
title: O("catalog.title", "Catalogs"),
|
|
143
144
|
description: O("catalog.description", "{{total}} catalogs", { total: $.length }),
|
|
144
|
-
actions: /* @__PURE__ */
|
|
145
|
+
actions: /* @__PURE__ */ v("div", {
|
|
145
146
|
className: "flex items-center gap-2",
|
|
146
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ _("button", {
|
|
147
148
|
type: "button",
|
|
148
|
-
onClick: () =>
|
|
149
|
-
disabled:
|
|
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__ */
|
|
153
|
-
}), /* @__PURE__ */
|
|
153
|
+
children: /* @__PURE__ */ _(oe, { className: `size-4 ${W ? "animate-spin" : ""}` })
|
|
154
|
+
}), E && /* @__PURE__ */ v("button", {
|
|
154
155
|
type: "button",
|
|
155
|
-
onClick: () =>
|
|
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__ */
|
|
158
|
+
children: [/* @__PURE__ */ _(g, { className: "size-4" }), O("catalog.createCatalog", "Create Catalog")]
|
|
158
159
|
})]
|
|
159
160
|
})
|
|
160
161
|
}),
|
|
161
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ v("div", {
|
|
162
163
|
className: "flex items-center gap-2 sm:gap-3 flex-wrap",
|
|
163
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
167
|
-
value:
|
|
168
|
-
onChange:
|
|
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__ */
|
|
173
|
+
}), /* @__PURE__ */ _("div", {
|
|
173
174
|
"data-tour": "vibecontrols-catalog-visibility-filter",
|
|
174
|
-
children: /* @__PURE__ */
|
|
175
|
+
children: /* @__PURE__ */ _(s, {
|
|
175
176
|
label: O("catalog.filterVisibility", "Visibility"),
|
|
176
|
-
value:
|
|
177
|
-
options:
|
|
178
|
-
onChange:
|
|
177
|
+
value: j,
|
|
178
|
+
options: le,
|
|
179
|
+
onChange: M
|
|
179
180
|
})
|
|
180
181
|
})]
|
|
181
182
|
}),
|
|
182
|
-
/* @__PURE__ */
|
|
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
|
-
}),
|
|
188
|
+
}), W && /* @__PURE__ */ _("span", {
|
|
188
189
|
className: "ml-2 text-text-muted",
|
|
189
190
|
children: O("common.refreshing", "(refreshing...)")
|
|
190
191
|
})]
|
|
191
192
|
}),
|
|
192
|
-
|
|
193
|
+
W && $.length === 0 ? /* @__PURE__ */ _(u, {
|
|
193
194
|
variant: "cards",
|
|
194
195
|
count: 6
|
|
195
|
-
}) : Q.length > 0 ? /* @__PURE__ */
|
|
196
|
+
}) : Q.length > 0 ? /* @__PURE__ */ _(ce, {
|
|
196
197
|
mode: "wait",
|
|
197
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
202
|
+
children: Q.map((e) => /* @__PURE__ */ _(y, { children: /* @__PURE__ */ _(ie, {
|
|
202
203
|
catalog: e,
|
|
203
|
-
onOpen:
|
|
204
|
+
onOpen: pe
|
|
204
205
|
}) }, e.id))
|
|
205
206
|
}, "catalog-grid")
|
|
206
|
-
}) : /* @__PURE__ */
|
|
207
|
-
icon: /* @__PURE__ */
|
|
208
|
-
title:
|
|
209
|
-
description:
|
|
210
|
-
action: !
|
|
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__ */
|
|
213
|
+
children: [E && /* @__PURE__ */ v("button", {
|
|
213
214
|
type: "button",
|
|
214
|
-
onClick: () =>
|
|
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__ */
|
|
217
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
221
|
+
Z && Q.length > 0 && /* @__PURE__ */ _("div", {
|
|
221
222
|
className: "flex justify-center pt-2",
|
|
222
|
-
children: /* @__PURE__ */
|
|
223
|
+
children: /* @__PURE__ */ _("button", {
|
|
223
224
|
type: "button",
|
|
224
|
-
onClick:
|
|
225
|
-
disabled:
|
|
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:
|
|
228
|
+
children: V ? O("common.loading", "Loading...") : O("common.loadMore", "Load more")
|
|
228
229
|
})
|
|
229
230
|
}),
|
|
230
|
-
|
|
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:
|
|
233
|
+
children: L
|
|
233
234
|
}),
|
|
234
|
-
/* @__PURE__ */
|
|
235
|
-
isOpen:
|
|
236
|
-
onClose: () =>
|
|
235
|
+
/* @__PURE__ */ _(n, {
|
|
236
|
+
isOpen: F,
|
|
237
|
+
onClose: () => I(!1),
|
|
237
238
|
onConfirm: () => {
|
|
238
|
-
|
|
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__ */
|
|
244
|
-
isOpen:
|
|
245
|
-
onClose: () =>
|
|
244
|
+
/* @__PURE__ */ _(ae, {
|
|
245
|
+
isOpen: N,
|
|
246
|
+
onClose: () => P(!1),
|
|
246
247
|
onSubmit: async (e) => {
|
|
247
248
|
try {
|
|
248
|
-
let t = await
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
265
|
+
P(!1), I(!0);
|
|
265
266
|
return;
|
|
266
267
|
}
|
|
267
268
|
throw e;
|
|
268
269
|
}
|
|
269
270
|
},
|
|
270
|
-
extraSection: /* @__PURE__ */
|
|
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__ */
|
|
274
|
+
}), /* @__PURE__ */ _(a, {
|
|
274
275
|
entityType: "VIBECONTROLS_CATALOG",
|
|
275
|
-
onDraftChange:
|
|
276
|
+
onDraftChange: J
|
|
276
277
|
})] })
|
|
277
278
|
})
|
|
278
279
|
]
|
|
279
280
|
});
|
|
280
281
|
}
|
|
281
282
|
//#endregion
|
|
282
|
-
export {
|
|
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":"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"}
|
|
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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"}
|