feat: ship v0.8.0 with writing logs and AI knowledge extraction
Deliver P5.2 writing day logs, cockpit heatmap, streak tracking, and chapter knowledge auto-extraction with merge review. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import { useOutlineStore } from '@renderer/stores/useOutlineStore'
|
||||
import { useReferenceStore } from '@renderer/stores/useReferenceStore'
|
||||
import { useSettingsStore } from '@renderer/stores/useSettingsStore'
|
||||
import { useCockpitStore } from '@renderer/stores/useCockpitStore'
|
||||
import { useWritingStatsStore } from '@renderer/stores/useWritingStatsStore'
|
||||
import { ipcCall } from '@renderer/lib/ipc-client'
|
||||
import { TipTapEditor, flushEditorSave } from '@renderer/components/editor/TipTapEditor'
|
||||
import { insertLandmarkInEditor } from '@renderer/lib/editor-commands'
|
||||
@@ -90,6 +91,9 @@ export function EditorLayout(): React.JSX.Element {
|
||||
const switchTarget = useEditStore((s) => s.switchTarget)
|
||||
const setTarget = useEditStore((s) => s.setTarget)
|
||||
const updateSchedule = useSettingsStore((s) => s.updateSchedule)
|
||||
const dailyWordGoal = useSettingsStore((s) => s.dailyWordGoal)
|
||||
const writingStats = useWritingStatsStore((s) => s.stats)
|
||||
const refreshWritingStats = useWritingStatsStore((s) => s.refresh)
|
||||
const bridgeChapterId = useCockpitStore((s) => s.bridgeChapterId)
|
||||
const clearBridgeChapter = useCockpitStore((s) => s.clearBridgeChapter)
|
||||
const updateChapterLocal = useBookStore((s) => s.updateChapterLocal)
|
||||
@@ -122,6 +126,11 @@ export function EditorLayout(): React.JSX.Element {
|
||||
}
|
||||
}, [currentBookId, target?.kind, target?.id])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentBookId) return
|
||||
void refreshWritingStats(currentBookId)
|
||||
}, [currentBookId, lastSaved, refreshWritingStats])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentBookId) return
|
||||
void ipcCall(() =>
|
||||
@@ -344,6 +353,19 @@ export function EditorLayout(): React.JSX.Element {
|
||||
))}
|
||||
{activePanel === 'chapters' && (
|
||||
<div className="sidebar-footer">
|
||||
{selectedChapterId && currentBookId && (
|
||||
<button
|
||||
type="button"
|
||||
data-testid="chapter-extract-knowledge"
|
||||
onClick={() =>
|
||||
void ipcCall(() =>
|
||||
window.electronAPI.knowledge.extractChapter(currentBookId, selectedChapterId)
|
||||
)
|
||||
}
|
||||
>
|
||||
{t('knowledge.extractChapter')}
|
||||
</button>
|
||||
)}
|
||||
<button type="button" onClick={() => void handleNewChapter()}>
|
||||
+ {t('editor.newChapter')}
|
||||
</button>
|
||||
@@ -405,6 +427,23 @@ export function EditorLayout(): React.JSX.Element {
|
||||
/>
|
||||
<div id="editor-statusbar">
|
||||
<span>{saveStatus}{lastSaved ? ` · ${lastSaved.toLocaleTimeString()}` : ''}</span>
|
||||
{dailyWordGoal > 0 && writingStats && (
|
||||
<span
|
||||
className={`status-daily-goal ${
|
||||
writingStats.goalProgress >= 1
|
||||
? 'goal-met'
|
||||
: writingStats.goalProgress >= 0.8
|
||||
? 'goal-near'
|
||||
: ''
|
||||
}`}
|
||||
data-testid="status-daily-goal"
|
||||
>
|
||||
{t('status.dailyGoal', {
|
||||
current: writingStats.todayWords,
|
||||
goal: dailyWordGoal
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
{showStockWarning && (
|
||||
<span className="status-stock-warning" data-testid="status-stock-warning">
|
||||
{t('stock.warning', {
|
||||
|
||||
Reference in New Issue
Block a user