Skip to content

fix: merge issues#3422

Merged
perkinsjr merged 2 commits intomainfrom
fixing-main
Jul 1, 2025
Merged

fix: merge issues#3422
perkinsjr merged 2 commits intomainfrom
fixing-main

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Jul 1, 2025

What does this PR do?

Fixes # (issue)

If there is not an issue for this, please create one first. This is used to tracking purposes and also helps use understand why this PR exists

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Test A
  • Test B

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

  • New Features

    • Introduced a new, reusable table component with sorting, filtering, pagination, column visibility toggling, and multi-row selection.
    • Added the ability to delete selected items directly from the table with confirmation dialogs and real-time feedback.
  • Refactor

    • Updated the source of UI components and improved integration with backend mutations for better consistency.

@changeset-bot
Copy link

changeset-bot bot commented Jul 1, 2025

⚠️ No Changeset found

Latest commit: b5faab2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Jul 1, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 1, 2025 5:07pm
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 1, 2025 5:07pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 1, 2025

📝 Walkthrough

Walkthrough

A generic, reusable DataTable React component was introduced for managing tabular data with advanced features such as sorting, filtering, pagination, and row selection. Additionally, the source of the Badge component import was switched from a local path to an external package, and the mutation hook for deleting root keys was updated to a new TRPC endpoint.

Changes

File(s) Change Summary
apps/dashboard/components/dashboard/root-key-table/index.tsx Changed Badge import from local to @unkey/ui and updated delete mutation hook to trpc.settings.rootKeys.delete.useMutation.
apps/dashboard/components/dashboard/root-key-table/table.tsx Added new exported generic DataTable component with sorting, filtering, pagination, row selection, and integration with TRPC mutation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DataTable
    participant TRPC
    participant Toast
    participant Page

    User->>DataTable: Interacts (sort/filter/select/delete)
    DataTable->>TRPC: Calls delete mutation for selected keys
    TRPC-->>DataTable: Returns success/error
    DataTable->>Toast: Shows success/error notification
    DataTable->>Page: Refreshes page on mutation completion
Loading

Possibly related PRs

  • chore: move badge to ui #3316: Both PRs modify the import source of the Badge component from a local UI path to the external @unkey/ui package, indicating a direct code-level connection.

Suggested reviewers

  • perkinsjr
  • mcstepp
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 1, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca56503 and b5faab2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • apps/dashboard/components/dashboard/root-key-table/index.tsx (2 hunks)
  • apps/dashboard/components/dashboard/root-key-table/table.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3103
File: apps/dashboard/app/(app)/settings/general/page.tsx:36-36
Timestamp: 2025-04-14T13:39:22.635Z
Learning: The Unkey team uses Linear for issue tracking rather than GitHub Issues.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3380
File: apps/dashboard/app/(app)/ratelimits/[namespaceId]/namespace-navbar.tsx:40-66
Timestamp: 2025-06-19T10:39:29.388Z
Learning: tRPC has built-in caching that prevents skeleton flashing during component re-renders and navigation, so concerns about `!data || isLoading` conditions causing loading state flashes are generally not needed.
apps/dashboard/components/dashboard/root-key-table/index.tsx (4)
Learnt from: chronark
PR: unkeyed/unkey#2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In `apps/api/src/routes/v1_keys_updateKey.ts`, the code intentionally handles `externalId` and `ownerId` separately for clarity. The `ownerId` field will be removed in the future, simplifying the code.
Learnt from: chronark
PR: unkeyed/unkey#2146
File: apps/dashboard/app/(app)/apis/[apiId]/settings/default-prefix.tsx:74-75
Timestamp: 2024-10-04T17:27:09.821Z
Learning: In `apps/dashboard/app/(app)/apis/[apiId]/settings/default-prefix.tsx`, the hidden `<input>` elements for `workspaceId` and `keyAuthId` work correctly without being registered with React Hook Form.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3292
File: apps/dashboard/lib/vault.ts:80-97
Timestamp: 2025-06-02T11:08:56.397Z
Learning: The vault.ts file in apps/dashboard/lib/vault.ts is a duplicate of the vault package from the `api` directory and should be kept consistent with that original implementation.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3380
File: apps/dashboard/app/(app)/ratelimits/[namespaceId]/namespace-navbar.tsx:40-66
Timestamp: 2025-06-19T10:39:29.388Z
Learning: tRPC has built-in caching that prevents skeleton flashing during component re-renders and navigation, so concerns about `!data || isLoading` conditions causing loading state flashes are generally not needed.
apps/dashboard/components/dashboard/root-key-table/table.tsx (3)
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/glossary/search.tsx:16-20
Timestamp: 2024-10-23T16:21:47.395Z
Learning: For the `FilterableCommand` component in `apps/www/components/glossary/search.tsx`, refactoring type definitions into an interface is not necessary at this time.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-datetime/index.tsx:0-0
Timestamp: 2025-01-30T20:38:00.058Z
Learning: In the logs dashboard, keyboard shortcuts that toggle UI elements (like popovers) should be implemented in the component that owns the state being toggled, not in the presentational wrapper components. For example, the 'T' shortcut for toggling the datetime filter is implemented in DatetimePopover, not in LogsDateTime.
🧬 Code Graph Analysis (1)
apps/dashboard/components/dashboard/root-key-table/index.tsx (1)
apps/dashboard/lib/trpc/server.ts (1)
  • trpc (7-14)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test ./internal/clickhouse
