Skip to content

feat: workspace settings page#3103

Merged
MichaelUnkey merged 51 commits intomainfrom
workspace-settings
Apr 30, 2025
Merged

feat: workspace settings page#3103
MichaelUnkey merged 51 commits intomainfrom
workspace-settings

Conversation

@MichaelUnkey
Copy link
Collaborator

@MichaelUnkey MichaelUnkey commented Apr 11, 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?

Navigation functions like it should
Looks match the Figma on other settings pages

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 unified WorkspaceNavbar for consistent navigation across all workspace settings pages.
    • Added a CopyWorkspaceId component to easily copy the workspace ID with a single click and receive a confirmation notification.
  • Refactor

    • Replaced legacy navigation and submenu components with the new WorkspaceNavbar on all settings pages.
    • Consolidated workspace ID display and copy functionality into a dedicated component.
    • Updated page layouts for settings sections (General, Team, Billing, Root Keys) for improved consistency and clarity.
    • Streamlined form naming, validation, and button logic in workspace name update.
    • Simplified conditional rendering and removed redundant wrappers in team settings.
    • Removed obsolete root keys navigation component and introduced new navigation with enhanced breadcrumbs and quick navigation popovers.
  • Style

    • Improved layout and alignment of setting cards and buttons for consistent appearance.
    • Adjusted input and button styles for better responsiveness and uniformity across components.
    • Minor updates to breadcrumb navigation for enhanced clarity.
    • Reordered CSS classes for consistent flexbox alignment.
  • Chores

    • Updated imports to use external UI libraries where applicable.
    • Removed unused or redundant components and code for cleaner structure.

@changeset-bot
Copy link

changeset-bot bot commented Apr 11, 2025

⚠️ No Changeset found

Latest commit: 3fa9b00

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 Apr 11, 2025

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

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 7 resolved Apr 30, 2025 11:28am
play ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 30, 2025 11:28am
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 30, 2025 11:28am
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
engineering ⬜️ Ignored (Inspect) Visit Preview Apr 30, 2025 11:28am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 11, 2025

📝 Walkthrough
## Walkthrough

This update introduces a new `WorkspaceNavbar` component to unify and streamline navigation across workspace settings pages. Multiple settings pages—including General, Billing, Team, and Root Keys—are refactored to use this new navigation bar, replacing older navigation components and adjusting page layouts for consistency. New utility components, such as `CopyWorkspaceId` and `RootKeyNav`, are added to enhance usability. Several UI components are updated for styling consistency, and navigation breadcrumbs are improved. The update also standardizes input and button imports across various settings forms and makes minor layout and class name adjustments throughout the dashboard settings UI.

## Changes

