Skip to content

feat: チーム選択をグローバル化し Cookie で永続化する#262

Merged
coji merged 11 commits intomainfrom
feat/259-global-team-filter
Mar 30, 2026
Merged

feat: チーム選択をグローバル化し Cookie で永続化する#262
coji merged 11 commits intomainfrom
feat/259-global-team-filter

Conversation

@coji
Copy link
Copy Markdown
Owner

@coji coji commented Mar 30, 2026

Summary

  • サイドバーに TeamSwitcher を追加し、チーム選択を全ページで共有
  • selected_team Cookie でチーム選択を永続化(7日間)
  • URL ?team パラメータがある場合はそちらを優先
  • 7 ページの PageHeaderActions から TeamFilter を削除
  • listTeams を layout loader に集約(各ページでの重複呼び出し排除)

Changes

  • New: app/libs/team-cookie.server.ts — サーバーサイド Cookie 読み取り
  • New: app/components/layout/team-switcher.tsx — サイドバー TeamSwitcher コンポーネント
  • Modified: app/routes/$orgSlug/_layout.tsx — layout loader で teams 取得、sidebar に渡す
  • Modified: app/components/layout/app-sidebar.tsx — TeamSwitcher 配置
  • Modified: 7 route loaders — Cookie フォールバック追加、TeamFilter 削除

Test plan

  • pnpm validate が通る
  • サイドバーにチームスイッチャーが表示される
  • チームを選択すると Cookie が設定されページがリロードされる
  • ページ遷移後も選択したチームが維持される
  • "All Teams" を選択すると Cookie がクリアされる
  • URL に ?team=xxx がある場合は Cookie より優先される
  • period/sort 等の他のクエリパラメータが保持される
  • サイドバー折りたたみ時はアイコンのみ表示

Closes #259

Generated with takt (spec-implement-accept piece)

Summary by CodeRabbit

新機能

  • サイドバーにチームスイッチャーを追加しました。チーム選択がクッキーで永続化され、URLパラメータからの指定にも対応しています。

リファクタリング

  • 複数の分析・スループットページを更新し、集中管理されたチームコンテキストを使用するようにしました。各ページの個別チームフィルタロジックを削除しています。

- サイドバーに TeamSwitcher コンポーネントを追加(OrgSwitcher の下に配置)
- team-cookie.server.ts でサーバーサイドの Cookie 読み取りを実装
- 7 ページの loader で Cookie をフォールバックとして使用(URL ?team > Cookie)
- 各ページの PageHeaderActions から TeamFilter を削除
- listTeams を layout loader に集約し、各ページでの重複呼び出しを排除

Closes #259

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

チーム選択をグローバル化し、Cookie で永続化する機能を実装。サイドバーに TeamSwitcher コンポーネントを追加し、ミドルウェアで teamContext を導入。複数の分析・スループット・ワークロードページから TeamFilter を削除し、各ページの team パラメータを URL クエリから teamContext に統一。

Changes

Cohort / File(s) Summary
Team Cookie インフラストラクチャ
app/libs/team-cookie.ts, app/libs/team-cookie.server.ts
Cookie 定数 (TEAM_COOKIE_NAME='selected_team', TEAM_COOKIE_MAX_AGE=2592000) と getSelectedTeam() サーバー関数を追加。Cookie からチーム ID を読み取る。
ミドルウェア & コンテキスト
app/middleware/context.ts, app/middleware/org-member.ts
teamContext React Router コンテキストを新規作成。orgMemberMiddleware を拡張し、URL パラメータと Cookie から selectedTeamId を解決して teamContext に保存。
レイアウト & コンポーネント
app/components/layout/app-sidebar.tsx, app/components/layout/team-switcher.tsx
AppSidebar に teamsselectedTeamId props を追加。新規 TeamSwitcher コンポーネントを実装し、チーム選択変更時に Cookie を更新・Remix revalidation をトリガー。
レイアウトルート
app/routes/$orgSlug/_layout.tsx
ローダーで teamContext から selectedTeamId を取得し listTeams() を呼び出し。AppSidebar に teamsselectedTeamId を渡す。
分析ページ
app/routes/$orgSlug/analysis/feedbacks/_index/index.tsx, app/routes/$orgSlug/analysis/inventory/index.tsx, app/routes/$orgSlug/analysis/reviews/index.tsx
TeamFilter コンポーネント削除。ローダーの listTeams() を削除。URL クエリパラメータの代わりに context.get(teamContext) から team を読み取り。
スループットページ
app/routes/$orgSlug/throughput/deployed/index.tsx, app/routes/$orgSlug/throughput/merged/index.tsx, app/routes/$orgSlug/throughput/ongoing/index.tsx
PageHeaderActions と TeamFilter UI 削除。ローダーで team を URL クエリから teamContext に変更。listTeams() 呼び出し削除。
ワークロードページ
app/routes/$orgSlug/workload/index.tsx
PageHeaderActions と TeamFilter 削除。ローダーで request.url から context.get(teamContext) に変更。ローダーから teams 削除。
スクリプト削除
scripts/poc-repo-add-api.ts
GitHub App API テストの PoC スクリプト全削除(90 行)。

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SideBar as Sidebar<br/>TeamSwitcher
    participant Client as Client Page
    participant Middleware as Middleware
    participant Cookie as Cookie Storage
    participant Context as teamContext
    participant Loader as Route Loader

    User->>SideBar: チーム選択変更
    SideBar->>Cookie: Cookie 更新<br/>(selected_team=teamId)
    SideBar->>Client: Remix revalidation<br/>トリガー
    
    Client->>Middleware: リクエスト送信
    Middleware->>Cookie: Cookie から<br/>selectedTeamId 読取
    Middleware->>Context: teamContext に<br/>selectedTeamId 保存
    Middleware->>Loader: コンテキスト付き
    
    Loader->>Context: teamContext から<br/>team パラメータ取得
    Loader->>Client: ローダーデータ返却
    Client->>Client: チームに基づいて<br/>データ再表示
    
    Note over SideBar,Loader: 複数ページ間でチーム<br/>選択が同期される
