Skip to content

refactor: unused component cleanup - Must be merged after #3242#3258

Merged
ogzhanolguncu merged 12 commits intomainfrom
unused-component-cleanup
May 29, 2025
Merged

refactor: unused component cleanup - Must be merged after #3242#3258
ogzhanolguncu merged 12 commits intomainfrom
unused-component-cleanup

Conversation

@ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented May 14, 2025

What does this PR do?

This PR removes unused components and refactors some components to use our own ui package components.

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?

Some critical changes

  • Auth sign-in / sign-up input component changes
  • Api Keys settings component changes
  • API create, workspace create component changes
  • Teams invite changes
  • Root key dialog changes

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

  • Refactor

    • Streamlined form handling by replacing custom form components with simplified structures using react-hook-form and unified UI components.
    • Consolidated UI imports, replacing local components with standardized external UI library components for checkboxes, inputs, tooltips, and related elements.
    • Replaced generic tooltips with specialized tooltip components for improved clarity and consistency.
  • Removals

    • Removed multiple UI components including custom form wrappers, inputs, checkboxes, tooltips, pagination, progress bars, skeleton loaders, accordion, alert dialogs, back button, and button groups.
    • Deleted dashboard components such as banners, loading states, API key tables, create key button, and feedback component refactor.
  • Style

    • Updated form layouts and spacing for a cleaner, more consistent user interface.
  • Bug Fixes

    • Enhanced form validation and error display for improved reliability and user experience.

@changeset-bot
Copy link

changeset-bot bot commented May 14, 2025

⚠️ No Changeset found

Latest commit: b5a9df5

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 May 14, 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 May 29, 2025 3:03pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
engineering ⬜️ Ignored (Inspect) Visit Preview May 29, 2025 3:03pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 14, 2025

📝 Walkthrough
## Walkthrough

This change refactors form components and UI primitives across the dashboard app to remove custom local UI implementations (such as form wrappers, input fields, checkboxes, tooltips, and related utilities) in favor of standardized components from the `@unkey/ui` library. Numerous local UI component files are deleted, and affected feature components are updated to use the new imports and simplified form integration patterns.

## Changes

