# 画面設計書 64-MR編集

## 概要

本ドキュメントは、GitLabプロジェクトのマージリクエスト編集画面の設計仕様を定義するものである。

### 本画面の処理概要

本画面は、既存のマージリクエスト（MR）の情報を編集するための画面である。タイトル、説明、アサイニー、レビュアー、ラベル、マイルストーンなどのメタデータを変更し、MRの内容を更新する機能を提供する。

**業務上の目的・背景**：マージリクエストの作成後、要件の変更やレビュープロセスの進行に伴い、タイトルや説明の修正、担当者の変更などが必要になることがある。本画面は、これらの変更を効率的に行うためのフォームインターフェースを提供し、チーム内での情報共有と作業管理を支援する。

**画面へのアクセス方法**：
1. MR詳細画面の「Edit」ボタンをクリック
2. URLに直接`/-/merge_requests/:iid/edit`を入力

**主要な操作・処理内容**：
1. MRタイトルの編集
2. MR説明文の編集（Markdownプレビュー対応）
3. アサイニーの変更
4. レビュアーの変更
5. ラベルの追加/削除
6. マイルストーンの変更
7. マージオプションの変更（squash、ソースブランチ削除）
8. MRクローズの実行
9. 変更の保存

**画面遷移**：
- 遷移元：MR詳細画面
- 遷移先：MR詳細画面（保存成功時）、MR編集画面（バリデーションエラー時）

**権限による表示制御**：
- 編集権限（作成者、Developer以上）：フォーム全体の表示
- 管理者権限（Maintainer以上）：詳細設定オプション

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | マージリクエスト編集 | 主機能 | マージリクエストの編集処理 |

## 画面種別

編集

## URL/ルーティング

| メソッド | URL | アクション | 説明 |
|----------|-----|-----------|------|
| GET | `/:namespace_id/:project_id/-/merge_requests/:id/edit` | edit | MR編集画面表示 |
| PATCH/PUT | `/:namespace_id/:project_id/-/merge_requests/:id` | update | MR更新処理 |

## 入出力項目

### 入力項目

| 項目名 | データ型 | 必須 | バリデーション | 説明 |
|--------|---------|------|---------------|------|
| title | string | ○ | 最大255文字、空白不可 | MRタイトル |
| description | text | - | 最大1MB | MR説明文（Markdown対応） |
| assignee_ids | integer[] | - | 存在するユーザー | アサイニーのユーザーID |
| reviewer_ids | integer[] | - | 存在するユーザー | レビュアーのユーザーID |
| label_ids | integer[] | - | 存在するラベル | ラベルID |
| milestone_id | integer | - | 存在するマイルストーン | マイルストーンID |
| target_branch | string | - | 存在するブランチ | ターゲットブランチ（変更可能） |
| squash | boolean | - | - | squashマージ設定 |
| discussion_locked | boolean | - | - | ディスカッションロック |
| allow_collaboration | boolean | - | - | 共同作業許可（フォーク時） |
| lock_version | integer | ○ | 楽観的ロック | 競合検出用バージョン |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| 現在のタイトル | string | 編集対象のタイトル |
| 現在の説明 | text | 編集対象の説明文 |
| ソースブランチ | string | マージ元ブランチ（変更不可） |
| ターゲットブランチ | string | マージ先ブランチ |
| 現在のアサイニー | object[] | 設定済みアサイニー |
| 現在のレビュアー | object[] | 設定済みレビュアー |
| 現在のラベル | object[] | 設定済みラベル |
| 現在のマイルストーン | object | 設定済みマイルストーン |

## イベント仕様

### 1-フォーム入力

各入力フィールドで値を編集する。Markdownプレビュータブで説明文のレンダリング結果を確認できる。

### 2-アサイニー/レビュアー選択

ドロップダウンからユーザーを検索・選択する。複数選択が可能（設定による）。

### 3-ラベル選択

ドロップダウンからラベルを検索・選択する。複数選択が可能。

### 4-マイルストーン選択

ドロップダウンからアクティブなマイルストーンを選択する。

### 5-保存ボタン押下

「Save changes」ボタンをクリックすると、入力内容のバリデーションが行われ、問題がなければPATCHリクエストでMRが更新される。更新成功時はMR詳細画面にリダイレクトされる。

### 6-キャンセル

「Cancel」リンクをクリックすると、変更を破棄してMR詳細画面に戻る。

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| MR更新 | merge_requests | UPDATE | MR基本情報の更新 |
| アサイン変更 | merge_request_assignees | INSERT/DELETE | アサイニー関連付け更新 |
| レビュアー変更 | merge_request_reviewers | INSERT/DELETE | レビュアー関連付け更新 |
| ラベル変更 | label_links | INSERT/DELETE | ラベル関連付け更新 |
| マイルストーン変更 | merge_requests | UPDATE | milestone_idの更新 |

