feat(v027): AutostartSection 토글 (진단 패널은 후속 task)
This commit is contained in:
@@ -19,6 +19,7 @@ import { ProviderHolder } from './ai/ProviderHolder.js';
|
||||
import { AiWorker } from './ai/AiWorker.js';
|
||||
import { registerCaptureApi } from './ipc/captureApi.js';
|
||||
import { registerInboxApi, pushNoteUpdated, pushOllamaStatus } from './ipc/inboxApi.js';
|
||||
import { registerSettingsApi } from './ipc/settingsApi.js';
|
||||
import { createInboxWindow, getInboxWindow } from './windows/inboxWindow.js';
|
||||
import {
|
||||
createQuickCaptureWindow, showQuickCapture, getQuickCaptureWindow
|
||||
@@ -162,6 +163,7 @@ app.whenReady().then(async () => {
|
||||
repo, continuity, capture, health, intent,
|
||||
getInboxWindow, settings: settingsSvc, providerHolder
|
||||
});
|
||||
registerSettingsApi();
|
||||
|
||||
const hotkeys = new HotkeyService();
|
||||
const reg = hotkeys.register({
|
||||
|
||||
23
src/main/ipc/settingsApi.ts
Normal file
23
src/main/ipc/settingsApi.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import electron from 'electron';
|
||||
const { ipcMain, app } = electron;
|
||||
|
||||
/**
|
||||
* v0.2.7 자동 실행 설정 IPC.
|
||||
*
|
||||
* 임시 채널명 (`settings:get-autostart` / `settings:set-autostart`).
|
||||
* Task 22 에서 정식 이름 (`settings:autostart-state` / `settings:autostart-set`) 으로 rename 예정.
|
||||
*
|
||||
* args=['--hidden'] 명시 — 자동 실행 시 백그라운드 모드로 시작 (Quick Capture only).
|
||||
*/
|
||||
export function registerSettingsApi(): void {
|
||||
ipcMain.handle('settings:get-autostart', () => {
|
||||
const r = app.getLoginItemSettings({ args: ['--hidden'] });
|
||||
return { openAtLogin: r.openAtLogin };
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:set-autostart', (_e, open: boolean) => {
|
||||
app.setLoginItemSettings({ openAtLogin: open, args: ['--hidden'] });
|
||||
const r = app.getLoginItemSettings({ args: ['--hidden'] });
|
||||
return { openAtLogin: r.openAtLogin };
|
||||
});
|
||||
}
|
||||
@@ -52,6 +52,9 @@ const api: InklingApi = {
|
||||
ipcRenderer.on('inbox:openOllamaSettings', handler);
|
||||
return () => ipcRenderer.removeListener('inbox:openOllamaSettings', handler);
|
||||
},
|
||||
// v0.2.7 자동 실행 (임시 채널 — Task 22 에서 settings:autostart-state / settings:autostart-set 으로 rename)
|
||||
getAutostart: () => ipcRenderer.invoke('settings:get-autostart'),
|
||||
setAutostart: (open: boolean) => ipcRenderer.invoke('settings:set-autostart', open),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useInbox } from '../store.js';
|
||||
import { AiProviderSection } from './settings/AiProviderSection.js';
|
||||
import { AutostartSection } from './settings/AutostartSection.js';
|
||||
|
||||
export function SettingsPage(): React.ReactElement {
|
||||
const setShowSettings = useInbox((s) => s.setShowSettings);
|
||||
@@ -27,7 +28,7 @@ export function SettingsPage(): React.ReactElement {
|
||||
</section>
|
||||
<section style={{ marginBottom: 24 }}>
|
||||
<h2 style={{ fontSize: 14, marginBottom: 8 }}>자동 실행</h2>
|
||||
{/* AutostartSection — Task 9 + Task 23/24 */}
|
||||
<AutostartSection />
|
||||
</section>
|
||||
<section style={{ marginBottom: 24 }}>
|
||||
<h2 style={{ fontSize: 14, marginBottom: 8 }}>백업 / 복원</h2>
|
||||
|
||||
31
src/renderer/inbox/components/settings/AutostartSection.tsx
Normal file
31
src/renderer/inbox/components/settings/AutostartSection.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { inboxApi } from '../../api.js';
|
||||
|
||||
export function AutostartSection(): React.ReactElement {
|
||||
const [openAtLogin, setOpenAtLogin] = useState<boolean | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
void (async () => {
|
||||
const r = await inboxApi.getAutostart();
|
||||
setOpenAtLogin(r.openAtLogin);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
async function onToggle(e: React.ChangeEvent<HTMLInputElement>): Promise<void> {
|
||||
const r = await inboxApi.setAutostart(e.target.checked);
|
||||
setOpenAtLogin(r.openAtLogin);
|
||||
}
|
||||
|
||||
if (openAtLogin === null) {
|
||||
return <div style={{ fontSize: 12, color: '#666' }}>로딩 중...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 13 }}>
|
||||
<input type="checkbox" checked={openAtLogin} onChange={onToggle} />
|
||||
앱 시작 시 자동으로 실행
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -92,6 +92,9 @@ export interface InboxApi {
|
||||
loadOllamaSettings(): Promise<{ endpoint: string; model: string } | null>;
|
||||
saveOllamaSettings(v: { endpoint: string; model: string }): Promise<{ ok: true } | { ok: false; reason: string }>;
|
||||
onOpenOllamaSettings(cb: () => void): () => void;
|
||||
// v0.2.7 자동 실행 (임시 채널 — Task 22 에서 정식 이름으로 rename)
|
||||
getAutostart(): Promise<{ openAtLogin: boolean }>;
|
||||
setAutostart(open: boolean): Promise<{ openAtLogin: boolean }>;
|
||||
}
|
||||
|
||||
export interface InklingApi {
|
||||
|
||||
34
tests/unit/AutostartSection.test.tsx
Normal file
34
tests/unit/AutostartSection.test.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react';
|
||||
|
||||
vi.mock('../../src/renderer/inbox/api.js', () => ({
|
||||
inboxApi: {
|
||||
getAutostart: vi.fn(async () => ({ openAtLogin: true })),
|
||||
setAutostart: vi.fn(async (open: boolean) => ({ openAtLogin: open }))
|
||||
}
|
||||
}));
|
||||
|
||||
import { AutostartSection } from '../../src/renderer/inbox/components/settings/AutostartSection';
|
||||
|
||||
describe('AutostartSection', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('renders toggle reflecting current state', async () => {
|
||||
render(<AutostartSection />);
|
||||
const toggle = await screen.findByRole('checkbox');
|
||||
expect(toggle).toBeChecked();
|
||||
});
|
||||
|
||||
it('clicking toggle calls setAutostart', async () => {
|
||||
const { inboxApi } = await import('../../src/renderer/inbox/api.js');
|
||||
render(<AutostartSection />);
|
||||
const toggle = await screen.findByRole('checkbox');
|
||||
fireEvent.click(toggle);
|
||||
await waitFor(() => expect(inboxApi.setAutostart).toHaveBeenCalledWith(false));
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,9 @@ vi.mock('../../src/renderer/inbox/api.js', () => ({
|
||||
inboxApi: {
|
||||
loadOllamaSettings: vi.fn(async () => null),
|
||||
saveOllamaSettings: vi.fn(async () => ({ ok: true })),
|
||||
ollamaRecheck: vi.fn(async () => ({ ok: true }))
|
||||
ollamaRecheck: vi.fn(async () => ({ ok: true })),
|
||||
getAutostart: vi.fn(async () => ({ openAtLogin: false })),
|
||||
setAutostart: vi.fn(async (open: boolean) => ({ openAtLogin: open }))
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user