Skip to content

chore: dialog and dialog container to ui#3213

Closed
MichaelUnkey wants to merge 4 commits intomainfrom
dialog-to-ui
Closed

chore: dialog and dialog container to ui#3213
MichaelUnkey wants to merge 4 commits intomainfrom
dialog-to-ui

Conversation

@MichaelUnkey
Copy link
Collaborator

@MichaelUnkey MichaelUnkey commented May 1, 2025

What does this PR do?

Fixes # (issue)

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

Type of change

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

How should this be tested?

  • All Dialogs that used the still function and look as they should

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 customizable Dialog Container component and supporting dialog UI parts for consistent modal dialogs across the app.
    • Added a dialog demonstration example and comprehensive documentation for usage and props.
  • Chores

    • Updated internal dependencies to include a dialog UI library.
    • Updated imports throughout the dashboard to use the new dialog component from the shared UI library, ensuring consistency and maintainability.

@changeset-bot
Copy link

changeset-bot bot commented May 1, 2025

⚠️ No Changeset found

Latest commit: 4a69554

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

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

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 5, 2025 11:38pm
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 5, 2025 11:38pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 1, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This change migrates all usages of the DialogContainer component in the dashboard application from a local implementation to the external @unkey/ui package. It introduces a new dialog system within the internal/ui package, including the DialogContainer component, reusable dialog parts, and a set of dialog primitives built on Radix UI. Documentation and example usage for the new dialog container are also added. The @radix-ui/react-dialog dependency is included in the design system to support the new components. No changes to logic or control flow occur in the consuming files; the update is limited to import paths and the introduction of the new dialog implementation.

Changes

Files/Group Change Summary
apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-api.tsx
delete-protection.tsx
authorization/_components/rbac-form.tsx
authorization/permissions/[permissionId]/delete-permission.tsx
authorization/roles/[roleId]/delete-role.tsx
ratelimits/[namespaceId]/_components/delete-dialog.tsx
ratelimits/[namespaceId]/_components/identifier-dialog.tsx
ratelimits/[namespaceId]/_components/namespace-delete-dialog.tsx
ratelimits/_components/create-namespace-button.tsx
settings/billing/components/confirmation.tsx
settings/team/invite.tsx
auth/sign-in/org-selector.tsx
Changed the import source of DialogContainer from a local path to the external @unkey/ui package. No other code or logic was modified in these files.
apps/engineering/content/design/components/dialog-container.example.tsx Added a new example React component DialogContainerExample demonstrating usage of the dialog container, including state management and UI composition for documentation/demo purposes.
apps/engineering/content/design/components/dialog-container.mdx Added new documentation file describing the Dialog Container component, its features, usage example, and a detailed props table.
internal/ui/package.json Added @radix-ui/react-dialog as a new dependency.
internal/ui/src/components/dialog/dialog-container.tsx Introduced new DialogContainer React component with customizable header, content, and footer, using Radix UI dialog primitives and default dialog parts. Exports dialog container and its parts.
internal/ui/src/components/dialog/dialog-parts.tsx Added new reusable dialog UI parts: DefaultDialogHeader, DefaultDialogContentArea, and DefaultDialogFooter, each with customizable props and styling.
internal/ui/src/components/dialog/dialog.tsx Added new dialog primitives built on Radix UI: Dialog, DialogTrigger, DialogPortal, DialogClose, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogTitle, and DialogDescription. Includes support for close warnings and ref forwarding.
internal/ui/src/index.ts Added export for dialog-container and its parts to the package index.

Sequence Diagram(s)

sequenceDiagram
    participant ConsumerComponent as Any Dashboard Component
    participant @unkey/ui as @unkey/ui/DialogContainer
    participant RadixDialog as Radix UI Dialog Primitives

    ConsumerComponent->>@unkey/ui: Import DialogContainer
    ConsumerComponent->>@unkey/ui: Render <DialogContainer ...props />
    @unkey/ui->>RadixDialog: Use Radix Dialog primitives for modal logic
    @unkey/ui->>ConsumerComponent: Render dialog with header, content, footer, and handle open/close events
Loading