| File(s)                                                                                                  | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `apps/dashboard/app/(app)/settings/workspace-navbar.tsx`<br>`apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx`<br>`apps/dashboard/app/(app)/settings/root-keys/root-key-nav.tsx` | Added new components: `WorkspaceNavbar` for unified workspace settings navigation, `CopyWorkspaceId` for copying the workspace ID, and `RootKeyNav` for root key section navigation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `apps/dashboard/app/(app)/settings/general/page.tsx`<br>`apps/dashboard/app/(app)/settings/billing/page.tsx`<br>`apps/dashboard/app/(app)/settings/team/page.tsx`<br>`apps/dashboard/app/(app)/settings/root-keys/page.tsx` | Refactored to use `WorkspaceNavbar`, replacing previous navigation components. Adjusted layout and removed old navigation/submenu components.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `apps/dashboard/app/(app)/settings/billing/client.tsx`<br>`apps/dashboard/app/(app)/settings/billing/components/shell.tsx`<br>`apps/dashboard/app/(app)/settings/billing/components/usage.tsx` | Updated layout to include `WorkspaceNavbar`, passed `workspace` prop to `Shell`, reordered and standardized class names, and adjusted component structure for consistency.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx`                                    | Refactored form schema and UI: renamed `name` to `workspaceName`, updated form control and button logic, replaced `Card` with `SettingCard`, and improved validation handling.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `apps/dashboard/components/navigation/sidebar/workspace-navigations.tsx`                                 | Added "General" as a submenu item under "Settings" in the workspace sidebar navigation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `apps/dashboard/app/(app)/settings/root-keys/navigation.tsx`                                             | Removed the old navigation component for root keys settings page.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `apps/dashboard/app/(app)/settings/root-keys/new/navigation.tsx`<br>`apps/dashboard/app/(app)/settings/root-keys/new/page.tsx` | Added new breadcrumb navigation for the "New Root Key" page and updated import paths accordingly.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `apps/dashboard/app/(app)/settings/root-keys/[keyId]/navigation.tsx`                                     | Added "Settings" as the first breadcrumb link for key details navigation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `apps/dashboard/app/(app)/ratelimits/[namespaceId]/settings/components/settings-client.tsx`              | Adjusted layout and styling of setting cards and buttons, including adding a bottom border and refining width classes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `apps/dashboard/app/(app)/apis/[apiId]/settings/components/copy-api-id.tsx`                             | Adjusted input width on large screens from 320px to 315px and consolidated imports.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx`<br>`.../default-prefix.tsx`<br>`.../delete-api.tsx`<br>`.../delete-protection.tsx`<br>`.../update-api-name.tsx`<br>`.../update-ip-whitelist.tsx` | Standardized import sources for `Input`/`Textarea` components to use `@unkey/ui`, updated button and input class names for layout consistency, and adjusted logic for form validation and button states in the IP whitelist component.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `apps/dashboard/app/(app)/settings/team/client.tsx`                                                      | Simplified the empty state layout by removing unnecessary wrappers and applying margin directly, changing centering approach from flexbox to absolute positioning.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `apps/dashboard/lib/trpc/routers/workspace/changeName.ts`                                                | Enhanced input validation for workspace name by adding a maximum length of 50 characters alongside the existing minimum length.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `apps/dashboard/app/(app)/apis/[apiId]/settings/components/settings-client.tsx`                          | Removed `Separator` imports and elements, adjusted container div classes for simplified layout without separators, and updated padding and spacing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `apps/dashboard/app/(app)/apis/[apiId]/settings/page.tsx`                                               | Removed `PageContent` wrapper around `SettingsClient` component, rendering it directly instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant WorkspaceNavbar
    participant SettingsPage (General/Billing/Team/Root Keys)
    participant CopyWorkspaceId (if applicable)
    participant RootKeyNav (if applicable)

    User->>SettingsPage: Navigates to a settings page
    SettingsPage->>WorkspaceNavbar: Renders WorkspaceNavbar with workspace info and active page
    WorkspaceNavbar-->>User: Displays breadcrumbs and actions
    alt General Settings
        SettingsPage->>CopyWorkspaceId: Renders CopyWorkspaceId with workspaceId
        User->>CopyWorkspaceId: Clicks copy button
        CopyWorkspaceId-->>User: Copies ID to clipboard and shows toast
    end
    alt Root Keys Section
        SettingsPage->>RootKeyNav: Renders RootKeyNav with active page
        RootKeyNav-->>User: Displays root key navigation and actions
    end

Possibly related PRs

Suggested labels

Feature, Dashboard

Suggested reviewers

  • perkinsjr
  • ogzhanolguncu
  • 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 d67c679ae193de2aa5ab57df6a703dfb172cf757 and 127dd7c14b42f635d7d6404541bcbea9fc617d67.

</details>

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

* `apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx` (2 hunks)

</details>

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

* apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx

</details>

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

* GitHub Check: Test Go API Local / Test (Shard 7/8)
* GitHub Check: Test Go API Local / Test (Shard 8/8)
* GitHub Check: Test Go API Local / Test (Shard 6/8)
* GitHub Check: Test Go API Local / Test (Shard 5/8)
* GitHub Check: Test Go API Local / Test (Shard 3/8)
* GitHub Check: Test Go API Local / Test (Shard 2/8)
* GitHub Check: Test Go API Local / Test (Shard 4/8)
* GitHub Check: Test Go API Local / Test (Shard 1/8)
* GitHub Check: Build / Build
* GitHub Check: Test API / API Test Local
* GitHub Check: Test Packages / Test ./internal/clickhouse
* 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=3103):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `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 generate unit testing code for this file.`
  -	`@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 generate unit testing code.`
  - `@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.`

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 Apr 11, 2025

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

@vercel vercel bot temporarily deployed to Preview – play April 11, 2025 17:59 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 11, 2025 18:01 Inactive
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: 1

🧹 Nitpick comments (2)
apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx (1)

32-37: Consider adding error handling for clipboard operations

While the current implementation works in modern browsers, clipboard operations can sometimes fail due to permissions or in certain environments.

 <button
   type="button"
   onClick={() => {
-    navigator.clipboard.writeText(workspaceId);
-    toast.success("Copied to clipboard", {
-      description: workspaceId,
-    });
+    navigator.clipboard.writeText(workspaceId)
+      .then(() => {
+        toast.success("Copied to clipboard", {
+          description: workspaceId,
+        });
+      })
+      .catch(() => {
+        toast.error("Failed to copy to clipboard");
+      });
   }}
 >
apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (1)

90-94: Remove unused onBlur handler

The onBlur event handler doesn't perform any meaningful action - it returns early if the value is empty but doesn't define any action for non-empty values.

-                    onBlur={(e) => {
-                      if (e.target.value === "") {
-                        return;
-                      }
-                    }}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 36becb3 and a5d3dfa.

📒 Files selected for processing (10)
  • apps/dashboard/app/(app)/settings/billing/client.tsx (9 hunks)
  • apps/dashboard/app/(app)/settings/billing/components/shell.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/billing/page.tsx (4 hunks)
  • apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/general/page.tsx (2 hunks)
  • apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (4 hunks)
  • apps/dashboard/app/(app)/settings/root-keys/page.tsx (2 hunks)
  • apps/dashboard/app/(app)/settings/team/page.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/workspace-navbar.tsx (1 hunks)
  • apps/dashboard/components/settings-card.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
apps/dashboard/app/(app)/settings/root-keys/page.tsx (3)
apps/dashboard/app/(app)/settings/workspace-navbar.tsx (1)
  • WorkspaceNavbar (32-79)
apps/dashboard/components/page-content.tsx (1)
  • PageContent (3-5)
apps/dashboard/components/dashboard/page-header.tsx (1)
  • PageHeader (18-50)
apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx (2)
apps/dashboard/components/settings-card.tsx (1)
  • SettingCard (12-49)
internal/icons/src/icons/clone.tsx (1)
  • Clone (15-50)
apps/dashboard/app/(app)/settings/billing/client.tsx (1)
apps/dashboard/app/(app)/settings/billing/components/shell.tsx (1)
  • Shell (7-26)
apps/dashboard/app/(app)/settings/team/page.tsx (2)
apps/dashboard/app/(app)/settings/workspace-navbar.tsx (1)
  • WorkspaceNavbar (32-79)
apps/dashboard/app/(app)/settings/team/client.tsx (1)
  • TeamPageClient (22-98)
apps/dashboard/app/(app)/settings/billing/components/shell.tsx (2)
apps/dashboard/app/(app)/settings/workspace-navbar.tsx (1)
  • WorkspaceNavbar (32-79)
apps/dashboard/components/page-content.tsx (1)
  • PageContent (3-5)
apps/dashboard/app/(app)/settings/general/page.tsx (4)
apps/dashboard/app/(app)/settings/workspace-navbar.tsx (1)
  • WorkspaceNavbar (32-79)
apps/dashboard/components/page-content.tsx (1)
  • PageContent (3-5)
apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (1)
  • UpdateWorkspaceName (28-118)
apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx (1)
  • CopyWorkspaceId (8-45)
⏰ Context from checks skipped due to timeout of 90000ms (19)
  • GitHub Check: Test Go API Local / Test (Shard 7/8)
  • GitHub Check: Test Go API Local / Test (Shard 4/8)
  • GitHub Check: Test Packages / Test ./apps/dashboard
  • 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 ./internal/clickhouse
  • GitHub Check: Test Packages / Test ./packages/api
  • GitHub Check: Test Packages / Test ./internal/hash
  • GitHub Check: Test Packages / Test ./internal/billing
  • GitHub Check: Test Packages / Test ./internal/keys
  • GitHub Check: Test Packages / Test ./internal/resend
  • GitHub Check: Test Packages / Test ./internal/id
  • GitHub Check: Test Packages / Test ./internal/encryption
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Agent Local / test_agent_local
  • GitHub Check: Build / Build
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (33)
apps/dashboard/components/settings-card.tsx (2)

4-4: Improved component flexibility!

Enhancing the title prop type to accept React nodes in addition to strings provides more flexibility. This change allows for complex content in titles, such as the combination of text and icons or other interactive elements.


43-43: LGTM - Class order change

Reordering the CSS classes from "text-accent-12 font-medium" to "font-medium text-accent-12" maintains the same visual appearance since Tailwind classes don't have order-dependent behavior. This change likely aligns with a team-wide style standard.

apps/dashboard/app/(app)/settings/general/copy-workspace-id.tsx (1)

8-45: Well-structured component implementation

The new CopyWorkspaceId component effectively encapsulates the workspace ID display and copy functionality. It appropriately leverages the enhanced SettingCard component, making good use of React nodes for both title and description to achieve the desired layout.

