Files
inkling/src/main/ipc/inboxApi.ts

137 lines
4.9 KiB
TypeScript

import electron from 'electron';
import type { BrowserWindow } from 'electron';
const { ipcMain, dialog } = electron;
import type { NoteRepository } from '../repository/NoteRepository.js';
import type { ContinuityService } from '../services/ContinuityService.js';
import type { CaptureService } from '../services/CaptureService.js';
import type { HealthChecker } from '../services/HealthChecker.js';
import type { IntentService } from '../services/IntentService.js';
import type { Note } from '@shared/types';
export interface InboxIpcDeps {
repo: NoteRepository;
continuity: ContinuityService;
capture: CaptureService;
health: HealthChecker;
intent: IntentService;
getInboxWindow: () => BrowserWindow | null;
}
export function registerInboxApi(deps: InboxIpcDeps): void {
ipcMain.handle('inbox:list', (_e, opts: { limit: number; cursor?: string }) =>
deps.repo.list(opts)
);
ipcMain.handle(
'inbox:updateAi',
(_e, arg: { noteId: string; fields: { title?: string; summary?: string; tags?: string[] } }) => {
deps.repo.updateUserAiFields(arg.noteId, arg.fields);
}
);
ipcMain.handle('inbox:setDueDate', (_e, arg: { noteId: string; date: string | null }) => {
deps.repo.setDueDate(arg.noteId, arg.date);
});
ipcMain.handle('inbox:delete', async (_e, noteId: string) => {
await deps.capture.deleteNote(noteId);
});
ipcMain.handle(
'inbox:setIntent',
(_e, arg: { noteId: string; text: string }) => {
deps.intent.setIntent(arg.noteId, arg.text);
}
);
ipcMain.handle('inbox:dismissIntent', (_e, noteId: string) => {
deps.intent.dismissIntent(noteId);
});
ipcMain.handle('inbox:continuity', () => deps.continuity.get());
ipcMain.handle('inbox:pendingCount', () => deps.repo.getPendingCount());
ipcMain.handle('inbox:ollamaStatus', () => deps.health.lastStatus());
ipcMain.handle('inbox:todayCount', () => deps.repo.countToday());
ipcMain.handle('inbox:restore', async (_e, noteId: string) => {
await deps.capture.restoreNote(noteId);
});
ipcMain.handle('inbox:permanentDelete', async (_e, noteId: string) => {
const win = deps.getInboxWindow();
const opts: Electron.MessageBoxOptions = {
type: 'question',
buttons: ['영구 삭제', '취소'],
defaultId: 1,
cancelId: 1,
title: 'Inkling',
message: '이 노트를 영구 삭제합니다',
detail: '이 작업은 되돌릴 수 없습니다. 첨부된 이미지도 함께 삭제됩니다.'
};
const r = win
? await dialog.showMessageBox(win, opts)
: await dialog.showMessageBox(opts);
if (r.response !== 0) return { confirmed: false };
await deps.capture.permanentDeleteNote(noteId);
return { confirmed: true };
});
ipcMain.handle('inbox:emptyTrash', async () => {
const fullCount = deps.repo.countTrashed();
if (fullCount === 0) return { confirmed: true, count: 0 };
const win = deps.getInboxWindow();
const opts: Electron.MessageBoxOptions = {
type: 'question',
buttons: ['휴지통 비우기', '취소'],
defaultId: 1,
cancelId: 1,
title: 'Inkling',
message: `휴지통의 노트 ${fullCount}개를 영구 삭제합니다`,
detail: '이 작업은 되돌릴 수 없습니다. 첨부된 이미지도 함께 삭제됩니다.'
};
const r = win
? await dialog.showMessageBox(win, opts)
: await dialog.showMessageBox(opts);
if (r.response !== 0) return { confirmed: false, count: 0 };
const result = await deps.capture.emptyTrash();
return { confirmed: true, count: result.count };
});
ipcMain.handle('inbox:listTrash', (_e, opts: { limit: number }) =>
deps.repo.listTrashed(opts)
);
ipcMain.handle('inbox:trashCount', () => deps.repo.countTrashed());
ipcMain.handle('inbox:listExpired', async () => deps.capture.listExpired());
ipcMain.handle(
'inbox:trashExpiredBatch',
async (_e, payload: { ids: string[] }) => {
if (payload.ids.length === 0) return { trashedCount: 0, confirmed: false };
const win = deps.getInboxWindow();
const opts: Electron.MessageBoxOptions = {
type: 'question',
buttons: ['옮기기', '취소'],
defaultId: 1,
cancelId: 1,
title: 'Inkling',
message: `선택한 노트 ${payload.ids.length}개를 휴지통으로 옮깁니다`,
detail: '복구는 휴지통 탭에서 가능합니다.'
};
const r = win
? await dialog.showMessageBox(win, opts)
: await dialog.showMessageBox(opts);
if (r.response !== 0) return { trashedCount: 0, confirmed: false };
const result = await deps.capture.trashExpiredBatch(payload.ids);
return { trashedCount: result.trashedCount, confirmed: true };
}
);
}
export function pushNoteUpdated(getWin: () => BrowserWindow | null, note: Note): void {
const w = getWin();
if (!w || w.isDestroyed()) return;
w.webContents.send('note:updated', note);
}