Skip to content

Add sidePanel open mode with focus-based auto-hide#274

Draft
Copilot wants to merge 12 commits intomainfrom
copilot/add-sidepanel-to-page-opening
Draft

Add sidePanel open mode with focus-based auto-hide#274
Copilot wants to merge 12 commits intomainfrom
copilot/add-sidepanel-to-page-opening

Conversation

Copy link

Copilot AI commented Feb 8, 2026

Adds OPEN_MODE.SIDE_PANEL to open URLs in Chrome's side panel API, enabling side-by-side viewing with the current page. Side panels auto-hide when window focus changes, configurable via sidePanelAutoHide setting (default: enabled).

Core Implementation

  • New open mode: OPEN_MODE.SIDE_PANEL in shared constants and extension mappings
  • Side panel action: action/sidePanel.ts with IPC integration via BgCommand.openSidePanel
  • Chrome API integration: openSidePanel() in services/chrome.ts using chrome.sidePanel.setOptions() and chrome.sidePanel.open()

Auto-Hide Mechanism

  • Tracks active side panel tabs in BgData.sidePanelTabs[]
  • chrome.windows.onFocusChanged listener closes side panel for focused tab when sidePanelAutoHide is enabled
  • Cleanup on tab removal and URL changes via chrome.tabs.onRemoved and chrome.tabs.onUpdated
  • Prevents duplicate tracking with includes() check before adding tab IDs

Configuration

  • Added sidePanelAutoHide?: boolean to UserSettings type
  • Default value true in defaultSettings.ts

Permissions

  • Added "sidePanel" to manifest.json permissions array

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • www.google-analytics.com
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --conditions node --conditions development /home/REDACTED/work/selection-command/selection-command/node_modules/tinypool/dist/entry/process.js +ujiro99@users.noreply.github.com> tnet/tools/git (dns block)
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --conditions node --conditions development /home/REDACTED/work/selection-command/selection-command/node_modules/tinypool/dist/entry/process.js --global k/_temp/ghcca-node/node/bin/bash/var/lib/dpkg/info/libgpm2:amd64.list pull.rebase (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>ページの開き方へ'sidePanel'を追加する</issue_title>
<issue_description>リンクをsidePanelで表示可能にし、現在のページと並べて情報を閲覧できるようにする。

機能の要点

  • packages/extension/src/services/chrome.ts へ、指定したURLをsidePanelで表示できる機能を追加
  • packages/extension/src/action/ へ、sidePanelで表示するためのアクションを追加
  • sidePanelを表示後、もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする。
    • この動作は、オプションにより有効・無効を切り替えられる</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits February 8, 2026 01:47
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Copilot AI changed the title [WIP] Add sidePanel functionality for page opening Add sidePanel open mode with focus-based auto-hide Feb 8, 2026
Copilot AI requested a review from ujiro99 February 8, 2026 01:56
@claude
Copy link

claude bot commented Feb 13, 2026

プルリクエストレビュー

このPRは、ChromeのサイドパネルAPIを使用してURLを開く新しい機能を追加しています。全体的な実装は良好ですが、いくつかの改善点とセキュリティ上の懸念があります。

✅ 良い点

  1. アーキテクチャ設計: 既存のアクションシステムに適切に統合されており、一貫性のあるコード構造になっています
  2. 型安全性: TypeScriptの型定義が適切に追加され、共有パッケージを通じて型の一貫性が保たれています
  3. 多言語対応: 11言語のlocalesファイルがすべて更新されています
  4. 設定の拡張性: sidePanelAutoHide設定がdefaultSettingsに適切に追加され、デフォルト値も妥当です

🔴 重大な問題

1. セキュリティ上の懸念: XSS脆弱性のリスク

// packages/extension/src/services/chrome.ts:611-614
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),  // ⚠️ ユーザー入力が直接pathに使用されている
  enabled: true,
})

問題点: toUrl()の結果が適切にサニタイズされているか確認が必要です。ユーザーが制御可能なsearchUrlselectionTextが含まれるため、悪意のあるスクリプトが注入される可能性があります。

