# 通知設計書 37-Unsupported paste

## 概要

本ドキュメントは、OpenCodeアプリケーションにおける「Unsupported paste（サポートされていない貼り付け）」トースト通知の設計仕様を定義する。

### 本通知の処理概要

ユーザーがプロンプト入力欄にサポートされていないファイル形式をペーストしようとした際に、その操作が無効であることを通知するトースト表示を行う機能である。

**業務上の目的・背景**：OpenCodeのプロンプト入力欄では、テキストに加えて画像（PNG、JPEG、GIF、WebP）やPDFファイルを添付してAIに送信することができる。しかし、これら以外のファイル形式（例：Excel、Word、音声ファイル等）はサポートされていない。ユーザーがサポート外のファイルをクリップボードからペーストしようとした場合、その操作が無効であることを明確に通知し、対応可能なファイル形式を案内する必要がある。この通知により、ユーザーはどのようなファイル形式が受け付けられるかを理解し、適切な形式に変換するか、テキストとして情報を入力することができる。

**通知の送信タイミング**：ユーザーがプロンプト入力欄でペースト操作（Ctrl+V / Cmd+V）を行い、クリップボードにファイルアイテムが含まれているが、そのファイル形式がサポート対象（image/png、image/jpeg、image/gif、image/webp、application/pdf）に含まれていない場合に通知が発生する。

**通知の受信者**：ペースト操作を行ったユーザー本人のみが受信する。アプリ内のトースト通知であり、外部への送信は行わない。

**通知内容の概要**：タイトルとして「Unsupported paste」（日本語：「サポートされていない貼り付け」）が表示され、説明文として「Only images or PDFs can be pasted here.」（日本語：「ここでは画像またはPDFのみ貼り付け可能です。」）が表示される。

**期待されるアクション**：ユーザーはサポートされている形式（画像またはPDF）に変換してから再度ペーストするか、ファイルの内容をテキストとして入力する。

## 通知種別

トースト通知（アプリ内通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（UIスレッド上で即時表示） |
| 優先度 | 低 |
| リトライ | 無し（UIトーストのため） |

### 送信先決定ロジック

操作を実行したユーザーのブラウザ/デスクトップアプリ画面に表示される。特別な送信先決定ロジックは不要。

## 通知テンプレート

### トースト通知の場合

| 項目 | 内容 |
|-----|------|
| バリアント | default |
| アイコン | なし |
| 持続性 | 非持続（自動消去） |

### 本文テンプレート

```
タイトル: Unsupported paste
説明: Only images or PDFs can be pasted here.
```

日本語の場合:
```
タイトル: サポートされていない貼り付け
説明: ここでは画像またはPDFのみ貼り付け可能です。
```

### 添付ファイル

なし（トースト通知のため添付ファイルは非対応）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | i18n: `prompt.toast.pasteUnsupported.title` | Yes |
| description | 説明文 | i18n: `prompt.toast.pasteUnsupported.description` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ペースト操作 | ファイルあり & サポート形式なし | クリップボードにファイルがあるが画像/PDFでない場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| サポート形式のファイル | 画像（PNG/JPEG/GIF/WebP）またはPDFの場合は通知されない |
| ファイルなし | クリップボードにファイルがない場合（テキストのみ）は通知されない |
| フォーカスなし | プロンプト入力欄にフォーカスがない場合は処理されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがペースト操作を実行] --> B{入力欄にフォーカスあり?}
    B -->|No| C[処理なし]
    B -->|Yes| D{クリップボードにファイルあり?}
    D -->|No| E[テキスト処理へ]
    D -->|Yes| F{サポート形式の画像/PDFあり?}
    F -->|Yes| G[画像添付処理へ]
    F -->|No| H[showToast - 警告通知表示]
    H --> I[return - 処理中断]
    C --> J[終了]
    E --> J
    G --> J
    I --> J
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はフロントエンド側のUI通知であり、直接的なデータベース参照は行わない。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | - | クリップボードデータの検証のため |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| N/A | - | 通知表示自体はデータベース更新を伴わない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バリデーションエラー | サポート外のファイル形式 | 本通知を表示し、対応形式を案内 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | N/A（バリデーションエラーのため） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ユーザー操作に応じて即時表示）