| Files/Paths                                                                                       | Change Summary |
|-------------------------------------------------------------------------------------------------|----------------|
| `apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx`,<br>`.../default-prefix.tsx`,<br>`.../update-api-name.tsx`,<br>`.../update-ip-whitelist.tsx`,<br>`.../settings/root-keys/[keyId]/update-root-key-name.tsx`,<br>`.../settings/team/invite.tsx`,<br>`.../new/create-api.tsx`,<br>`.../new/create-workspace.tsx` | Refactored form handling to remove custom form components and use `react-hook-form`'s `Controller` and `FormInput` from `@unkey/ui`, simplifying form structure and validation logic. |
| `apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/rbac/permissions.tsx`,<br>`.../authorization/roles/[roleId]/permission-toggle.tsx`,<br>`.../settings/root-keys/[keyId]/permissions/permission_toggle.tsx`,<br>`.../settings/root-keys/new/client.tsx` | Changed `Checkbox` import from local UI to `@unkey/ui`. |
| `apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx`,<br>`.../components/dashboard/root-key-table/index.tsx`,<br>`.../components/logs/details/request-response-details.tsx`,<br>`.../components/navigation/sidebar/team-switcher.tsx` | Replaced generic tooltip components with domain-specific `RatelimitOverviewTooltip` for permission and workspace tooltips. |
| `apps/dashboard/app/(app)/settings/vercel/client.tsx`,<br>`.../components/ui/sidebar.tsx`,<br>`.../components/logs/llm-search/components/search-example-tooltip.tsx` | Changed `Tooltip`, `Input`, and `Select` imports to `@unkey/ui`. |
| `apps/dashboard/app/auth/sign-in/email-signin.tsx`,<br>`.../sign-up/email-signup.tsx` | Replaced local `Input` with `FormInput` from `@unkey/ui` and adjusted form layout and styling. |
| `apps/dashboard/app/layout.tsx` | Removed `TooltipProvider` wrapper from layout. |
| `apps/dashboard/components/logs/checkbox/filter-checkbox.tsx`,<br>`.../filter-operator-input/index.tsx` | Changed `Checkbox` and `Textarea` imports to `@unkey/ui` and simplified textarea styling. |
| `apps/dashboard/components/dashboard/feedback-component.tsx` | Refactored feedback dialog to use `DialogContainer`, simplified form structure, and improved error handling. |
| `apps/dashboard/components/dashboard/api-key-table/index.tsx`,<br>`.../table.tsx`,<br>`.../create-key-button.tsx`,<br>`.../root-key-table/table.tsx`,<br>`.../ui/accordion.tsx`,<br>`.../ui/alert-dialog.tsx`,<br>`.../ui/back-button.tsx`,<br>`.../ui/checkbox.tsx`,<br>`.../ui/form.tsx`,<br>`.../ui/group-button.tsx`,<br>`.../ui/input.tsx`,<br>`.../ui/pagination.tsx`,<br>`.../ui/progress.tsx`,<br>`.../ui/skeleton.tsx`,<br>`.../ui/textarea.tsx`,<br>`.../ui/tooltip.tsx`,<br>`.../components/banner.tsx`,<br>`.../app/(app)/ratelimits/loading.tsx`,<br>`.../app/(app)/settings/loading.tsx` | Deleted local UI component implementations and feature components that are now replaced by standardized components from `@unkey/ui` or no longer needed. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant User
  participant FormComponent
  participant react-hook-form
  participant @unkey/ui

  User->>FormComponent: Interact with form (input/change/submit)
  FormComponent->>@unkey/ui: Render FormInput, Checkbox, etc.
  FormComponent->>react-hook-form: Register fields via Controller
  react-hook-form-->>FormComponent: Provide field state (isDirty, isValid, errors)
  User->>FormComponent: Submit form
  FormComponent->>react-hook-form: handleSubmit(onSubmit)
  react-hook-form->>FormComponent: Validate and pass data
  FormComponent->>API: (if applicable) Submit data

Possibly related PRs

  • unkeyed/unkey#2146: Introduces the DefaultBytes component and related form logic, which is refactored in this PR.
  • unkeyed/unkey#2910: Introduces the FormInput component from @unkey/ui, which is now widely adopted in this PR.
  • unkeyed/unkey#3280: Focuses on fixing default key settings by adding revalidation and default overrides; related to default bytes and prefix but addresses different aspects.

Suggested labels

Improvement

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark

</details>

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9db6964d7cfe56fca9cd8567f104167e2921411b and b5a9df50bc7eeef87c6e52c492fd29e5007199f2.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx` (3 hunks)
* `apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx
* apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (6)</summary>

* GitHub Check: Test Packages / Test ./apps/dashboard
* GitHub Check: Test Packages / Test ./packages/nextjs
* GitHub Check: Test Packages / Test ./internal/clickhouse
* GitHub Check: Test Packages / Test ./packages/cache
* GitHub Check: autofix
* GitHub Check: Analyze (javascript-typescript)

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=unkeyed/unkey&utm_content=3258):