apps/dashboard/app/(app)/settings/root-keys/page.tsx (2)

35-38: Improved navigation consistency

Replacing the previous navigation component with WorkspaceNavbar enhances consistency across the application's settings pages. The component properly receives the workspace context and active page information.


45-45: LGTM - Class reordering

The reordering of CSS classes from "mb-20 grid grid-cols-1 gap-8 w-full" to "grid w-full grid-cols-1 gap-8 mb-20" maintains the same visual appearance since Tailwind classes don't have order-dependent behavior.

apps/dashboard/app/(app)/settings/billing/client.tsx (3)

86-86: Improved component context with workspace prop

Passing the workspace prop to the Shell component aligns with the application-wide refactoring to provide components with workspace context. This change enables more cohesive navigation and workspace-specific functionality.


117-124: LGTM - Consistent class reordering

The class reorderings throughout this section (and elsewhere in the file) are consistent with the style changes seen in other files. These changes don't affect functionality but help maintain a consistent style convention across the codebase.


236-237: LGTM - Link styling adjustments

The reordering of "text-info-11 underline" to "underline text-info-11" is consistent with the style standards being applied elsewhere in the code.

apps/dashboard/app/(app)/settings/billing/page.tsx (4)

11-11: LGTM: Importing the new WorkspaceNavbar component

The import statement correctly references the new WorkspaceNavbar component from the parent directory.


35-44: UI improvement for the error state

Good enhancement to the error state UI. Now when Stripe is not configured, users still see the consistent workspace navigation rather than just an error message, providing better context and navigation options.


77-77: Appropriate prop update for Shell component

The Shell component now correctly receives the workspace information it needs for the new navigation structure.


118-118: Minor style adjustment

Simple class order adjustment that maintains the same styling functionality.

apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (5)

3-4: LGTM: Updated imports for the UI redesign

The imports have been appropriately updated to include the new SettingCard and Form-related components needed for the UI redesign.


18-18: Improved field naming

Renaming from name to workspaceName enhances clarity about what the field represents while maintaining the same validation requirements.


38-38: Consistent field renaming in default values

The default values have been correctly updated to use workspaceName to maintain consistency with the schema update.


54-54: More explicit submission object structure

The submission function now uses a more explicit object structure, clearly specifying which properties are being sent to the API.


59-114: Improved UI with SettingCard component

The UI redesign with SettingCard provides better context and usability. The improved button validation logic (disabling when appropriate) enhances user experience.

apps/dashboard/app/(app)/settings/team/page.tsx (5)

4-4: LGTM: Importing the WorkspaceNavbar component

The import statement correctly references the WorkspaceNavbar component, consistent with other files in this PR.


11-11: Improved variable naming

Renaming from ws to workspace enhances code readability by using a more descriptive variable name.


16-16: Consistent variable usage

The team property access has been updated to use the renamed workspace variable.


18-34: Better error handling with conditional rendering

Good improvement to handle the case when a workspace isn't found, providing a clear fallback message to the user instead of potentially crashing.


20-23: Consistent navigation pattern with WorkspaceNavbar

The navigation has been updated to use the new WorkspaceNavbar component, matching the new navigation pattern implemented across settings pages.

apps/dashboard/app/(app)/settings/workspace-navbar.tsx (4)

1-8: LGTM: Well-structured component imports

The imports are organized logically, separating client directive, component imports, and UI elements.


9-30: Good navigation data structure

The settings navigation data is well-organized in a clear, maintainable array structure that makes it easy to add, remove or modify navigation items in the future.


32-44: Clear component interface with TypeScript props

The WorkspaceNavbar component has a well-defined interface with TypeScript types that clearly communicate what data the component expects.


45-78: Well-implemented navigation with advanced features

The component implementation effectively combines several UI elements:

  1. Breadcrumb navigation for context
  2. QuickNavPopover for efficient navigation between settings
  3. Workspace ID display with copy functionality

This provides a consistent, user-friendly navigation experience across settings pages.

apps/dashboard/app/(app)/settings/billing/components/shell.tsx (3)

5-13: Good implementation of the new WorkspaceNavbar pattern

The code now uses the standardized WorkspaceNavbar component, which creates a consistent navigation experience across workspace settings pages. The implementation correctly passes both the workspace object and the appropriate activePage props.


7-10: Well-structured prop typing

Good job on properly typing the workspace prop with explicit shape ({ id: string; name: string }). This ensures type safety and makes the component contract clearer for other developers.