🔇 Additional comments (4)
apps/dashboard/components/dashboard/root-key-table/index.tsx (2)

22-22: LGTM! UI library consolidation.

Moving to the centralized @unkey/ui package for the Badge component improves consistency across the dashboard.


45-45: TRPC endpoint update verified across codebase

All occurrences of the old trpc.rootKey.delete endpoint have been removed and replaced with trpc.settings.rootKeys.delete. The backend route definition in
apps/dashboard/lib/trpc/routers/settings/root-keys/delete.ts
exists and aligns with the frontend usage.

• Old endpoint usage: none found
• New endpoint usage in:

  • apps/dashboard/components/dashboard/root-key-table/index.tsx
  • apps/dashboard/components/dashboard/root-key-table/table.tsx
  • apps/dashboard/app/(app)/settings/root-keys/.../use-delete-root-key.ts

No further changes required.

apps/dashboard/components/dashboard/root-key-table/table.tsx (2)

50-207: Consider performance optimizations for large datasets.

For better performance with large datasets, consider these optimizations:

  1. Memoize the table instance to prevent unnecessary re-renders
  2. Add virtualization for tables with many rows (similar to LogsTable)
  3. Debounce the filter input

Would you like me to provide an implementation with these performance optimizations?

⛔ Skipped due to learnings
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/glossary/terms-rolodex-desktop.tsx:26-37
Timestamp: 2024-10-23T16:20:19.324Z
Learning: When reviewing React components in this project, avoid suggesting manual memoization with `useMemo` for performance optimizations, as the team prefers to rely on the React compiler to handle such optimizations.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-datetime/index.tsx:0-0
Timestamp: 2025-01-30T20:38:00.058Z
Learning: In the logs dashboard, keyboard shortcuts that toggle UI elements (like popovers) should be implemented in the component that owns the state being toggled, not in the presentational wrapper components. For example, the 'T' shortcut for toggling the datetime filter is implemented in DatetimePopover, not in LogsDateTime.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/lib/trpc/routers/logs/query-distinct-paths.ts:29-36
Timestamp: 2025-01-30T20:46:29.482Z
Learning: The team prefers to implement pagination and other optimizations only when they become necessary, rather than prematurely optimizing. This was demonstrated in the context of unique paths query where a simple LIMIT clause was deemed sufficient until proven otherwise.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/app/(app)/logs/components/log-details/resizable-panel.tsx:37-49
Timestamp: 2024-12-03T14:23:07.189Z
Learning: In `apps/dashboard/app/(app)/logs/components/log-details/resizable-panel.tsx`, the resize handler is already debounced.

97-128: Add keyboard accessibility for bulk actions.

The bulk delete dialog should be keyboard accessible. Consider adding keyboard shortcuts for power users.

               <DialogTrigger asChild>
-                <Button className="min-w-full md:min-w-min ">Revoke selected keys</Button>
+                <Button 
+                  className="min-w-full md:min-w-min"
+                  aria-label={`Revoke ${Object.keys(rowSelection).length} selected keys`}
+                >
+                  Revoke selected keys
+                </Button>
               </DialogTrigger>
