Skip to content

chore: dialog loading improvements - Merge after #3280#3281

Merged
ogzhanolguncu merged 4 commits intomainfrom
dialog-loading-improvements
May 29, 2025
Merged

chore: dialog loading improvements - Merge after #3280#3281
ogzhanolguncu merged 4 commits intomainfrom
dialog-loading-improvements

Conversation

@ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented May 29, 2025

What does this PR do?

Reduced initial bundle size by lazy-loading heavy components that aren't always needed.

Changes

  • CreateKeyDialog - Only loads when user has keyspace access
  • KeysTableActionPopover - Loads per table row interaction, reducing table overhead
  • DialogContainer & RBACDialogContent - Load only when dialogs are opened
  • Added loading fallbacks to prevent layout shift

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?

  • KeysTableActionPopover - Test dots menu in keys table rows opens and all actions function
  • RBAC Dialog - Click "Permissions" button on key details, verify dialog opens and permissions load
  • Dialog interactions - Ensure all dialogs open/close properly and maintain functionality
  • Loading states - Check that loading fallbacks appear briefly before components load

Checklist

Required

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

Appreciated

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

Summary by CodeRabbit

  • New Features

    • Introduced a new permissions dialog displaying detailed role-based access control (RBAC) information for API keys, with dynamic loading and improved UI feedback.
    • Added support for default keyspace values (prefix and bytes) that are dynamically reflected in the key creation dialog and settings.
  • Improvements

    • Enhanced the API settings page to ensure default prefix and byte values are updated and revalidated immediately after changes.
    • Improved performance by dynamically loading certain components only when needed, reducing initial load times.
  • Bug Fixes

    • Ensured that updates to keyspace defaults are immediately reflected in forms by resetting and clearing persisted form data when defaults change.

@changeset-bot
Copy link

changeset-bot bot commented May 29, 2025

⚠️ No Changeset found

Latest commit: 4c3e986

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 29, 2025

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

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 1 resolved May 29, 2025 6:55pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
engineering ⬜️ Ignored (Inspect) Visit Preview May 29, 2025 6:55pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 29, 2025

📝 Walkthrough

Walkthrough

This change introduces a new keyspaceDefaults property for APIs, enabling dynamic default values for key creation forms. It adds a utility for deep merging objects, refactors component imports to use dynamic loading, and modularizes permissions management by extracting RBAC logic into a dedicated component. Several component signatures and prop passing patterns are updated accordingly.

Changes

File(s) Change Summary
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.utils.ts,
apps/dashboard/lib/utils.ts
Added a deepMerge utility and updated getDefaultValues to accept overrides and merge them with defaults.
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx Updated CreateKeyDialog to accept and react to keyspaceDefaults prop, resetting form on changes.
apps/dashboard/app/(app)/apis/[apiId]/actions.ts Extended ApiLayoutData and API fetching logic to include new keyspaceDefaults property.
apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx,
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx
Refactored to use dynamic imports for several components, including RBACDialogContent and KeysTableActionPopover. Updated prop passing for keyspaceDefaults.
apps/dashboard/app/(app)/apis/[apiId]/_components/rbac-dialog-content.tsx Added new RBACDialogContent component for modular RBAC/permissions UI and logic.
apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-bytes.tsx,
apps/dashboard/app/(app)/apis/[apiId]/settings/components/default-prefix.tsx
Added apiId prop to DefaultBytes and DefaultPrefix, and trigger revalidation on mutation.
apps/dashboard/app/(app)/apis/[apiId]/settings/components/settings-client.tsx Passed apiId prop to DefaultBytes and DefaultPrefix components.
apps/dashboard/app/(app)/apis/[apiId]/settings/page.tsx Constructed and passed a new currentApi object with keyspaceDefaults to ApisNavbar.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ApisNavbar
    participant CreateKeyDialog
    participant RBACDialogContent
    participant DB

    User->>ApisNavbar: Open Create Key Dialog
    ApisNavbar->>CreateKeyDialog: Pass keyspaceDefaults prop
    CreateKeyDialog->>CreateKeyDialog: Initialize form with getDefaultValues(keyspaceDefaults)
    Note over CreateKeyDialog: Form resets if keyspaceDefaults change

    User->>ApisNavbar: Open Permissions Dialog
    ApisNavbar->>RBACDialogContent: Render with keyId, keyspaceId
    RBACDialogContent->>DB: Fetch permissions via TRPC
    RBACDialogContent-->>ApisNavbar: Display RBAC info
Loading

Suggested labels

