feat(v029): settings:* IPC (ai-enabled/onboarding-completed/get) + App.tsx 첫 launch 분기
This commit is contained in:
@@ -202,7 +202,7 @@ app.whenReady().then(async () => {
|
||||
// v0.2.7 Task 10 — 설정 페이지 IPC (autostart + backup/export/import/sync/telemetry).
|
||||
// backup / exportSvc / importSvc / syncSvc / telemetry 가 모두 준비된 뒤 등록.
|
||||
registerSettingsApi({
|
||||
backup, exportSvc, importSvc, syncSvc, telemetry, getInboxWindow
|
||||
backup, exportSvc, importSvc, syncSvc, telemetry, settings: settingsSvc, getInboxWindow
|
||||
});
|
||||
|
||||
let backupOnQuitDone = false;
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { ExportService } from '../services/ExportService.js';
|
||||
import type { ImportService } from '../services/ImportService.js';
|
||||
import type { SyncService } from '../services/SyncService.js';
|
||||
import type { TelemetryService } from '../services/TelemetryService.js';
|
||||
import type { SettingsService } from '../services/SettingsService.js';
|
||||
import { collectAutostartState } from '../services/AutostartDiagnostic.js';
|
||||
import { getInboxWindow as getInboxWindowSingleton } from '../windows/inboxWindow.js';
|
||||
|
||||
@@ -33,6 +34,7 @@ export interface SettingsIpcDeps {
|
||||
importSvc: ImportService;
|
||||
syncSvc: SyncService;
|
||||
telemetry: TelemetryService;
|
||||
settings: SettingsService;
|
||||
getInboxWindow: () => BrowserWindow | null;
|
||||
}
|
||||
|
||||
@@ -88,7 +90,21 @@ export function registerSettingsApi(deps?: SettingsIpcDeps): void {
|
||||
});
|
||||
|
||||
if (!deps) return;
|
||||
const { backup, exportSvc, importSvc, syncSvc, telemetry, getInboxWindow } = deps;
|
||||
const { backup, exportSvc, importSvc, syncSvc, telemetry, settings, getInboxWindow } = deps;
|
||||
|
||||
// v0.2.9 Cut B Task 12 — settings read + AI/onboarding 토글.
|
||||
// 첫 launch 시 OnboardingWizard 분기 (App.tsx) 와 SettingsPage 의 ai_enabled 토글 통합.
|
||||
ipcMain.handle('settings:get', async () => settings.getAll());
|
||||
|
||||
ipcMain.handle('settings:set-ai-enabled', async (_e, enabled: boolean) => {
|
||||
await settings.setAiEnabled(enabled);
|
||||
return { ok: true as const };
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:set-onboarding-completed', async (_e, completed: boolean) => {
|
||||
await settings.setOnboardingCompleted(completed);
|
||||
return { ok: true as const };
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:run-backup', async () => {
|
||||
try {
|
||||
|
||||
@@ -39,6 +39,14 @@ export class SettingsService {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* v0.2.9 Cut B Task 12 — settings:get IPC 핸들러용 read-only accessor.
|
||||
* 첫 launch onboarding 분기에서 onboarding_completed 키 확인.
|
||||
*/
|
||||
async getAll(): Promise<Settings> {
|
||||
return this.load();
|
||||
}
|
||||
|
||||
async setOllama(value: OllamaSettings): Promise<void> {
|
||||
const validated = OllamaSettingsSchema.parse(value);
|
||||
const current = await this.load();
|
||||
|
||||
@@ -74,6 +74,10 @@ const api: InklingApi = {
|
||||
// v0.2.9 Cut B Task 8 — 4분기 status 전이 + AI 자동 분류 추천.
|
||||
setStatus: (id, status, reason) => ipcRenderer.invoke('inbox:set-status', id, status, reason),
|
||||
classifyStatus: (id, reason) => ipcRenderer.invoke('ai:classify-status', id, reason),
|
||||
// v0.2.9 Cut B Task 12 — settings read + AI/onboarding 토글 (첫 launch wizard 분기 포함).
|
||||
getSettings: () => ipcRenderer.invoke('settings:get'),
|
||||
setAiEnabled: (enabled: boolean) => ipcRenderer.invoke('settings:set-ai-enabled', enabled),
|
||||
setOnboardingCompleted: (completed: boolean) => ipcRenderer.invoke('settings:set-onboarding-completed', completed),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ExpiryBanner } from './components/ExpiryBanner.js';
|
||||
import { FailedBanner } from './components/FailedBanner.js';
|
||||
import { RecallBanner } from './components/RecallBanner.js';
|
||||
import { SettingsPage } from './components/SettingsPage.js';
|
||||
import { OnboardingWizard } from './components/OnboardingWizard.js';
|
||||
|
||||
export function App(): React.ReactElement {
|
||||
const {
|
||||
@@ -28,6 +29,20 @@ export function App(): React.ReactElement {
|
||||
const counts = useInbox((s) => s.counts);
|
||||
const setView = useInbox((s) => s.setView);
|
||||
const [recoveryDismissed, setRecoveryDismissed] = useState(isRecoveryDismissedToday());
|
||||
// v0.2.9 Cut B Task 12 — 첫 launch onboarding 분기. null = 로딩, true = 표시, false = 미표시.
|
||||
const [showOnboarding, setShowOnboarding] = useState<boolean | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
void (async () => {
|
||||
try {
|
||||
const settings = await inboxApi.getSettings();
|
||||
setShowOnboarding(!settings.onboarding_completed);
|
||||
} catch {
|
||||
// 안전한 fallback — settings 읽기 실패 시 wizard 미표시 (기존 사용자 무영향).
|
||||
setShowOnboarding(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
void loadInitial();
|
||||
@@ -49,6 +64,9 @@ export function App(): React.ReactElement {
|
||||
// deps array 에 추가 불필요. mount 시 1회 구독 + unmount 시 해제.
|
||||
}, [loadInitial, refreshMeta, upsertNote]);
|
||||
|
||||
if (showOnboarding === null) return <></>;
|
||||
if (showOnboarding) return <OnboardingWizard onClose={() => setShowOnboarding(false)} />;
|
||||
|
||||
if (showSettings) return <SettingsPage />;
|
||||
|
||||
const showRecovery = continuity.showRecoveryToast && !recoveryDismissed;
|
||||
|
||||
@@ -145,6 +145,14 @@ export interface InboxApi {
|
||||
reason: string | null
|
||||
): Promise<{ ok: true } | { ok: false; reason: string }>;
|
||||
classifyStatus(id: string, reason: string): Promise<{ recommended: NoteStatus; rationale: string }>;
|
||||
// v0.2.9 Cut B Task 12 — settings read + AI/onboarding 토글.
|
||||
getSettings(): Promise<{
|
||||
ollama?: { endpoint: string; model: string };
|
||||
ai_enabled?: boolean;
|
||||
onboarding_completed?: boolean;
|
||||
}>;
|
||||
setAiEnabled(enabled: boolean): Promise<{ ok: true }>;
|
||||
setOnboardingCompleted(completed: boolean): Promise<{ ok: true }>;
|
||||
}
|
||||
|
||||
export interface InklingApi {
|
||||
|
||||
Reference in New Issue
Block a user