Skip to content

refactor(ui): migrate policy attachments table onto shared DataTable - #33827

Merged
yuneng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_/migrate-simple-table-62e90a
Jul 18, 2026
Merged

refactor(ui): migrate policy attachments table onto shared DataTable#33827
yuneng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_/migrate-simple-table-62e90a

Conversation

@yuneng-berri

Copy link
Copy Markdown
Collaborator

Relevant issues

Related: #25546 (closed as stale); the broken delete control it tried to repair is replaced here by a real button inside the row actions menu

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Verified live against a proxy on localhost:4000 (dev config, DB-backed) and the dashboard dev server, at commit 45f4567. Steps to reproduce the states:

  1. Start the proxy and the dashboard dev server (npm run dev in ui/litellm-dashboard)
  2. Seed data:
curl -X POST "http://localhost:4000/policies" -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" -d '{"policy_name": "pii-baseline", "description": "Baseline PII guardrails", "guardrails_add": ["pii-mask"]}'
for body in '{"policy_name": "pii-baseline", "scope": "*"}' '{"policy_name": "pii-baseline", "teams": ["team-alpha*", "team-beta*", "team-gamma*", "team-delta*"]}' '{"policy_name": "pii-baseline", "keys": ["dev-*", "sk-prod*"], "models": ["anthropic-*", "voyage-*", "gemini-*"]}' '{"policy_name": "pii-baseline", "tags": ["healthcare"]}'; do curl -X POST "http://localhost:4000/policies/attachments" -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" -d "$body"; done
  1. Open http://localhost:3000/policies and click the Attachments tab: rows sort newest first, the ID renders as truncated mono text, Global (*) shows an amber badge, list columns render chips with a +N overflow tooltip, and each row has the blast radius eye plus an actions menu
  2. Open the actions menu on a row: Copy attachment ID, then Delete attachment (admins only) which opens the existing Delete Attachment modal; confirming removes the row
  3. Empty state: delete all attachments (curl -X DELETE "http://localhost:4000/policies/attachments/<id>" -H "Authorization: Bearer sk-1234") and reload
  4. Loading state: in the browser console wrap fetch with a delay for /policies/attachments/list, then delete a row to trigger a refetch; compact skeleton rows render at the same height as data rows

Type

🧹 Refactoring

Changes

Rewrites the Policy Attachments table (Policies page, Attachments tab) from a hand-rolled TanStack + tremor renderer onto the shared DataTable and cell library, matching the sibling PolicyTable that migrated in #33357. The container becomes a thin client-mode DataTable consumer and the column defs move to a new AttachmentTableColumns.tsx; the legacy files are renamed to PascalCase (AttachmentTable.tsx, AttachmentTable.test.tsx) via git mv

Data behavior is preserved: default sort stays created_at descending, the attachment ID renders as plain truncated mono text, Global (*) scope keeps an amber badge, the four list columns (teams, keys, models, tags) keep the show-2-then-+N-overflow-with-tooltip pattern, and delete stays admin-only. Sortable headers are now deliberate (Policy and Created At) instead of every column, per the unified table design