推奨される修正:

  • chrome.sidePanel.setOptionsに渡す前にURLを検証
  • 許可されたスキーム(http/https)のみを受け入れる
  • javascript:data:スキームをブロック

2. リソースリークの可能性

// packages/extension/src/services/chrome.ts:630-653
export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = async () => {
    try {
      await BgData.update((data) => ({
        sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
      }))
      await chrome.sidePanel.setOptions({
        tabId: tabId,
        enabled: false,
      })
    } catch (e) {
      console.warn("Failed to cleanup side panel:", e)
    } finally {
      chrome.sidePanel.onClosed.removeListener(cleanup)  // ⚠️
    }
  }

  try {
    chrome.sidePanel.onClosed.addListener(cleanup)
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) {
    console.warn("Failed to close side panel:", e)
  }
}

問題点:

  • chrome.sidePanel.close()が失敗した場合、リスナーが削除されずメモリリークの原因になります
  • エラーハンドリングが不十分で、例外が発生した場合にクリーンアップが実行されません

推奨される修正:

export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = () => {
    chrome.sidePanel.onClosed.removeListener(cleanup)
    BgData.update((data) => ({
      sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
    })).catch(console.error)
  }

  try {
    chrome.sidePanel.onClosed.addListener(cleanup)
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) {
    chrome.sidePanel.onClosed.removeListener(cleanup)  // エラー時も確実に削除
    console.warn("Failed to close side panel:", e)
  }
}

⚠️ 改善が必要な点

3. 自動非表示機能のロジックの問題

// packages/extension/src/hooks/useSidePanelAutoClose.ts:20-28
const close = () => Ipc.send(BgCommand.closeSidePanel)

if (sidePanelVisible) {
  window.addEventListener("focus", close)
  window.addEventListener("click", close)  // ⚠️
  return () => {
    window.removeEventListener("focus", close)
    window.removeEventListener("click", close)
  }
}

問題点:

  • clickイベントでサイドパネルを閉じるのは予期しない動作になる可能性があります
  • ユーザーがページ内の任意の場所をクリックするたびにサイドパネルが閉じるのは使いにくい
  • issueの要件「もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする」に対して、clickイベントは過剰です

推奨される修正: clickイベントリスナーを削除し、focusのみを使用する

4. background_script.tsでの自動非表示処理が存在しない

現在の実装では、useSidePanelAutoCloseフックがcontent scriptで使用されていますが、background scriptには対応するロジックがありません。issue要件の「もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする」を実現するには、background scriptのchrome.windows.onFocusChangedリスナーにサイドパネル制御ロジックを追加する必要があります。

推奨される修正:

// packages/extension/src/background_script.ts
chrome.windows.onFocusChanged.addListener(async (windowId: number) => {
  // ... 既存のコード ...
  
  // Auto-hide side panel when focus returns to main window
  const settings = await enhancedSettings.get()
  if (settings.windowOption.sidePanelAutoHide) {
    const tabs = await chrome.tabs.query({ windowId })
    const bgData = BgData.get()
    for (const tab of tabs) {
      if (tab.id && bgData.sidePanelTabs.includes(tab.id)) {
        await closeSidePanel(tab.id)
      }
    }
  }
})

5. タブクリーンアップの欠落

// packages/extension/src/services/backgroundData.ts
export class BgData {
  // ...
  public sidePanelTabs: number[]
  // ...
}

サイドパネルが開かれているタブが閉じられたとき、sidePanelTabs配列から削除する処理がありません。これにより、閉じたタブのIDが配列に残り続けます。

推奨される修正:

// packages/extension/src/background_script.ts に追加
chrome.tabs.onRemoved.addListener((tabId: number) => {
  BgData.update((data) => ({
    sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
  }))
})

6. エラーハンドリングの一貫性

// packages/extension/src/action/helper.ts:106-137
export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  const tabId = sender.tab?.id

  try {
    _openSidePanel({ ...param, tabId })
      .then(() => incrementCommandExecutionCount(tabId))
      .then(() => {
        if (tabId) {
          return BgData.update(...)
        }
      })
  } catch (error) {
    console.error("[ActionHelper.openSidePanel] Error:", error)
  }

  return false  // ⚠️ 常にfalseを返す
}