15-18: Minor styling adjustments maintain layout consistency

The subtle adjustments to padding and spacing in the layout container help maintain visual consistency while accommodating the new navigation component.

apps/dashboard/app/(app)/settings/general/page.tsx (4)

2-7: Good modularization of imports

The import changes reflect the improved component organization, with separate components for specific functionality (Separator, WorkspaceNavbar, CopyWorkspaceId) instead of generic UI components.


28-34: Clean implementation of consistent workspace navigation

The WorkspaceNavbar implementation aligns with the pattern used in other settings pages, creating a unified navigation experience. The section header with proper styling helps establish visual hierarchy.


37-38: Good use of semantic components for visual separation

Using the Separator component before the CopyWorkspaceId creates clear visual grouping, which improves the UX by distinguishing between different functional areas of the settings page.


30-31: Responsive layout considerations

The container uses lg:w-[760px] for larger screens while remaining flexible on smaller screens. This is a good practice for maintaining a responsive design.

@vercel vercel bot temporarily deployed to Preview – play April 14, 2025 12:50 Inactive
@vercel vercel bot temporarily deployed to Preview – engineering April 14, 2025 12:51 Inactive
@vercel vercel bot temporarily deployed to Preview – www April 14, 2025 12:52 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 14, 2025 12:53 Inactive
@MichaelUnkey MichaelUnkey enabled auto-merge April 14, 2025 12:59
Copy link
Collaborator

@chronark chronark left a comment

Choose a reason for hiding this comment

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

see vercel comment

@vercel vercel bot temporarily deployed to Preview – engineering April 15, 2025 00:26 Inactive
@vercel vercel bot temporarily deployed to Preview – www April 15, 2025 00:27 Inactive
@vercel vercel bot temporarily deployed to Preview – play April 15, 2025 00:30 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 15, 2025 00:31 Inactive
@perkinsjr perkinsjr marked this pull request as draft April 15, 2025 20:40
auto-merge was automatically disabled April 15, 2025 20:40

Pull request was converted to draft

@vercel vercel bot temporarily deployed to Preview – engineering April 15, 2025 20:42 Inactive
@vercel vercel bot temporarily deployed to Preview – www April 15, 2025 20:42 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 25, 2025 15:48 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 25, 2025 16:48 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard April 28, 2025 14:00 Inactive
@vercel vercel bot temporarily deployed to Preview – engineering April 28, 2025 14:01 Inactive
Copy link
Contributor

should I take this over :thinkies:

Copy link
Contributor

@MichaelUnkey are we close to merging wdyt?

Copy link
Collaborator Author

MichaelUnkey commented Apr 28, 2025

Yeah just fixed some imports. Should be good if it builds this time.

@ogzhanolguncu
Copy link
Contributor

I can double submit. Because briefly button becomes submittable.

Screen.Recording.2025-04-28.at.17.57.04.mov

@ogzhanolguncu
Copy link
Contributor

image If submitted name is longer than 256 this will fail. I think we should validate the input before submit it. image Above its disabled coz its less than 3 chars, but we don't notify the user about this.

@ogzhanolguncu
Copy link
Contributor

image image I think those settings pages should look identical. For instance, save buttons have different radiuses etc... Copyable fields look different. I think it should look like ratelimits settings readonly/disabled and some contrast on copy button.

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: 2

🧹 Nitpick comments (3)
apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (3)

54-57: Improve validation error messages

The current error message combines two different validation cases (unchanged name or empty name). Consider providing distinct error messages for each case for better user experience.

  async function onSubmit(values: z.infer<typeof formSchema>) {
-   if (name === values.workspaceName || !values.workspaceName) {
-     return toast.error("Please provide a different name before saving.");
-   }
+   if (!values.workspaceName) {
+     return toast.error("Workspace name cannot be empty.");
+   }
+   
+   if (name === values.workspaceName) {
+     return toast.error("Please provide a different name before saving.");
+   }

    await updateName.mutateAsync({ workspaceId: workspace.id, name: values.workspaceName });
  }

97-101: Remove empty onBlur handler

This onBlur handler doesn't perform any action as it only contains a return statement inside a condition. Consider removing it if it's not needed or implement proper validation feedback.

                      {...field}
                      autoComplete="off"
-                     onBlur={(e) => {
-                       if (e.target.value === "") {
-                         return;
-                       }
-                     }}

111-115: Consider displaying validation feedback to users

