# 画面設計書 17-スニペット一覧

## 概要

本ドキュメントは、GitLabダッシュボードのスニペット一覧画面（Dashboard Snippets Index）の画面設計を定義したものである。

### 本画面の処理概要

ログインユーザーが作成したスニペットの一覧を表示し、コードスニペットの管理を支援するダッシュボード画面である。

**業務上の目的・背景**：スニペットは、再利用可能なコード断片やテキストを保存・共有するための機能である。本画面は、ユーザーが作成した個人スニペットを一元管理し、素早くアクセス・編集できるようにする。スニペットは公開・内部・非公開の可視性設定が可能で、チーム内での知識共有に活用される。

**画面へのアクセス方法**：ログイン後、サイドバーまたはナビゲーションから「Snippets」メニューを選択。直接URLアクセスの場合は `/dashboard/snippets` へアクセスする。

**主要な操作・処理内容**：
1. スニペット一覧の表示（ページネーション対応）
2. スコープによるフィルタリング（All、Private、Internal、Public）
3. ソート順の変更
4. 各スニペットの詳細画面への遷移
5. 新規スニペット作成画面への遷移

**画面遷移**：
- 遷移元：ログイン画面、サイドバー、ナビゲーション
- 遷移先：スニペット詳細画面、スニペット新規作成画面

**権限による表示制御**：ログインユーザーのみアクセス可能。表示されるスニペットはログインユーザー自身が作成したスニペットのみ。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 72 | 個人スニペット | 主機能 | ユーザースニペットの一覧表示 |

## 画面種別

一覧

## URL/ルーティング

| URL | HTTPメソッド | 説明 |
|-----|-------------|------|
| `/dashboard/snippets` | GET | スニペット一覧 |

## 入出力項目

### 入力項目（フィルタ）

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| scope | string | No | スコープ（all, are_private, are_internal, are_public） |
| sort | string | No | ソート順 |
| page | integer | No | ページ番号 |

### 出力項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @snippets | Array | スニペット一覧 |
| @snippet_counts | Hash | スコープ別カウント |
| @noteable_meta_data | Hash | ノートメタデータ |

## 表示項目

### スニペット一覧

| 項目名 | 説明 | 備考 |
|--------|------|------|
| スニペットタイトル | スニペットのタイトル | リンク |
| ファイル名 | スニペットのファイル名 | |
| 作成者 | スニペットの作成者 | アバター表示 |
| 可視性 | Private/Internal/Public | アイコン表示 |
| 作成日時 | スニペット作成日時 | 相対時間表示 |
| 更新日時 | 最終更新日時 | 相対時間表示 |
| コメント数 | コメント数 | |
| プロジェクト | 所属プロジェクト（あれば） | リンク |

## イベント仕様

### 1-スニペットリストの読み込み

ページ読み込み時にSnippetsFinderを使用してスニペット一覧を取得する。

**処理フロー**：
1. SnippetsFinderによるスニペット検索
2. ページネーション処理
3. スコープ別カウントの取得
4. テンプレートレンダリング

### 2-スコープフィルタの変更

スコープタブ（All、Private、Internal、Public）をクリックすると、該当スコープのスニペットが表示される。

### 3-新規スニペット作成

「New snippet」ボタンをクリックすると、新規スニペット作成画面へ遷移する。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ表示 | snippets | SELECT | フィルタ条件に合致するスニペットを取得 |
| ページ表示 | snippet_statistics | SELECT | スニペット統計情報を取得 |

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

#### snippets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, title, file_name, visibility_level, author_id, project_id, created_at, updated_at | author: current_user | SnippetsFinder経由 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 情報 | "No snippets found" | スニペットが存在しない場合 |

## 例外処理

| 例外条件 | 処理内容 | 表示メッセージ |
|----------|----------|---------------|
| 未ログイン | ログイン画面へリダイレクト | - |
| ページ範囲外 | リダイレクト | - |

## 備考

- サーバーサイドレンダリングによる従来型のRails実装
- スニペットが存在しない場合は専用のempty_statesパーシャルを表示
- SnippetsSort concernによるソート機能
- Snippets::CountServiceでスコープ別カウントを取得
- Current.organizationによる組織スコープのフィルタリング

---

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

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

### 推奨読解順序

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

まず、スニペットのデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | snippet.rb | `app/models/snippet.rb` | Snippetモデルの定義、可視性レベル |
| 1-2 | snippets_finder.rb | `app/finders/snippets_finder.rb` | スニペット検索ロジック |

**読解のコツ**: Snippetは Gitlab::VisibilityLevel を含み、Private/Internal/Public の可視性設定を持つ。

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

処理の起点となるコントローラを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | snippets_controller.rb | `app/controllers/dashboard/snippets_controller.rb` | indexアクション |

**主要処理フロー**:
1. **Line 4-6**: PaginatedCollection、Gitlab::NoteableMetadata、SnippetsSortをinclude
2. **Line 12-15**: Snippets::CountServiceでスコープ別カウント取得
3. **Line 17-23**: SnippetsFinderでスニペット検索、ページネーション
4. **Line 27**: noteable_meta_dataでノートメタデータ取得

#### Step 3: ビューテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.haml | `app/views/dashboard/snippets/index.html.haml` | HAMLテンプレート |

**主要処理フロー**:
- **Line 4-6**: スニペット有無による条件分岐
- **Line 5**: _snippets_headパーシャルのレンダリング
- **Line 6**: スコープメニューとスニペットリスト表示
- **Line 9**: 空状態の表示

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

```
Dashboard::SnippetsController#index
    |
    +-- Snippets::CountService.new(current_user, author: current_user).execute
    |
    +-- SnippetsFinder.new(current_user, organization_id: Current.organization.id, author: current_user, scope: params[:scope], sort: sort_param)
    |       |
    |       +-- execute
    |       +-- page(pagination_params[:page])
    |       +-- inc_author
    |       +-- inc_projects_namespace_route
    |       +-- inc_statistics
    |
    +-- redirect_out_of_range(@snippets) (ページ範囲チェック)
    |
    +-- noteable_meta_data(@snippets, 'Snippet')
    |
    +-- render 'dashboard/snippets/index'
           |
           +-- '_snippets_head' partial
           +-- 'snippets/snippets_scope_menu' partial
           +-- 'shared/snippets/list' partial
```

### データフロー図

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

URLパラメータ ───▶ Dashboard::SnippetsController ───▶ HTMLレスポンス
(scope, sort)           |
                        |
                        v
                  SnippetsFinder
                        |
                        v
                  Snippet (Model)
                        |
                        v
                  PostgreSQL
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| snippets_controller.rb | `app/controllers/dashboard/snippets_controller.rb` | コントローラ | リクエスト処理 |
| index.html.haml | `app/views/dashboard/snippets/index.html.haml` | ビュー | 画面テンプレート |
| snippets_finder.rb | `app/finders/snippets_finder.rb` | ファインダー | スニペット検索 |
| snippet.rb | `app/models/snippet.rb` | モデル | スニペットデータ定義 |
| count_service.rb | `app/services/snippets/count_service.rb` | サービス | スコープ別カウント |
| dashboard.rb | `config/routes/dashboard.rb` | ルート | URL定義 |
