100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
|
|
|
||
|
|
'use server';
|
||
|
|
|
||
|
|
import db from '@/lib/db';
|
||
|
|
import { z } from 'zod';
|
||
|
|
import { revalidatePath } from 'next/cache';
|
||
|
|
import { redirect } from 'next/navigation';
|
||
|
|
|
||
|
|
export type Flow = {
|
||
|
|
id: number;
|
||
|
|
name: string;
|
||
|
|
description: string | null;
|
||
|
|
path: string;
|
||
|
|
createdAt: string;
|
||
|
|
updatedAt: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
const flowSchema = z.object({
|
||
|
|
id: z.coerce.number().optional(),
|
||
|
|
name: z.string().min(1, 'Name is required'),
|
||
|
|
description: z.string().optional(),
|
||
|
|
path: z.string().min(1, 'Path is required').startsWith('/', { message: 'Path must start with /' }),
|
||
|
|
});
|
||
|
|
|
||
|
|
export async function getFlows(): Promise<Flow[]> {
|
||
|
|
try {
|
||
|
|
const stmt = db.prepare(
|
||
|
|
'SELECT id, name, description, path, createdAt, updatedAt FROM flows ORDER BY createdAt DESC'
|
||
|
|
);
|
||
|
|
const flows = stmt.all() as Flow[];
|
||
|
|
return flows;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to fetch flows:', error);
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getFlow(id: number): Promise<Flow | null> {
|
||
|
|
try {
|
||
|
|
const stmt = db.prepare('SELECT * FROM flows WHERE id = ?');
|
||
|
|
const flow = stmt.get(id) as Flow | undefined;
|
||
|
|
return flow || null;
|
||
|
|
} catch (error) {
|
||
|
|
console.error(`Failed to fetch flow with id ${id}:`, error);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function saveFlow(formData: FormData) {
|
||
|
|
const validatedFields = flowSchema.safeParse(Object.fromEntries(formData.entries()));
|
||
|
|
|
||
|
|
if (!validatedFields.success) {
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
message: 'Invalid fields.',
|
||
|
|
errors: validatedFields.error.flatten().fieldErrors,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const { id, name, description, path } = validatedFields.data;
|
||
|
|
|
||
|
|
try {
|
||
|
|
if (id) {
|
||
|
|
// Update existing flow
|
||
|
|
const stmt = db.prepare(
|
||
|
|
'UPDATE flows SET name = ?, description = ?, path = ?, updatedAt = CURRENT_TIMESTAMP WHERE id = ?'
|
||
|
|
);
|
||
|
|
stmt.run(name, description || null, path, id);
|
||
|
|
} else {
|
||
|
|
// Create new flow
|
||
|
|
const stmt = db.prepare(
|
||
|
|
'INSERT INTO flows (name, description, path) VALUES (?, ?, ?)'
|
||
|
|
);
|
||
|
|
stmt.run(name, description || null, path);
|
||
|
|
}
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error('Failed to save flow:', error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
message: error.code === 'SQLITE_CONSTRAINT_UNIQUE' ? 'A flow with this path already exists.' : 'An internal error occurred.',
|
||
|
|
errors: null,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
revalidatePath('/admin/flows');
|
||
|
|
redirect('/admin/flows');
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function deleteFlow(id: number): Promise<{ success: boolean, message: string }> {
|
||
|
|
try {
|
||
|
|
const stmt = db.prepare('DELETE FROM flows WHERE id = ?');
|
||
|
|
stmt.run(id);
|
||
|
|
revalidatePath('/admin/flows');
|
||
|
|
return { success: true, message: 'Flow deleted successfully.' };
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to delete flow:', error);
|
||
|
|
return { success: false, message: 'An internal error occurred.' };
|
||
|
|
}
|
||
|
|
}
|