SSR Settings + Loading UI#147
Conversation
- Added a new `Loading` component to display a fallback UI while organization settings are loading. - Created `SettingsFallback` component with placeholders for organization name, website, and delete confirmation. - Wrapped organization settings in `Suspense` to handle loading state effectively.
- Updated `createApiKeyAction` and `revokeApiKeyAction` to include path revalidation after successful operations. - Improved error handling for API key actions with specific messages for unique and foreign key constraints. - Replaced the `SettingsFallback` component with a more structured loading UI using `Card` components for organization settings. - Introduced a new `Loading` component for the API keys page, featuring a spinner and descriptive cards. - Removed the deprecated `SettingsFallback` component to streamline the codebase.
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Caution Review failedThe pull request is closed. WalkthroughThis pull request updates API key management and several dashboard pages. The API key creation and revocation actions now trigger a cache revalidation using Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Action as API Key Action
participant DB as Database
participant Cache as revalidatePath
User->>Action: Request create/revoke API key
Action->>DB: Perform database operation
DB-->>Action: Return operation result
Action->>Cache: revalidatePath("/settings/api-keys")
Action-->>User: Return success response
sequenceDiagram
participant User as User
participant Page as API Keys Page
participant GK as getApiKeys
participant Table as ApiKeysTable
User->>Page: Navigate to API Keys dashboard
Page->>GK: Fetch active API keys (with caching)
GK-->>Page: Return API keys data
Page->>Table: Render table with API keys
sequenceDiagram
participant User as User
participant Settings as Settings Page
participant Suspense as Suspense Wrapper
participant Org as OrganizationSettings
User->>Settings: Visit organization settings
Settings->>Suspense: Wrap organization settings component
Suspense->>Org: Load settings components asynchronously
Org-->>Suspense: Return rendered settings
Suspense-->>Settings: Display loaded settings
Possibly related PRs
Poem
Tip ⚡🧪 Multi-step agentic review comment chat (experimental)
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/page.tsx (1)
29-35: Consider adding a fallback prop to SuspenseWhile wrapping the components with
Suspenseenables asynchronous rendering, you might want to specify a fallback UI to show during loading.- <Suspense> + <Suspense fallback={<Loading />}> <div className="space-y-12"> <UpdateOrganizationName organizationName={organization?.name ?? ""} /> <UpdateOrganizationWebsite organizationWebsite={organization?.website ?? ""} /> <DeleteOrganization organizationId={organization?.id ?? ""} /> </div> </Suspense>This would require importing the
Loadingcomponent from your loading.tsx file.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/app/src/actions/organization/create-api-key-action.ts(1 hunks)apps/app/src/actions/organization/revoke-api-key-action.ts(1 hunks)apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/loading.tsx(1 hunks)apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/page.tsx(1 hunks)apps/app/src/app/[locale]/(app)/(dashboard)/settings/loading.tsx(1 hunks)apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx(1 hunks)apps/app/src/app/[locale]/(app)/(dashboard)/settings/page.tsx(2 hunks)apps/app/src/components/logo-spinner.tsx(1 hunks)apps/app/src/components/tables/api-keys/index.tsx(1 hunks)
🧰 Additional context used
🧬 Code Definitions (6)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/loading.tsx (3)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx (1) (1)
Loading(8-56)apps/app/src/app/[locale]/(app)/(dashboard)/settings/loading.tsx (1) (1)
Loading(7-64)apps/app/src/components/logo-spinner.tsx (1) (1)
LogoSpinner(14-85)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/loading.tsx (2)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/loading.tsx (1) (1)
Loading(7-34)apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx (1) (1)
Loading(8-56)
apps/app/src/actions/organization/create-api-key-action.ts (2)
apps/app/src/actions/schema.ts (1) (1)
apiKeySchema(318-324)apps/app/src/lib/api-key.ts (3) (3)
generateApiKey(10-15)generateSalt(21-23)hashApiKey(31-40)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/page.tsx (1)
apps/app/src/components/tables/api-keys/index.tsx (1) (1)
ApiKeysTable(37-217)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx (3)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/loading.tsx (1) (1)
Loading(7-34)apps/app/src/app/[locale]/(app)/(dashboard)/settings/loading.tsx (1) (1)
Loading(7-64)apps/app/src/components/logo-spinner.tsx (1) (1)
LogoSpinner(14-85)
apps/app/src/components/tables/api-keys/index.tsx (2)
apps/app/src/hooks/use-api-keys.ts (1) (1)
ApiKey(8-15)apps/app/src/actions/organization/revoke-api-key-action.ts (1) (1)
revokeApiKeyAction(12-55)
🔇 Additional comments (31)
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/loading.tsx (1)
1-34: Well-implemented loading component for API keys pageThis new loading component follows the established pattern in your application for creating consistent loading states. The implementation uses internationalization correctly for text content and includes the new
LogoSpinnercomponent to provide visual feedback during loading.The structure mirrors what users will see in the loaded state, providing a seamless transition when data becomes available.
apps/app/src/actions/organization/create-api-key-action.ts (2)
7-7: Good addition of cache revalidationAdding the
revalidatePathimport for cache invalidation is a good practice.
69-69: Cache revalidation ensures UI consistencyAdding
revalidatePath("/settings/api-keys")after creating an API key ensures that users immediately see the updated list of keys without requiring a manual refresh. This improves the user experience.apps/app/src/app/[locale]/(app)/(dashboard)/settings/page.tsx (1)
10-10: Added Suspense for asynchronous renderingImporting both
cacheandSuspensefrom React provides the foundation for the improved loading behavior.apps/app/src/actions/organization/revoke-api-key-action.ts (2)
6-6: Good addition of cache revalidationAdding the
revalidatePathimport for cache invalidation is a good practice.
42-42: Cache revalidation ensures UI consistencyAdding
revalidatePath("/settings/api-keys")after revoking an API key ensures that users immediately see the updated list of keys without requiring a manual refresh. This improves the user experience.apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx (5)
1-7: Well-structured imports.Clean organization of imports, separating UI components, server utilities, and custom components.
8-10: Good use of async server component.The component properly fetches i18n translations asynchronously, which aligns with Next.js server component best practices.
11-22: Clean tab implementation.The tabs implementation is well-structured with appropriate styling and default value. The custom styling for tab list and triggers creates a visually integrated design.
23-33: Good loading state for members tab.The members tab content displays a clean card with appropriate title and loading spinner.
35-52: Thoughtful loading UI for invite tab.I like the use of blur effects on certain elements to indicate loading state, while still showing the general structure. This creates a better user experience by maintaining layout continuity.
apps/app/src/app/[locale]/(app)/(dashboard)/settings/loading.tsx (5)
1-6: Well-organized imports.Imports are logically grouped by their source and purpose.
7-9: Proper async server component implementation.The Loading component correctly uses the async pattern to fetch i18n translations.
10-26: Well-structured organization name card.The card follows best practices with:
- Clear title and description
- Disabled input with appropriate placeholder
- Well-styled footer with tip and disabled save button
- Proper accessibility with aria-label
28-42: Consistent organization website card.This card maintains the same structure and styling as the organization name card, creating a consistent user experience.
44-61: Appropriate destructive styling for delete card.The delete organization card correctly uses destructive styling to indicate danger. The AlertDialog is properly implemented with disabled trigger button and appropriate aria-label.
apps/app/src/app/[locale]/(app)/(dashboard)/settings/api-keys/page.tsx (4)
7-8: Added necessary imports for database access and caching.The new imports enable server-side data fetching with caching capability.
10-24: Improved session handling and authentication check.The component now properly validates the user session and redirects if the user doesn't have an organization ID.
25-31: Server-side data fetching implementation.The component now fetches API keys server-side and passes them to the ApiKeysTable component, following the recommended pattern for Next.js server components.
48-73: Well-implemented cached data fetching function.The
getApiKeysfunction:
- Uses React's cache for performance optimization
- Implements proper database query with filtering and ordering
- Selects only necessary fields
- Properly formats date fields to ISO strings for client-side consumption
This approach improves performance and separates data fetching from presentation.
apps/app/src/components/logo-spinner.tsx (5)
1-7: Correct client directive and imports.The "use client" directive is properly placed at the top of the file. Imports are well-organized, including the motion components from framer-motion.
8-12: Clear props interface definition.The LogoSpinnerProps interface properly extends SVG props and defines additional custom properties with appropriate types.
14-29: Well-structured component with proper hooks usage.The component:
- Uses destructuring with default values for props
- Implements useRef and useState correctly
- Uses useEffect appropriately to calculate path length on mount
33-54: Clean SVG implementation with motion animations.The SVG implementation:
- Is wrapped in a flex container for proper centering
- Uses motion.svg with scale animation
- Spreads additional props correctly
- Provides a clear comment for the path
56-81: Well-implemented animation for the racing line.The motion.path implementation:
- References the path for measurement
- Uses the custom color prop
- Has appropriate stroke styling
- Implements smooth animation with infinite repeat
- Includes appropriate timing and easing
The racing line effect creates a visually appealing loading indicator that matches the application's branding.
apps/app/src/components/tables/api-keys/index.tsx (6)
4-4: Updated import for ApiKey type looks goodThe component now only imports the type definition for ApiKey instead of using the hook for fetching data, aligning with the component's new data-receiving approach.
37-37: Well-structured component signature changeThe component now accepts API keys as a prop instead of fetching them internally, which is a good architectural change following separation of concerns. This allows the parent component to handle data fetching and caching while this component focuses on presentation.
38-57: Simplified state management and API key revocationThe component no longer manages loading or error states for API key fetching, making the code cleaner. The revocation functionality remains intact with appropriate toast notifications and state resets.
99-103: Improved conditional rendering logicThe rendering logic has been simplified to directly check the apiKeys array length, making the code more straightforward. This approach eliminates the need for separate loading states and simplifies the UI logic.
124-166: Proper rendering of API keys from propsThe component now directly maps over the provided apiKeys prop to render the table rows. The responsive design with different displays for mobile and desktop viewports is well-maintained.
182-214: Revoke dialog implementation looks goodThe dialog for revoking API keys is well-implemented with appropriate loading states, cancel functionality, and error handling. The responsive design adjustments for different screen sizes are maintained.
- Replaced Loader2 with LogoSpinner for improved loading indication. - Removed completed status section to streamline the UI. - Cleaned up unnecessary code and ensured consistent formatting.
Summary by CodeRabbit
LogoSpinnercomponent has been added to enhance loading indicators throughout the application.RealtimeStatuscomponent has been simplified by removing the completed state handling.