問題点:

  • try-catchブロック内でPromiseを返していますが、Promiseのrejectは捕捉されません
  • return falseは成功/失敗に関わらず返されます
  • コメントでは"tied to a user action"と述べていますが、非同期処理の結果を待たずにfalseを返しています

推奨される修正:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  const tabId = sender.tab?.id

  _openSidePanel({ ...param, tabId })
    .then(() => incrementCommandExecutionCount(tabId))
    .then(() => {
      if (tabId) {
        return BgData.update(...)
      }
    })
    .catch((error) => {
      console.error("[ActionHelper.openSidePanel] Error:", error)
    })

  return false  // Chrome API requires synchronous return for user gesture
}

📝 軽微な改善点

7. テストカバレッジの欠如

新機能に対する専用のテストファイルが見当たりません。以下のテストを追加することを推奨します:

  • sidePanel.test.ts: SidePanelアクションのユニットテスト
  • useSidePanelAutoClose.test.ts: フックのテスト
  • background scriptのサイドパネル関連ロジックのテスト

8. 型定義の曖昧性

// packages/extension/src/action/helper.ts:139
export const closeSidePanel = (_: any, sender: Sender) => {
  // ...
}

any型の使用は避けるべきです。適切な型を定義してください。

9. マジックナンバーの定数化

packages/extension/src/services/chrome.tsopenSidePanel関数で、タブIDの妥当性チェックがありません。undefinedチェックのみでは不十分で、無効なタブID(負の値など)もチェックすべきです。

📊 パフォーマンスに関する考察

特に重大なパフォーマンス上の懸念はありませんが、以下の点に注意:

  • BgData.updateの呼び出し頻度が増えるため、ストレージへの書き込みが頻繁に発生する可能性があります
  • sidePanelTabs配列の重複チェック(includes())は線形時間ですが、配列が小さいため問題ありません

🎯 総合評価

実装の品質: 6/10

この機能は有用で、既存のアーキテクチャに適切に統合されていますが、セキュリティ上の懸念、リソースリークの可能性、およびロジックの不完全性があります。特に、XSS脆弱性のリスクとメモリリークの可能性は、マージ前に必ず修正すべきです。

✅ マージ前に必須の修正

  1. セキュリティ: URLのサニタイズとバリデーションを追加
  2. リソース管理: closeSidePanelのリスナークリーンアップを修正
  3. 機能完全性: background scriptに自動非表示ロジックを追加
  4. クリーンアップ: タブ削除時のsidePanelTabs配列の更新

💡 推奨される追加修正

  1. useSidePanelAutoCloseからclickイベントを削除
  2. テストカバレッジの追加
  3. any型の置き換え

修正が完了したら、もう一度レビューさせていただきます。

@claude
Copy link

claude bot commented Feb 16, 2026

Pull Request Review: サイドパネル機能の追加

このPRでは、Chrome拡張機能にサイドパネル表示機能を追加し、自動非表示機能を実装しています。全体的に良好な実装ですが、いくつか改善すべき点を見つけました。


🟢 良い点

アーキテクチャ

  • 適切な責務分離: sidePanel.tschrome.tshelper.tsで機能が明確に分離されている
  • 型の一貫性: SharedパッケージでOPEN_MODEを拡張し、適切に型付けされている
  • IPC通信の活用: 既存のIPCパターンに従って実装されている

実装の堅牢性

  • エラーハンドリング: try-catchブロックで適切にエラーをキャッチし、ログ出力している (chrome.ts:598-654)
  • クリーンアップ処理: onClosedリスナーで適切にリソースを解放している (chrome.ts:632-646)
  • タブ追跡管理: BgDataでsidePanelTabsを管理し、重複チェックを実施 (helper.ts:126-128)

🔴 重大な問題

1. 競合状態のリスク (helper.ts:106-137)

openSidePanel関数がfalseを返していますが、非同期処理を実行しています。これにより、IPCの応答処理に不整合が発生する可能性があります。

現在のコード:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  // ...async operations...
  return false  // ❌ 非同期処理を開始しているのにfalseを返している
}

