feat: dashboard 3-column layout — project folders treeview, project cards with open button, info panel
This commit is contained in:
@@ -11,6 +11,7 @@ import type {
|
||||
DBElement, DBBlock, DBSetting, DBUser, DBSession,
|
||||
DBNotification, DBProjectShare,
|
||||
DBGlobalBlockFolder, DBGlobalBlock,
|
||||
DBProjectFolder,
|
||||
} from './DatabaseInterface.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
@@ -28,6 +29,11 @@ export class SqliteAdapter implements DatabaseInterface {
|
||||
const schemaPath = join(__dirname, 'schema.sql');
|
||||
const schema = readFileSync(schemaPath, 'utf-8');
|
||||
this.db.exec(schema);
|
||||
// Add folder_id column to projects table for existing databases
|
||||
const columns = this.db.prepare("PRAGMA table_info('projects')").all() as { name: string }[];
|
||||
if (!columns.some(col => col.name === 'folder_id')) {
|
||||
this.db.exec('ALTER TABLE projects ADD COLUMN folder_id TEXT REFERENCES project_folders(id) ON DELETE SET NULL');
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
@@ -74,10 +80,22 @@ export class SqliteAdapter implements DatabaseInterface {
|
||||
}
|
||||
|
||||
// ─── Projects ──────────────────────────────────────
|
||||
listProjects(ownerId?: string): DBProject[] {
|
||||
listProjects(ownerId?: string, folderId?: string | null): DBProject[] {
|
||||
if (ownerId && folderId !== undefined) {
|
||||
if (folderId === null) {
|
||||
return this.db.prepare('SELECT * FROM projects WHERE owner_id = ? AND folder_id IS NULL ORDER BY updated_at DESC').all(ownerId) as DBProject[];
|
||||
}
|
||||
return this.db.prepare('SELECT * FROM projects WHERE owner_id = ? AND folder_id = ? ORDER BY updated_at DESC').all(ownerId, folderId) as DBProject[];
|
||||
}
|
||||
if (ownerId) {
|
||||
return this.db.prepare('SELECT * FROM projects WHERE owner_id = ? ORDER BY updated_at DESC').all(ownerId) as DBProject[];
|
||||
}
|
||||
if (folderId !== undefined) {
|
||||
if (folderId === null) {
|
||||
return this.db.prepare('SELECT * FROM projects WHERE folder_id IS NULL ORDER BY updated_at DESC').all() as DBProject[];
|
||||
}
|
||||
return this.db.prepare('SELECT * FROM projects WHERE folder_id = ? ORDER BY updated_at DESC').all(folderId) as DBProject[];
|
||||
}
|
||||
return this.db.prepare('SELECT * FROM projects ORDER BY updated_at DESC').all() as DBProject[];
|
||||
}
|
||||
|
||||
@@ -88,16 +106,17 @@ export class SqliteAdapter implements DatabaseInterface {
|
||||
createProject(data: Partial<DBProject>): DBProject {
|
||||
const id = data.id ?? `proj-${Date.now()}`;
|
||||
this.db.prepare(
|
||||
'INSERT INTO projects (id, name, description, owner_id) VALUES (?, ?, ?, ?)',
|
||||
).run(id, data.name ?? 'Unbenannt', data.description ?? null, data.owner_id ?? 'user-default');
|
||||
'INSERT INTO projects (id, name, description, owner_id, folder_id) VALUES (?, ?, ?, ?, ?)',
|
||||
).run(id, data.name ?? 'Unbenannt', data.description ?? null, data.owner_id ?? 'user-default', data.folder_id ?? null);
|
||||
return this.getProject(id)!;
|
||||
}
|
||||
|
||||
updateProject(id: string, data: Partial<DBProject>): DBProject | null {
|
||||
const sets: string[] = [];
|
||||
const vals: any[] = [];
|
||||
const vals: unknown[] = [];
|
||||
if (data.name !== undefined) { sets.push('name = ?'); vals.push(data.name); }
|
||||
if (data.description !== undefined) { sets.push('description = ?'); vals.push(data.description); }
|
||||
if (data.folder_id !== undefined) { sets.push('folder_id = ?'); vals.push(data.folder_id); }
|
||||
sets.push("updated_at = datetime('now')");
|
||||
if (sets.length > 1) {
|
||||
this.db.prepare(`UPDATE projects SET ${sets.join(', ')} WHERE id = ?`).run(...vals, id);
|
||||
@@ -109,6 +128,45 @@ export class SqliteAdapter implements DatabaseInterface {
|
||||
return this.db.prepare('DELETE FROM projects WHERE id = ?').run(id).changes > 0;
|
||||
}
|
||||
|
||||
moveProjectToFolder(projectId: string, folderId: string | null): DBProject | null {
|
||||
this.db.prepare('UPDATE projects SET folder_id = ?, updated_at = datetime(\'now\') WHERE id = ?').run(folderId, projectId);
|
||||
return this.getProject(projectId);
|
||||
}
|
||||
|
||||
// ─── Project Folders ─────────────────────────────────
|
||||
listProjectFolders(ownerId: string): DBProjectFolder[] {
|
||||
return this.db.prepare('SELECT * FROM project_folders WHERE owner_id = ? ORDER BY name').all(ownerId) as DBProjectFolder[];
|
||||
}
|
||||
|
||||
getProjectFolder(id: string): DBProjectFolder | null {
|
||||
return (this.db.prepare('SELECT * FROM project_folders WHERE id = ?').get(id) as DBProjectFolder) ?? null;
|
||||
}
|
||||
|
||||
createProjectFolder(data: Partial<DBProjectFolder>): DBProjectFolder {
|
||||
const id = data.id ?? `pfolder-${Date.now()}`;
|
||||
this.db.prepare(
|
||||
'INSERT INTO project_folders (id, name, parent_id, owner_id) VALUES (?, ?, ?, ?)',
|
||||
).run(id, data.name ?? 'Neuer Ordner', data.parent_id ?? null, data.owner_id ?? 'user-default');
|
||||
return this.getProjectFolder(id)!;
|
||||
}
|
||||
|
||||
updateProjectFolder(id: string, data: Partial<DBProjectFolder>): DBProjectFolder | null {
|
||||
const sets: string[] = [];
|
||||
const vals: unknown[] = [];
|
||||
if (data.name !== undefined) { sets.push('name = ?'); vals.push(data.name); }
|
||||
if (data.parent_id !== undefined) { sets.push('parent_id = ?'); vals.push(data.parent_id); }
|
||||
if (sets.length > 0) {
|
||||
this.db.prepare(`UPDATE project_folders SET ${sets.join(', ')} WHERE id = ?`).run(...vals, id);
|
||||
}
|
||||
return this.getProjectFolder(id);
|
||||
}
|
||||
|
||||
deleteProjectFolder(id: string): boolean {
|
||||
// Move projects inside this folder to root (folder_id = NULL) before deleting
|
||||
this.db.prepare('UPDATE projects SET folder_id = NULL WHERE folder_id = ?').run(id);
|
||||
return this.db.prepare('DELETE FROM project_folders WHERE id = ?').run(id).changes > 0;
|
||||
}
|
||||
|
||||
// ─── Drawings ──────────────────────────────────────
|
||||
listDrawings(projectId: string): DBDrawing[] {
|
||||
return this.db.prepare('SELECT * FROM drawings WHERE project_id = ? ORDER BY updated_at DESC').all(projectId) as DBDrawing[];
|
||||
|
||||
Reference in New Issue
Block a user