feat: add description field to dataset and update related components for dataset creation and editing
This commit is contained in:
@@ -6,7 +6,7 @@ import { eq } from 'drizzle-orm';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { requireAdmin } from '@/lib/auth';
|
||||
|
||||
export async function createDataset({ name }: { name: string }) {
|
||||
export async function createDataset({ name, description }: { name: string; description?: string }) {
|
||||
const result = await requireAdmin();
|
||||
if (!result.authenticated || !result.admin) {
|
||||
throw new Error('Unauthorized');
|
||||
@@ -17,7 +17,10 @@ export async function createDataset({ name }: { name: string }) {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await db.insert(dataset).values({ name: name.trim() });
|
||||
const result = await db.insert(dataset).values({
|
||||
name: name.trim(),
|
||||
description: description?.trim() || null
|
||||
});
|
||||
revalidatePath('/admin');
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -28,7 +31,7 @@ export async function createDataset({ name }: { name: string }) {
|
||||
|
||||
export async function updateDataset(
|
||||
id: number,
|
||||
updates: { name?: string }
|
||||
updates: { name?: string; description?: string }
|
||||
) {
|
||||
const result = await requireAdmin();
|
||||
if (!result.authenticated || !result.admin) {
|
||||
@@ -40,12 +43,18 @@ export async function updateDataset(
|
||||
}
|
||||
|
||||
try {
|
||||
const updateData: any = {};
|
||||
if (updates.name !== undefined) {
|
||||
updateData.name = updates.name.trim();
|
||||
}
|
||||
if (updates.description !== undefined) {
|
||||
updateData.description = updates.description.trim() || null;
|
||||
}
|
||||
updateData.updatedAt = new Date();
|
||||
|
||||
const result = await db
|
||||
.update(dataset)
|
||||
.set({
|
||||
name: updates.name?.trim(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.set(updateData)
|
||||
.where(eq(dataset.id, id));
|
||||
revalidatePath(`/admin/datasets/${id}`);
|
||||
revalidatePath('/admin');
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createDataset } from '@/app/actions/datasets';
|
||||
|
||||
export default function CreateDatasetForm() {
|
||||
const [name, setName] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
@@ -21,8 +22,12 @@ export default function CreateDatasetForm() {
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
await createDataset({ name: name.trim() });
|
||||
await createDataset({
|
||||
name: name.trim(),
|
||||
description: description.trim() || undefined
|
||||
});
|
||||
setName('');
|
||||
setDescription('');
|
||||
setSuccess(true);
|
||||
setTimeout(() => setSuccess(false), 3000);
|
||||
// Refresh the page to show the new dataset
|
||||
@@ -53,6 +58,21 @@ export default function CreateDatasetForm() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label htmlFor="description" className="block text-sm font-medium mb-2">
|
||||
Description (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
id="description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Enter dataset description"
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
|
||||
{error}
|
||||
|
||||
@@ -21,6 +21,7 @@ export default async function DatasetsList() {
|
||||
className="border border-gray-300 rounded-lg p-4 bg-white shadow-sm hover:shadow-md transition-shadow block cursor-pointer"
|
||||
>
|
||||
<h3 className="text-lg font-semibold">{ds.name}</h3>
|
||||
<p className="text-md text-gray-600">{ds.description}</p>
|
||||
<p className="text-sm text-gray-600 mt-2">
|
||||
ID: {ds.id}
|
||||
</p>
|
||||
|
||||
@@ -13,6 +13,7 @@ export default function EditableDatasetHeader({
|
||||
}: EditableDatasetHeaderProps) {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [name, setName] = useState(dataset.name);
|
||||
const [description, setDescription] = useState(dataset.description || '');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -26,7 +27,10 @@ export default function EditableDatasetHeader({
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
await updateDataset(dataset.id, { name: name.trim() });
|
||||
await updateDataset(dataset.id, {
|
||||
name: name.trim(),
|
||||
description: description.trim() || undefined
|
||||
});
|
||||
setIsEditing(false);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to update dataset');
|
||||
@@ -37,6 +41,7 @@ export default function EditableDatasetHeader({
|
||||
|
||||
function handleCancel() {
|
||||
setName(dataset.name);
|
||||
setDescription(dataset.description || '');
|
||||
setError(null);
|
||||
setIsEditing(false);
|
||||
}
|
||||
@@ -57,6 +62,18 @@ export default function EditableDatasetHeader({
|
||||
disabled={loading}
|
||||
/>
|
||||
|
||||
<label htmlFor="description" className="block text-sm font-medium mb-2">
|
||||
Description (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
id="description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 mb-4 resize-none"
|
||||
disabled={loading}
|
||||
/>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded text-sm">
|
||||
{error}
|
||||
@@ -91,6 +108,9 @@ export default function EditableDatasetHeader({
|
||||
Edit
|
||||
</button>
|
||||
</div>
|
||||
{dataset.description && (
|
||||
<p className="text-gray-700 mb-4">{dataset.description}</p>
|
||||
)}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">Dataset ID</p>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { dataset_entry } from './dataset_entry';
|
||||
export const dataset = sqliteTable('dataset', {
|
||||
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||
name: text('name').notNull(),
|
||||
description: text('description'),
|
||||
createdAt: integer('created_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.default(sql`(unixepoch())`),
|
||||
|
||||
Reference in New Issue
Block a user