Possibly related PRs

  • unkeyed/unkey#2667: Introduced the new DialogContainer component and dialog parts in the design system, which are now being adopted in this PR.

Suggested reviewers

  • perkinsjr
  • chronark
  • mcstepp

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.
    • 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.

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

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

@MichaelUnkey MichaelUnkey marked this pull request as ready for review May 1, 2025 20:25
@MichaelUnkey MichaelUnkey enabled auto-merge May 1, 2025 20:25
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 (6)
apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx (1)

6-8: Approve import update; consider consolidating @unkey/ui imports
The DialogContainer import has been correctly switched to the shared UI library. To reduce duplication and improve readability, you can merge the three separate @unkey/ui imports into a single statement:

-from "@unkey/ui";
+import { DialogContainer, InlineLink, Input, SettingCard, Button } from "@unkey/ui";
apps/dashboard/app/auth/sign-in/org-selector.tsx (1)

3-6: Approve import update; consolidate @unkey/ui imports
The DialogContainer import from @unkey/ui is correct. You may also merge the two separate @unkey/ui imports into one for clarity:

-import { DialogContainer } from "@unkey/ui";
-import { Button } from "@unkey/ui";
+import { DialogContainer, Button } from "@unkey/ui";
apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/delete-dialog.tsx (1)

6-7: Approve import update; consolidate @unkey/ui imports
The update to import DialogContainer from @unkey/ui is correct. For consistency, combine both imports into a single one:

-import { DialogContainer } from "@unkey/ui";
-import { Button, Input } from "@unkey/ui";
+import { DialogContainer, Button, Input } from "@unkey/ui";
apps/engineering/content/design/components/dialog-container.mdx (1)

34-34: Nit: unify spelling of “autofocus”
In the props table, consider using “autofocus” (one word) instead of “auto-focus” to align with common conventions and the prop name preventAutoFocus.

🧰 Tools
🪛 LanguageTool

[misspelling] ~34-~34: This word is normally spelled as one.
Context: ... | false | Whether to prevent auto-focus on open | | children ...

(EN_COMPOUNDS_AUTO_FOCUS)

apps/engineering/content/design/components/dialog-container.example.tsx (1)

25-45: Consider refining the onOpenChange handler implementation.

The current implementation toggles the state rather than using the provided value.

-            onOpenChange={() => setIsOpen(!isOpen)}
+            onOpenChange={(open) => setIsOpen(open)}

This approach is more in line with controlled component patterns and prevents potential state mismatches.

internal/ui/src/components/dialog/dialog-container.tsx (1)

20-30: Consider documenting the preventAutoFocus behavior.

The preventAutoFocus prop defaults to true, which may impact accessibility for keyboard users. Consider adding a comment explaining this choice.

-  preventAutoFocus = true,
+  // Default to preventing autofocus to avoid unexpected focus shifts
+  // Set to false when keyboard accessibility is a priority
+  preventAutoFocus = true,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f5d8fe8 and adb1230.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-api.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/_components/rbac-form.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/permissions/[permissionId]/delete-permission.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/roles/[roleId]/delete-role.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/delete-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/namespace-delete-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/_components/create-namespace-button.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/billing/components/confirmation.tsx (1 hunks)
  • apps/dashboard/app/(app)/settings/team/invite.tsx (1 hunks)
  • apps/dashboard/app/auth/sign-in/org-selector.tsx (1 hunks)
  • apps/engineering/content/design/components/dialog-container.example.tsx (1 hunks)
  • apps/engineering/content/design/components/dialog-container.mdx (1 hunks)
  • internal/ui/package.json (1 hunks)
  • internal/ui/src/components/dialog/dialog-container.tsx (1 hunks)
  • internal/ui/src/components/dialog/dialog-parts.tsx (1 hunks)
  • internal/ui/src/components/dialog/dialog.tsx (1 hunks)
  • internal/ui/src/index.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
internal/ui/src/components/dialog/dialog-container.tsx (3)
internal/ui/src/components/dialog/dialog.tsx (2)
  • Dialog (152-152)
  • DialogContent (157-157)
apps/dashboard/lib/utils.ts (1)
  • cn (5-7)
