clear db button
This commit is contained in:
parent
f9352ad5b0
commit
a6a4cb9f89
@ -13,6 +13,8 @@
|
||||
"build:client": "vite build",
|
||||
"start": "node dist/server/index.js",
|
||||
"db:migrate": "tsx src/server/db/migrate.ts",
|
||||
"db:clear": "tsx src/server/db/clear.ts",
|
||||
"db:drop": "tsx src/server/db/clear.ts --drop",
|
||||
"pipeline:run": "tsx src/server/pipeline/run.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@ -135,11 +135,24 @@ export const App: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Clear database
|
||||
const handleClearDatabase = async () => {
|
||||
try {
|
||||
const result = await api.clearDatabase();
|
||||
addToast(`Database cleared! Deleted ${result.jobsDeleted} jobs.`, 'success');
|
||||
loadJobs();
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to clear database';
|
||||
addToast(message, 'error');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
onRunPipeline={handleRunPipeline}
|
||||
onRefresh={loadJobs}
|
||||
onClearDatabase={handleClearDatabase}
|
||||
isPipelineRunning={isPipelineRunning}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
|
||||
@ -89,3 +89,18 @@ export async function runPipeline(config?: {
|
||||
body: JSON.stringify(config || {}),
|
||||
});
|
||||
}
|
||||
|
||||
// Database API
|
||||
export async function clearDatabase(): Promise<{
|
||||
message: string;
|
||||
jobsDeleted: number;
|
||||
runsDeleted: number;
|
||||
}> {
|
||||
return fetchApi<{
|
||||
message: string;
|
||||
jobsDeleted: number;
|
||||
runsDeleted: number;
|
||||
}>('/database', {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,11 +3,12 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { RocketIcon, PlayIcon, RefreshIcon } from './Icons';
|
||||
import { RocketIcon, PlayIcon, RefreshIcon, TrashIcon } from './Icons';
|
||||
|
||||
interface HeaderProps {
|
||||
onRunPipeline: () => void;
|
||||
onRefresh: () => void;
|
||||
onClearDatabase: () => void;
|
||||
isPipelineRunning: boolean;
|
||||
isLoading: boolean;
|
||||
}
|
||||
@ -15,9 +16,16 @@ interface HeaderProps {
|
||||
export const Header: React.FC<HeaderProps> = ({
|
||||
onRunPipeline,
|
||||
onRefresh,
|
||||
onClearDatabase,
|
||||
isPipelineRunning,
|
||||
isLoading,
|
||||
}) => {
|
||||
const handleClearDatabase = () => {
|
||||
if (window.confirm('Are you sure you want to clear all jobs from the database? This cannot be undone.')) {
|
||||
onClearDatabase();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="header">
|
||||
<div className="container">
|
||||
@ -30,6 +38,16 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
className="btn btn-ghost"
|
||||
onClick={handleClearDatabase}
|
||||
disabled={isLoading}
|
||||
title="Clear all jobs from database"
|
||||
>
|
||||
<TrashIcon size={16} />
|
||||
Clear DB
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="btn btn-ghost"
|
||||
onClick={onRefresh}
|
||||
|
||||
@ -116,3 +116,12 @@ export const RocketIcon: React.FC<IconProps> = ({ className, size = 16 }) => (
|
||||
<path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const TrashIcon: React.FC<IconProps> = ({ className, size = 16 }) => (
|
||||
<svg className={className} width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="3 6 5 6 21 6"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@ -8,6 +8,7 @@ import * as jobsRepo from '../repositories/jobs.js';
|
||||
import * as pipelineRepo from '../repositories/pipeline.js';
|
||||
import { runPipeline, processJob, getPipelineStatus } from '../pipeline/index.js';
|
||||
import { createNotionEntry } from '../services/notion.js';
|
||||
import { clearDatabase } from '../db/clear.js';
|
||||
import type { JobStatus, ApiResponse, JobsListResponse, PipelineStatusResponse } from '../../shared/types.js';
|
||||
|
||||
export const apiRouter = Router();
|
||||
@ -270,3 +271,28 @@ apiRouter.post('/webhook/trigger', async (req: Request, res: Response) => {
|
||||
res.status(500).json({ success: false, error: message });
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Database Management
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* DELETE /api/database - Clear all data from the database
|
||||
*/
|
||||
apiRouter.delete('/database', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const result = clearDatabase();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
message: 'Database cleared',
|
||||
jobsDeleted: result.jobsDeleted,
|
||||
runsDeleted: result.runsDeleted,
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
res.status(500).json({ success: false, error: message });
|
||||
}
|
||||
});
|
||||
|
||||
56
orchestrator/src/server/db/clear.ts
Normal file
56
orchestrator/src/server/db/clear.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Database utility scripts.
|
||||
*/
|
||||
|
||||
import Database from 'better-sqlite3';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const DB_PATH = join(__dirname, '../../../data/jobs.db');
|
||||
|
||||
/**
|
||||
* Clear all data from the database (keeps the schema intact).
|
||||
*/
|
||||
export function clearDatabase(): { jobsDeleted: number; runsDeleted: number } {
|
||||
const sqlite = new Database(DB_PATH);
|
||||
|
||||
try {
|
||||
const jobsResult = sqlite.prepare('DELETE FROM jobs').run();
|
||||
const runsResult = sqlite.prepare('DELETE FROM pipeline_runs').run();
|
||||
|
||||
console.log(`🗑️ Cleared database: ${jobsResult.changes} jobs, ${runsResult.changes} pipeline runs`);
|
||||
|
||||
return {
|
||||
jobsDeleted: jobsResult.changes,
|
||||
runsDeleted: runsResult.changes,
|
||||
};
|
||||
} finally {
|
||||
sqlite.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete database file completely (will recreate on next run).
|
||||
*/
|
||||
export function dropDatabase(): void {
|
||||
const { unlinkSync, existsSync } = require('fs');
|
||||
|
||||
if (existsSync(DB_PATH)) {
|
||||
unlinkSync(DB_PATH);
|
||||
console.log('🗑️ Database file deleted');
|
||||
} else {
|
||||
console.log('ℹ️ No database file to delete');
|
||||
}
|
||||
}
|
||||
|
||||
// CLI execution
|
||||
if (process.argv[1]?.includes('clear.ts')) {
|
||||
const arg = process.argv[2];
|
||||
|
||||
if (arg === '--drop') {
|
||||
dropDatabase();
|
||||
} else {
|
||||
clearDatabase();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user