feat: add session move endpoint and project-session cascading delete
- Add sessions table to database with projectId and deletedAt columns - Create POST /api/sessions/:id/move endpoint to reassign sessions - Update DELETE /api/projects/:id to cascade soft-delete to sessions - Support moving sessions between projects or to unassigned state - Handle both active (in-memory) and historical sessions Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
83
server.js
83
server.js
@@ -633,6 +633,74 @@ app.delete('/claude/api/claude/sessions/:id', requireAuth, (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Move session to different project
|
||||
app.post('/api/sessions/:id/move', requireAuth, (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { projectId } = req.body;
|
||||
|
||||
// Check if session exists (in-memory or historical)
|
||||
let session = claudeService.sessions.get(id);
|
||||
if (!session) {
|
||||
// Check historical sessions
|
||||
const historicalSessions = claudeService.loadHistoricalSessions();
|
||||
session = historicalSessions.find(s => s.id === id);
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
return res.status(404).json({ error: 'Session not found' });
|
||||
}
|
||||
|
||||
// If projectId is provided, validate it exists and is not deleted
|
||||
if (projectId !== null && projectId !== undefined) {
|
||||
const validatedId = validateProjectId(projectId);
|
||||
if (!validatedId) {
|
||||
return res.status(400).json({ error: 'Invalid project ID' });
|
||||
}
|
||||
|
||||
const project = db.prepare(`
|
||||
SELECT id FROM projects
|
||||
WHERE id = ? AND deletedAt IS NULL
|
||||
`).get(validatedId);
|
||||
|
||||
if (!project) {
|
||||
return res.status(404).json({ error: 'Project not found' });
|
||||
}
|
||||
|
||||
// Update session's metadata with projectId
|
||||
if (claudeService.sessions.get(id)) {
|
||||
// Active session - update metadata
|
||||
const activeSession = claudeService.sessions.get(id);
|
||||
activeSession.metadata.projectId = validatedId;
|
||||
} else {
|
||||
// Historical session - update in database
|
||||
db.prepare(`
|
||||
INSERT OR REPLACE INTO sessions (id, projectId, deletedAt)
|
||||
VALUES (?, ?, NULL)
|
||||
`).run(id, validatedId);
|
||||
}
|
||||
} else {
|
||||
// Move to unassigned (projectId = null)
|
||||
if (claudeService.sessions.get(id)) {
|
||||
// Active session - remove projectId from metadata
|
||||
const activeSession = claudeService.sessions.get(id);
|
||||
delete activeSession.metadata.projectId;
|
||||
} else {
|
||||
// Historical session - update in database
|
||||
db.prepare(`
|
||||
INSERT OR REPLACE INTO sessions (id, projectId, deletedAt)
|
||||
VALUES (?, NULL, NULL)
|
||||
`).run(id);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error moving session:', error);
|
||||
res.status(500).json({ error: 'Failed to move session' });
|
||||
}
|
||||
});
|
||||
|
||||
// Preview Management - Start preview server
|
||||
app.post('/claude/api/claude/sessions/:id/preview/start', requireAuth, async (req, res) => {
|
||||
try {
|
||||
@@ -1006,6 +1074,21 @@ app.delete('/api/projects/:id', requireAuth, (req, res) => {
|
||||
WHERE id = ?
|
||||
`).run(now, validatedId);
|
||||
|
||||
// Soft delete all sessions associated with this project
|
||||
db.prepare(`
|
||||
UPDATE sessions
|
||||
SET deletedAt = ?
|
||||
WHERE projectId = ?
|
||||
`).run(now, validatedId);
|
||||
|
||||
// Also update in-memory sessions
|
||||
for (const [sessionId, session] of claudeService.sessions.entries()) {
|
||||
if (session.metadata.projectId === validatedId) {
|
||||
// Mark as deleted in metadata
|
||||
session.metadata.deletedAt = now;
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error soft deleting project:', error);
|
||||
|
||||
Reference in New Issue
Block a user