経歴書 保存時の左右 diff プレビュー(VSCode 風)を追加#306
Conversation
保存ボタン押下時に baseline(保存済み)と編集中フォームの差分を一覧表示し、 旧→新/追加・削除・修正を区別して確認できるダイアログを追加。各変更行で 「元に戻す」を押すと、その項目だけ baseline 値へ戻し、他の変更は保持したまま保存できる。 - utils/setAtPath.ts: immutable な path 単位の set/insert/remove(ロールバック適用の土台) - utils/careerDiff.ts: baseline vs form の変更点リスト生成(既存 isDeepEqual を再利用、 配列は useCareerDirty と同じ index 突合。途中削除は近似表示) - components/forms/CareerSaveConfirmDialog: 確認+項目別ロールバック UI - CareerResumeForm: 保存フローにダイアログを差し込み(setForm/save を流用) - constants/messages.ts: CAREER_DIFF_LABELS / DIFF_DIALOG_MESSAGES を追加 - careerDiff.test.ts / setAtPath.test.ts: ユニットテスト https://claude.ai/code/session_01NKa8AgchLkcdc3fXi737AF
第1弾のフィールド要約ダイアログを、PDF プレビューのレイアウトで左右に並べる diff モーダルに作り替えた。左=保存済み / 右=編集中を整形 HTML で並べ、変更箇所を 緑(追加)/赤(削除)/黄(修正)でハイライト。変更点サイドバーから矢印(↩)で項目別ロールバック。 主な変更: - backend: POST /api/resumes/preview(認証・DB非更新)を新設し整形 HTML+CSS を返す。 _build_html の各値ノードに data-fp(careerDiff パスと一致)、各項目に data-unit を付与 (PDF 出力は不変)。CSS 読込を _load_css(for_screen) に分離。 - frontend: CareerDiffModal(iframe srcdoc・sandbox)/ useResumeDiffPreview(baseline 1回・ 編集中 debounce)/ diffHighlight(着色・変更なし領域の折りたたみ・削除プレースホルダ)を追加。 CareerSaveConfirmDialog は廃止。careerDiff / setAtPath は流用。 - 変更なし項目は <details> で折りたたみ、削除項目は編集中側に「(削除)…」スタブを表示。 検証: frontend は vitest(238)/eslint/messages-lint/build green。 backend は新規エンドポイント/生成系のテストを追加(実行は nix/WeasyPrint 環境が必要)。 https://claude.ai/code/session_01NKa8AgchLkcdc3fXi737AF
diff モーダル表示中に form が変わるのはロールバック操作のみで連続入力が無いため、 編集中プレビュー再取得の debounce を 300ms→0ms にし、矢印クリック直後に右ペインへ反映する。 https://claude.ai/code/session_01NKa8AgchLkcdc3fXi737AF
…-discussion-i2n0V # Conflicts: # backend/app/services/pdf/generators/resume_generator.py
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
🚧 Files skipped from review as they are similar to previous changes (7)
📝 WalkthroughWalkthroughThis PR adds a backend preview endpoint that returns annotated resume HTML and screen CSS, and a frontend save-confirmation flow that computes diffs, shows a side-by-side modal preview with rollback controls, and integrates tests and E2E wiring. ChangesResume Preview and Diff-Confirmation Flow
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- generated.ts: 新規 /api/resumes/preview の path / schema(ResumePreviewResponse) / operation を OpenAPI 生成物に反映(codegen-drift 解消、ADR-0007)。 - e2e career-dirty-indicator: 保存ボタンが diff モーダルを開く挙動に変わったため、 プレビュー API モックを追加し「この内容で保存」で確定するフローに更新。 https://claude.ai/code/session_01NKa8AgchLkcdc3fXi737AF
|
@coderabbitai review Generated by Claude Code |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
frontend/src/hooks/career/useResumeDiffPreview.test.ts (1)
36-77: ⚡ Quick winAdd regression tests for cancel/stale-state paths.
Please add cases for (1)
baselinetransitioning tonullafter an initial successful fetch and (2) disabling/unmounting during an in-flight edited fetch to assertloadingresets. These paths are currently untested and are easy to regress.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/hooks/career/useResumeDiffPreview.test.ts` around lines 36 - 77, Add two tests to cover regression paths: (1) "baseline -> null after success": renderHook(() => useResumeDiffPreview(validForm, baseline, true)), advance timers to let initial baseline/edited fetch resolve, assert baselineHtml is set, then rerender with baseline = null and assert baselineHtml becomes null and no new baseline fetch is triggered (verify mockPreview call counts); (2) "cancel/unmount during in-flight edited fetch resets loading": start the hook enabled, advance timers just enough to start the edited fetch (use vi.advanceTimersByTimeAsync to simulate delay), then either rerender with enabled=false or call unmount(), await remaining timers, and assert result.current.loading is false and that in-flight resolution does not set editedHtml (also verify mockPreview call counts to ensure no stray state updates). Use existing helpers renderHook/act/mockPreview/useResumeDiffPreview/validForm/baseline names to locate and implement the tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/services/pdf/generators/resume_generator.py`:
- Around line 165-166: The period display spans in resume_generator.py (the
f-strings that produce the "vacation-header" and "vacation-body" nodes keyed to
f"{fp}.vacation_start_date") only bind to start_date so edits to end_date or
is_current won't be highlighted; update these renderings in the generate resume
HTML to either (a) bind the aggregated period node to the parent path (use
data-fp="{fp}" or data-fp="{parent_fp}" so changes to any child field map) or
(b) split the period into separate spans each with its own data-fp for
start_date, end_date and is_current (e.g., data-fp="{fp}.vacation_start_date",
data-fp="{fp}.vacation_end_date", data-fp="{fp}.vacation_is_current"); apply the
same fix to the other occurrence noted around lines 239-240 so all
period/experience date ranges are properly highlighted.
In `@frontend/src/api/resumes.ts`:
- Around line 6-9: The comment for the ResumePreviewResponse mirror is outdated;
update the doc comment to remove the claim that OpenAPI has not reflected
ResumePreviewResponse and instead note that the type is available from the
generated API types (ResumePreviewResponse in generated API types), or
completely remove the manual-mirror remark so future readers don't duplicate
types; change the comment near the top of the file that references
ResumePreviewResponse accordingly and, if appropriate, replace any hand-written
type usage with the generated ResumePreviewResponse type.
In `@frontend/src/components/forms/CareerDiffModal.tsx`:
- Line 113: The backdrop click currently calls onCancel unconditionally in the
CareerDiffModal (<div className={styles.overlay} onClick={onCancel}>), allowing
the modal to close while a save is in progress; update the overlay click handler
to check the saving prop/state and only invoke onCancel when saving is false
(i.e., ignore/backdrop-click when saving === true) so the modal cannot be
dismissed while an in-flight save is happening.
In `@frontend/src/hooks/career/useResumeDiffPreview.ts`:
- Around line 82-101: The cleanup currently flips the local `active` flag to
false so the in-flight promise handlers skip state updates, which can leave
`loading` stuck true; ensure `loading` is reset deterministically by either (a)
removing the `active` guard around the finally branch so `setLoading(false)`
always runs after `getCareerResumePreview` resolves/rejects, or (b) explicitly
call `setLoading(false)` inside the cleanup function in addition to `active =
false`; locate the debounce block using `handle`, `active`, `setLoading`,
`setFetchError`, and `getCareerResumePreview` (and `EDITED_DEBOUNCE_MS`) and
apply one of these fixes so cleanup cannot leave `loading` true.
- Around line 107-113: baselineHtml currently returns stale HTML from cached
baselinePreview even when the current baseline/preview is disabled or null;
update useResumeDiffPreview so baselineHtml is gated by the current inputs
(e.g., return baselineHtml: (enabled && baselinePayload) ? baselinePreview?.html
?? null : null) or explicitly clear/reset baselinePreview when baseline or
enabled becomes falsy; modify the return object and/or the effect that sets
baselinePreview (referencing baselineHtml, baselinePreview, baselinePayload,
enabled in useResumeDiffPreview) so the left-pane cannot show stale baseline
HTML.
In `@frontend/src/utils/diffHighlight.ts`:
- Around line 121-131: The anchor lookup in the loop that handles changes
(variables: change, index, prefix, anchor, lastByPrefix, doc) only searches
backward from index-1 so removals at index 0 (or when earlier siblings are
missing) never render a removed-stub; update the logic after the backward search
to, if anchor is still null, perform a forward search for the next existing
sibling by querying doc for data-unit="${prefix}.${k}" with k=index+1.. until
found, and if found insert the removed stub before that forward anchor (or
otherwise fall back to existing behavior), ensuring removed-stubs are shown for
head deletions and when earlier siblings are absent.
---
Nitpick comments:
In `@frontend/src/hooks/career/useResumeDiffPreview.test.ts`:
- Around line 36-77: Add two tests to cover regression paths: (1) "baseline ->
null after success": renderHook(() => useResumeDiffPreview(validForm, baseline,
true)), advance timers to let initial baseline/edited fetch resolve, assert
baselineHtml is set, then rerender with baseline = null and assert baselineHtml
becomes null and no new baseline fetch is triggered (verify mockPreview call
counts); (2) "cancel/unmount during in-flight edited fetch resets loading":
start the hook enabled, advance timers just enough to start the edited fetch
(use vi.advanceTimersByTimeAsync to simulate delay), then either rerender with
enabled=false or call unmount(), await remaining timers, and assert
result.current.loading is false and that in-flight resolution does not set
editedHtml (also verify mockPreview call counts to ensure no stray state
updates). Use existing helpers
renderHook/act/mockPreview/useResumeDiffPreview/validForm/baseline names to
locate and implement the tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 527a9958-d927-41a2-bff5-d2f288ba8eff
📒 Files selected for processing (22)
backend/app/routers/resumes.pybackend/app/schemas/__init__.pybackend/app/schemas/resume.pybackend/app/services/pdf/generators/resume_generator.pybackend/tests/test_endpoints.pybackend/tests/test_pdf_generator.pyfrontend/e2e/career-dirty-indicator.spec.tsfrontend/src/api/generated.tsfrontend/src/api/paths.tsfrontend/src/api/resumes.tsfrontend/src/components/forms/CareerDiffModal.module.cssfrontend/src/components/forms/CareerDiffModal.tsxfrontend/src/components/forms/CareerResumeForm.tsxfrontend/src/constants/messages.tsfrontend/src/hooks/career/useResumeDiffPreview.test.tsfrontend/src/hooks/career/useResumeDiffPreview.tsfrontend/src/utils/careerDiff.test.tsfrontend/src/utils/careerDiff.tsfrontend/src/utils/diffHighlight.test.tsfrontend/src/utils/diffHighlight.tsfrontend/src/utils/setAtPath.test.tsfrontend/src/utils/setAtPath.ts
- 期間ハイライトをフィールド単位に分割し end_date / is_current の編集も着色 (_format_period_html を新設。experiences / vacation に適用。PDF レイアウトは不変) - ResumePreviewResponse を OpenAPI 生成型から再利用(手書きミラーと古いコメントを削除) - 保存中は背景クリックでモーダルを閉じないようガード - プレビュー取得のキャンセル時に loading を確定的に下ろす - baseline 無効化後に古い左ペイン HTML を出さないよう baselineHtml をゲート - 先頭削除時に前方アンカーの直前へ削除スタブを挿入する fallback を追加 https://claude.ai/code/session_01NDGfhgFWa2nxHpU598xVJN
|
@coderabbitai pvして! |
|
(ノ´ヮ`)ノ*: ・゚ ✅ Action performedReview finished.
|
概要
経歴書(職務経歴書)の保存ボタン押下時に、保存済み(左)と編集中(右)を PDF プレビューと同じ整形レイアウトで左右に並べて比較できる diff モーダルを追加しました。VSCode フォークの diff のように、変更箇所をハイライトし、項目ごとに編集前へ戻せます。
主な機能
<details>で「▸ 変更なし N 項目を表示」に畳み、差分に集中できる。実装
Backend
POST /api/resumes/preview(認証必須・DB 非更新)を新設。ResumeCreateを受けて整形 HTML と画面用 CSS を返す。_build_htmlの各値ノードにdata-fp(FEcareerDiffのパスと一致)、各項目にdata-unitを付与(PDF 出力は不変)。CSS 読込を_load_css(for_screen)に分離。Frontend
CareerDiffModal(全画面・iframe sandbox)/useResumeDiffPreview(baseline は1回・編集中はロールバック都度=即時取得)/diffHighlight(着色・折りたたみ・削除スタブ)を追加。careerDiff/setAtPathは流用。テスト
lint-frontend-messages/ build すべて green。_build_htmlのdata-fp/data-unit付与・PDF 回帰のテストを追加(実行は nix/WeasyPrint 環境が前提)。補足 / 残課題
https://claude.ai/code/session_01NKa8AgchLkcdc3fXi737AF
Generated by Claude Code
Summary by CodeRabbit
New Features
Tests / E2E