internal/ui/src/components/dialog/dialog-parts.tsx (3)
  • DefaultDialogHeader (19-30)
  • DefaultDialogContentArea (36-45)
  • DefaultDialogFooter (51-59)
internal/ui/src/components/dialog/dialog-parts.tsx (2)
internal/ui/src/components/dialog/dialog-container.tsx (3)
  • DefaultDialogHeader (52-52)
  • DefaultDialogContentArea (52-52)
  • DefaultDialogFooter (52-52)
apps/dashboard/lib/utils.ts (1)
  • cn (5-7)
internal/ui/src/components/dialog/dialog.tsx (1)
apps/dashboard/lib/utils.ts (1)
  • cn (5-7)
🪛 LanguageTool
apps/engineering/content/design/components/dialog-container.mdx

[misspelling] ~34-~34: This word is normally spelled as one.
Context: ... | false | Whether to prevent auto-focus on open | | children ...

(EN_COMPOUNDS_AUTO_FOCUS)

🔇 Additional comments (26)
apps/dashboard/app/(app)/settings/team/invite.tsx (1)

23-23: Import DialogContainer from external UI package.
This aligns with the new centralized component location in @unkey/ui.

apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx (1)

15-15: Update DialogContainer import source.
Importing from @unkey/ui centralizes usage of the new dialog component across the app.

internal/ui/package.json (1)

19-19: Add Radix UI Dialog dependency.
The new @radix-ui/react-dialog package is required by the dialog components in internal/ui/src/components/dialog. Version ^1.0.5 aligns with the other Radix UI dependencies.

apps/dashboard/app/(app)/authorization/permissions/[permissionId]/delete-permission.tsx (1)

6-6: Centralize DialogContainer import.
Switching to @unkey/ui for consistent dialog behavior across the dashboard.

apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-api.tsx (1)

7-7: Update DialogContainer import path.
Importing from the shared @unkey/ui package to use the new centralized dialog component.

apps/dashboard/app/(app)/authorization/_components/rbac-form.tsx (1)

7-7: Standardize DialogContainer import
Switched from the local DialogContainer implementation to the centralized component in @unkey/ui, ensuring consistency across the codebase.

apps/dashboard/app/(app)/authorization/roles/[roleId]/delete-role.tsx (1)

5-5: Standardize DialogContainer import
Updated the DialogContainer import to use the shared component from @unkey/ui, aligning with the new design system.

apps/dashboard/app/(app)/ratelimits/_components/create-namespace-button.tsx (1)

8-8: Standardize DialogContainer import
Migrated the DialogContainer import to @unkey/ui for a unified dialog component across rate limit UIs.

apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/namespace-delete-dialog.tsx (1)

8-8: Standardize DialogContainer import
Replaced the local dialog container import with the shared DialogContainer from @unkey/ui to maintain consistency.

apps/dashboard/app/(app)/settings/billing/components/confirmation.tsx (1)

3-3: Standardize DialogContainer import
Changed to use the centralized DialogContainer from @unkey/ui, matching the updated component library conventions.

internal/ui/src/index.ts (1)

12-12: Expose the new DialogContainer component
Adding export * from "./components/dialog/dialog-container"; correctly surfaces the new DialogContainer (and its related parts) for external use.

apps/engineering/content/design/components/dialog-container.example.tsx (3)

3-4: LGTM: Clean import structure.

The imports correctly separate the Dialog components from the UI components they use.


7-15: Solid state management implementation.

The component properly manages dialog state, input state, and result state. The submission handler correctly updates state and closes the dialog.


47-55: LGTM: Well-structured dialog content.

The dialog content is well-structured with appropriate text styling and input implementation.

internal/ui/src/components/dialog/dialog-container.tsx (3)

9-18: LGTM: Comprehensive props interface.

The DialogContainerProps interface is well-defined with appropriate types and optional properties.


32-42: LGTM: Well-implemented focus prevention.

The event handler correctly prevents autofocus when specified. The implementation is clean and effective.


44-47: LGTM: Clear composition of dialog parts.

The component clearly composes the dialog parts with appropriate props and conditional rendering for the footer.

internal/ui/src/components/dialog/dialog-parts.tsx (4)

13-17: LGTM: Well-defined type for dialog header props.

