@burdenoff/microfe-vibecontrols 2026.520.1 → 2026.520.2
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/AgentForm.js +152 -148
- package/dist/components/agents/AgentForm.js.map +1 -1
- package/dist/components/catalog/CatalogForm.js +46 -42
- package/dist/components/catalog/CatalogForm.js.map +1 -1
- package/dist/components/idp-components/ComponentForm.js +69 -65
- package/dist/components/idp-components/ComponentForm.js.map +1 -1
- package/dist/components/shared/EntityTagPicker.js +5 -1
- package/dist/components/shared/EntityTagPicker.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js +45 -54
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/hooks/useDraftEntityTags.js +29 -0
- package/dist/hooks/useDraftEntityTags.js.map +1 -0
- package/dist/pages/ActionsPage.js +109 -96
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +345 -336
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +107 -97
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +126 -116
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +598 -586
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +499 -485
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +310 -300
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibesPage.js +309 -296
- package/dist/pages/VibesPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,51 +3,53 @@ import { useVibeNavigate as n } from "../providers/VibeControlsProvider.js";
|
|
|
3
3
|
import { PageHeader as r } from "../components/shared/PageHeader.js";
|
|
4
4
|
import { LoadingState as i } from "../components/shared/LoadingState.js";
|
|
5
5
|
import { ErrorState as a } from "../components/shared/ErrorState.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { EntityTagPicker as o } from "../components/shared/EntityTagPicker.js";
|
|
7
|
+
import { useDraftEntityTags as s } from "../hooks/useDraftEntityTags.js";
|
|
8
|
+
import { EmptyState as c } from "../components/shared/EmptyState.js";
|
|
9
|
+
import { SearchInput as l } from "../components/shared/SearchInput.js";
|
|
10
|
+
import { FilterDropdown as u } from "../components/shared/FilterDropdown.js";
|
|
11
|
+
import { GetHelpButton as d } from "../components/shared/GetHelpButton.js";
|
|
10
12
|
import "../components/shared/index.js";
|
|
11
|
-
import { VIBE_PERMISSIONS as
|
|
12
|
-
import { CatalogCard as
|
|
13
|
-
import { CatalogForm as
|
|
13
|
+
import { VIBE_PERMISSIONS as f } from "../constants/permissions.js";
|
|
14
|
+
import { CatalogCard as p } from "../components/catalog/CatalogCard.js";
|
|
15
|
+
import { CatalogForm as m } from "../components/catalog/CatalogForm.js";
|
|
14
16
|
import "../components/catalog/index.js";
|
|
15
|
-
import { useCallback as
|
|
16
|
-
import { useI18n as
|
|
17
|
-
import { BookOpen as
|
|
18
|
-
import { usePermissions as
|
|
19
|
-
import { AnimatePresence as
|
|
20
|
-
import { jsx as
|
|
21
|
-
import { MotionItem as
|
|
17
|
+
import { useCallback as h, useMemo as g, useState as _ } from "react";
|
|
18
|
+
import { useI18n as v } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
19
|
+
import { BookOpen as y, Plus as b, RefreshCw as x } from "lucide-react";
|
|
20
|
+
import { usePermissions as S } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
21
|
+
import { AnimatePresence as C } from "framer-motion";
|
|
22
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
23
|
+
import { MotionItem as E, MotionList as D, MotionPage as O } from "@burdenoff/fe-libs/shared/motion";
|
|
22
24
|
//#region src/pages/CatalogPage.tsx
|
|
23
|
-
function
|
|
24
|
-
let
|
|
25
|
-
let r =
|
|
25
|
+
function k() {
|
|
26
|
+
let k = n(), { t: A } = v(), { hasPermission: j, isLoading: M } = S(), N = h((e, t, n) => {
|
|
27
|
+
let r = A(e, n), i = r === e ? t : r;
|
|
26
28
|
return n ? Object.entries(n).reduce((e, [t, n]) => e.replace(`{{${t}}}`, String(n)), i) : i;
|
|
27
|
-
}, [
|
|
29
|
+
}, [A]), P = [
|
|
28
30
|
{
|
|
29
31
|
value: "all",
|
|
30
|
-
label:
|
|
32
|
+
label: N("catalog.allVisibility", "All Visibility")
|
|
31
33
|
},
|
|
32
34
|
{
|
|
33
35
|
value: "PRIVATE",
|
|
34
|
-
label:
|
|
36
|
+
label: N("catalog.visibilityPrivate", "Private")
|
|
35
37
|
},
|
|
36
38
|
{
|
|
37
39
|
value: "INTERNAL",
|
|
38
|
-
label:
|
|
40
|
+
label: N("catalog.visibilityInternal", "Internal")
|
|
39
41
|
},
|
|
40
42
|
{
|
|
41
43
|
value: "PUBLIC",
|
|
42
|
-
label:
|
|
44
|
+
label: N("catalog.visibilityPublic", "Public")
|
|
43
45
|
}
|
|
44
|
-
], [
|
|
46
|
+
], [F, I] = _(""), [L, R] = _("all"), [z, B] = _(!1), [V, H] = _(null), { data: U, loading: W, error: G, refetch: K } = t({
|
|
45
47
|
variables: {
|
|
46
|
-
filter: { visibility:
|
|
47
|
-
...
|
|
48
|
+
filter: { visibility: L === "all" ? void 0 : L },
|
|
49
|
+
...F ? { pagination: { limit: 1e3 } } : {}
|
|
48
50
|
},
|
|
49
51
|
fetchPolicy: "cache-and-network"
|
|
50
|
-
}), [
|
|
52
|
+
}), [q] = e({ refetchQueries: ["ListCatalogs"] }), { setDraftTagIds: J, flushTags: Y } = s("VIBECONTROLS_CATALOG"), X = g(() => (U?.vibecontrolsCatalogs?.items ?? []).map((e) => ({
|
|
51
53
|
id: e.id,
|
|
52
54
|
name: e.name,
|
|
53
55
|
description: e.description || null,
|
|
@@ -57,133 +59,141 @@ function D() {
|
|
|
57
59
|
tags: e.tags || [],
|
|
58
60
|
createdAt: e.createdAt,
|
|
59
61
|
updatedAt: e.updatedAt
|
|
60
|
-
})), [
|
|
61
|
-
if (!
|
|
62
|
-
let e =
|
|
63
|
-
return
|
|
64
|
-
}, [
|
|
65
|
-
if (
|
|
62
|
+
})), [U?.vibecontrolsCatalogs?.items]), Z = g(() => {
|
|
63
|
+
if (!F) return X;
|
|
64
|
+
let e = F.toLowerCase();
|
|
65
|
+
return X.filter((t) => t.name.toLowerCase().includes(e) || t.description?.toLowerCase().includes(e) || t.tags?.some((t) => t.toLowerCase().includes(e)));
|
|
66
|
+
}, [X, F]);
|
|
67
|
+
if (M) return /* @__PURE__ */ w("div", {
|
|
66
68
|
className: "flex items-center justify-center min-h-[400px]",
|
|
67
|
-
children: /* @__PURE__ */
|
|
69
|
+
children: /* @__PURE__ */ w("p", {
|
|
68
70
|
className: "text-text-secondary",
|
|
69
71
|
children: "Loading permissions..."
|
|
70
72
|
})
|
|
71
73
|
});
|
|
72
|
-
if (!
|
|
74
|
+
if (!j(f.VIBE_LIST)) return /* @__PURE__ */ w("div", {
|
|
73
75
|
className: "flex items-center justify-center min-h-[400px]",
|
|
74
|
-
children: /* @__PURE__ */
|
|
76
|
+
children: /* @__PURE__ */ T("div", {
|
|
75
77
|
className: "text-center space-y-2",
|
|
76
|
-
children: [/* @__PURE__ */
|
|
78
|
+
children: [/* @__PURE__ */ w("h2", {
|
|
77
79
|
className: "text-lg font-semibold text-foreground",
|
|
78
80
|
children: "Access Denied"
|
|
79
|
-
}), /* @__PURE__ */
|
|
81
|
+
}), /* @__PURE__ */ w("p", {
|
|
80
82
|
className: "text-sm text-text-secondary",
|
|
81
83
|
children: "You don't have permission to access this page."
|
|
82
84
|
})]
|
|
83
85
|
})
|
|
84
86
|
});
|
|
85
|
-
let
|
|
86
|
-
|
|
87
|
+
let Q = (e) => {
|
|
88
|
+
k(`/catalogs/${e.id}`);
|
|
87
89
|
};
|
|
88
|
-
return
|
|
90
|
+
return W && X.length === 0 ? /* @__PURE__ */ w(O, {
|
|
89
91
|
className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
|
|
90
|
-
children: /* @__PURE__ */
|
|
91
|
-
}) :
|
|
92
|
+
children: /* @__PURE__ */ w(i, { message: N("catalog.loading", "Loading catalogs...") })
|
|
93
|
+
}) : G && X.length === 0 ? /* @__PURE__ */ w(O, {
|
|
92
94
|
className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
|
|
93
|
-
children: /* @__PURE__ */
|
|
94
|
-
title:
|
|
95
|
-
message:
|
|
96
|
-
onRetry: () =>
|
|
95
|
+
children: /* @__PURE__ */ w(a, {
|
|
96
|
+
title: N("catalog.failedLoad", "Failed to load catalogs"),
|
|
97
|
+
message: G.message,
|
|
98
|
+
onRetry: () => K()
|
|
97
99
|
})
|
|
98
|
-
}) : /* @__PURE__ */
|
|
100
|
+
}) : /* @__PURE__ */ T(O, {
|
|
99
101
|
className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
|
|
100
102
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
102
|
-
title:
|
|
103
|
-
description:
|
|
104
|
-
actions: /* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ w(r, {
|
|
104
|
+
title: N("catalog.title", "Catalogs"),
|
|
105
|
+
description: N("catalog.description", "{{total}} catalogs", { total: X.length }),
|
|
106
|
+
actions: /* @__PURE__ */ T("div", {
|
|
105
107
|
className: "flex items-center gap-2",
|
|
106
|
-
children: [/* @__PURE__ */
|
|
107
|
-
onClick: () =>
|
|
108
|
-
disabled:
|
|
108
|
+
children: [/* @__PURE__ */ w("button", {
|
|
109
|
+
onClick: () => K(),
|
|
110
|
+
disabled: W,
|
|
109
111
|
className: "flex items-center gap-2 px-3 py-2 text-text-secondary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50",
|
|
110
|
-
title:
|
|
111
|
-
children: /* @__PURE__ */
|
|
112
|
-
}), /* @__PURE__ */
|
|
113
|
-
onClick: () =>
|
|
112
|
+
title: N("common.refresh", "Refresh"),
|
|
113
|
+
children: /* @__PURE__ */ w(x, { className: `w-4 h-4 ${W ? "animate-spin" : ""}` })
|
|
114
|
+
}), /* @__PURE__ */ T("button", {
|
|
115
|
+
onClick: () => B(!0),
|
|
114
116
|
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",
|
|
115
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ w(b, { className: "w-4 h-4" }), N("catalog.createCatalog", "Create Catalog")]
|
|
116
118
|
})]
|
|
117
119
|
})
|
|
118
120
|
}),
|
|
119
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ T("div", {
|
|
120
122
|
className: "flex items-center gap-2 sm:gap-3 flex-wrap",
|
|
121
|
-
children: [/* @__PURE__ */
|
|
122
|
-
value: N,
|
|
123
|
-
onChange: P,
|
|
124
|
-
placeholder: j("catalog.searchPlaceholder", "Search catalogs..."),
|
|
125
|
-
className: "flex-1 sm:w-64 sm:flex-none"
|
|
126
|
-
}), /* @__PURE__ */ S(c, {
|
|
127
|
-
label: j("catalog.filterVisibility", "Visibility"),
|
|
123
|
+
children: [/* @__PURE__ */ w(l, {
|
|
128
124
|
value: F,
|
|
129
|
-
|
|
130
|
-
|
|
125
|
+
onChange: I,
|
|
126
|
+
placeholder: N("catalog.searchPlaceholder", "Search catalogs..."),
|
|
127
|
+
className: "flex-1 sm:w-64 sm:flex-none"
|
|
128
|
+
}), /* @__PURE__ */ w(u, {
|
|
129
|
+
label: N("catalog.filterVisibility", "Visibility"),
|
|
130
|
+
value: L,
|
|
131
|
+
options: P,
|
|
132
|
+
onChange: R
|
|
131
133
|
})]
|
|
132
134
|
}),
|
|
133
|
-
(
|
|
135
|
+
(F || L !== "all") && /* @__PURE__ */ T("p", {
|
|
134
136
|
className: "text-sm text-text-secondary",
|
|
135
|
-
children: [
|
|
136
|
-
filtered:
|
|
137
|
-
total:
|
|
138
|
-
}),
|
|
137
|
+
children: [N("catalog.showingResults", "Showing {{filtered}} of {{total}} catalogs", {
|
|
138
|
+
filtered: Z.length,
|
|
139
|
+
total: X.length
|
|
140
|
+
}), W && /* @__PURE__ */ w("span", {
|
|
139
141
|
className: "ml-2 text-text-muted",
|
|
140
|
-
children:
|
|
142
|
+
children: N("common.refreshing", "(refreshing...)")
|
|
141
143
|
})]
|
|
142
144
|
}),
|
|
143
|
-
|
|
145
|
+
Z.length > 0 ? /* @__PURE__ */ w(C, {
|
|
144
146
|
mode: "wait",
|
|
145
|
-
children: /* @__PURE__ */
|
|
147
|
+
children: /* @__PURE__ */ w(D, {
|
|
146
148
|
stagger: .04,
|
|
147
149
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
148
|
-
children:
|
|
150
|
+
children: Z.map((e) => /* @__PURE__ */ w(E, { children: /* @__PURE__ */ w(p, {
|
|
149
151
|
catalog: e,
|
|
150
|
-
onOpen:
|
|
152
|
+
onOpen: Q
|
|
151
153
|
}) }, e.id))
|
|
152
154
|
}, "catalog-grid")
|
|
153
|
-
}) : /* @__PURE__ */
|
|
154
|
-
icon: /* @__PURE__ */
|
|
155
|
-
title:
|
|
156
|
-
description:
|
|
157
|
-
action: !
|
|
155
|
+
}) : /* @__PURE__ */ w(c, {
|
|
156
|
+
icon: /* @__PURE__ */ w(y, { className: "w-8 h-8 text-text-secondary" }),
|
|
157
|
+
title: F || L !== "all" ? N("catalog.emptyNoResults", "No catalogs found") : N("catalog.emptyNoCatalogs", "No catalogs yet"),
|
|
158
|
+
description: F || L !== "all" ? N("catalog.emptyAdjustSearch", "Try adjusting your search or filters") : N("catalog.emptyCreate", "Create your first catalog to organize components"),
|
|
159
|
+
action: !F && L === "all" ? /* @__PURE__ */ T("div", {
|
|
158
160
|
className: "flex items-center gap-2",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
160
|
-
onClick: () =>
|
|
161
|
+
children: [/* @__PURE__ */ T("button", {
|
|
162
|
+
onClick: () => B(!0),
|
|
161
163
|
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",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
163
|
-
}), /* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ w(b, { className: "w-4 h-4" }), N("catalog.createCatalog", "Create Catalog")]
|
|
165
|
+
}), /* @__PURE__ */ w(d, { prompt: "What is a Catalog in VibeControls and how do I create one?" })]
|
|
164
166
|
}) : void 0
|
|
165
167
|
}),
|
|
166
|
-
|
|
168
|
+
V && /* @__PURE__ */ w("div", {
|
|
167
169
|
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",
|
|
168
|
-
children:
|
|
170
|
+
children: V
|
|
169
171
|
}),
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
-
isOpen:
|
|
172
|
-
onClose: () =>
|
|
172
|
+
/* @__PURE__ */ w(m, {
|
|
173
|
+
isOpen: z,
|
|
174
|
+
onClose: () => B(!1),
|
|
173
175
|
onSubmit: async (e) => {
|
|
174
|
-
await
|
|
176
|
+
let t = (await q({ variables: { input: {
|
|
175
177
|
name: e.name,
|
|
176
178
|
description: e.description || void 0,
|
|
177
179
|
visibility: e.visibility,
|
|
178
180
|
ownerName: e.owner || void 0,
|
|
179
181
|
tags: e.tags.length > 0 ? e.tags : void 0
|
|
180
|
-
} } })
|
|
181
|
-
|
|
182
|
+
} } })).data?.createVibecontrolsCatalog?.id;
|
|
183
|
+
t && await Y(t), H(N("catalog.createdSuccess", "Catalog created successfully")), setTimeout(() => H(null), 3e3);
|
|
184
|
+
},
|
|
185
|
+
extraSection: /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h3", {
|
|
186
|
+
className: "text-sm font-medium text-text-secondary mb-2",
|
|
187
|
+
children: N("catalog.tags", "Tags")
|
|
188
|
+
}), /* @__PURE__ */ w(o, {
|
|
189
|
+
entityType: "VIBECONTROLS_CATALOG",
|
|
190
|
+
onDraftChange: J
|
|
191
|
+
})] })
|
|
182
192
|
})
|
|
183
193
|
]
|
|
184
194
|
});
|
|
185
195
|
}
|
|
186
196
|
//#endregion
|
|
187
|
-
export {
|
|
197
|
+
export { k as CatalogPage };
|
|
188
198
|
|
|
189
199
|
//# sourceMappingURL=CatalogPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CatalogPage.js","names":[],"sources":["../../src/pages/CatalogPage.tsx"],"sourcesContent":["import { useState, useMemo, useCallback } 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 {\n PageHeader,\n SearchInput,\n FilterDropdown,\n EmptyState,\n LoadingState,\n ErrorState,\n GetHelpButton,\n} from '@/components/shared';\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 [searchQuery, setSearchQuery] = useState('');\n const [visibilityFilter, setVisibilityFilter] = useState('all');\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const { data, loading, error, refetch } = useListCatalogsQuery({\n variables: {\n filter: {\n visibility:\n visibilityFilter !== 'all'\n ? (visibilityFilter as 'PRIVATE' | 'INTERNAL' | 'PUBLIC')\n : undefined,\n },\n ...(searchQuery ? { pagination: { limit: 1000 } } : {}),\n },\n fetchPolicy: 'cache-and-network',\n });\n\n const [createCatalog] = useCreateCatalogMutation({ refetchQueries: ['ListCatalogs'] });\n\n const catalogs: CatalogCardData[] = useMemo(() => {\n const items = data?.vibecontrolsCatalogs?.items ?? [];\n return items.map((item: Record<string, unknown>) => ({\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 }, [data?.vibecontrolsCatalogs?.items]);\n\n const filteredCatalogs = useMemo(() => {\n if (!searchQuery) return catalogs;\n const query = searchQuery.toLowerCase();\n return catalogs.filter(\n (c) =>\n c.name.toLowerCase().includes(query) ||\n c.description?.toLowerCase().includes(query) ||\n c.tags?.some((tag) => tag.toLowerCase().includes(query))\n );\n }, [catalogs, searchQuery]);\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 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 setSuccessMessage(tr('catalog.createdSuccess', 'Catalog created successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n };\n\n if (loading && catalogs.length === 0) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <LoadingState message={tr('catalog.loading', 'Loading catalogs...')} />\n </MotionPage>\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 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={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <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=\"w-4 h-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n </div>\n }\n />\n\n {/* Filters */}\n <div className=\"flex items-center gap-2 sm:gap-3 flex-wrap\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('catalog.searchPlaceholder', 'Search catalogs...')}\n className=\"flex-1 sm:w-64 sm:flex-none\"\n />\n <FilterDropdown\n label={tr('catalog.filterVisibility', 'Visibility')}\n value={visibilityFilter}\n options={visibilityOptions}\n onChange={setVisibilityFilter}\n />\n </div>\n\n {/* Results count */}\n {(searchQuery || visibilityFilter !== 'all') && (\n <p className=\"text-sm text-text-secondary\">\n {tr('catalog.showingResults', 'Showing {{filtered}} of {{total}} catalogs', {\n filtered: filteredCatalogs.length,\n total: catalogs.length,\n })}\n {loading && (\n <span className=\"ml-2 text-text-muted\">\n {tr('common.refreshing', '(refreshing...)')}\n </span>\n )}\n </p>\n )}\n\n {/* Grid */}\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 >\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=\"w-8 h-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 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=\"w-4 h-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 {/* 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 {/* Create Form */}\n <CatalogForm\n isOpen={showCreateForm}\n onClose={() => setShowCreateForm(false)}\n onSubmit={handleCreateCatalog}\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, useMemo, useCallback } 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 { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport {\n PageHeader,\n SearchInput,\n FilterDropdown,\n EmptyState,\n LoadingState,\n ErrorState,\n GetHelpButton,\n} from '@/components/shared';\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 [searchQuery, setSearchQuery] = useState('');\n const [visibilityFilter, setVisibilityFilter] = useState('all');\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const { data, loading, error, refetch } = useListCatalogsQuery({\n variables: {\n filter: {\n visibility:\n visibilityFilter !== 'all'\n ? (visibilityFilter as 'PRIVATE' | 'INTERNAL' | 'PUBLIC')\n : undefined,\n },\n ...(searchQuery ? { pagination: { limit: 1000 } } : {}),\n },\n fetchPolicy: 'cache-and-network',\n });\n\n const [createCatalog] = useCreateCatalogMutation({ refetchQueries: ['ListCatalogs'] });\n const { setDraftTagIds, flushTags } = useDraftEntityTags('VIBECONTROLS_CATALOG');\n\n const catalogs: CatalogCardData[] = useMemo(() => {\n const items = data?.vibecontrolsCatalogs?.items ?? [];\n return items.map((item: Record<string, unknown>) => ({\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 }, [data?.vibecontrolsCatalogs?.items]);\n\n const filteredCatalogs = useMemo(() => {\n if (!searchQuery) return catalogs;\n const query = searchQuery.toLowerCase();\n return catalogs.filter(\n (c) =>\n c.name.toLowerCase().includes(query) ||\n c.description?.toLowerCase().includes(query) ||\n c.tags?.some((tag) => tag.toLowerCase().includes(query))\n );\n }, [catalogs, searchQuery]);\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 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 const newCatalogId = res.data?.createVibecontrolsCatalog?.id;\n if (newCatalogId) await flushTags(newCatalogId);\n setSuccessMessage(tr('catalog.createdSuccess', 'Catalog created successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n };\n\n if (loading && catalogs.length === 0) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <LoadingState message={tr('catalog.loading', 'Loading catalogs...')} />\n </MotionPage>\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 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={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <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=\"w-4 h-4\" />\n {tr('catalog.createCatalog', 'Create Catalog')}\n </button>\n </div>\n }\n />\n\n {/* Filters */}\n <div className=\"flex items-center gap-2 sm:gap-3 flex-wrap\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('catalog.searchPlaceholder', 'Search catalogs...')}\n className=\"flex-1 sm:w-64 sm:flex-none\"\n />\n <FilterDropdown\n label={tr('catalog.filterVisibility', 'Visibility')}\n value={visibilityFilter}\n options={visibilityOptions}\n onChange={setVisibilityFilter}\n />\n </div>\n\n {/* Results count */}\n {(searchQuery || visibilityFilter !== 'all') && (\n <p className=\"text-sm text-text-secondary\">\n {tr('catalog.showingResults', 'Showing {{filtered}} of {{total}} catalogs', {\n filtered: filteredCatalogs.length,\n total: catalogs.length,\n })}\n {loading && (\n <span className=\"ml-2 text-text-muted\">\n {tr('common.refreshing', '(refreshing...)')}\n </span>\n )}\n </p>\n )}\n\n {/* Grid */}\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 >\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=\"w-8 h-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 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=\"w-4 h-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 {/* 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 {/* 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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"}
|