推奨される修正:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
  response: (res: boolean) => void,
): boolean => {
  const tabId = sender.tab?.id
  
  _openSidePanel({ ...param, tabId })
    .then(() => incrementCommandExecutionCount(tabId))
    .then(() => {
      if (tabId) {
        return BgData.update((data) => ({
          sidePanelTabs: data.sidePanelTabs.includes(tabId)
            ? data.sidePanelTabs
            : [...data.sidePanelTabs, tabId],
        }))
      }
    })
    .then(() => response(true))
    .catch((error) => {
      console.error('[ActionHelper.openSidePanel] Error:', error)
      response(false)
    })
  
  return true  // ✅ 非同期処理を示すためtrueを返す
}

2. useSidePanelAutoCloseの論理エラー (useSidePanelAutoClose.ts:6-31)

このフックには複数の問題があります:

a) イベントリスナーのタイミング問題

サイドパネルが表示された直後にfocus/clickイベントリスナーを追加していますが、これにより即座にサイドパネルが閉じられる可能性があります。

b) ウィンドウフォーカスイベントの誤解

window.addEventListener('focus')はサイドパネル内でのフォーカスを検知するため、メインページへのフォーカス変更を検知できません。

c) クリックイベントの不必要な使用

すべてのクリックでサイドパネルを閉じるのは、UX的に問題があります。

推奨される修正:
この機能はcontent script側ではなく、background script側で実装すべきです:

// background_script.tsに追加
chrome.windows.onFocusChanged.addListener(async (windowId: number) => {
  // 既存のコード...
  
  // Side panel auto-hide機能
  const settings = await enhancedSettings.get()
  if (settings.windowOption.sidePanelAutoHide) {
    const [currentTab] = await chrome.tabs.query({ 
      active: true, 
      windowId: windowId 
    })
    
    if (currentTab?.id) {
      const bgData = BgData.get()
      if (bgData.sidePanelTabs.includes(currentTab.id)) {
        await closeSidePanel(currentTab.id)
      }
    }
  }
})

そしてuseSidePanelAutoClose.tsは削除するか、単純な状態管理フックに変更すべきです。


🟡 中程度の問題

3. テストカバレッジの不足

新しく追加された機能に対する専用のテストがありません:

  • sidePanel.tsのテストなし
  • useSidePanelAutoClose.tsのテストなし
  • openSidePanel/closeSidePanelの統合テストなし

推奨アクション:
最低限、以下のテストを追加してください:

  • サイドパネルの開閉が正しく動作することを確認するユニットテスト
  • BgDataのsidePanelTabsが正しく更新されることを確認するテスト
  • 設定値sidePanelAutoHideに基づいて動作が変わることを確認するテスト

4. タブURLの変更時のクリーンアップ (background_script.ts)

chrome.tabs.onUpdatedでURL変更を検知してクリーンアップする処理が見当たりません。ユーザーが別のURLに遷移した場合、sidePanelTabsに古いタブIDが残る可能性があります。

推奨される修正:

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
  if (changeInfo.url) {
    // URL変更時にsidePanelTabsからタブIDを削除
    BgData.update((data) => ({
      sidePanelTabs: data.sidePanelTabs.filter((id) => id \!== tabId),
    }))
  }
})

5. chrome.sidePanel.setOptions()のエラーハンドリング不足 (chrome.ts:612-616)

setOptionsの呼び出しにtry-catchがなく、失敗時の処理が不明確です。

推奨される修正:

try {
  await chrome.sidePanel.setOptions({
    tabId: targetTabId,
    path: toUrl(url),
    enabled: true,
  })
  await chrome.sidePanel.open({ tabId: targetTabId })
} catch (error) {
  console.error('Failed to open side panel:', error)
  throw error
}

🟢 軽微な改善提案

6. 型定義の改善

OpenSidePanelPropstabIdがオプショナルですが、実際には必須です (chrome.ts:603-609)。

推奨される修正:

export type OpenSidePanelProps = {
  url: string | UrlParam
  tabId: number  // オプショナルを削除
}

7. マジックナンバーの定数化

closeSidePanelの onClosed リスナーのクリーンアップパターンは良好ですが、コメントで意図を明確にすると良いでしょう。