### テーブル別更新項目詳細

#### merge_requests

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | title | フォーム入力値 | 必須 |
| UPDATE | description | フォーム入力値 | |
| UPDATE | target_branch | フォーム入力値 | |
| UPDATE | milestone_id | 選択されたマイルストーンID | |
| UPDATE | squash | フォーム入力値 | |
| UPDATE | discussion_locked | フォーム入力値 | |
| UPDATE | allow_collaboration | フォーム入力値 | |
| UPDATE | updated_at | 現在時刻 | 自動更新 |
| UPDATE | lock_version | インクリメント | 楽観的ロック |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| エラー | Title can't be blank | タイトル未入力 |
| エラー | Someone edited this merge request at the same time | 楽観的ロック競合 |
| エラー | Target branch not found | ターゲットブランチが存在しない |
| 成功 | (リダイレクト) | 更新成功時は詳細画面へ |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| MRが見つからない | 404エラーページを表示 |
| 編集権限がない | 403エラーページを表示 |
| 楽観的ロック競合 | 競合メッセージを表示、再読み込み促す |
| バリデーションエラー | フォーム再表示とエラーメッセージ表示 |

## 備考

- 楽観的ロック（lock_version）により同時編集を検出
- ソースブランチは編集不可（変更するには新規MR作成が必要）
- 共有Issuableフォームコンポーネントを使用

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | merge_request.rb | `app/models/merge_request.rb` | MRモデルの属性・バリデーション |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | editアクションとupdateアクション |

**主要処理フロー**:
1. **行252-254**: `edit`アクション - `define_edit_vars`を呼び出し
2. **行256-284**: `update`アクション - UpdateServiceでMR更新
3. **行577-585**: `define_edit_vars` - フォーム表示用変数の設定

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_service.rb | `app/services/merge_requests/update_service.rb` | MR更新サービス |

**主要処理フロー**:
- `execute`メソッドでMR更新処理を実行
- 変更内容の検出と通知
- システムノートの自動生成

#### Step 4: ビュー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | edit.html.haml | `app/views/projects/merge_requests/edit.html.haml` | メインビュー（行1-9） |
| 4-2 | _form.html.haml | `app/views/projects/merge_requests/_form.html.haml` | フォームパーシャル（行1-4） |
| 4-3 | form.html.haml | `app/views/shared/issuable/_form.html.haml` | 共有Issuableフォーム |

**主要処理フロー**:
- **edit.html.haml行7-8**: PageHeadingコンポーネントとフォームレンダリング
- **_form.html.haml行1-3**: gitlab_ui_form_forで共有フォームを使用

### プログラム呼び出し階層図

```
HTTP Request (GET /project/-/merge_requests/:id/edit)
    │
    ├─ MergeRequestsController#edit
    │      │
    │      ├─ before_action :authorize_update_issuable!
    │      │
    │      └─ define_edit_vars
    │             ├─ @source_project = @merge_request.source_project
    │             ├─ @target_project = @merge_request.target_project
    │             └─ @mr_presenter = @merge_request.present
    │
    └─ render 'edit' → _form.html.haml → shared/issuable/_form

HTTP Request (PATCH /project/-/merge_requests/:id)
    │
    ├─ MergeRequestsController#update
    │      │
    │      └─ MergeRequests::UpdateService#execute
    │             ├─ MR属性更新
    │             ├─ アサイニー/レビュアー更新
    │             ├─ ラベル/マイルストーン更新
    │             └─ システムノート生成
    │
    └─ redirect_to MR詳細 or render :edit
```

### データフロー図

```
[入力]                    [処理]                         [出力]

MR ID ──────────────▶ MergeRequestsController#edit ──▶ 編集フォーム
                          │
                          └─ define_edit_vars
                                 ├─ @source_project
                                 ├─ @target_project
                                 └─ @mr_presenter
                                            │
                                            ▼
フォーム送信 ──────▶ UpdateService#execute ──────▶ MR更新
                          │
                          ├─ バリデーション
                          ├─ DB更新
                          └─ システムノート生成
                                            │
                                            ▼
                          ──────────────▶ MR詳細画面
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | コントローラー | リクエストハンドリング |
| edit.html.haml | `app/views/projects/merge_requests/edit.html.haml` | ビュー | メインビュー |
| _form.html.haml | `app/views/projects/merge_requests/_form.html.haml` | パーシャル | フォームラッパー |
| _form.html.haml | `app/views/shared/issuable/_form.html.haml` | パーシャル | 共有Issuableフォーム |
| update_service.rb | `app/services/merge_requests/update_service.rb` | サービス | 更新ロジック |
| merge_request.rb | `app/models/merge_request.rb` | モデル | データモデル |
