mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-16 05:19:50 +08:00
* feat: add outline review preview flow * style: refine outline review editor * fix(home): make draft cache survive round-trips through generation flows The `useDraftCache` hook initialised state via `useState`'s lazy initialiser. Under React 18+ SSR, the initialiser runs on the server (returns `undefined` because `window` is missing), the SSR'd state is sent to the client, and React reuses it on hydration without re-running the initialiser. As a result `cachedValue` was always `undefined` and nothing ever rehydrated from `localStorage`. The home page's `prevCachedRequirement` derived-state pattern then masked the symptom: it initialised `prev` to the same (always undefined) `cachedRequirement`, so the comparison never fired and the restore branch was unreachable. Switch to an effect-based read so consumers actually receive a state update after mount, and replace the home page's derived-state restore with a `useEffect` + `useRef` guard that only fills the input when it is empty. Side benefit: PBL chat draft and quiz answer caches start working too — they used the same broken pattern. * feat(outline-review): clickable streaming card morphs into editor + UX overhaul Major refresh of the outline review surface introduced in #198, applying the placement design from docs/superpowers/specs. Key shifts: Streaming card → editor morph - The streaming preview card in the generation-preview page is now an interactive surface (tilt + hover-straighten + always-visible "点击审阅" affordance) that morphs into the full editor via shared `layoutId`. - SSE keeps streaming uninterrupted into the expanded editor; the editor consumes either `session.sceneOutlines` or live `streamingOutlines` so scenes appear as they arrive and stay in sync after edits. - A header collapse button shrinks back to the preview card. Mid-stream collapse keeps SSE running; post-stream collapse re-arms the same 2.5s auto-continue timer the no-review path uses, so the card doesn't strand. Document-style editor - Replaces the bordered card + accordion + numbered rail with a Notion- feeling stack: drag handle and number share a flex left rail aligned to the title baseline; title/description are inline-editable borderless textareas with auto-resize. - ⋮ overflow menu and explicit move-up/move-down are removed; reordering is drag-only, with hover-revealed delete (popover-confirmed) next to the type pill. - Hover-revealed `+` insert dividers between scenes; faint `+` at the list edges replaces the "Add scene" bar so insertion is uniform. - Quiz config popover redesigned: stepper for question count, segmented control for difficulty, multi-select pills for question types so mixed types from the LLM round-trip correctly (the previous single-select silently truncated `questionTypes` to one element). - Streaming placeholder row pulses below the latest scene during SSE. - Scene types use a colour-coded pill that doubles as the type switcher. State + flow plumbing - Adds `previewPhase: 'review'` entry from the streaming visualizer via `outlineReviewIntentRef`; SSE-completion ORs in this intent when deciding whether to wait for confirmation. - `localStorage.removeItem('requirementDraft')` moves to after the review promise resolves so "Back to requirements" actually restores the draft. - Auto-start condition broadened so refreshes during early-review reattach to a fresh SSE rather than stalling on an empty editor. - Six new locales (en-US, zh-CN, zh-TW, ja-JP, ru-RU, ar-SA) for the expand hint, streaming progress, collapse, delete confirmation, insert hint, and quiz summary; locale coverage test asserts the new keys plus the `{{count}}` interpolation contracts. Removed: the redundant "Review outline" button + auto-continue caption under the preview card, since the card itself is now the entry point. Removed: the home toolbar "Outline" tab from #198 — placement design explicitly rejects adding another always-visible toolbar control. * fix(outline-review): address code review feedback (PR #558) Single follow-up commit batching the issues raised in code review: Critical - E2E page object's reviewOutlineButton was hunting for the removed "Review outline" button. Re-target it to the streaming card's outlineExpandHint aria-label across all six locales. Important - waitForOutlineReviewChoice now accepts an AbortSignal and rejects on abort, so goBackToHome / unmount settle the parked promise instead of leaking the awaiting startGeneration closure. The existing AbortError catch swallows the rejection cleanly. - Add CLDR plural variants for the count-bearing strings: en gets _one; ru gets _one and _few for quizConfigSummary; ar gets _one and _two for the three count-bearing strings. Bare key remains as _other fallback. (zh / zh-TW / ja have a single plural form.) - Document the mid-stream collapse intent: dropping outlineReviewIntentRef is deliberate so SSE-completion takes the no-review path. - Add keyboard reorder on the drag handle (Ctrl/⌘ + ArrowUp/ArrowDown) with aria-keyshortcuts; replace dragScene copy with dragSceneHint that surfaces the shortcut. Restores WCAG 2.1.1 reachability for reorder. - KeyPointInput no longer commits on blur — only Enter / comma. Avoids surprise chips when users click away mid-typing. Minor - Drop unused i18n keys: reviewOutlineAction, moveSceneUp/Down, dragScene, sceneDescriptionLabel, keyPointsLabel/Placeholder, quizConfigLabel, addScene. Locale coverage test pruned to match actual usage. - requestAnimationFrame-batch useAutoResize so a burst of edits doesn't thrash layout (forced reflow per keystroke). - Reset isConfirmingOutlines in the no-parked-promise fallback path of handleConfirmOutlines so state doesn't linger. * chore(outline-review): prettier format + drop redundant session check - Run prettier on outlines-editor.tsx (CI Lint job was red). - Remove `&& session` from the StepVisualizer onExpandOutline conditional; `session` is guaranteed non-null at that point by the early-return guard above (flagged by github-code-quality bot). * fix(home): silence react-hooks/set-state-in-effect on draft restore Match the existing eslint-disable convention already used in app/page.tsx for the other localStorage-hydration effects. The setState calls are deliberate: client-side state hydration from localStorage must happen in an effect to remain SSR-safe (the lazy useState initialiser runs on the server with `window` undefined). * revert(i18n): drop CLDR plural variants until key-alignment check supports them scripts/check-i18n-keys.mjs enforces strict key equality across all locales, which is incompatible with i18next's per-locale plural-suffix keys (a Russian locale needs `_one`/`_few`/`_many`/`_other`, an Arabic one adds `_two`/`_zero`, while zh / ja need none). The check script doesn't strip plural suffixes before comparing, so any partial pluralization breaks alignment. Roll back the partial fix from PR review #2 and revert to the bare keys. The original "ungrammatical for n=1" wording stays, to be addressed in a follow-up that also teaches check-i18n-keys.mjs to ignore CLDR plural suffixes when comparing key sets. * fix(outline-review): make streaming card expand-hint pill actually visible The "Tap to review" pill was rendering but invisible in practice because: - Both the bottom white gradient (z-auto) and the pill (z-10) sit inside the same parent stacking context, but motion.div applies a transform that creates per-element stacking contexts; the implicit ordering put the gradient above the pill in some browsers. - text-[9px] + bg-blue-500/95 was too thin/translucent to read against the white gradient even when on top. Make stacking explicit (gradient z-0, pill z-20), bump the pill to text-[10px] font-semibold with solid bg-blue-500, larger Maximize icon, and lift it slightly to bottom-2 so it sits above the gradient haze.