@powerhousedao/vetra-builder-package 0.0.10 → 0.0.11
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/document-models/builder-account/src/reducers/packages.js +7 -6
- package/dist/editors/builder-account-editor/editor.js +16 -21
- package/dist/processors/vetra-read-model/builder-account-handlers.d.ts +27 -0
- package/dist/processors/vetra-read-model/builder-account-handlers.js +249 -0
- package/dist/processors/vetra-read-model/database-helpers.d.ts +34 -0
- package/dist/processors/vetra-read-model/database-helpers.js +121 -0
- package/dist/processors/vetra-read-model/package-handlers.d.ts +20 -0
- package/dist/processors/vetra-read-model/package-handlers.js +116 -0
- package/dist/processors/vetra-read-model/schema.d.ts +41 -38
- package/dist/processors/vetra-read-model/types.d.ts +32 -0
- package/dist/processors/vetra-read-model/types.js +1 -0
- package/dist/style.css +7 -0
- package/package.json +1 -1
|
@@ -58,12 +58,13 @@ export const reducer = {
|
|
|
58
58
|
updatePackageOperation(state, action, dispatch) {
|
|
59
59
|
const { id, title, description } = action.input;
|
|
60
60
|
for (const space of state.spaces) {
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
const packageIndex = space.packages.findIndex((packageObject) => packageObject.id === id);
|
|
62
|
+
if (packageIndex !== -1) {
|
|
63
|
+
// Update the package in place
|
|
64
|
+
space.packages[packageIndex] = {
|
|
65
|
+
...space.packages[packageIndex],
|
|
66
|
+
name: title ?? space.packages[packageIndex].name,
|
|
67
|
+
description: description ?? space.packages[packageIndex].description ?? "",
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -21,6 +21,7 @@ export default function Editor(props) {
|
|
|
21
21
|
const [newPackageCategory, setNewPackageCategory] = useState("");
|
|
22
22
|
const [newPackageGithub, setNewPackageGithub] = useState("");
|
|
23
23
|
const [newPackageNpm, setNewPackageNpm] = useState("");
|
|
24
|
+
const [newPackageVetraDrive, setNewPackageVetraDrive] = useState("");
|
|
24
25
|
const [newMemberAddress, setNewMemberAddress] = useState("");
|
|
25
26
|
const [selectedSpaceForPackage, setSelectedSpaceForPackage] = useState("");
|
|
26
27
|
// Editing form states
|
|
@@ -31,6 +32,7 @@ export default function Editor(props) {
|
|
|
31
32
|
const [editingPackageCategory, setEditingPackageCategory] = useState("");
|
|
32
33
|
const [editingPackageGithub, setEditingPackageGithub] = useState("");
|
|
33
34
|
const [editingPackageNpm, setEditingPackageNpm] = useState("");
|
|
35
|
+
const [editingPackageVetraDrive, setEditingPackageVetraDrive] = useState("");
|
|
34
36
|
const { state: { global } } = typedDocument;
|
|
35
37
|
const { profile, spaces, members } = global;
|
|
36
38
|
// Profile handlers
|
|
@@ -115,6 +117,7 @@ export default function Editor(props) {
|
|
|
115
117
|
category: newPackageCategory.trim() || null,
|
|
116
118
|
github: newPackageGithub.trim() || null,
|
|
117
119
|
npm: newPackageNpm.trim() || null,
|
|
120
|
+
vetraDriveUrl: newPackageVetraDrive.trim() || null,
|
|
118
121
|
spaceId: selectedSpaceForPackage,
|
|
119
122
|
author: {
|
|
120
123
|
name: profile.name,
|
|
@@ -126,10 +129,11 @@ export default function Editor(props) {
|
|
|
126
129
|
setNewPackageCategory("");
|
|
127
130
|
setNewPackageGithub("");
|
|
128
131
|
setNewPackageNpm("");
|
|
132
|
+
setNewPackageVetraDrive("");
|
|
129
133
|
setSelectedSpaceForPackage("");
|
|
130
134
|
setIsAddingPackage(false);
|
|
131
135
|
}
|
|
132
|
-
}, [newPackageName, newPackageDescription, newPackageCategory, newPackageGithub, newPackageNpm, selectedSpaceForPackage, profile, dispatch]);
|
|
136
|
+
}, [newPackageName, newPackageDescription, newPackageCategory, newPackageGithub, newPackageNpm, newPackageVetraDrive, selectedSpaceForPackage, profile, dispatch]);
|
|
133
137
|
const handleDeletePackage = useCallback((packageId) => {
|
|
134
138
|
dispatch(actions.deletePackage({ id: packageId }));
|
|
135
139
|
}, [dispatch]);
|
|
@@ -144,38 +148,28 @@ export default function Editor(props) {
|
|
|
144
148
|
setEditingPackageCategory(pkg.category || "");
|
|
145
149
|
setEditingPackageGithub(pkg.github || "");
|
|
146
150
|
setEditingPackageNpm(pkg.npm || "");
|
|
151
|
+
setEditingPackageVetraDrive(pkg.vetraDriveUrl || "");
|
|
147
152
|
break;
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
}, [spaces]);
|
|
151
156
|
const handleSavePackageEdit = useCallback(() => {
|
|
152
157
|
if (editingPackageId && editingPackageName.trim()) {
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
dispatch(actions.deletePackage({ id: editingPackageId }));
|
|
160
|
-
dispatch(actions.addPackage({
|
|
161
|
-
name: editingPackageName.trim(),
|
|
162
|
-
description: editingPackageDescription.trim() || null,
|
|
163
|
-
category: editingPackageCategory.trim() || null,
|
|
164
|
-
github: editingPackageGithub.trim() || null,
|
|
165
|
-
npm: editingPackageNpm.trim() || null,
|
|
166
|
-
spaceId: space.id,
|
|
167
|
-
author: originalPackage.author,
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
}
|
|
158
|
+
// Use the proper updatePackage action
|
|
159
|
+
dispatch(actions.updatePackage({
|
|
160
|
+
id: editingPackageId,
|
|
161
|
+
title: editingPackageName.trim(),
|
|
162
|
+
description: editingPackageDescription.trim() || null,
|
|
163
|
+
}));
|
|
171
164
|
setEditingPackageId(null);
|
|
172
165
|
setEditingPackageName("");
|
|
173
166
|
setEditingPackageDescription("");
|
|
174
167
|
setEditingPackageCategory("");
|
|
175
168
|
setEditingPackageGithub("");
|
|
176
169
|
setEditingPackageNpm("");
|
|
170
|
+
setEditingPackageVetraDrive("");
|
|
177
171
|
}
|
|
178
|
-
}, [editingPackageId, editingPackageName, editingPackageDescription,
|
|
172
|
+
}, [editingPackageId, editingPackageName, editingPackageDescription, dispatch]);
|
|
179
173
|
const handleCancelPackageEdit = useCallback(() => {
|
|
180
174
|
setEditingPackageId(null);
|
|
181
175
|
setEditingPackageName("");
|
|
@@ -183,6 +177,7 @@ export default function Editor(props) {
|
|
|
183
177
|
setEditingPackageCategory("");
|
|
184
178
|
setEditingPackageGithub("");
|
|
185
179
|
setEditingPackageNpm("");
|
|
180
|
+
setEditingPackageVetraDrive("");
|
|
186
181
|
}, []);
|
|
187
182
|
// Member handlers
|
|
188
183
|
const handleAddMember = useCallback(() => {
|
|
@@ -197,5 +192,5 @@ export default function Editor(props) {
|
|
|
197
192
|
return (_jsxs("div", { className: "html-defaults-container min-h-screen bg-gray-50", children: [_jsx("div", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "py-6", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("div", { className: "flex-shrink-0", children: profile.logo ? (_jsx("img", { className: "w-12 h-12 rounded-lg object-cover", src: profile.logo, alt: "Logo" })) : (_jsx("div", { className: "w-12 h-12 bg-blue-600 rounded-lg flex items-center justify-center", children: _jsx("svg", { className: "w-6 h-6 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }) })) }), _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900", children: profile.name || "Builder Account" }), _jsx("p", { className: "text-sm text-gray-500", children: profile.slug ? `@${profile.slug}` : "Manage your builder profile and packages" })] })] }), _jsx("div", { className: "flex items-center space-x-3", children: _jsx(Button, { color: "light", onClick: () => setIsEditingProfile(!isEditingProfile), children: isEditingProfile ? "Cancel" : "Edit Profile" }) })] }) }) }) }), _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-8", children: [_jsxs("div", { className: "lg:col-span-2 space-y-8", children: [_jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsxs("div", { className: "px-6 py-4 border-b border-gray-200", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Profile Information" }), _jsx("p", { className: "text-sm text-gray-500", children: "Manage your builder profile details" })] }), _jsx("div", { className: "p-6", children: isEditingProfile ? (_jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-6", children: [_jsx(StringField, { name: "profileName", label: "Profile Name", value: profile.name, onChange: (e) => handleSetProfileName(e.target.value), placeholder: "Enter your profile name", description: "Your public display name" }), _jsx(StringField, { name: "slug", label: "Slug", value: profile.slug, onChange: (e) => handleSetSlug(e.target.value), placeholder: "your-slug", description: "Unique identifier for your profile (used in URLs)" }), _jsx(StringField, { name: "description", label: "Description", value: profile.description || "", onChange: (e) => handleSetProfileDescription(e.target.value), placeholder: "Tell us about yourself and your work", description: "Brief description of your work and interests" }), _jsx(UrlField, { name: "logo", label: "Logo URL", value: profile.logo || "", onChange: (e) => handleSetLogo(e.target.value), placeholder: "https://example.com/logo.png", description: "URL to your profile logo image" }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-md font-medium text-gray-900", children: "Social Links" }), _jsx(UrlField, { name: "github", label: "GitHub", value: profile.socials.github || "", onChange: (e) => handleUpdateSocials({ ...profile.socials, github: e.target.value }), placeholder: "https://github.com/username" }), _jsx(UrlField, { name: "website", label: "Website", value: profile.socials.website || "", onChange: (e) => handleUpdateSocials({ ...profile.socials, website: e.target.value }), placeholder: "https://your-website.com" }), _jsx(UrlField, { name: "x", label: "X (Twitter)", value: profile.socials.xProfile || "", onChange: (e) => handleUpdateSocials({ ...profile.socials, x: e.target.value }), placeholder: "https://x.com/username" })] }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsEditingProfile(false), children: "Cancel" }), _jsx(Button, { onClick: () => setIsEditingProfile(false), children: "Save Changes" })] })] }) })) : (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: "Name" }), _jsx("p", { className: "mt-1 text-sm text-gray-900", children: profile.name || "Not set" })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: "Slug" }), _jsx("p", { className: "mt-1 text-sm text-gray-900", children: profile.slug ? `@${profile.slug}` : "Not set" })] })] }), profile.description && (_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: "Description" }), _jsx("p", { className: "mt-1 text-sm text-gray-900", children: profile.description })] })), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: "Social Links" }), _jsxs("div", { className: "mt-2 flex space-x-4", children: [profile.socials.github && (_jsx("a", { href: profile.socials.github, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:text-blue-800", children: "GitHub" })), profile.socials.website && (_jsx("a", { href: profile.socials.website, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:text-blue-800", children: "Website" })), profile.socials.xProfile && (_jsx("a", { href: profile.socials.xProfile, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:text-blue-800", children: "X (Twitter)" })), !profile.socials.github && !profile.socials.website && !profile.socials.xProfile && (_jsx("span", { className: "text-gray-500 text-sm", children: "No social links added" }))] })] })] })) })] }), _jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Spaces" }), _jsx("p", { className: "text-sm text-gray-500", children: "Organize your packages into spaces" })] }), _jsx(Button, { onClick: () => setIsAddingSpace(true), children: "Add Space" })] }) }), _jsxs("div", { className: "p-6", children: [isAddingSpace ? (_jsx("div", { className: "p-4 bg-gray-50 rounded-lg", children: _jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-4", children: [_jsx(StringField, { name: "spaceTitle", label: "Space Title", value: newSpaceTitle, onChange: (e) => setNewSpaceTitle(e.target.value), placeholder: "Enter space title" }), _jsx(StringField, { name: "spaceDescription", label: "Description (optional)", value: newSpaceDescription, onChange: (e) => setNewSpaceDescription(e.target.value), placeholder: "Enter space description" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsAddingSpace(false), children: "Cancel" }), _jsx(Button, { onClick: handleAddSpace, disabled: !newSpaceTitle.trim(), children: "Add Space" })] })] }) }) })) : null, _jsx("div", { className: "space-y-4", children: spaces.length > 0 ? (spaces.map((space) => (_jsxs("div", { className: "border border-gray-200 rounded-lg p-4", children: [editingSpaceId === space.id ? (_jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-4", children: [_jsx(StringField, { name: "editingSpaceTitle", label: "Space Title", value: editingSpaceTitle, onChange: (e) => setEditingSpaceTitle(e.target.value), placeholder: "Enter space title" }), _jsx(StringField, { name: "editingSpaceDescription", label: "Description (optional)", value: editingSpaceDescription, onChange: (e) => setEditingSpaceDescription(e.target.value), placeholder: "Enter space description" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: handleCancelSpaceEdit, children: "Cancel" }), _jsx(Button, { onClick: handleSaveSpaceEdit, disabled: !editingSpaceTitle.trim(), children: "Save Changes" })] })] }) })) : (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-md font-medium text-gray-900", children: space.title }), space.description && (_jsx("p", { className: "text-sm text-gray-500 mt-1", children: space.description })), _jsxs("p", { className: "text-xs text-gray-400 mt-1", children: [space.packages.length, " package", space.packages.length !== 1 ? 's' : ''] })] }), _jsxs("div", { className: "flex space-x-2", children: [_jsx(Button, { color: "light", size: "sm", onClick: () => handleStartEditingSpace(space.id), children: "Edit" }), _jsx(Button, { color: "light", size: "sm", onClick: () => {
|
|
198
193
|
setSelectedSpaceForPackage(space.id);
|
|
199
194
|
setIsAddingPackage(true);
|
|
200
|
-
}, children: "Add Package" }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleDeleteSpace(space.id), children: "Delete" })] })] })), space.packages.length > 0 && (_jsx("div", { className: "mt-4 space-y-2", children: space.packages.map((pkg) => (_jsx("div", { className: "p-3 bg-gray-50 rounded border", children: editingPackageId === pkg.id ? (_jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-3", children: [_jsx(StringField, { name: "editingPackageName", label: "Package Name", value: editingPackageName, onChange: (e) => setEditingPackageName(e.target.value), placeholder: "Enter package name" }), _jsx(StringField, { name: "editingPackageDescription", label: "Description", value: editingPackageDescription, onChange: (e) => setEditingPackageDescription(e.target.value), placeholder: "Enter package description" }), _jsx(StringField, { name: "editingPackageCategory", label: "Category", value: editingPackageCategory, onChange: (e) => setEditingPackageCategory(e.target.value), placeholder: "Enter package category" }), _jsx(UrlField, { name: "editingPackageGithub", label: "GitHub URL", value: editingPackageGithub, onChange: (e) => setEditingPackageGithub(e.target.value), placeholder: "https://github.com/username/repo" }), _jsx(UrlField, { name: "editingPackageNpm", label: "NPM URL", value: editingPackageNpm, onChange: (e) => setEditingPackageNpm(e.target.value), placeholder: "https://www.npmjs.com/package/package-name" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: handleCancelPackageEdit, children: "Cancel" }), _jsx(Button, { onClick: handleSavePackageEdit, disabled: !editingPackageName.trim(), children: "Save Changes" })] })] }) })) : (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium text-gray-900", children: pkg.name }), pkg.description && (_jsx("p", { className: "text-sm text-gray-500", children: pkg.description })), pkg.category && (_jsxs("p", { className: "text-xs text-gray-400", children: ["Category: ", pkg.category] }))] }), _jsxs("div", { className: "flex space-x-2", children: [_jsx(Button, { color: "light", size: "sm", onClick: () => handleStartEditingPackage(pkg.id), children: "Edit" }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleDeletePackage(pkg.id), children: "Remove" })] })] })) }, pkg.id))) }))] }, space.id)))) : (_jsx("div", { className: "text-center py-8 text-gray-500", children: _jsx("p", { children: "No spaces created yet. Create a space to organize your packages." }) })) })] })] }), isAddingPackage && (_jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200", children: _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Add Package" }) }), _jsx("div", { className: "p-6", children: _jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-4", children: [_jsx(StringField, { name: "packageName", label: "Package Name", value: newPackageName, onChange: (e) => setNewPackageName(e.target.value), placeholder: "Enter package name" }), _jsx(StringField, { name: "packageDescription", label: "Description", value: newPackageDescription, onChange: (e) => setNewPackageDescription(e.target.value), placeholder: "Enter package description" }), _jsx(StringField, { name: "packageCategory", label: "Category", value: newPackageCategory, onChange: (e) => setNewPackageCategory(e.target.value), placeholder: "Enter package category" }), _jsx(UrlField, { name: "packageGithub", label: "GitHub URL", value: newPackageGithub, onChange: (e) => setNewPackageGithub(e.target.value), placeholder: "https://github.com/username/repo" }), _jsx(UrlField, { name: "packageNpm", label: "NPM URL", value: newPackageNpm, onChange: (e) => setNewPackageNpm(e.target.value), placeholder: "https://www.npmjs.com/package/package-name" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsAddingPackage(false), children: "Cancel" }), _jsx(Button, { onClick: handleAddPackage, disabled: !newPackageName.trim() || !selectedSpaceForPackage, children: "Add Package" })] })] }) }) })] }))] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsxs("div", { className: "px-6 py-4 border-b border-gray-200", children: [_jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Team Members" }), _jsx("p", { className: "text-sm text-gray-500", children: "Manage team access" })] }), _jsx("div", { className: "p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex space-x-2", children: [_jsx("input", { type: "text", value: newMemberAddress, onChange: (e) => setNewMemberAddress(e.target.value), placeholder: "0x...", className: "flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" }), _jsx(Button, { onClick: handleAddMember, disabled: !newMemberAddress.trim(), children: "Add" })] }), _jsx("div", { className: "space-y-2", children: members.length > 0 ? (members.map((address, index) => (_jsxs("div", { className: "flex items-center justify-between p-2 bg-gray-50 rounded border", children: [_jsx("span", { className: "text-sm font-mono text-gray-700 truncate", children: address }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleRemoveMember(address), children: "Remove" })] }, index)))) : (_jsx("p", { className: "text-sm text-gray-500", children: "No team members added yet" })) })] }) })] }), _jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200", children: _jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Quick Stats" }) }), _jsx("div", { className: "p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Spaces" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: spaces.length })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Total Packages" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: spaces.reduce((total, space) => total + space.packages.length, 0) })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Team Members" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: members.length })] })] }) })] })] })] }) })] }));
|
|
195
|
+
}, children: "Add Package" }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleDeleteSpace(space.id), children: "Delete" })] })] })), space.packages.length > 0 && (_jsx("div", { className: "mt-4 space-y-2", children: space.packages.map((pkg) => (_jsx("div", { className: "p-3 bg-gray-50 rounded border", children: editingPackageId === pkg.id ? (_jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-3", children: [_jsx(StringField, { name: "editingPackageName", label: "Package Name", value: editingPackageName, onChange: (e) => setEditingPackageName(e.target.value), placeholder: "Enter package name" }), _jsx(StringField, { name: "editingPackageDescription", label: "Description", value: editingPackageDescription, onChange: (e) => setEditingPackageDescription(e.target.value), placeholder: "Enter package description" }), _jsx(StringField, { name: "editingPackageCategory", label: "Category", value: editingPackageCategory, onChange: (e) => setEditingPackageCategory(e.target.value), placeholder: "Enter package category" }), _jsx(UrlField, { name: "editingPackageGithub", label: "GitHub URL", value: editingPackageGithub, onChange: (e) => setEditingPackageGithub(e.target.value), placeholder: "https://github.com/username/repo" }), _jsx(UrlField, { name: "editingPackageNpm", label: "NPM URL", value: editingPackageNpm, onChange: (e) => setEditingPackageNpm(e.target.value), placeholder: "https://www.npmjs.com/package/package-name" }), _jsx(UrlField, { name: "editingPackageVetraDrive", label: "Vetra Drive URL", value: editingPackageVetraDrive, onChange: (e) => setEditingPackageVetraDrive(e.target.value), placeholder: "https://vetra.to/drive/..." }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: handleCancelPackageEdit, children: "Cancel" }), _jsx(Button, { onClick: handleSavePackageEdit, disabled: !editingPackageName.trim(), children: "Save Changes" })] })] }) })) : (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium text-gray-900", children: pkg.name }), pkg.description && (_jsx("p", { className: "text-sm text-gray-500", children: pkg.description })), pkg.category && (_jsxs("p", { className: "text-xs text-gray-400", children: ["Category: ", pkg.category] })), pkg.vetraDriveUrl && (_jsx("p", { className: "text-xs text-blue-600", children: _jsx("a", { href: pkg.vetraDriveUrl, target: "_blank", rel: "noopener noreferrer", className: "hover:underline", children: "Vetra Drive" }) }))] }), _jsxs("div", { className: "flex space-x-2", children: [_jsx(Button, { color: "light", size: "sm", onClick: () => handleStartEditingPackage(pkg.id), children: "Edit" }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleDeletePackage(pkg.id), children: "Remove" })] })] })) }, pkg.id))) }))] }, space.id)))) : (_jsx("div", { className: "text-center py-8 text-gray-500", children: _jsx("p", { children: "No spaces created yet. Create a space to organize your packages." }) })) })] })] }), isAddingPackage && (_jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200", children: _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Add Package" }) }), _jsx("div", { className: "p-6", children: _jsx(Form, { onSubmit: (e) => e.preventDefault(), children: _jsxs("div", { className: "space-y-4", children: [_jsx(StringField, { name: "packageName", label: "Package Name", value: newPackageName, onChange: (e) => setNewPackageName(e.target.value), placeholder: "Enter package name" }), _jsx(StringField, { name: "packageDescription", label: "Description", value: newPackageDescription, onChange: (e) => setNewPackageDescription(e.target.value), placeholder: "Enter package description" }), _jsx(StringField, { name: "packageCategory", label: "Category", value: newPackageCategory, onChange: (e) => setNewPackageCategory(e.target.value), placeholder: "Enter package category" }), _jsx(UrlField, { name: "packageGithub", label: "GitHub URL", value: newPackageGithub, onChange: (e) => setNewPackageGithub(e.target.value), placeholder: "https://github.com/username/repo" }), _jsx(UrlField, { name: "packageNpm", label: "NPM URL", value: newPackageNpm, onChange: (e) => setNewPackageNpm(e.target.value), placeholder: "https://www.npmjs.com/package/package-name" }), _jsx(UrlField, { name: "packageVetraDrive", label: "Vetra Drive URL", value: newPackageVetraDrive, onChange: (e) => setNewPackageVetraDrive(e.target.value), placeholder: "https://vetra.to/drive/..." }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsAddingPackage(false), children: "Cancel" }), _jsx(Button, { onClick: handleAddPackage, disabled: !newPackageName.trim() || !selectedSpaceForPackage, children: "Add Package" })] })] }) }) })] }))] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsxs("div", { className: "px-6 py-4 border-b border-gray-200", children: [_jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Team Members" }), _jsx("p", { className: "text-sm text-gray-500", children: "Manage team access" })] }), _jsx("div", { className: "p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex space-x-2", children: [_jsx("input", { type: "text", value: newMemberAddress, onChange: (e) => setNewMemberAddress(e.target.value), placeholder: "0x...", className: "flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" }), _jsx(Button, { onClick: handleAddMember, disabled: !newMemberAddress.trim(), children: "Add" })] }), _jsx("div", { className: "space-y-2", children: members.length > 0 ? (members.map((address, index) => (_jsxs("div", { className: "flex items-center justify-between p-2 bg-gray-50 rounded border", children: [_jsx("span", { className: "text-sm font-mono text-gray-700 truncate", children: address }), _jsx(Button, { color: "red", size: "sm", onClick: () => handleRemoveMember(address), children: "Remove" })] }, index)))) : (_jsx("p", { className: "text-sm text-gray-500", children: "No team members added yet" })) })] }) })] }), _jsxs("div", { className: "bg-white rounded-lg shadow-sm border", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200", children: _jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Quick Stats" }) }), _jsx("div", { className: "p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Spaces" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: spaces.length })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Total Packages" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: spaces.reduce((total, space) => total + space.packages.length, 0) })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm text-gray-500", children: "Team Members" }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: members.length })] })] }) })] })] })] }) })] }));
|
|
201
196
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BuilderAccountAction } from "../../document-models/builder-account/gen/actions.js";
|
|
2
|
+
import type { BuilderAccountState } from "document-models/builder-account/index.js";
|
|
3
|
+
import type { DB } from "./schema.js";
|
|
4
|
+
import type { IRelationalDb } from "document-drive";
|
|
5
|
+
export declare class BuilderAccountHandlers {
|
|
6
|
+
private db;
|
|
7
|
+
private dbHelpers;
|
|
8
|
+
constructor(db: IRelationalDb<DB>);
|
|
9
|
+
handleBuilderAccountOperation(documentId: string, action: BuilderAccountAction, state: BuilderAccountState, driveId?: string): Promise<void>;
|
|
10
|
+
private handleSetLogo;
|
|
11
|
+
private handleSetProfileName;
|
|
12
|
+
private handleSetSlug;
|
|
13
|
+
private handleSetProfileDescription;
|
|
14
|
+
private handleUpdateSocials;
|
|
15
|
+
private handleAddMember;
|
|
16
|
+
private handleRemoveMember;
|
|
17
|
+
private handleAddSpace;
|
|
18
|
+
private handleDeleteSpace;
|
|
19
|
+
private handleSetSpaceTitle;
|
|
20
|
+
private handleSetSpaceDescription;
|
|
21
|
+
private handleReorderSpaces;
|
|
22
|
+
private handleAddPackage;
|
|
23
|
+
private handleSetPackageDriveId;
|
|
24
|
+
private handleUpdatePackage;
|
|
25
|
+
private handleReorderPackages;
|
|
26
|
+
private handleDeletePackage;
|
|
27
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { toPascalCase } from "document-drive/utils/misc";
|
|
2
|
+
import { DatabaseHelpers } from "./database-helpers.js";
|
|
3
|
+
export class BuilderAccountHandlers {
|
|
4
|
+
db;
|
|
5
|
+
dbHelpers;
|
|
6
|
+
constructor(db) {
|
|
7
|
+
this.db = db;
|
|
8
|
+
this.dbHelpers = new DatabaseHelpers(db);
|
|
9
|
+
}
|
|
10
|
+
async handleBuilderAccountOperation(documentId, action, state, driveId) {
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
// Profile operations
|
|
13
|
+
case "SET_LOGO":
|
|
14
|
+
await this.handleSetLogo(documentId, action, state);
|
|
15
|
+
break;
|
|
16
|
+
case "SET_PROFILE_NAME":
|
|
17
|
+
await this.handleSetProfileName(documentId, action, state);
|
|
18
|
+
break;
|
|
19
|
+
case "SET_SLUG":
|
|
20
|
+
await this.handleSetSlug(documentId, action, state);
|
|
21
|
+
break;
|
|
22
|
+
case "SET_PROFILE_DESCRIPTION":
|
|
23
|
+
await this.handleSetProfileDescription(documentId, action, state);
|
|
24
|
+
break;
|
|
25
|
+
case "UPDATE_SOCIALS":
|
|
26
|
+
await this.handleUpdateSocials(documentId, action, state);
|
|
27
|
+
break;
|
|
28
|
+
// Members operations
|
|
29
|
+
case "ADD_MEMBER":
|
|
30
|
+
await this.handleAddMember(documentId, action, state);
|
|
31
|
+
break;
|
|
32
|
+
case "REMOVE_MEMBER":
|
|
33
|
+
await this.handleRemoveMember(documentId, action, state);
|
|
34
|
+
break;
|
|
35
|
+
// Spaces operations
|
|
36
|
+
case "ADD_SPACE":
|
|
37
|
+
await this.handleAddSpace(documentId, action, state);
|
|
38
|
+
break;
|
|
39
|
+
case "DELETE_SPACE":
|
|
40
|
+
await this.handleDeleteSpace(documentId, action, state);
|
|
41
|
+
break;
|
|
42
|
+
case "SET_SPACE_TITLE":
|
|
43
|
+
await this.handleSetSpaceTitle(documentId, action, state);
|
|
44
|
+
break;
|
|
45
|
+
case "SET_SPACE_DESCRIPTION":
|
|
46
|
+
await this.handleSetSpaceDescription(documentId, action, state);
|
|
47
|
+
break;
|
|
48
|
+
case "REORDER_SPACES":
|
|
49
|
+
await this.handleReorderSpaces(documentId, action, state);
|
|
50
|
+
break;
|
|
51
|
+
// Packages operations
|
|
52
|
+
case "ADD_PACKAGE":
|
|
53
|
+
await this.handleAddPackage(documentId, action, state);
|
|
54
|
+
break;
|
|
55
|
+
case "SET_PACKAGE_DRIVE_ID":
|
|
56
|
+
await this.handleSetPackageDriveId(documentId, action, state);
|
|
57
|
+
break;
|
|
58
|
+
case "UPDATE_PACKAGE":
|
|
59
|
+
await this.handleUpdatePackage(documentId, action, state);
|
|
60
|
+
break;
|
|
61
|
+
case "REORDER_PACKAGES":
|
|
62
|
+
await this.handleReorderPackages(documentId, action, state);
|
|
63
|
+
break;
|
|
64
|
+
case "DELETE_PACKAGE":
|
|
65
|
+
await this.handleDeletePackage(documentId, action, state);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Profile operations
|
|
70
|
+
async handleSetLogo(documentId, action, state) {
|
|
71
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
72
|
+
await this.dbHelpers.updateBuilderAccount(documentId, {
|
|
73
|
+
profile_logo: action.input.logoUrl,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async handleSetProfileName(documentId, action, state) {
|
|
77
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
78
|
+
await this.dbHelpers.updateBuilderAccount(documentId, {
|
|
79
|
+
profile_name: action.input.name,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async handleSetSlug(documentId, action, state) {
|
|
83
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
84
|
+
await this.dbHelpers.updateBuilderAccount(documentId, {
|
|
85
|
+
profile_slug: action.input.slug,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async handleSetProfileDescription(documentId, action, state) {
|
|
89
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
90
|
+
await this.dbHelpers.updateBuilderAccount(documentId, {
|
|
91
|
+
profile_description: action.input.description,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async handleUpdateSocials(documentId, action, state) {
|
|
95
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
96
|
+
await this.dbHelpers.updateBuilderAccount(documentId, {
|
|
97
|
+
profile_socials_x: action.input.x,
|
|
98
|
+
profile_socials_github: action.input.github,
|
|
99
|
+
profile_socials_website: action.input.website,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// Members operations
|
|
103
|
+
async handleAddMember(documentId, action, state) {
|
|
104
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
105
|
+
if (!action.input.ethAddress)
|
|
106
|
+
return;
|
|
107
|
+
const memberExists = await this.dbHelpers.memberExists(documentId, action.input.ethAddress);
|
|
108
|
+
if (!memberExists) {
|
|
109
|
+
await this.db
|
|
110
|
+
.insertInto("builder_account_members")
|
|
111
|
+
.values({
|
|
112
|
+
id: action.input.ethAddress,
|
|
113
|
+
builder_account_id: documentId,
|
|
114
|
+
eth_address: action.input.ethAddress,
|
|
115
|
+
created_at: new Date(),
|
|
116
|
+
})
|
|
117
|
+
.execute();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async handleRemoveMember(documentId, action, state) {
|
|
121
|
+
if (!action.input.ethAddress)
|
|
122
|
+
return;
|
|
123
|
+
await this.db
|
|
124
|
+
.deleteFrom("builder_account_members")
|
|
125
|
+
.where("builder_account_id", "=", documentId)
|
|
126
|
+
.where("eth_address", "=", action.input.ethAddress)
|
|
127
|
+
.execute();
|
|
128
|
+
}
|
|
129
|
+
// Spaces operations
|
|
130
|
+
async handleAddSpace(documentId, action, state) {
|
|
131
|
+
await this.dbHelpers.ensureBuilderAccount(documentId);
|
|
132
|
+
const spaceId = toPascalCase(action.input.title);
|
|
133
|
+
await this.db
|
|
134
|
+
.insertInto("builder_spaces")
|
|
135
|
+
.values({
|
|
136
|
+
id: spaceId,
|
|
137
|
+
builder_account_id: documentId,
|
|
138
|
+
title: action.input.title,
|
|
139
|
+
description: action.input.description || null,
|
|
140
|
+
sort_order: 0,
|
|
141
|
+
created_at: new Date(),
|
|
142
|
+
updated_at: new Date(),
|
|
143
|
+
})
|
|
144
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
145
|
+
.execute();
|
|
146
|
+
}
|
|
147
|
+
async handleDeleteSpace(documentId, action, state) {
|
|
148
|
+
await this.db
|
|
149
|
+
.deleteFrom("builder_spaces")
|
|
150
|
+
.where("id", "=", action.input.id)
|
|
151
|
+
.where("builder_account_id", "=", documentId)
|
|
152
|
+
.execute();
|
|
153
|
+
}
|
|
154
|
+
async handleSetSpaceTitle(documentId, action, state) {
|
|
155
|
+
await this.dbHelpers.updateBuilderSpace(action.input.id, documentId, {
|
|
156
|
+
title: action.input.newTitle,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async handleSetSpaceDescription(documentId, action, state) {
|
|
160
|
+
await this.dbHelpers.updateBuilderSpace(action.input.id, documentId, {
|
|
161
|
+
description: action.input.description,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async handleReorderSpaces(documentId, action, state) {
|
|
165
|
+
const { ids, insertAfter } = action.input;
|
|
166
|
+
for (let i = 0; i < ids.length; i++) {
|
|
167
|
+
const spaceId = ids[i];
|
|
168
|
+
const sortOrder = insertAfter !== null ? Number(insertAfter) + i + 1 : i;
|
|
169
|
+
await this.dbHelpers.updateBuilderSpace(spaceId, documentId, {
|
|
170
|
+
sort_order: sortOrder,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Packages operations
|
|
175
|
+
async handleAddPackage(documentId, action, state) {
|
|
176
|
+
const packageId = action.input.spaceId + "-" + toPascalCase(action.input.name);
|
|
177
|
+
await this.db
|
|
178
|
+
.insertInto("builder_packages")
|
|
179
|
+
.values({
|
|
180
|
+
id: `${packageId}`,
|
|
181
|
+
space_id: action.input.spaceId,
|
|
182
|
+
name: action.input.name,
|
|
183
|
+
description: action.input.description || null,
|
|
184
|
+
category: action.input.category || null,
|
|
185
|
+
author_name: action.input.author?.name || "",
|
|
186
|
+
author_website: action.input.author?.website || null,
|
|
187
|
+
github_url: action.input.github || null,
|
|
188
|
+
npm_url: action.input.npm || null,
|
|
189
|
+
vetra_drive_url: action.input.vetraDriveUrl || null,
|
|
190
|
+
drive_id: null,
|
|
191
|
+
sort_order: 0,
|
|
192
|
+
created_at: new Date(),
|
|
193
|
+
updated_at: new Date(),
|
|
194
|
+
})
|
|
195
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
196
|
+
.execute();
|
|
197
|
+
// Add keywords if provided
|
|
198
|
+
if (action.input.keywords && action.input.keywords.length > 0) {
|
|
199
|
+
for (const keyword of action.input.keywords) {
|
|
200
|
+
await this.db
|
|
201
|
+
.insertInto("builder_package_keywords")
|
|
202
|
+
.values({
|
|
203
|
+
id: `${packageId}-${keyword}`,
|
|
204
|
+
package_id: packageId,
|
|
205
|
+
label: keyword,
|
|
206
|
+
created_at: new Date(),
|
|
207
|
+
})
|
|
208
|
+
.execute();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async handleSetPackageDriveId(documentId, action, state) {
|
|
213
|
+
await this.dbHelpers.updateBuilderPackage(action.input.packageId, {
|
|
214
|
+
drive_id: action.input.driveId,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async handleUpdatePackage(documentId, action, state) {
|
|
218
|
+
const updates = {};
|
|
219
|
+
if (action.input.title !== undefined) {
|
|
220
|
+
updates.name = action.input.title;
|
|
221
|
+
}
|
|
222
|
+
if (action.input.description !== undefined) {
|
|
223
|
+
updates.description = action.input.description;
|
|
224
|
+
}
|
|
225
|
+
await this.dbHelpers.updateBuilderPackage(action.input.id, updates);
|
|
226
|
+
}
|
|
227
|
+
async handleReorderPackages(documentId, action, state) {
|
|
228
|
+
const { ids, insertAfter, spaceId } = action.input;
|
|
229
|
+
for (let i = 0; i < ids.length; i++) {
|
|
230
|
+
const packageId = ids[i];
|
|
231
|
+
const sortOrder = insertAfter !== null ? Number(insertAfter) + i + 1 : i;
|
|
232
|
+
await this.db
|
|
233
|
+
.updateTable("builder_packages")
|
|
234
|
+
.set({
|
|
235
|
+
sort_order: sortOrder,
|
|
236
|
+
updated_at: new Date(),
|
|
237
|
+
})
|
|
238
|
+
.where("id", "=", packageId)
|
|
239
|
+
.where("space_id", "=", spaceId)
|
|
240
|
+
.execute();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async handleDeletePackage(documentId, action, state) {
|
|
244
|
+
await this.db
|
|
245
|
+
.deleteFrom("builder_packages")
|
|
246
|
+
.where("id", "=", action.input.id)
|
|
247
|
+
.execute();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { IRelationalDb } from "document-drive";
|
|
2
|
+
import type { DB } from "./schema.js";
|
|
3
|
+
export declare class DatabaseHelpers {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(db: IRelationalDb<DB>);
|
|
6
|
+
/**
|
|
7
|
+
* Ensures a package exists in the database, creating it if it doesn't
|
|
8
|
+
*/
|
|
9
|
+
ensurePackageExists(documentId: string, driveId: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Ensures a builder account exists in the database, creating it if it doesn't
|
|
12
|
+
*/
|
|
13
|
+
ensureBuilderAccount(documentId: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Updates a package with the provided data
|
|
16
|
+
*/
|
|
17
|
+
updatePackage(documentId: string, updates: Record<string, any>): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Updates a builder account with the provided data
|
|
20
|
+
*/
|
|
21
|
+
updateBuilderAccount(documentId: string, updates: Record<string, any>): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Updates a builder space with the provided data
|
|
24
|
+
*/
|
|
25
|
+
updateBuilderSpace(spaceId: string, documentId: string, updates: Record<string, any>): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Updates a builder package with the provided data
|
|
28
|
+
*/
|
|
29
|
+
updateBuilderPackage(packageId: string, updates: Record<string, any>): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a member already exists for a builder account
|
|
32
|
+
*/
|
|
33
|
+
memberExists(documentId: string, ethAddress: string): Promise<boolean>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export class DatabaseHelpers {
|
|
2
|
+
db;
|
|
3
|
+
constructor(db) {
|
|
4
|
+
this.db = db;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Ensures a package exists in the database, creating it if it doesn't
|
|
8
|
+
*/
|
|
9
|
+
async ensurePackageExists(documentId, driveId) {
|
|
10
|
+
const existing = await this.db
|
|
11
|
+
.selectFrom("builder_packages")
|
|
12
|
+
.select("id")
|
|
13
|
+
.where("id", "=", documentId)
|
|
14
|
+
.executeTakeFirst();
|
|
15
|
+
if (!existing) {
|
|
16
|
+
await this.db
|
|
17
|
+
.insertInto("builder_packages")
|
|
18
|
+
.values({
|
|
19
|
+
id: documentId,
|
|
20
|
+
drive_id: driveId,
|
|
21
|
+
author_name: "",
|
|
22
|
+
name: "",
|
|
23
|
+
space_id: "",
|
|
24
|
+
})
|
|
25
|
+
.execute();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Ensures a builder account exists in the database, creating it if it doesn't
|
|
30
|
+
*/
|
|
31
|
+
async ensureBuilderAccount(documentId) {
|
|
32
|
+
const existing = await this.db
|
|
33
|
+
.selectFrom("builder_accounts")
|
|
34
|
+
.select("id")
|
|
35
|
+
.where("id", "=", documentId)
|
|
36
|
+
.executeTakeFirst();
|
|
37
|
+
if (!existing) {
|
|
38
|
+
await this.db
|
|
39
|
+
.insertInto("builder_accounts")
|
|
40
|
+
.values({
|
|
41
|
+
id: documentId,
|
|
42
|
+
profile_name: "",
|
|
43
|
+
profile_slug: "",
|
|
44
|
+
profile_logo: null,
|
|
45
|
+
profile_description: null,
|
|
46
|
+
profile_socials_x: null,
|
|
47
|
+
profile_socials_github: null,
|
|
48
|
+
profile_socials_website: null,
|
|
49
|
+
created_at: new Date(),
|
|
50
|
+
updated_at: new Date(),
|
|
51
|
+
})
|
|
52
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
53
|
+
.execute();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Updates a package with the provided data
|
|
58
|
+
*/
|
|
59
|
+
async updatePackage(documentId, updates) {
|
|
60
|
+
await this.db
|
|
61
|
+
.updateTable("builder_packages")
|
|
62
|
+
.set({
|
|
63
|
+
...updates,
|
|
64
|
+
updated_at: new Date(),
|
|
65
|
+
})
|
|
66
|
+
.where("id", "=", documentId)
|
|
67
|
+
.execute();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Updates a builder account with the provided data
|
|
71
|
+
*/
|
|
72
|
+
async updateBuilderAccount(documentId, updates) {
|
|
73
|
+
await this.db
|
|
74
|
+
.updateTable("builder_accounts")
|
|
75
|
+
.set({
|
|
76
|
+
...updates,
|
|
77
|
+
updated_at: new Date(),
|
|
78
|
+
})
|
|
79
|
+
.where("id", "=", documentId)
|
|
80
|
+
.execute();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Updates a builder space with the provided data
|
|
84
|
+
*/
|
|
85
|
+
async updateBuilderSpace(spaceId, documentId, updates) {
|
|
86
|
+
await this.db
|
|
87
|
+
.updateTable("builder_spaces")
|
|
88
|
+
.set({
|
|
89
|
+
...updates,
|
|
90
|
+
updated_at: new Date(),
|
|
91
|
+
})
|
|
92
|
+
.where("id", "=", spaceId)
|
|
93
|
+
.where("builder_account_id", "=", documentId)
|
|
94
|
+
.execute();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Updates a builder package with the provided data
|
|
98
|
+
*/
|
|
99
|
+
async updateBuilderPackage(packageId, updates) {
|
|
100
|
+
await this.db
|
|
101
|
+
.updateTable("builder_packages")
|
|
102
|
+
.set({
|
|
103
|
+
...updates,
|
|
104
|
+
updated_at: new Date(),
|
|
105
|
+
})
|
|
106
|
+
.where("id", "=", packageId)
|
|
107
|
+
.execute();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Checks if a member already exists for a builder account
|
|
111
|
+
*/
|
|
112
|
+
async memberExists(documentId, ethAddress) {
|
|
113
|
+
const existing = await this.db
|
|
114
|
+
.selectFrom("builder_account_members")
|
|
115
|
+
.select("id")
|
|
116
|
+
.where("builder_account_id", "=", documentId)
|
|
117
|
+
.where("eth_address", "=", ethAddress)
|
|
118
|
+
.executeTakeFirst();
|
|
119
|
+
return !!existing;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Action } from "document-model";
|
|
2
|
+
import type { BuilderAccountState } from "document-models/builder-account/index.js";
|
|
3
|
+
import type { DB } from "./schema.js";
|
|
4
|
+
import type { IRelationalDb } from "document-drive";
|
|
5
|
+
export declare class PackageHandlers {
|
|
6
|
+
private db;
|
|
7
|
+
private dbHelpers;
|
|
8
|
+
constructor(db: IRelationalDb<DB>);
|
|
9
|
+
handlePackageOperation(documentId: string, action: Action, state: BuilderAccountState, driveId?: string): Promise<void>;
|
|
10
|
+
private handleSetPackageName;
|
|
11
|
+
private handleSetPackageDescription;
|
|
12
|
+
private handleSetPackageCategory;
|
|
13
|
+
private handleSetPackageAuthor;
|
|
14
|
+
private handleSetPackageAuthorName;
|
|
15
|
+
private handleSetPackageAuthorWebsite;
|
|
16
|
+
private handleAddPackageKeyword;
|
|
17
|
+
private handleRemovePackageKeyword;
|
|
18
|
+
private handleSetPackageGithubUrl;
|
|
19
|
+
private handleSetPackageNpmUrl;
|
|
20
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { DatabaseHelpers } from "./database-helpers.js";
|
|
2
|
+
export class PackageHandlers {
|
|
3
|
+
db;
|
|
4
|
+
dbHelpers;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
this.dbHelpers = new DatabaseHelpers(db);
|
|
8
|
+
}
|
|
9
|
+
async handlePackageOperation(documentId, action, state, driveId) {
|
|
10
|
+
const packageDriveId = driveId || "";
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case "SET_PACKAGE_NAME":
|
|
13
|
+
await this.handleSetPackageName(documentId, packageDriveId, action, state);
|
|
14
|
+
break;
|
|
15
|
+
case "SET_PACKAGE_DESCRIPTION":
|
|
16
|
+
await this.handleSetPackageDescription(documentId, packageDriveId, action, state);
|
|
17
|
+
break;
|
|
18
|
+
case "SET_PACKAGE_CATEGORY":
|
|
19
|
+
await this.handleSetPackageCategory(documentId, packageDriveId, action, state);
|
|
20
|
+
break;
|
|
21
|
+
case "SET_PACKAGE_AUTHOR":
|
|
22
|
+
await this.handleSetPackageAuthor(documentId, packageDriveId, action, state);
|
|
23
|
+
break;
|
|
24
|
+
case "SET_PACKAGE_AUTHOR_NAME":
|
|
25
|
+
await this.handleSetPackageAuthorName(documentId, packageDriveId, action, state);
|
|
26
|
+
break;
|
|
27
|
+
case "SET_PACKAGE_AUTHOR_WEBSITE":
|
|
28
|
+
await this.handleSetPackageAuthorWebsite(documentId, packageDriveId, action, state);
|
|
29
|
+
break;
|
|
30
|
+
case "ADD_PACKAGE_KEYWORD":
|
|
31
|
+
await this.handleAddPackageKeyword(documentId, packageDriveId, action, state);
|
|
32
|
+
break;
|
|
33
|
+
case "REMOVE_PACKAGE_KEYWORD":
|
|
34
|
+
await this.handleRemovePackageKeyword(documentId, packageDriveId, action, state);
|
|
35
|
+
break;
|
|
36
|
+
case "SET_PACKAGE_GITHUB_URL":
|
|
37
|
+
await this.handleSetPackageGithubUrl(documentId, packageDriveId, action, state);
|
|
38
|
+
break;
|
|
39
|
+
case "SET_PACKAGE_NPM_URL":
|
|
40
|
+
await this.handleSetPackageNpmUrl(documentId, packageDriveId, action, state);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async handleSetPackageName(documentId, driveId, action, state) {
|
|
45
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
46
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
47
|
+
name: action.input.name,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async handleSetPackageDescription(documentId, driveId, action, state) {
|
|
51
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
52
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
53
|
+
description: action.input.description,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async handleSetPackageCategory(documentId, driveId, action, state) {
|
|
57
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
58
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
59
|
+
category: action.input.category,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async handleSetPackageAuthor(documentId, driveId, action, state) {
|
|
63
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
64
|
+
const input = action.input;
|
|
65
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
66
|
+
author_name: input.name,
|
|
67
|
+
author_website: input.website,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async handleSetPackageAuthorName(documentId, driveId, action, state) {
|
|
71
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
72
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
73
|
+
author_name: action.input.name,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async handleSetPackageAuthorWebsite(documentId, driveId, action, state) {
|
|
77
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
78
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
79
|
+
author_website: action.input.website,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async handleAddPackageKeyword(documentId, driveId, action, state) {
|
|
83
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
84
|
+
const input = action.input;
|
|
85
|
+
await this.db
|
|
86
|
+
.insertInto("builder_package_keywords")
|
|
87
|
+
.values({
|
|
88
|
+
id: input.id,
|
|
89
|
+
package_id: documentId,
|
|
90
|
+
label: input.label,
|
|
91
|
+
created_at: new Date(),
|
|
92
|
+
})
|
|
93
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
94
|
+
.execute();
|
|
95
|
+
}
|
|
96
|
+
async handleRemovePackageKeyword(documentId, driveId, action, state) {
|
|
97
|
+
const input = action.input;
|
|
98
|
+
await this.db
|
|
99
|
+
.deleteFrom("builder_package_keywords")
|
|
100
|
+
.where("id", "=", input.id)
|
|
101
|
+
.where("package_id", "=", documentId)
|
|
102
|
+
.execute();
|
|
103
|
+
}
|
|
104
|
+
async handleSetPackageGithubUrl(documentId, driveId, action, state) {
|
|
105
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
106
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
107
|
+
github_url: action.input.url,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async handleSetPackageNpmUrl(documentId, driveId, action, state) {
|
|
111
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
112
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
113
|
+
npm_url: action.input.url,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,56 +1,59 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ColumnType } from "kysely";
|
|
2
|
+
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;
|
|
3
|
+
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
|
4
|
+
export interface BuilderAccountMembers {
|
|
5
|
+
builder_account_id: string;
|
|
6
|
+
created_at: Generated<Timestamp>;
|
|
7
|
+
eth_address: string;
|
|
2
8
|
id: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BuilderAccounts {
|
|
11
|
+
created_at: Generated<Timestamp>;
|
|
12
|
+
id: string;
|
|
13
|
+
profile_description: string | null;
|
|
14
|
+
profile_logo: string | null;
|
|
3
15
|
profile_name: string;
|
|
4
16
|
profile_slug: string;
|
|
5
|
-
profile_logo: string | null;
|
|
6
|
-
profile_description: string | null;
|
|
7
|
-
profile_socials_x: string | null;
|
|
8
17
|
profile_socials_github: string | null;
|
|
9
18
|
profile_socials_website: string | null;
|
|
10
|
-
|
|
11
|
-
updated_at:
|
|
12
|
-
}
|
|
13
|
-
export interface BuilderAccountMember {
|
|
14
|
-
id: string;
|
|
15
|
-
builder_account_id: string;
|
|
16
|
-
eth_address: string;
|
|
17
|
-
created_at: Date;
|
|
19
|
+
profile_socials_x: string | null;
|
|
20
|
+
updated_at: Generated<Timestamp>;
|
|
18
21
|
}
|
|
19
|
-
export interface
|
|
22
|
+
export interface BuilderPackageKeywords {
|
|
23
|
+
created_at: Generated<Timestamp>;
|
|
20
24
|
id: string;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
description: string | null;
|
|
24
|
-
sort_order: number;
|
|
25
|
-
created_at: Date;
|
|
26
|
-
updated_at: Date;
|
|
25
|
+
label: string;
|
|
26
|
+
package_id: string;
|
|
27
27
|
}
|
|
28
|
-
export interface
|
|
29
|
-
id: string;
|
|
30
|
-
space_id: string;
|
|
31
|
-
name: string;
|
|
32
|
-
description: string | null;
|
|
33
|
-
category: string | null;
|
|
28
|
+
export interface BuilderPackages {
|
|
34
29
|
author_name: string;
|
|
35
30
|
author_website: string | null;
|
|
31
|
+
category: string | null;
|
|
32
|
+
created_at: Generated<Timestamp>;
|
|
33
|
+
description: string | null;
|
|
34
|
+
drive_id: string | null;
|
|
36
35
|
github_url: string | null;
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
37
38
|
npm_url: string | null;
|
|
39
|
+
sort_order: Generated<number>;
|
|
40
|
+
space_id: string;
|
|
41
|
+
updated_at: Generated<Timestamp>;
|
|
38
42
|
vetra_drive_url: string | null;
|
|
39
|
-
drive_id: string | null;
|
|
40
|
-
sort_order: number;
|
|
41
|
-
created_at: Date;
|
|
42
|
-
updated_at: Date;
|
|
43
43
|
}
|
|
44
|
-
export interface
|
|
44
|
+
export interface BuilderSpaces {
|
|
45
|
+
builder_account_id: string;
|
|
46
|
+
created_at: Generated<Timestamp>;
|
|
47
|
+
description: string | null;
|
|
45
48
|
id: string;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
sort_order: Generated<number>;
|
|
50
|
+
title: string;
|
|
51
|
+
updated_at: Generated<Timestamp>;
|
|
49
52
|
}
|
|
50
53
|
export interface DB {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
builder_packages:
|
|
55
|
-
|
|
54
|
+
builder_account_members: BuilderAccountMembers;
|
|
55
|
+
builder_accounts: BuilderAccounts;
|
|
56
|
+
builder_package_keywords: BuilderPackageKeywords;
|
|
57
|
+
builder_packages: BuilderPackages;
|
|
58
|
+
builder_spaces: BuilderSpaces;
|
|
56
59
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface SetPackageNameInput {
|
|
2
|
+
name: string;
|
|
3
|
+
}
|
|
4
|
+
export interface SetPackageDescriptionInput {
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SetPackageCategoryInput {
|
|
8
|
+
category: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SetPackageAuthorInput {
|
|
11
|
+
name?: string | null;
|
|
12
|
+
website?: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface SetPackageAuthorNameInput {
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SetPackageAuthorWebsiteInput {
|
|
18
|
+
website: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AddPackageKeywordInput {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RemovePackageKeywordInput {
|
|
25
|
+
id: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SetPackageGithubUrlInput {
|
|
28
|
+
url: string;
|
|
29
|
+
}
|
|
30
|
+
export interface SetPackageNpmUrlInput {
|
|
31
|
+
url: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/style.css
CHANGED