Dashboard

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark
✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@github-actions
Copy link
Contributor

github-actions bot commented May 29, 2025

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx (1)

14-61: Well-implemented dynamic imports with appropriate loading states.

The dynamic imports correctly disable SSR and provide loading fallbacks for user-facing components. This aligns with the PR objective of reducing initial bundle size.

Consider adding a loading fallback for DialogContainer to ensure consistent loading behavior:

 const DialogContainer = dynamic(
   () => import("@/components/dialog-container").then((mod) => mod.DialogContainer),
   {
     ssr: false,
+    loading: () => <div className="fixed inset-0 bg-black/50" />,
   },
 );
apps/dashboard/app/(app)/apis/[apiId]/_components/rbac-dialog-content.tsx (3)

9-23: Consider adding loading fallbacks for dynamic components.

For consistency with other dynamic imports and better UX, consider adding loading states:

 const PermissionList = dynamic(
   () =>
     import("../keys/[keyAuthId]/[keyId]/components/rbac/permissions").then((mod) => ({
       default: mod.PermissionList,
     })),
-  { ssr: false },
+  { 
+    ssr: false,
+    loading: () => <div className="animate-pulse h-32 bg-gray-100 rounded" />
+  },
 );

 const RBACButtons = dynamic(
   () =>
     import("../keys/[keyAuthId]/[keyId]/components/rbac/rbac-buttons").then((mod) => ({
       default: mod.RBACButtons,
     })),
-  { ssr: false },
+  { 
+    ssr: false,
+    loading: () => <div className="animate-pulse h-10 w-24 bg-gray-100 rounded" />
+  },
 );

53-80: Robust error handling with retry capability.

The implementation provides clear error messaging and proper retry functionality through cache invalidation.

Consider displaying more specific error messages based on the error type:

-        <div className="text-accent-10 text-sm">Could not retrieve permission data</div>
+        <div className="text-accent-10 text-sm">
+          {error?.message || "Could not retrieve permission data"}
+        </div>

119-155: Consider improving type safety in the helper function.

The logic is correct, but using any types reduces type safety:

-  const roles = permissionsData.workspace.roles.map((role: any) => {
+  const roles = permissionsData.workspace.roles.map((role) => {
     return {
       id: role.id,
       name: role.name,
-      isActive: permissionsData.roles.some((keyRole: any) => keyRole.roleId === role.id),
+      isActive: permissionsData.roles.some((keyRole) => keyRole.roleId === role.id),
     };
   });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 51768aa and a22b450.

📒 Files selected for processing (11)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.utils.ts (4 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx (4 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/_components/rbac-dialog-content.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/actions.ts (3 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx (4 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx (3 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/settings-client.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/page.tsx (1 hunks)
  • apps/dashboard/lib/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx (3)
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/actions/keys-table-action.popover.tsx (1)
  • KeysTableActionPopover (27-138)
apps/dashboard/lib/utils.ts (1)
  • cn (5-7)
internal/icons/src/icons/dots.tsx (1)
  • Dots (15-60)
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx (1)
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.utils.ts (1)
  • getDefaultValues (89-125)
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.utils.ts (2)
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.schema.ts (1)
  • FormValueTypes (337-359)
apps/dashboard/lib/utils.ts (1)
  • deepMerge (187-209)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (23)
apps/dashboard/app/(app)/apis/[apiId]/settings/components/settings-client.tsx (1)

31-32: LGTM!

Properly passing the apiId prop to child components to enable revalidation after mutations. This is a clean implementation that maintains component separation of concerns.

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

2-2: LGTM!

Proper import of the revalidate function to enable cache invalidation after mutations.


25-25: LGTM!

Correctly added the apiId prop to the Props type definition.


28-28: LGTM!

Properly updated the component function signature to accept the apiId prop.


61-61: LGTM!

Excellent placement of the revalidate call after successful mutation to ensure the UI reflects the updated settings immediately.

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

2-2: LGTM!

Proper import of the revalidate function, consistent with the DefaultBytes component.


27-27: LGTM!

Correctly added the apiId prop to the Props type definition, maintaining consistency with the DefaultBytes component.


30-30: LGTM!

Properly updated the component function signature to accept the apiId prop.


61-61: LGTM!

Excellent placement of the revalidate call after successful mutation, ensuring immediate UI updates and consistency with the DefaultBytes component implementation.

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/keys-list.tsx (2)

5-5: Good addition of the Dots icon import.

The Dots icon is correctly imported to support the loading fallback component.


37-56: Excellent implementation of lazy loading with consistent styling.

The dynamic import implementation follows Next.js best practices:

  • SSR is properly disabled for client-side components
  • Loading fallback maintains visual consistency with the actual component
  • The styling in the fallback matches the actual component's button styling from the relevant code snippets

This change effectively reduces the initial bundle size by deferring the KeysTableActionPopover component load until user interaction.

apps/dashboard/app/(app)/apis/[apiId]/settings/page.tsx (1)

42-51: Well-structured data transformation for keyspace defaults.

The currentApi object construction properly extracts and reshapes the necessary properties. The use of logical OR (||) with undefined ensures consistent nullish values instead of mixed falsy values, which is good for type safety downstream.

This transformation aligns with the API interface expected by ApisNavbar and enables the keyspace defaults to be passed through the component hierarchy.

apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/index.tsx (3)

36-44: Proper prop type definition for keyspace defaults.

The keyspaceDefaults prop is well-defined with optional prefix and bytes properties, allowing for flexible default value configuration.


61-61: Correct integration of keyspace defaults in form initialization.

The form now properly uses keyspaceDefaults for initial values, ensuring the form reflects the keyspace configuration from the database.


77-82: Excellent form synchronization logic.

The useEffect properly handles form state updates when keyspaceDefaults change after revalidation:

  • Clears persisted data to prevent stale state
  • Resets form with new default values
  • Has correct dependencies to avoid unnecessary re-renders

This ensures the form always reflects the current keyspace defaults, improving user experience.

apps/dashboard/app/(app)/apis/[apiId]/actions.ts (3)

14-17: Well-defined type extension for keyspace defaults.

The keyspaceDefaults property is properly typed with optional prefix and bytes fields, maintaining type safety while allowing for flexible configuration.


41-46: Efficient database query modification.

The keyAuth relation is added with selective column fetching (defaultPrefix and defaultBytes), which is efficient as it only retrieves the necessary data for keyspace defaults.


75-78: Proper data mapping with consistent null handling.

The keyspaceDefaults object construction correctly maps database values and uses logical OR with undefined to ensure consistent nullish value handling, which aligns with the type definition and downstream usage.

apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/create-key.utils.ts (2)

89-91: LGTM! Well-designed function signature.

The optional overrides parameter with Partial<FormValueTypes> | null type allows for flexible default value customization while maintaining backward compatibility.


103-103: Good type safety improvement.

Using as const ensures TypeScript treats this as a literal type, providing better type safety when working with union types.

apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx (2)

73-77: Good type definition for keyspaceDefaults.

The nullable object with optional properties provides flexibility for API-specific default configurations.


196-206: Clean implementation of RBAC dialog.

The modular approach with RBACDialogContent handling all permissions logic improves code organization and maintainability.

apps/dashboard/app/(app)/apis/[apiId]/_components/rbac-dialog-content.tsx (1)

30-106: Well-structured component with proper state handling.

The component correctly handles all states (loading, error, success) and provides a good user experience with retry functionality and appropriate loading indicators.

@chronark chronark requested a review from MichaelUnkey May 29, 2025 09:06
@chronark
Copy link
Collaborator

@ogzhanolguncu there's a conflict
@MichaelUnkey can you review this one please?

@ogzhanolguncu
Copy link
Contributor Author

This one is good to go. @MichaelUnkey

@vercel vercel bot temporarily deployed to Preview – dashboard May 29, 2025 15:37 Inactive
Copy link
Collaborator

@MichaelUnkey MichaelUnkey left a comment

Choose a reason for hiding this comment

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

It looks good. Just have a couple questions.

  1. Is there a purpose to having the "Add Permission" button. You can add a permission but it does not get added to the key.
  2. Should we be able to see permissions in the Dialog and add them?

Copy link
Contributor Author

@MichaelUnkey Where is that "Add Permission" :thinkies:. Permission section is a temporary solution till we refactor it with new RBAC design. This PRs goal is to reduce the bundle if possible and make it a tiny bit faster by dynamically loading

@ogzhanolguncu ogzhanolguncu enabled auto-merge May 29, 2025 18:48
@vercel vercel bot temporarily deployed to Preview – dashboard May 29, 2025 18:55 Inactive
@ogzhanolguncu ogzhanolguncu added this pull request to the merge queue May 29, 2025
Merged via the queue into main with commit 94fd1f1 May 29, 2025
30 checks passed
@ogzhanolguncu ogzhanolguncu deleted the dialog-loading-improvements branch May 29, 2025 19:02
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.

4 participants