Row actions unify to the shared pattern: a dropdown menu with Copy attachment ID for everyone and a destructive Delete attachment item appended for admins. The tremor Icon delete control (not a real button; the thing #25546 tried to repair before going stale) is gone. The blast radius popover stays as an inline control next to the menu trigger because an antd Popover must stay anchored to a mounted element; a menu item unmounts when the menu closes on select

The parent panel only changes its import path; its loading and refetch semantics are untouched. Tests: the table test is rewritten for the menu pattern (menu-open flow, clipboard assertion via readText, admin gate mutation-checked by forcing it open and confirming the non-admin test fails), the two panel-level delete-flow tests now drive the menu instead of the old icon, and a new test pins the created_at descending default sort. The renamed file's stale entries in eslint-suppressions.json are pruned

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates the Policy Attachments table from a hand-rolled TanStack + Tremor renderer onto the shared DataTable and cell library, matching the sibling PolicyTable migration in #33357. All data behaviour is preserved — default sort (created_at desc), Global * amber badge, show-2-then-+N chip overflow, and admin-gated delete — with the legacy Tremor Icon delete control replaced by a proper dropdown menu.

  • AttachmentTableColumns.tsx (new): column definitions using shared StatusBadge, IdCell, DateCell, and DataTableSortHeader primitives; row actions are a DropdownMenu with Copy (all users) and Delete (admins only); copyToClipboard reuses the established codebase utility that handles success/error feedback internally.
  • AttachmentTable.tsx (new, renamed from attachment_table.tsx): thin DataTable wrapper with a stable DEFAULT_SORTING constant and columns memoized on isAdmin/accessToken/onDeleteClick.
  • Tests (AttachmentTable.test.tsx, index.test.tsx): rewritten to drive the new dropdown-menu interaction via data-testid; cover default sort, admin gate, clipboard copy, and blast-radius visibility; stale heroicons/tremor mock entries removed.

Confidence Score: 5/5

Safe to merge — this is a pure UI refactor with no backend changes, no new API calls, and no altered data flow.

The change is a straightforward component migration: the old hand-rolled table is deleted and replaced by the shared DataTable with identical data behaviour. All interaction patterns (delete flow, clipboard copy, blast-radius popover) are covered by updated tests that verify the correct UI elements and user flows. No logic has been introduced that could cause regressions in the policy attachment delete or display paths.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTableColumns.tsx New column definitions file; uses shared cell primitives and dropdown pattern consistently. copyToClipboard is the established codebase pattern that handles success/failure internally.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.tsx Thin DataTable wrapper with client-side sorting and a stable DEFAULT_SORTING constant; columns are memoized on isAdmin/accessToken/onDeleteClick. Clean.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.test.tsx Tests rewritten for the new dropdown-menu interaction pattern; covers default sort, non-admin gate, clipboard copy, and blast-radius availability. No coverage gaps or weakened assertions visible.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.test.tsx Panel-level delete-flow tests updated from the old TrashIcon button to the new data-testid-driven menu; stale heroicons and tremor Icon mocks removed.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.tsx Single import path change from attachment_table to AttachmentTable; all other logic untouched.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/attachment_table.tsx Deleted — replaced by AttachmentTable.tsx (PascalCase) and AttachmentTableColumns.tsx. Removal is clean.
ui/litellm-dashboard/eslint-suppressions.json Stale suppression entries for the deleted snake_case files removed; no new suppressions added.

Reviews (2): Last reviewed commit: "refactor(ui): pass a specific success me..." | Re-trigger Greptile

@codspeed-hq

codspeed-hq Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_/migrate-simple-table-62e90a (64ca754) with litellm_internal_staging (3ba5266)

Open in CodSpeed

@yuneng-berri

Copy link
Copy Markdown
Collaborator Author

@greptile the copy to clipboard reuses what we already have. this is known pattern. Please review again

@devin-ai-integration

Copy link
Copy Markdown
Contributor

QA: Policy Attachments table migration to shared DataTable

QA'd live against a local proxy + dashboard on this branch. Seeded pii-baseline with 4 attachments (global *, teams, keys+models, tags). All migrated behavior is present, no functional regressions.

Populated table

Mono truncated attachment IDs, pii-baseline policy pill, Global * amber badge, teams/keys/models/tags chips capped at 2 with a +N overflow, default newest-first sort, sortable Policy and Created At headers, inline blast-radius eye and per-row actions menu.

table

+N overflow tooltip

Hovering +2 on the Teams column reveals the hidden values (team-gamma*, team-delta*).

overflow tooltip

Blast-radius popover

Inline eye control still opens the Blast Radius popover with affected keys/teams.

blast radius

Row actions menu

Shared overflow menu shows Copy attachment ID (all users) and admin-only Delete attachment.

actions menu

Copy attachment ID

Copy fires the specific success toast "Attachment ID copied".

copy toast

Delete attachment

Delete opens the existing Delete Attachment modal with attachment info, confirming removes the row and refetches the list ("Attachment deleted successfully", 4 to 3 rows).

delete modal

delete success

Empty state

After deleting all attachments, the table shows the rich empty state "No attachments found" with guidance text.

empty state

Walkthrough

walkthrough

Verified: render, sort default + sortable headers, chip overflow + tooltip, blast-radius popover, copy toast, admin-only delete + modal + refetch, empty state. No regressions found.

@yuneng-berri
yuneng-berri merged commit 377d54e into litellm_internal_staging Jul 18, 2026
77 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_/migrate-simple-table-62e90a branch July 18, 2026 18:37
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.

2 participants