Skip to content

Undo/Redo 機能を追加 (#41)#45

Open
sugama-satsuki wants to merge 1 commit intomainfrom
feature/undo-redo
Open

Undo/Redo 機能を追加 (#41)#45
sugama-satsuki wants to merge 1 commit intomainfrom
feature/undo-redo

Conversation

@sugama-satsuki
Copy link
Collaborator

@sugama-satsuki sugama-satsuki commented Feb 19, 2026

Summary

  • useUndoable フック(useReducer ベース)で features 状態の履歴管理を実装
  • Ctrl+Z / Cmd+Z で Undo、Ctrl+Shift+Z / Cmd+Shift+Z で Redo
  • DrawControlPanel に Undo/Redo ボタンを追加(無効時はグレーアウト)
  • 最大50件の履歴を保持(メモリ上限対策)
  • フィーチャ追加・削除・プロパティ変更・インポート・リセットすべてが Undo/Redo 対象

Test plan

  • ユニットテスト: useUndoable.test.ts (10件) — npm test でパス
  • E2E: undo-redo.feature (5シナリオ) — npm run test:e2e で44シナリオすべてパス

Closes #41

Summary by CodeRabbit

リリースノート

  • 新機能

    • マップへの点追加操作に対して、元に戻す(Undo)・やり直す(Redo)機能を追加しました。
    • Undo/Redoボタンをコントロールパネルに追加しました。
    • キーボードショートカット(Ctrl/Cmd+Z でUndo、Ctrl/Cmd+Y または Ctrl+Shift+Z でRedo)に対応しました。
  • テスト

    • Undo/Redo機能の動作を検証するエンドツーエンドテストを追加しました。
    • ロジックの正確性を確認する単体テストを追加しました。

- useUndoable フック(useReducer ベース)で features の履歴管理
- Ctrl+Z / Cmd+Z でUndo、Ctrl+Shift+Z / Cmd+Shift+Z でRedo
- DrawControlPanel に Undo/Redo ボタンを追加
- 最大50件の履歴を保持
- ユニットテスト10件、E2Eシナリオ5件追加

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

Undo/Redo機能を地図描画アプリケーションに追加します。useUndoableカスタムフックで状態管理を実装し、キーボードショートカット(Ctrl+Z、Ctrl+Shift+Z)とUIボタンでUndo/Redo操作をサポートします。E2Eテストとユニットテストで動作を検証します。

Changes

Cohort / File(s) Summary
Undoable State Management Hook
src/hooks/useUndoable.ts, src/lib/__tests__/useUndoable.test.ts
新しいカスタムフックuseUndoableを導入し、過去・現在・未来の状態スライスを管理します。SET、SET_FN、UNDO、REDOアクションをサポートし、MAX_HISTORY=50で履歴を制限します。ユニットテストで履歴管理ロジックを検証します。
UI Component Integration
src/components/DrawControlPanel.tsx, src/components/MapView.tsx
DrawControlPanelにUndo/Redoボタンとpropsを追加、MapViewでuseUndoableを統合し、キーボードショートカット(Ctrl+Z、Ctrl+Shift+Z)を実装します。DrawControlPanelにcanUndo、canRedo、onUndo、onRedoプロパティを追加。
E2E Test Specifications
e2e/features/undo-redo.feature, e2e/step-definitions/undo-redo-steps.ts
日本語で記述されたUndo/Redo機能のE2Eテスト仕様と、Playwrightを使用したステップ定義を追加します。ボタンのクリックとDisabled状態の検証を実装。

Sequence Diagram

sequenceDiagram
    participant User
    participant Keyboard
    participant MapView
    participant useUndoable
    participant DrawControlPanel
    participant UI

    User->>Keyboard: Press Ctrl+Z
    Keyboard->>MapView: Trigger keyboard event
    MapView->>useUndoable: Call undo()
    useUndoable->>useUndoable: Move current to future,<br/>restore from past
    useUndoable-->>MapView: Return updated features
    MapView->>DrawControlPanel: Update canUndo/canRedo props
    DrawControlPanel->>UI: Render button states
    UI-->>User: Display updated map
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Undo、Redoのボタン追加
履歴を優しく記憶して
Ctrl+Z のキーで戻れる
描き間違えも怖くない
編集体験、ぐんと上昇! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR タイトルは「Undo/Redo 機能を追加」で、主要な変更(Undo/Redo 機能の実装)を正確に反映しており、簡潔で明確です。
Linked Issues check ✅ Passed Issue #41 の要件(Ctrl+Z/Cmd+Z による Undo、Ctrl+Shift+Z/Cmd+Shift+Z による Redo、フィーチャ追加・削除・プロパティ変更対応)がすべて実装されています。
Out of Scope Changes check ✅ Passed すべての変更が Issue #41 で定義された Undo/Redo 機能の実装に関連しており、スコープ外の変更は見当たりません。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/undo-redo

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/DrawControlPanel.tsx (1)

152-176: Undo/Redo ボタンに aria-label を追加してください。
アイコンのみのボタンはスクリーンリーダーで識別しづらいので、明示的なラベル付与が望ましいです。

♿ 例: aria-label を追加
   <button
     type='button'
     onClick={onUndo}
     disabled={!canUndo}
+    aria-label='元に戻す'
     title='元に戻す (Ctrl+Z)'
     className={`draw-control-panel__action-button${!canUndo ? ' draw-control-panel__action-button--disabled' : ''}`}
   >
...
   <button
     type='button'
     onClick={onRedo}
     disabled={!canRedo}
+    aria-label='やり直す'
     title='やり直す (Ctrl+Shift+Z)'
     className={`draw-control-panel__action-button${!canRedo ? ' draw-control-panel__action-button--disabled' : ''}`}
   >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/DrawControlPanel.tsx` around lines 152 - 176, The undo/redo
icon-only buttons in DrawControlPanel are missing accessible labels; update the
two button elements that use onUndo/canUndo and onRedo/canRedo to include
aria-label attributes (e.g., aria-label="元に戻す" for the onUndo button and
aria-label="やり直す" for the onRedo button) so screen readers can identify the
controls while keeping existing title, disabled and className behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/MapView.tsx`:
- Around line 414-430: The global keyboard handler (handleKeyDown in the
useEffect that binds window keydown) currently triggers
undoFeatures/redoFeatures even when focus is in input fields; update
handleKeyDown to bail out early if the event target is an editable element
(e.g., tagName input, textarea, select, or an element with isContentEditable
true) or if the focused element has a role/attribute indicating an editor, so
the shortcut is ignored while editing; keep the existing mac vs ctrl logic and
existing undoFeatures/redoFeatures calls otherwise.

---

Nitpick comments:
In `@src/components/DrawControlPanel.tsx`:
- Around line 152-176: The undo/redo icon-only buttons in DrawControlPanel are
missing accessible labels; update the two button elements that use
onUndo/canUndo and onRedo/canRedo to include aria-label attributes (e.g.,
aria-label="元に戻す" for the onUndo button and aria-label="やり直す" for the onRedo
button) so screen readers can identify the controls while keeping existing
title, disabled and className behavior intact.

Comment on lines +414 to +430
// Undo/Redo キーボードショートカット
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const isMac = /mac/i.test(navigator.userAgent)
const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
if (!ctrlOrCmd) return
if (e.key === 'z' && !e.shiftKey) {
e.preventDefault()
undoFeatures()
} else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
e.preventDefault()
redoFeatures()
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [undoFeatures, redoFeatures])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

入力欄での Ctrl/Cmd+Z を奪わないようにしてください。
現在の実装だと、プロパティ編集などの入力中でも Undo/Redo が発火し、編集体験を壊します。入力系要素ではショートカットを無視する条件を追加してください。

🛠 例: 編集可能要素を除外
   const handleKeyDown = (e: KeyboardEvent) => {
     const isMac = /mac/i.test(navigator.userAgent)
     const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
+    const target = e.target as HTMLElement | null
+    if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) return
     if (!ctrlOrCmd) return
     if (e.key === 'z' && !e.shiftKey) {
       e.preventDefault()
       undoFeatures()
     } else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
       e.preventDefault()
       redoFeatures()
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Undo/Redo キーボードショートカット
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const isMac = /mac/i.test(navigator.userAgent)
const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
if (!ctrlOrCmd) return
if (e.key === 'z' && !e.shiftKey) {
e.preventDefault()
undoFeatures()
} else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
e.preventDefault()
redoFeatures()
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [undoFeatures, redoFeatures])
// Undo/Redo キーボードショートカット
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const isMac = /mac/i.test(navigator.userAgent)
const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
const target = e.target as HTMLElement | null
if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) return
if (!ctrlOrCmd) return
if (e.key === 'z' && !e.shiftKey) {
e.preventDefault()
undoFeatures()
} else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
e.preventDefault()
redoFeatures()
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [undoFeatures, redoFeatures])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/MapView.tsx` around lines 414 - 430, The global keyboard
handler (handleKeyDown in the useEffect that binds window keydown) currently
triggers undoFeatures/redoFeatures even when focus is in input fields; update
handleKeyDown to bail out early if the event target is an editable element
(e.g., tagName input, textarea, select, or an element with isContentEditable
true) or if the focused element has a role/attribute indicating an editor, so
the shortcut is ignored while editing; keep the existing mac vs ctrl logic and
existing undoFeatures/redoFeatures calls otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Undo/Redo 機能の追加

1 participant

Comments