Skip to content

Commit

Permalink
implement backend for local hub items + placeholder endpoints to fetc…
Browse files Browse the repository at this point in the history
…h hub app data
  • Loading branch information
shatfield4 committed Oct 29, 2024
1 parent 795c87d commit de7866c
Show file tree
Hide file tree
Showing 9 changed files with 486 additions and 169 deletions.
68 changes: 39 additions & 29 deletions frontend/src/models/hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,82 @@ const Hub = {
});
},

// Import a new item from the hub
importItem: async (data) => {
return await fetch(`${API_BASE}/hub/items`, {
// Update hub settings (API key, etc.)
updateSettings: async (data) => {
return await fetch(`${API_BASE}/hub/settings`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify(data),
})
.then((res) => {
if (!res.ok) throw new Error("Failed to import item.");
return res.json();
.then(async (res) => {
const response = await res.json();
if (!res.ok)
throw new Error(response.error || "Failed to update settings");
return { success: true, error: null };
})
.catch((e) => ({
success: false,
error: e.message,
}));
},

// Delete an imported item
// Get hub settings
getSettings: async () => {
return await fetch(`${API_BASE}/hub/settings`, {
method: "GET",
headers: baseHeaders(),
})
.then(async (res) => {
const response = await res.json();
if (!res.ok)
throw new Error(response.error || "Failed to fetch settings");
return { settings: response.settings, error: null };
})
.catch((e) => ({
settings: { hasApiKey: false },
error: e.message,
}));
},

// Delete an item
deleteItem: async (id) => {
return await fetch(`${API_BASE}/hub/items/${id}`, {
method: "DELETE",
headers: baseHeaders(),
})
.then((res) => res.ok)
.then((res) => res.json())
.catch((e) => {
console.error(e);
return false;
return { success: false, error: e.message };
});
},

// Get hub API key from system settings
getApiKey: async () => {
return await fetch(`${API_BASE}/system/settings?labels=hub_api_key`, {
method: "GET",
// Import by string
importByString: async (data) => {
return await fetch(`${API_BASE}/hub/import`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify(data),
})
.then((res) => res.json())
.then((res) => res.settings?.hub_api_key || null)
.catch((e) => {
console.error(e);
return null;
return { success: false, error: e.message };
});
},

// Fetch hub settings (API key, etc.)
getSettings: async () => {
return await fetch(`${API_BASE}/hub/settings`, {
// Explore items
explore: async () => {
return await fetch(`${API_BASE}/hub/explore`, {
method: "GET",
headers: baseHeaders(),
})
.then((res) => res.json())
.then((res) => res.settings)
.catch((e) => {
console.error(e);
return { hasApiKey: false };
return { success: false, error: e.message };
});
},

// Update hub settings (API key, etc.)
updateSettings: async (data) => {
return await fetch(`${API_BASE}/hub/settings`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify(data),
});
},
};

export default Hub;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Trash } from "@phosphor-icons/react";
import { useState } from "react";
import showToast from "@/utils/toast";
import Hub from "@/models/hub";

export default function HubItemRow({ item, onDelete }) {
const [deleting, setDeleting] = useState(false);

const handleDelete = async () => {
if (deleting) return;
setDeleting(true);
const success = await Hub.deleteItem(item.id);
if (!success) {
showToast("Failed to delete item", "error");
setDeleting(false);
return;
}
showToast("Item deleted successfully", "success");
onDelete(item.id);
};

return (
<tr className="bg-transparent text-white text-opacity-80 text-sm font-medium">
<td className="px-6 py-4">{item.name}</td>
<td className="px-6 py-4 capitalize">{item.type}</td>
<td className="px-6 py-4">
{new Date(item.createdAt).toLocaleDateString()}
</td>
<td className="px-6 py-4 cursor-pointer">
<button
onClick={handleDelete}
disabled={deleting}
className="transition-all duration-300 p-2 rounded-lg text-white/60 hover:text-white hover:bg-white/10"
>
<Trash className="h-5 w-5" />
</button>
</td>
</tr>
);
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { useState } from "react";
import ModalWrapper from "@/components/ModalWrapper";
import { X } from "@phosphor-icons/react";

const IMPORT_TYPES = [
{ label: "System Prompt", value: "prompt" },
{ label: "Agent Skill", value: "skill" },
{ label: "Workspace", value: "workspace" },
{ label: "Slash Command", value: "command" },
];
import Hub from "@/models/hub";
import showToast from "@/utils/toast";

export default function ImportModal({ isOpen, closeModal }) {
const [selectedType, setSelectedType] = useState("prompt");
const [importString, setImportString] = useState("");

const handleImport = async (e) => {
e.preventDefault();
// Handle import logic here
const response = await Hub.importByString({ importString });
if (response.success) {
showToast("Items imported successfully", "success");
} else {
showToast(response.error, "error");
}
closeModal();
};

Expand All @@ -34,23 +33,6 @@ export default function ImportModal({ isOpen, closeModal }) {

<form onSubmit={handleImport}>
<div className="p-4 space-y-6">
<div>
<label className="block text-sm font-medium text-white mb-2">
Import Type
</label>
<select
value={selectedType}
onChange={(e) => setSelectedType(e.target.value)}
className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
{IMPORT_TYPES.map((type) => (
<option key={type.value} value={type.value}>
{type.label}
</option>
))}
</select>
</div>

<div>
<label className="block text-sm font-medium text-white mb-2">
Import String
Expand All @@ -75,7 +57,7 @@ export default function ImportModal({ isOpen, closeModal }) {
</button>
<button
type="submit"
className="text-white bg-primary-button hover:bg-secondary focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center"
className="text-black bg-primary-button hover:bg-secondary focus:ring-4 focus:outline-none focus:ring-blue-300 hover:text-white font-medium rounded-lg text-sm px-5 py-2.5 text-center"
>
Import
</button>
Expand Down
Loading

0 comments on commit de7866c

Please sign in to comment.