Loading
sequenceDiagram
    participant User
    participant Browser as ブラウザ
    participant Layout as Layout Route
    participant OrgMember as org-member<br/>Middleware
    participant TeamDB as Teams API
    participant Component as AppSidebar<br/>TeamSwitcher

    User->>Browser: $orgSlug ページへアクセス
    Browser->>OrgMember: リクエスト処理開始
    OrgMember->>Browser: URL ?team パラメータ<br/>チェック
    OrgMember->>Browser: Cookie から<br/>selected_team 読取
    OrgMember->>TeamDB: organization.teams 取得
    OrgMember->>OrgMember: selectedTeamId 決定<br/>(URL > Cookie > null)
    OrgMember->>Browser: teamContext に<br/>保存
    
    Browser->>Layout: ローダー実行
    Layout->>OrgMember: teamContext.get()
    Layout->>TeamDB: listTeams()
    Layout->>Component: teams + selectedTeamId<br/>を props で渡す
    Component->>Browser: SideBar 内に<br/>TeamSwitcher 描画
    Browser->>User: 現在チーム表示
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 Cookie に団子(チーム)を積み重ね、サイドバーに総長の席を据え、
ページをまたいで消えぬ記憶。クエリは隠れ、Context に光る。
~ 七ページの煩雑さ、ひとつの選択で統べられり ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Out of Scope Changes check ❓ Inconclusive All changes align with the linked issue scope. The deletion of the PoC script (poc-repo-add-api.ts) is incidental cleanup not related to the feature and represents a minor out-of-scope change. Clarify whether the removal of scripts/poc-repo-add-api.ts was intentional as part of this feature or should be addressed separately.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main objective: globalizing team selection and persisting it via cookies, which is the core feature of this changeset.
Linked Issues check ✅ Passed The implementation fully addresses all coding requirements from issue #259: team selection is globalized via middleware context, persisted in cookies with URL parameter priority, sidebar TeamSwitcher component added, and TeamFilter removed from 7 pages.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/259-global-team-filter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

coji and others added 10 commits March 30, 2026 20:46
既存の sidebar.tsx と同じ document.cookie パターンのため biome-ignore で抑制。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GitHub App Installation Token の API 検証用スクリプト。
検証完了済みのため削除。lint warning 5件も解消。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DropdownMenu + SidebarMenuButton の組織スイッチャー風から、
Select + UsersIcon のシンプルな見た目に変更。
サイドバー内での視覚的階層を適切にする。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Cookie 名・max-age を共有定数ファイル (team-cookie.ts) に抽出
- team-cookie.server.ts が共有定数を import
- team-switcher.tsx が共有定数を import(stringly-typed 重複を解消)
- orgMemberMiddleware で teamContext をセット
  - URL ?team > Cookie の優先順位で解決
  - teams リストで検証済み(stale cookie で空データになるバグを修正)
- 7 ページの loader から getSelectedTeam(request) を排除
  → context.get(teamContext) に統一

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- split('=')[1] → slice(prefix.length) で = を含む値も正しく取得
- decodeURIComponent を try-catch で囲み malformed 入力で null を返す

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coji coji merged commit 5847127 into main Mar 30, 2026
6 checks passed
@coji coji deleted the feat/259-global-team-filter branch March 30, 2026 12:46
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.

チーム選択をグローバル化し Cookie で永続化する

1 participant