The button is correctly disabled when the form is invalid, but users may not understand why. Consider adding validation error messages near the input field to explain requirements (like minimum 3 characters).

            <FormField
              control={form.control}
              name="workspaceName"
              render={({ field }) => (
                <FormItem>
                  <FormControl>
                    <Input
                      type="text"
                      id="workspaceName"
                      disabled={form?.formState?.isSubmitting || form.formState.isLoading}
                      className="w-[20rem] lg:w-[16rem]"
                      {...field}
                      autoComplete="off"
                    />
                  </FormControl>
+                 {form.formState.errors.workspaceName && (
+                   <div className="text-sm text-red-500 mt-1">
+                     {form.formState.errors.workspaceName.message}
+                   </div>
+                 )}
                </FormItem>
              )}
            />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 37ed258 and ab1fd9d.

📒 Files selected for processing (12)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/copy-api-id.tsx (2 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx (2 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx (2 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-api.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx (2 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-api-name.tsx (2 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/settings/components/settings-client.tsx (5 hunks)
  • apps/dashboard/app/(app)/settings/general/update-workspace-name.tsx (2 hunks)
  • apps/dashboard/app/(app)/settings/root-keys/page.tsx (2 hunks)
  • apps/dashboard/app/(app)/settings/team/client.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/team/page.tsx (1 hunks)
  • apps/dashboard/lib/trpc/routers/workspace/changeName.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/copy-api-id.tsx
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/settings/components/settings-client.tsx
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-api.tsx
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-api-name.tsx
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx
  • apps/dashboard/app/(app)/settings/root-keys/page.tsx
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx
  • apps/dashboard/app/(app)/settings/team/page.tsx
  • apps/dashboard/app/(app)/settings/team/client.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Test Packages / Test ./internal/clickhouse
🔇 Additional comments (1)
apps/dashboard/lib/trpc/routers/workspace/changeName.ts (1)

12-15: Good addition of maximum length validation

Adding a maximum length constraint of 50 characters is a good improvement that prevents overly long workspace names. The error message is clear and informative.

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: 0

🧹 Nitpick comments (4)
apps/dashboard/app/(app)/settings/root-keys/new/navigation.tsx (4)

37-43: Simplify the unnecessary flattening operation.

The flatMap is being used but not actually flattening any nested arrays, making it unnecessarily complex. A simple map would be more appropriate here.

- items={settingsNavbar.flatMap((setting) => [
-   {
-     id: setting.href,
-     label: setting.text,
-     href: `/settings/${setting.href}`,
-   },
- ])}
+ items={settingsNavbar.map((setting) => ({
+   id: setting.href,
+   label: setting.text,
+   href: `/settings/${setting.href}`,
+ }))}

47-47: Use dynamic value instead of hardcoded string.

The "Root Keys" text is hardcoded here, but it could be sourced from the navigation items for better maintainability. This ensures consistency if the display text ever changes.

- {"Root Keys"}
+ {settingsNavbar.find(item => item.id === "root-keys")?.text || "Root Keys"}

30-56: Enhance accessibility for the navigation component.

The navigation component looks well-structured, but consider adding ARIA attributes to improve accessibility for screen readers, especially for the popover interaction.

Enhance the QuickNavPopover trigger with appropriate ARIA labels:

<div className="flex items-center gap-1 p-1 rounded-lg hover:bg-gray-3"
+    aria-label="Navigate to settings sections"
+    role="button"
+    aria-haspopup="menu"
>

7-28: Consider using path constants for navigation links.

The navigation structure is well-defined, but consider extracting these paths to constants that can be reused across the application. This would ensure consistency if routes change.

Consider creating a separate paths constant file that can be imported wherever navigation paths are needed.

// Example: constants/paths.ts
export const SETTINGS_PATHS = {
  GENERAL: '/settings/general',
  TEAM: '/settings/team',
  ROOT_KEYS: '/settings/root-keys',
  BILLING: '/settings/billing',
};

// Then use them like:
// href: SETTINGS_PATHS.GENERAL.split('/').pop(),
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ab1fd9d and 98b1f06.

📒 Files selected for processing (1)
  • apps/dashboard/app/(app)/settings/root-keys/new/navigation.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/dashboard/app/(app)/settings/root-keys/new/navigation.tsx (1)

1-56: Overall implementation of the workspace navigation is well-structured.

The Navigation component effectively implements breadcrumb navigation with a quick navigation popover, which enhances the user experience by providing easy access to different settings sections. The component composition is clean and the code is well-organized.

Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

  • Every settings page look identical.
  • Root key creation still works
  • Workspace settings works
  • Api settings works

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