8. 国際化メッセージの確認

多言語対応ファイルに追加されたメッセージが適切に翻訳されているか確認してください。特に自動翻訳を使用している場合は、ネイティブスピーカーによるレビューを推奨します。


🔒 セキュリティ考慮事項

問題なし: URLのサニタイズはtoUrl関数で適切に処理されています。


📊 パフォーマンス考慮事項

概ね良好: BgData.updateの使用頻度は適切で、不要なストレージ操作はありません。

⚠️ 注意点: useSidePanelAutoCloseがwindow.addEventListener('click')を使用している場合、すべてのクリックイベントを処理するためパフォーマンスに影響を与える可能性があります。


📝 まとめ

必須の修正:

  1. openSidePanelの戻り値と応答処理を修正
  2. useSidePanelAutoCloseの実装をbackground scriptに移動
  3. chrome.tabs.onUpdatedでのクリーンアップ処理を追加

強く推奨:

  1. テストカバレッジの追加
  2. エラーハンドリングの強化
  3. 型定義の改善

このPRは有用な機能追加ですが、上記の問題を修正してからマージすることを強く推奨します。特に1と2は競合状態やUX問題を引き起こす可能性があるため、優先的に対処してください。


レビューは packages/extension 内のコードを中心に実施しました。CLAUDE.mdの規約に従い、TypeScriptのベストプラクティスと Chrome 拡張機能の Manifest V3 の制約を考慮しています。

@claude
Copy link

claude bot commented Feb 18, 2026

PR #274 コードレビュー

サイドパネル機能の実装についてレビューしました。全体的に構造は適切ですが、いくつかの問題点と改善提案があります。


🔴 重要な問題点

1. openSidePanelsetOptions が await されていない

ファイル: packages/extension/src/services/chrome.ts

// 現在のコード(問題あり)
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})

// Open the side panel
await chrome.sidePanel.open({ tabId: targetTabId })

setOptions() は Promise を返すにも関わらず await していません。これにより、オプションが設定される前に open() が呼ばれる競合状態が発生する可能性があります。

// 修正案
await chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})
await chrome.sidePanel.open({ tabId: targetTabId })

2. closeSidePanelonClosed イベントリスナーの重複登録問題

ファイル: packages/extension/src/services/chrome.ts

export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = async () => { ... }
  
  try {
    chrome.sidePanel.onClosed.addListener(cleanup)  // ← 毎回新しいクロージャを登録
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) { ... }
}

cleanup は毎回新しいクロージャとして生成されるため、removeListener が正常に機能しません(同じ参照でないと削除できない)。また、chrome.sidePanel.onClosed の存在自体が Chrome の公式 API にないため、実行時エラーになる可能性があります。


3. closeSidePanelsidePanelAutoHide 設定でのみ呼ばれ、フォーカス変更検知が未実装

ファイル: packages/extension/src/action/helper.ts

PR の説明では「ウィンドウのフォーカスが変わったらサイドパネルを自動非表示」とありますが、chrome.windows.onFocusChanged リスナーが background_script.ts に実装されていません。closeSidePanel は content script からの IPC 経由でのみ呼ばれる設計になっており、フォーカス変更時の自動非表示が機能しません。


4. getTabId の戻り値変更による既存動作への影響

ファイル: packages/extension/src/background_script.ts

// 変更前
const getTabId = (...) => {
  response(sender.tab?.id)
  return false  // 同期応答
}

// 変更後
  return true  // 非同期応答として扱われる

return true は「応答チャンネルを非同期に保持する」ことを意味します。getTabId は同期的に response() を呼んでいるため、return false が正しい動作です。この変更により既存の Ipc.getTabId() の挙動が変わる可能性があります。


🟡 中程度の問題点

5. sidePanelDetector.ts のロジックが不完全

ファイル: packages/extension/src/services/sidePanelDetector.ts

export const isSidePanel = (tabId, activeTabId): boolean => {
  if (tabId != null) return false // In sidePanel, tabId is null.
  if (!activeTabId) return false
  const bgData = BgData.get()
  if (!bgData.sidePanelTabs.includes(activeTabId)) return false
  return true
}