The type definition is clear and includes appropriate optional properties.


19-30: LGTM: Well-implemented dialog header.

The header component is well-structured with appropriate styling and correctly handles conditional rendering of the subtitle.


32-45: LGTM: Clean content area implementation.

The content area component has a clean implementation with flexible class name composition.


47-59: LGTM: Consistent dialog footer implementation.

The footer component maintains styling consistency with the other dialog parts and allows for flexible content.

internal/ui/src/components/dialog/dialog.tsx (5)

16-32: LGTM: Well-structured dialog overlay with close warning support.

The DialogOverlay component correctly implements the forwardRef pattern and includes support for close warnings.


34-56: LGTM: Thorough type definitions for DialogContent.

The component's type definitions are comprehensive, including support for close warnings and custom refs.


89-106: LGTM: Well-implemented conditional close button rendering.

The component conditionally renders either a standard close button or a button that triggers the warning flow based on the showCloseWarning prop.


114-149: LGTM: Well-structured dialog helper components.

The DialogHeader, DialogFooter, DialogTitle, and DialogDescription components are well-implemented with appropriate styling and ref forwarding.


66-83:

Details

❓ Verification inconclusive

Consider improving the close protection logic.

The current implementation has a comment indicating that more robust checks might be needed for complex content.


🏁 Script executed:

#!/bin/bash
# Look for any DialogContent usage that might have complex nested content that could conflict with the current close protection logic

echo "Searching for complex DialogContent usage with nested interactive elements:"
rg -A 3 -B 3 "DialogContent.*showCloseWarning" --glob "*.{tsx,jsx}"

Length of output: 230


Further inspect the actual implementation to confirm whether clicks on nested content are correctly ignored:


🏁 Script executed:

#!/bin/bash
# Locate the dialog.tsx file and show the handlers around lines 66–83 for full context
file=$(fd --hidden --full-path "dialog.tsx")
echo "Found file: $file"
echo "Showing lines 1–120 for context:"
sed -n '1,120p' "$file"

Length of output: 2975


Let’s target the exact internal/ui dialog file and pull the relevant handler block:


🏁 Script executed:

#!/bin/bash
# Find the internal dialog.tsx path
dialog_file=$(fd --hidden "internal/ui/src/components/dialog/dialog.tsx")
echo "Using file: $dialog_file"
echo "Showing lines 50–100 for close-handler context:"
sed -n '50,100p' "$dialog_file"

Length of output: 278


Further verify the exact handler logic in the source:


🏁 Script executed:

#!/bin/bash
file="internal/ui/src/components/dialog/dialog.tsx"
if [ -f "$file" ]; then
  echo "Displaying lines 66–83 from $file:"
  sed -n '66,83p' "$file"
else
  echo "ERROR: $file not found"
fi

Length of output: 1108


Confirm dialog close protection logic

I reviewed the close-handler in internal/ui/src/components/dialog/dialog.tsx (lines 66–83). The current checks prevent Escape-key and outside-click closures when showCloseWarning is true and correctly target the overlay via closest('[role="dialog"]').

• No existing dialogs use deeply nested interactive elements that would bypass this logic.
• If you plan to embed more complex content (custom portals, nested modals, tooltips), you may want to enhance the onPointerDownOutside check (e.g., use data attributes or more specific selectors) to avoid false positives.

Please verify that your dialog content won’t require additional guards.

@ogzhanolguncu ogzhanolguncu self-assigned this May 1, 2025
@ogzhanolguncu
Copy link
Contributor

We should also add NavigableDialog(Dialog that we use for Create Key) here too. I'm not sure about the name tho. If you have a better name for it we can do that. And, maybe we should make it part of regular Dialog and make them more composable. Let's discuss that tomorrow.

@MichaelUnkey MichaelUnkey marked this pull request as draft May 4, 2025 17:19
auto-merge was automatically disabled May 4, 2025 17:19

Pull request was converted to draft

@vercel vercel bot temporarily deployed to Preview – engineering May 5, 2025 23:35 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard May 5, 2025 23:38 Inactive
@imeyer imeyer deleted the dialog-to-ui branch August 6, 2025 21:24
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