⛔ Skipped due to learnings
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-datetime/index.tsx:0-0
Timestamp: 2025-01-30T20:38:00.058Z
Learning: In the logs dashboard, keyboard shortcuts that toggle UI elements (like popovers) should be implemented in the component that owns the state being toggled, not in the presentational wrapper components. For example, the 'T' shortcut for toggling the datetime filter is implemented in DatetimePopover, not in LogsDateTime.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.

Comment on lines +129 to +134
<Input
placeholder="Filter keys"
value={(table.getColumn("start")?.getFilterValue() as string) ?? ""}
onChange={(event) => table.getColumn("start")?.setFilterValue(event.target.value)}
className="max-w-sm md:max-w-2xl"
/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Add proper ARIA labels for better accessibility.

The filter input should have proper labeling for screen readers.

           <Input
             placeholder="Filter keys"
+            aria-label="Filter root keys"
             value={(table.getColumn("start")?.getFilterValue() as string) ?? ""}
             onChange={(event) => table.getColumn("start")?.setFilterValue(event.target.value)}
             className="max-w-sm md:max-w-2xl"
           />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Input
placeholder="Filter keys"
value={(table.getColumn("start")?.getFilterValue() as string) ?? ""}
onChange={(event) => table.getColumn("start")?.setFilterValue(event.target.value)}
className="max-w-sm md:max-w-2xl"
/>
<Input
placeholder="Filter keys"
aria-label="Filter root keys"
value={(table.getColumn("start")?.getFilterValue() as string) ?? ""}
onChange={(event) => table.getColumn("start")?.setFilterValue(event.target.value)}
className="max-w-sm md:max-w-2xl"
/>
🤖 Prompt for AI Agents
In apps/dashboard/components/dashboard/root-key-table/table.tsx around lines 129
to 134, the Input component used for filtering keys lacks proper ARIA labels,
which reduces accessibility for screen reader users. Add an appropriate
aria-label attribute to the Input element that clearly describes its purpose,
such as "Filter keys input," to improve accessibility compliance.

Comment on lines +115 to +119
const keyIds = table
.getSelectedRowModel()
// @ts-ignore
.rows.map((row) => row.original.id as string);
deleteKey.mutate({ keyIds });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove @ts-ignore and fix the type issue properly.

The @ts-ignore comment indicates a TypeScript issue that should be resolved. Based on the context, the row data should be properly typed.

-                      const keyIds = table
-                        .getSelectedRowModel()
-                        // @ts-ignore
-                        .rows.map((row) => row.original.id as string);
+                      const keyIds = table
+                        .getSelectedRowModel()
+                        .rows.map((row) => (row.original as { id: string }).id);

Alternatively, ensure the generic type TData extends a base type with an id property:

interface BaseRowData {
  id: string;
}

export function DataTable<TData extends BaseRowData, TValue>({ data, columns }: DataTableProps<TData, TValue>) {
🤖 Prompt for AI Agents
In apps/dashboard/components/dashboard/root-key-table/table.tsx around lines 115
to 119, remove the @ts-ignore comment and fix the type issue by properly typing
the row data. Ensure that the generic type TData extends a base interface that
includes an id property (e.g., interface BaseRowData { id: string }). Update the
DataTable component's generic constraint to TData extends BaseRowData so that
row.original.id is recognized as a string without type errors.

onError: (err, variables) => {
router.refresh();
console.error(err);
toast.error(`Could not delete key ${JSON.stringify(variables)}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Maintain consistency in toast notifications.

The error toast here uses toast.error(), while in index.tsx it uses toast(). Use consistent toast methods across components.

-      toast.error(`Could not delete key ${JSON.stringify(variables)}`);
+      toast(`Could not delete key ${JSON.stringify(variables)}`);

Or update both files to use the semantic toast.error() method for error cases.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
toast.error(`Could not delete key ${JSON.stringify(variables)}`);
toast(`Could not delete key ${JSON.stringify(variables)}`);
🤖 Prompt for AI Agents
In apps/dashboard/components/dashboard/root-key-table/table.tsx at line 70, the
toast notification for errors uses toast.error(), which is inconsistent with the
toast() method used in index.tsx. To maintain consistency, update the toast call
in this file to use the same method as in index.tsx, or alternatively, update
both files to use toast.error() for error notifications to keep semantic
clarity. Choose one approach and apply it consistently across both files.

@perkinsjr perkinsjr merged commit 334cec4 into main Jul 1, 2025
45 of 63 checks passed
@perkinsjr perkinsjr deleted the fixing-main branch July 1, 2025 17:47
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.

3 participants