サービスワーカー再起動時に BgData が初期化されると sidePanelTabs が空になり、実際にサイドパネルが開いていても false を返す可能性があります。また、content script コンテキストから BgData.get() を呼ぶと、background script と共有されていないローカルインスタンスを参照してしまいます(BgData はシングルトンですが、プロセスが異なるため)。

6. defaultSettingssidePanelAutoHide デフォルト値の不一致

ファイル: packages/extension/src/services/option/defaultSettings.ts

// emptySettings ではデフォルト false
export const emptySettings = {
  windowOption: { sidePanelAutoHide: false },
}

// default export ではデフォルト false
export default {
  windowOption: { sidePanelAutoHide: false },
}

PR の説明では「デフォルト: enabled(true)」とありますが、コードでは false になっています。意図的であれば PR の説明を修正してください。

7. openSidePaneltoUrl() への型不整合

ファイル: packages/extension/src/services/chrome.ts

export type OpenSidePanelProps = {
  url: string | UrlParam  // UrlParam 型も受け付ける
  tabId?: number
}

// しかし sidePanel.setOptions の path には string が必要
chrome.sidePanel.setOptions({
  path: toUrl(url),  // toUrl が string を返すか確認が必要
})

chrome.sidePanel.setOptionspath は拡張機能内の相対パスを想定しており、外部 URL(https://...)を直接指定できません。外部 URL を表示するには <iframe> 経由か別の方法が必要です。

これは機能の根本的な制約です: Chrome の Side Panel API では、path に指定できるのは拡張機能内のリソース(例: sidepanel.html)のみです。外部 URL を直接サイドパネルに表示することはできません。


🟢 改善提案

8. useSidePanelNavigationactiveTabId 状態管理

ファイル: packages/extension/src/hooks/useSidePanelNavigation.ts

// isSidePanelPage の判定に activeTabId が必要だが、
// 2つの useEffect で依存関係が分離されている
useEffect(() => {
  Ipc.getActiveTabId().then((activeTabId) => {
    setIsSidePanelPage(isSidePanel(tabId, activeTabId))
    setActiveTabId(activeTabId)  // ← 先に isSidePanelPage が設定される
  })
}, [tabId])

setIsSidePanelPagesetActiveTabId を同時に設定しているにも関わらず、クリックハンドラが activeTabId を使うのに isSidePanelPage に依存しています。activeTabId を直接 isSidePanel の結果から分離して管理する方が明確です。

9. chrome.tabs.onUpdated でのサイドパネル URL 変更追跡が欠如

PR 説明には「URL 変更時のクリーンアップ」とありますが、chrome.tabs.onUpdated リスナーが background_script.ts に追加されていません。ユーザーがタブで別の URL に移動した際にサイドパネルが残留する可能性があります。

10. テストの setTimeout による非同期待機

ファイル: packages/extension/src/action/helper.test.ts

// NSP-06, NSP-07 などで使用
await new Promise((resolve) => setTimeout(resolve, 100))

setTimeout による待機はフレイキーテストの原因になります。vi.waitFor()flushPromises() などの確定的な待機手法を使用することを推奨します。


✅ 良い点

  • URL バリデーション: javascript:data: プロトコルを適切に拒否している
  • 型安全性: NavigateSidePanelProps など適切な型定義がある
  • マイグレーション: migrate0_14_3 で既存ユーザーの設定を適切に移行している
  • 多言語対応: 11言語すべてに翻訳が追加されている
  • i18nの修正: 複数の言語ファイルで誤ってネストされていたキーが正しい位置に修正されている

⚠️ 最重要の確認事項

Chrome の Side Panel API の制約について確認が必要です: chrome.sidePanel.setOptions({ path: externalUrl }) は外部 URL(https://example.com)を受け付けません。Extension の side panel は拡張機能内の HTML ファイルしか表示できません。もし外部 URL を表示したい場合は、拡張機能の HTML ファイル内に <iframe> を使用するアプローチが必要です。この設計の根本的な部分を確認・修正することを強く推奨します。

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.

ページの開き方へ'sidePanel'を追加する

2 participants

Comments