## セキュリティ考慮事項

- クリップボードのファイル形式情報のみを検証
- ファイル内容自体は検査しない（形式チェックのみ）
- 機密情報は通知に含まれない

## 備考

- サポートされているファイル形式は以下の通り:
  - 画像: `image/png`, `image/jpeg`, `image/gif`, `image/webp`
  - ドキュメント: `application/pdf`
- 通知後は `return` で処理が中断され、ファイルは添付されない

---

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

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

### 推奨読解順序

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

サポートされているファイル形式の定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | attachments.ts | `packages/app/src/components/prompt-input/attachments.ts` | ACCEPTED_IMAGE_TYPES と ACCEPTED_FILE_TYPES の定義（8-9行目） |
| 1-2 | en.ts | `packages/app/src/i18n/en.ts` | 278-279行目の `prompt.toast.pasteUnsupported.*` キーを確認 |

**読解のコツ**: `ACCEPTED_FILE_TYPES` には画像形式に加えて `application/pdf` が含まれている。

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

ペーストイベントハンドラの実装を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | attachments.ts | `packages/app/src/components/prompt-input/attachments.ts` | handlePaste関数（65-116行目） |

**主要処理フロー**:
1. **66行目**: フォーカスチェック（`!input.isFocused()` なら早期リターン）
2. **73-74行目**: クリップボードアイテムをファイルでフィルタ
3. **75行目**: サポート形式でフィルタ → `imageItems`
4. **77-83行目**: サポート形式があれば画像添付処理
5. **85-91行目**: **ファイルがあるがサポート形式がない場合、showToast呼び出し（本通知の発生箇所）**

#### Step 3: ファイル形式の判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | attachments.ts | `packages/app/src/components/prompt-input/attachments.ts` | フィルタ条件（74-75行目） |

**主要処理フロー**:
- **74行目**: `items.filter((item) => item.kind === "file")` - ファイルアイテムのみ抽出
- **75行目**: `fileItems.filter((item) => ACCEPTED_FILE_TYPES.includes(item.type))` - サポート形式のみ抽出
- **85行目**: `fileItems.length > 0` かつ `imageItems.length === 0` の場合に通知

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

```
attachments.ts::createPromptAttachments()
    │
    └─ handlePaste(event: ClipboardEvent)
           │
           ├─ [!input.isFocused()] → return
           │
           ├─ clipboardData.items → fileItems (kind === "file")
           │
           ├─ fileItems.filter(ACCEPTED_FILE_TYPES) → imageItems
           │
           ├─ [imageItems.length > 0]
           │      └─ addImageAttachment() → return
           │
           └─ [fileItems.length > 0 && imageItems.length === 0]
                  │
                  └─ showToast({
                         title: "prompt.toast.pasteUnsupported.title",
                         description: "prompt.toast.pasteUnsupported.description"
                     })
                     │
                     └─ return（処理中断）
```

### データフロー図

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

クリップボード         handlePaste関数                   バリデーション通知
ペースト操作 ───▶    ファイルアイテム抽出 ───▶    形式チェック
                            │                              │
                      [サポート外形式]                      ▼
                            │                    showToast()
                            ▼                    「Unsupported paste」
                      return（処理中断）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| attachments.ts | `packages/app/src/components/prompt-input/attachments.ts` | ソース | ペースト処理とファイル形式検証 |
| toast.tsx | `packages/ui/src/components/toast.tsx` | ソース | showToast関数 |
| en.ts | `packages/app/src/i18n/en.ts` | 設定 | 英語の国際化メッセージ定義 |
| ja.ts | `packages/app/src/i18n/ja.ts` | 設定 | 日本語の国際化メッセージ定義 |
