feat: dashboard on start
This commit is contained in:
@@ -668,6 +668,81 @@ export class PostEngine extends EventEmitter {
|
||||
return Array.from(categories).sort();
|
||||
}
|
||||
|
||||
async getTagsWithCounts(): Promise<{ tag: string; count: number }[]> {
|
||||
const db = getDatabase().getLocal();
|
||||
const dbPosts = await db
|
||||
.select({ tags: posts.tags })
|
||||
.from(posts)
|
||||
.where(eq(posts.projectId, this.currentProjectId))
|
||||
.all();
|
||||
|
||||
const tagCounts = new Map<string, number>();
|
||||
for (const row of dbPosts) {
|
||||
const parsed: string[] = JSON.parse(row.tags || '[]');
|
||||
for (const tag of parsed) {
|
||||
tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(tagCounts.entries())
|
||||
.map(([tag, count]) => ({ tag, count }))
|
||||
.sort((a, b) => b.count - a.count);
|
||||
}
|
||||
|
||||
async getCategoriesWithCounts(): Promise<{ category: string; count: number }[]> {
|
||||
const db = getDatabase().getLocal();
|
||||
const dbPosts = await db
|
||||
.select({ categories: posts.categories })
|
||||
.from(posts)
|
||||
.where(eq(posts.projectId, this.currentProjectId))
|
||||
.all();
|
||||
|
||||
const catCounts = new Map<string, number>();
|
||||
for (const row of dbPosts) {
|
||||
const parsed: string[] = JSON.parse(row.categories || '[]');
|
||||
for (const cat of parsed) {
|
||||
catCounts.set(cat, (catCounts.get(cat) || 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(catCounts.entries())
|
||||
.map(([category, count]) => ({ category, count }))
|
||||
.sort((a, b) => b.count - a.count);
|
||||
}
|
||||
|
||||
async getDashboardStats(): Promise<{
|
||||
totalPosts: number;
|
||||
draftCount: number;
|
||||
publishedCount: number;
|
||||
archivedCount: number;
|
||||
}> {
|
||||
const db = getDatabase().getLocal();
|
||||
const dbPosts = await db
|
||||
.select({ status: posts.status })
|
||||
.from(posts)
|
||||
.where(eq(posts.projectId, this.currentProjectId))
|
||||
.all();
|
||||
|
||||
let draftCount = 0;
|
||||
let publishedCount = 0;
|
||||
let archivedCount = 0;
|
||||
|
||||
for (const row of dbPosts) {
|
||||
switch (row.status) {
|
||||
case 'draft': draftCount++; break;
|
||||
case 'published': publishedCount++; break;
|
||||
case 'archived': archivedCount++; break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalPosts: dbPosts.length,
|
||||
draftCount,
|
||||
publishedCount,
|
||||
archivedCount,
|
||||
};
|
||||
}
|
||||
|
||||
async getPostsByYearMonth(): Promise<{ year: number; month: number; count: number }[]> {
|
||||
const allPosts = await this.getAllPostsUnpaginated();
|
||||
const counts = new Map<string, { year: number; month: number; count: number }>();
|
||||
|
||||
@@ -168,6 +168,21 @@ export function registerIpcHandlers(): void {
|
||||
return engine.getPostsByYearMonth();
|
||||
});
|
||||
|
||||
ipcMain.handle('posts:getTagsWithCounts', async () => {
|
||||
const engine = getPostEngine();
|
||||
return engine.getTagsWithCounts();
|
||||
});
|
||||
|
||||
ipcMain.handle('posts:getCategoriesWithCounts', async () => {
|
||||
const engine = getPostEngine();
|
||||
return engine.getCategoriesWithCounts();
|
||||
});
|
||||
|
||||
ipcMain.handle('posts:getDashboardStats', async () => {
|
||||
const engine = getPostEngine();
|
||||
return engine.getDashboardStats();
|
||||
});
|
||||
|
||||
ipcMain.handle('posts:getLinksTo', async (_, id: string) => {
|
||||
const engine = getPostEngine();
|
||||
return engine.getLinksTo(id);
|
||||
|
||||
@@ -32,6 +32,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
getTags: () => ipcRenderer.invoke('posts:getTags'),
|
||||
getCategories: () => ipcRenderer.invoke('posts:getCategories'),
|
||||
getByYearMonth: () => ipcRenderer.invoke('posts:getByYearMonth'),
|
||||
getTagsWithCounts: () => ipcRenderer.invoke('posts:getTagsWithCounts'),
|
||||
getCategoriesWithCounts: () => ipcRenderer.invoke('posts:getCategoriesWithCounts'),
|
||||
getDashboardStats: () => ipcRenderer.invoke('posts:getDashboardStats'),
|
||||
getLinksTo: (id: string) => ipcRenderer.invoke('posts:getLinksTo', id),
|
||||
getLinkedBy: (id: string) => ipcRenderer.invoke('posts:getLinkedBy', id),
|
||||
rebuildLinks: () => ipcRenderer.invoke('posts:rebuildLinks'),
|
||||
@@ -134,6 +137,9 @@ export interface ElectronAPI {
|
||||
getTags: () => Promise<string[]>;
|
||||
getCategories: () => Promise<string[]>;
|
||||
getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>;
|
||||
getTagsWithCounts: () => Promise<{ tag: string; count: number }[]>;
|
||||
getCategoriesWithCounts: () => Promise<{ category: string; count: number }[]>;
|
||||
getDashboardStats: () => Promise<{ totalPosts: number; draftCount: number; publishedCount: number; archivedCount: number }>;
|
||||
getLinksTo: (id: string) => Promise<{ id: string; title: string; slug: string }[]>;
|
||||
getLinkedBy: (id: string) => Promise<{ id: string; title: string; slug: string }[]>;
|
||||
rebuildLinks: () => Promise<void>;
|
||||
|
||||
Reference in New Issue
Block a user