- 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](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@github-actions
Copy link
Contributor

github-actions bot commented May 14, 2025

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

@vercel vercel bot temporarily deployed to Preview – engineering May 14, 2025 13:25 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard May 14, 2025 13:26 Inactive
@ogzhanolguncu ogzhanolguncu changed the title refactor: unused component cleanup refactor: unused component cleanup - Must be merged after #3242 May 14, 2025
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

🔭 Outside diff range comments (1)
apps/dashboard/components/dashboard/feedback-component.tsx (1)

52-61: 🛠️ Refactor suggestion

Reset the form after a successful submission

The dialog closes, but the component stays mounted, meaning the next time the user opens it the previous input is still there.
Calling reset() restores the default values and avoids this confusion.

-    onSuccess: () => {
-      setOpen(false);
+    onSuccess: () => {
+      reset();          // clear the form
+      setOpen(false);
🧹 Nitpick comments (5)
apps/dashboard/app/new/create-workspace.tsx (1)

113-143: Form implementation is successfully simplified

The form implementation has been properly streamlined by:

  1. Using the Controller pattern with FormInput
  2. Leveraging react-hook-form's handleSubmit
  3. Properly managing button states with form validation

Consider adding a placeholder to the FormInput for better user guidance.

 <FormInput
   {...field}
   error={errors.name?.message}
   description="What should your workspace be called?"
+  placeholder="My Awesome Workspace"
 />
apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx (1)

65-105: Form layout simplified correctly

The refactored form layout with SettingCard and Controller pattern is cleaner. The number input handling is properly implemented with regex pattern to only allow digits.

One edge case to consider: the current onChange handler may convert empty input to 0, which could be unexpected for users.

 <FormInput
   {...field}
   className="w-[16.5rem]"
   autoComplete="off"
   type="text"
-  onChange={(e) => field.onChange(Number(e.target.value.replace(/\D/g, "")))}
+  onChange={(e) => {
+    const value = e.target.value.replace(/\D/g, "");
+    field.onChange(value ? Number(value) : undefined);
+  }}
+  placeholder="8-255"
 />
apps/dashboard/app/(app)/settings/team/invite.tsx (1)

112-144: Form implementation properly modernized

The form is correctly refactored using both direct register for simple fields and Controller for complex inputs. Error handling is properly implemented.

For consistency with the FormInput component, consider adding an error state to the Select component when validation fails.

 <Select onValueChange={field.onChange} value={field.value}>
-  <SelectTrigger className="h-9">
+  <SelectTrigger className={`h-9 ${errors.role ? "border-error-7 focus:border-error-8" : ""}`}>
   <SelectValue placeholder="Select a role" />
 </SelectTrigger>
apps/dashboard/components/dashboard/feedback-component.tsx (2)

63-69: Remove the redundant try/catch block

mutateAsync already triggers the onError callback and returns a rejected promise, so this try/catch only duplicates console output without adding error handling value.

-  const onSubmitForm = async (values: FormValues) => {
-    try {
-      await create.mutateAsync(values);
-    } catch (error) {
-      console.error("Form submission error:", error);
-    }
-  };
+  const onSubmitForm = (values: FormValues) => create.mutateAsync(values);

80-86: Disable the button when the form is invalid

With isValid (see earlier comment) the button can be disabled until all validation passes, preventing an avoidable round-trip.

-            disabled={isSubmitting || create.isLoading}
-            loading={isSubmitting || create.isLoading}
+            disabled={!isValid || isSubmitting || create.isLoading}
+            loading={isSubmitting || create.isLoading}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 320e6f9 and 02de220.

📒 Files selected for processing (44)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx (3 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx (3 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-api-name.tsx (4 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx (5 hunks)
  • apps/dashboard/app/(app)/authorization/roles/[roleId]/permission-toggle.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx (2 hunks)
  • apps/dashboard/app/(app)/ratelimits/loading.tsx (0 hunks)
  • apps/dashboard/app/(app)/settings/loading.tsx (0 hunks)
  • apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/permission_toggle.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/root-keys/[keyId]/update-root-key-name.tsx (3 hunks)
  • apps/dashboard/app/(app)/settings/root-keys/new/client.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/team/invite.tsx (3 hunks)
  • apps/dashboard/app/(app)/settings/vercel/client.tsx (1 hunks)
  • apps/dashboard/app/auth/sign-in/email-signin.tsx (2 hunks)
  • apps/dashboard/app/auth/sign-up/email-signup.tsx (2 hunks)
  • apps/dashboard/app/layout.tsx (1 hunks)
  • apps/dashboard/app/new/create-api.tsx (4 hunks)
  • apps/dashboard/app/new/create-workspace.tsx (2 hunks)
  • apps/dashboard/components/banner.tsx (0 hunks)
  • apps/dashboard/components/dashboard/api-key-table/index.tsx (0 hunks)
  • apps/dashboard/components/dashboard/api-key-table/table.tsx (0 hunks)
  • apps/dashboard/components/dashboard/create-key-button.tsx (0 hunks)
  • apps/dashboard/components/dashboard/feedback-component.tsx (3 hunks)
  • apps/dashboard/components/dashboard/root-key-table/index.tsx (3 hunks)
  • apps/dashboard/components/dashboard/root-key-table/table.tsx (1 hunks)
  • apps/dashboard/components/logs/checkbox/filter-checkbox.tsx (1 hunks)
  • apps/dashboard/components/logs/details/request-response-details.tsx (2 hunks)
  • apps/dashboard/components/logs/filter-operator-input/index.tsx (2 hunks)
  • apps/dashboard/components/logs/llm-search/components/search-example-tooltip.tsx (1 hunks)
  • apps/dashboard/components/navigation/sidebar/team-switcher.tsx (2 hunks)
  • apps/dashboard/components/ui/accordion.tsx (0 hunks)
  • apps/dashboard/components/ui/alert-dialog.tsx (0 hunks)
  • apps/dashboard/components/ui/back-button.tsx (0 hunks)
  • apps/dashboard/components/ui/checkbox.tsx (0 hunks)
  • apps/dashboard/components/ui/form.tsx (0 hunks)
  • apps/dashboard/components/ui/group-button.tsx (0 hunks)
  • apps/dashboard/components/ui/input.tsx (0 hunks)
  • apps/dashboard/components/ui/pagination.tsx (0 hunks)
  • apps/dashboard/components/ui/progress.tsx (0 hunks)
  • apps/dashboard/components/ui/sidebar.tsx (1 hunks)
  • apps/dashboard/components/ui/skeleton.tsx (0 hunks)
  • apps/dashboard/components/ui/textarea.tsx (0 hunks)
  • apps/dashboard/components/ui/tooltip.tsx (0 hunks)
💤 Files with no reviewable changes (18)
  • apps/dashboard/components/ui/back-button.tsx
  • apps/dashboard/components/ui/checkbox.tsx
  • apps/dashboard/components/ui/skeleton.tsx
  • apps/dashboard/components/ui/textarea.tsx
  • apps/dashboard/components/dashboard/api-key-table/table.tsx
  • apps/dashboard/app/(app)/settings/loading.tsx
  • apps/dashboard/components/banner.tsx
  • apps/dashboard/components/ui/tooltip.tsx
  • apps/dashboard/components/dashboard/create-key-button.tsx
  • apps/dashboard/components/ui/alert-dialog.tsx
  • apps/dashboard/components/ui/progress.tsx
  • apps/dashboard/app/(app)/ratelimits/loading.tsx
  • apps/dashboard/components/ui/group-button.tsx
  • apps/dashboard/components/ui/pagination.tsx
  • apps/dashboard/components/ui/accordion.tsx
  • apps/dashboard/components/ui/input.tsx
  • apps/dashboard/components/dashboard/api-key-table/index.tsx
  • apps/dashboard/components/ui/form.tsx
🧰 Additional context used
🧠 Learnings (1)
apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx (1)
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.
🧬 Code Graph Analysis (7)
apps/dashboard/app/layout.tsx (2)
apps/dashboard/components/dashboard/command-menu.tsx (1)
  • CommandMenu (16-49)
apps/dashboard/components/dashboard/feedback-component.tsx (1)
  • Feedback (36-177)
apps/dashboard/components/navigation/sidebar/team-switcher.tsx (1)
apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/components/ratelimit-overview-tooltip.tsx (1)
  • RatelimitOverviewTooltip (10-37)
apps/dashboard/components/logs/details/request-response-details.tsx (1)
apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/components/ratelimit-overview-tooltip.tsx (1)
  • RatelimitOverviewTooltip (10-37)
apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx (3)
apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/components/ratelimit-overview-tooltip.tsx (1)
  • RatelimitOverviewTooltip (10-37)
apps/dashboard/components/dashboard/copy-button.tsx (1)
  • CopyButton (15-52)
apps/dashboard/app/(app)/authorization/roles/[roleId]/permission-toggle.tsx (1)
  • PermissionToggle (15-83)
apps/dashboard/app/auth/sign-in/email-signin.tsx (1)
internal/ui/src/components/form/form-input.tsx (1)
  • FormInput (18-89)
apps/dashboard/app/auth/sign-up/email-signup.tsx (2)
internal/ui/src/components/form/form-input.tsx (1)
  • FormInput (18-89)
apps/dashboard/app/(app)/apis/loading.tsx (1)
  • Loading (5-156)
apps/dashboard/app/(app)/settings/team/invite.tsx (3)
internal/icons/src/icons/plus.tsx (1)
  • Plus (16-52)
apps/dashboard/components/dialog-container/dialog-container.tsx (1)
  • DialogContainer (18-48)
internal/ui/src/components/form/form-input.tsx (1)
  • FormInput (18-89)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: Test Packages / Test ./packages/cache
  • GitHub Check: Test Packages / Test ./packages/nextjs
  • GitHub Check: Test Packages / Test ./packages/hono
  • GitHub Check: Test Packages / Test ./packages/api
  • GitHub Check: Test Packages / Test ./internal/keys
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: Test Packages / Test ./internal/encryption
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (57)
apps/dashboard/app/(app)/authorization/roles/[roleId]/permission-toggle.tsx (1)

5-5:

Details

❓ Verification inconclusive

Standardize Checkbox import from external UI library
Importing Checkbox from @unkey/ui aligns with the broader UI cleanup. Verify that the Checkbox API (props like checked and onClick) matches the previous implementation to avoid regressions.

Run the following to ensure no leftover local imports:


🏁 Script executed:

rg 'from "@/components/ui/checkbox"' -n

Length of output: 41


Standardize external Checkbox import
No remaining local imports of Checkbox detected. Please confirm that the new Checkbox from @unkey/ui preserves the previous API (props such as checked, onClick, etc.) to avoid regressions.

apps/dashboard/components/logs/llm-search/components/search-example-tooltip.tsx (1)

2-2: Replace local Tooltip imports with external library
Swapping in Tooltip, TooltipContent, TooltipProvider, and TooltipTrigger from @unkey/ui standardizes the tooltip primitives. Confirm that these components support the same props (delayDuration, asChild, etc.) and styling behavior as the removed local implementation.

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx (1)

4-4: Migrate Checkbox to external UI library
This replaces the deleted local Checkbox with the one from @unkey/ui. Please verify that it fully supports the checked and onCheckedChange props used below, and that there are no breaking API changes.

apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/permission_toggle.tsx (1)

6-6: Ensure correct event handler for Checkbox
@unkey/ui’s Checkbox may expect an onCheckedChange callback instead of onClick. Please verify the component’s API and update the handler prop to match (e.g., using onCheckedChange={(val) => …}) to ensure toggles work as intended.

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

42-42: Standardize Button and Input imports
Replacing local Input and Button with @unkey/ui components improves consistency. Confirm that the new components’ APIs (especially value, onChange, disabled, and className) align with their previous behavior to prevent regressions in filtering and dialog actions.

apps/dashboard/components/ui/sidebar.tsx (1)

17-17: Good refactoring to use centralized UI components.

The change to import tooltip components from @unkey/ui instead of a local implementation aligns with the PR's objective of cleaning up unused components and standardizing UI imports.

apps/dashboard/components/logs/checkbox/filter-checkbox.tsx (1)

2-2: Appropriate consolidation of UI component imports.

Importing Button and Checkbox from @unkey/ui instead of local implementations supports the codebase cleanup objective while maintaining the same functionality.

apps/dashboard/app/layout.tsx (1)

62-66: Simplified component hierarchy by removing TooltipProvider.

The removal of TooltipProvider wrapper around children, CommandMenu, and Feedback is consistent with the refactoring approach to move away from generic tooltip providers in favor of more specific tooltip implementations imported from @unkey/ui.

apps/dashboard/app/(app)/settings/root-keys/new/client.tsx (1)

7-7: Consolidated UI imports from centralized package.

Replacing separate imports of UI components with a single import from @unkey/ui improves code maintainability and supports the goal of removing unused local component implementations.

apps/dashboard/components/logs/filter-operator-input/index.tsx (2)

2-2: Good move on consolidating UI component imports.

Importing Textarea from @unkey/ui aligns with the overall refactoring effort to standardize UI components.


141-141: Clean simplification of textarea styling.

Simplifying the styling to just h-20 makes the code more maintainable by leveraging the default styles from the @unkey/ui package.

apps/dashboard/app/(app)/settings/vercel/client.tsx (2)

23-33: Good consolidation of UI component imports.

Consolidating imports from @unkey/ui package improves maintainability and consistency across the codebase.


1-4: Verify if this file should be included in cleanup.

This file is marked as "Deprecated with new auth". Consider if it's worth including in the component cleanup effort if it will be removed in the near future.

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

3-3: Good addition of specialized tooltip component.

Adding RatelimitOverviewTooltip import to replace the generic tooltip implementation improves consistency.


24-24: Good consolidation of UI component imports.

Importing Checkbox from @unkey/ui package aligns with the refactoring effort to standardize components.


91-101: Improved tooltip implementation.

Replacing the generic tooltip with RatelimitOverviewTooltip improves UI consistency and simplifies the tooltip configuration through props.

apps/dashboard/components/navigation/sidebar/team-switcher.tsx (2)

2-2: Good addition of specialized tooltip component.

Adding RatelimitOverviewTooltip import to replace the generic tooltip implementation improves consistency.


113-119: Improved tooltip implementation.

Replacing the generic tooltip with the specialized RatelimitOverviewTooltip component improves UI consistency. The minor font size adjustment from text-sm to text-[13px] maintains the intended design.

apps/dashboard/app/auth/sign-in/email-signin.tsx (4)

2-2: Improved component import using shared UI library.

Replacing the local input component with FormInput from @unkey/ui package aligns with the codebase's refactoring goal of centralizing UI components.


32-33: Improved form spacing with consistent grid layout.

Increasing the vertical gaps (gap-16 on form and gap-6 on container) improves the visual hierarchy and readability of the form.


34-46: Enhanced input field with proper labeling and accessibility.

The FormInput implementation adds important accessibility improvements:

  • Proper label association with the input
  • Consistent styling with the design system
  • Better semantics with the fieldset/label structure (from FormInput implementation)

The dark background styling (dark !bg-black) maintains visual consistency with the authentication UI.


48-51: Simplified button styling while maintaining functionality.

The button styling was streamlined by removing the relative positioning while preserving all the interactive states and behavior.

apps/dashboard/components/logs/details/request-response-details.tsx (2)

1-1: Consolidated tooltip import from a specialized component.

Replacing generic tooltip components with the specialized RatelimitOverviewTooltip component aligns with the codebase's refactoring to remove local UI implementations in favor of shared, reusable components.


86-97: Improved tooltip implementation with consistent positioning.

The specialized tooltip implementation:

  • Simplifies the component structure by using asChild to wrap content directly
  • Provides explicit positioning control with side: "bottom", align: "end"
  • Maintains the same functionality while reducing code complexity
  • Creates a more consistent tooltip experience across the application

This change is part of a broader refactoring to remove the generic tooltip components in favor of domain-specific implementations.

apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx (2)

3-3: Consolidated tooltip import from a specialized component.

Replacing generic tooltip components with the specialized RatelimitOverviewTooltip component aligns with the codebase's refactoring to standardize tooltip usage.


91-111: Improved tooltip implementation for permission items.

The specialized tooltip implementation:

  • Simplifies rendering by using content prop to define tooltip content
  • Applies consistent positioning with side: "top", align: "start"
  • Uses asChild to integrate with the existing element structure
  • Maintains the same functionality while reducing nested component complexity

This change fits well with the PR objective of cleaning up unused components by moving toward standardized UI patterns.

apps/dashboard/app/auth/sign-up/email-signup.tsx (5)

8-8: Improved component import using shared UI library.

Replacing local input components with FormInput from @unkey/ui aligns with the refactoring goal of centralizing UI components and removing unused local components.


58-59: Enhanced form layout with improved spacing.

Increasing the gaps between form elements (gap-16 for the form and gap-10 for the container) improves visual hierarchy and readability.


60-83: Improved first and last name field implementation with proper labels.

The name fields now:

  • Include proper labels for accessibility
  • Have consistent styling with dark backgrounds
  • Maintain the same layout in a flex row with appropriate spacing
  • Include the same validation attributes

This improves both the visual consistency and accessibility of the form.


84-97: Enhanced email input with proper labeling and email-specific attributes.

The email field now:

  • Includes a proper label for accessibility
  • Specifies autoComplete="email" for browser autofill support
  • Has consistent styling with the other form fields
  • Properly preserves the email value from URL parameters

These improvements enhance both usability and accessibility.


98-110: Well-implemented conditional rendering in submit button.

The button implementation:

  • Maintains the same loading state behavior
  • Has consistent styling with other authentication buttons
  • Properly handles client-side hydration to prevent UI flicker

The client-side rendering approach correctly handles the loading spinner state.

apps/dashboard/app/(app)/settings/root-keys/[keyId]/update-root-key-name.tsx (3)

3-12: Good cleanup of imports for the form refactoring.

The imports have been appropriately updated to use FormInput from @unkey/ui and Controller from react-hook-form, aligning with the broader pattern of consolidating UI components from the shared library.


31-44: Nice simplification of the form state management.

The direct destructuring of handleSubmit, control, and formState from useForm hook is a cleaner approach than nesting these properties within a form object. This pattern makes the code more readable and maintainable.


62-98: Well-structured form with Controller pattern.

The form structure has been successfully refactored to use React Hook Form's Controller pattern with the FormInput component from @unkey/ui. This approach:

  • Simplifies the form markup
  • Encapsulates input, error, and description handling into a single component
  • Makes the code more maintainable

The Button's loading prop is also properly utilized for the loading state.

apps/dashboard/app/new/create-api.tsx (4)

8-12: Good import cleanup for form components.

The imports have been appropriately updated to use FormInput from @unkey/ui and Controller from react-hook-form, consistent with the project-wide refactoring to consolidate UI components.


26-34: Good form hook refactoring.

The direct destructuring of handleSubmit, control, reset, and formState properties from useForm makes the code cleaner and more maintainable.


81-104: Well-implemented form with Controller pattern.

The form structure has been successfully refactored to use React Hook Form's Controller with the FormInput component. The description is properly handled with JSX elements inside the description prop.


105-116: Good button state management.

The button is correctly using the isValid flag from form state to disable submission when the form is invalid, and the loading prop handles the loading state.

apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx (4)

30-43: Well-structured form hook setup.

The destructuring of form properties directly from useForm is clean and follows modern React patterns. Using isValid, isSubmitting, and isDirty for button state management is a good practice.


64-78: Good use of SettingCard component.

Using the SettingCard component from @unkey/ui creates a consistent UI pattern across the application for settings forms.


79-96: Well-implemented Controller with FormInput.

The Controller pattern is implemented correctly with proper handling of the onBlur event, which only calls field.onBlur() if the value is not empty. This maintains good form validation behavior.

Based on the retrieved learnings, it's good that you kept the hidden input for keyAuthId which works correctly without being registered with React Hook Form.


97-107: Good button state handling.

The button's disabled state properly accounts for form validity, submission state, and whether the form is dirty. The loading state is also handled correctly.

apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-api-name.tsx (5)

7-10: Good import cleanup for UI components.

The imports have been correctly updated to use components from @unkey/ui and react-hook-form, consistent with the project-wide refactoring.


31-45: Well-structured form hook setup.

The destructuring of form properties from useForm is clean and follows modern React patterns. The form configuration with validation options is well-organized.


74-85: Good form structure with hidden inputs.

The form structure with SettingCard is clean and maintains the necessary hidden inputs for apiId and workspaceId.


86-103: Well-implemented onChange handler in Controller.

The custom onChange handler properly prevents updating the field when the input value is empty, which helps maintain form validation integrity.


104-114: Good button state management.

The button's disabled state correctly accounts for form validity, submission state, mutation loading, and form dirtiness. The loading state handles both form submission and mutation loading states.

apps/dashboard/app/new/create-workspace.tsx (2)

9-15: Good job on cleanup and standardization

Using shared UI components from @unkey/ui and simplifying imports aligns with the PR's goal of removing unused components.


21-28: Form state management is improved

Nice refactoring to destructure the React Hook Form properties for cleaner usage in the component.

apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx (2)

5-8: Successfully unified UI component imports

Good replacement of local UI components with the standardized @unkey/ui library.


29-42: Form state handling is improved

Destructuring form state properties and using a cleaner resolver setup improves readability.

apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx (3)

7-11: UI component imports properly updated

Good work consolidating component imports from @unkey/ui.


35-46: Form state management properly refactored

Destructuring form state properties improves code clarity and maintainability.


96-123: Form layout correctly simplified

Form controls are properly implemented with the Controller pattern. The form submission state control using isDirty is good practice.

apps/dashboard/app/(app)/settings/team/invite.tsx (3)

7-20: Import consolidation is well executed

Good replacement of local icon and UI components with standardized imports from @unkey/icons and @unkey/ui libraries.


36-47: Form state successfully consolidated

The form management is properly unified with a single useForm instance and appropriate defaults.


94-110: Dialog interface improved

Good improvement moving the subtitle text into the DialogContainer component and simplifying the footer layout.

@mcstepp mcstepp self-assigned this May 16, 2025
Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

just a few code rabbit suggestions, the big one is about the form validation with trimming whitespace. there's a non-blocking refactor suggestion too.

also not sure what the difference is between @/components and @unkey/ui -- is it just that we don't have everything migrated over to @unkey/ui?

Copy link
Contributor Author

lemme fix them up

@vercel vercel bot temporarily deployed to Preview – engineering May 16, 2025 18:45 Inactive
@ogzhanolguncu
Copy link
Contributor Author

just a few code rabbit suggestions, the big one is about the form validation with trimming whitespace. there's a non-blocking refactor suggestion too.

also not sure what the difference is between @/components and @unkey/ui -- is it just that we don't have everything migrated over to @unkey/ui?

Yes. Not everything should be in the @unkey/ui, but some important elements like select, checkbox, etc... they are still being migrated there. We actually moved most of them, but we never had enough time to do a proper cleanup, so this PR achieves that."

@vercel vercel bot temporarily deployed to Preview – dashboard May 16, 2025 18:46 Inactive
@ogzhanolguncu ogzhanolguncu requested a review from mcstepp May 16, 2025 18:46
Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

👍

needs merge conflict fixes though

Copy link
Contributor Author

.../components/update-ip-whitelist.tsx: I'll allow it then, if its gets rendered as target=_blank like you say

Yup

Copy link
Contributor Author

I’ll fix the conflict 🫡

@ogzhanolguncu ogzhanolguncu enabled auto-merge May 29, 2025 15:00
@mcstepp mcstepp self-requested a review May 29, 2025 15:01
Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

👍

@vercel vercel bot temporarily deployed to Preview – dashboard May 29, 2025 15:03 Inactive
@ogzhanolguncu ogzhanolguncu added this pull request to the merge queue May 29, 2025
Merged via the queue into main with commit 84f8c97 May 29, 2025
31 checks passed
@ogzhanolguncu ogzhanolguncu deleted the unused-component-cleanup branch May 29, 2025 15:05
@coderabbitai coderabbitai bot mentioned this pull request Jun 2, 2025
18 tasks
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