Skip to content

chore: UI improvements v2#4060

Merged
mcstepp merged 12 commits intomainfrom
ui-improvements-v2
Oct 8, 2025
Merged

chore: UI improvements v2#4060
mcstepp merged 12 commits intomainfrom
ui-improvements-v2

Conversation

@ogzhanolguncu
Copy link
Contributor

What does this PR do?

This PR addresses issues on this linear ticket: https://linear.app/unkey/issue/ENG-2098/small-ui-tweaks.
I also updated some keyboard shortcuts. Two of them were broken and they had quite strange positions. So its on Q-W and A-S so its always easy to access.
image

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?

  • Read the linear ticket and verify the changes yourself

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

@changeset-bot
Copy link

changeset-bot bot commented Oct 3, 2025

⚠️ No Changeset found

Latest commit: 9ad3fef

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 Oct 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Oct 8, 2025 9:49am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Oct 8, 2025 9:49am

@github-actions
Copy link
Contributor

github-actions bot commented Oct 3, 2025

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

📝 Walkthrough

Walkthrough

Removes legacy promotion/rollback dialog files and reintroduces them under a new actions path; adds shared DeploymentCard/DeploymentSection/DomainsSection UI, ProximityPrefetch, and collection preload; replaces Project.updatedAt with latestDeploymentId across schema and queries; simplifies Go deploy polling by removing per-step updates; several UI/shortcut tweaks.

Changes

Cohort / File(s) Summary
Dialog relocation & refactor
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/promotion-dialog.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/rollback-dialog.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/promotion-dialog.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/rollback-dialog.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/deployment-list-table-action.popover.constants.tsx
Removes old dialog files and adds new PromotionDialog/RollbackDialog under table/components/actions; updates import paths and gateway-logs route construction; dialogs perform TRPC mutations, cache invalidation, toast reporting, and best-effort refetches.
Shared deployment UI components
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-card.tsx, .../deployment-section.tsx, .../domains-section.tsx
Adds DeploymentCard, DeploymentSection, and DomainsSection components to render compact deployment summaries and domain lists with props for live/target and optional signal display.
Deployments list key stabilization
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/deployments-list.tsx
DomainList key now includes project?.latestDeploymentId to trigger remount when the latest deployment ID changes.
Active deployment UI tweaks
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/filter-button.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/index.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/domain-row.tsx
Adjusts inactive icon sizing; makes header a button to toggle expansion; renames log filter labels (“Errors”→“5XX”, “Warnings”→“4XX”); DomainRow accepts optional className and composes classes.
Project layout refetch trigger
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx
Adds lastestDeploymentId/latestDeploymentId usage and switches domain refetch dependency from liveDeploymentId to latestDeploymentId.
OpenAPI diff UI adjustments
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx
Improves empty/error UIs, uses shortenId(deploymentId) for labels, changes preselection behavior, and tweaks loading/layout padding and error card.
Projects list prefetching
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/index.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx, apps/dashboard/components/proximity-prefetch.tsx
Wraps ProjectCard in new ProximityPrefetch to prefetch routes and invoke collectionManager.preloadProject on proximity; updates project actions to include workspaceSlug and route to gateway logs.
Collections & TRPC schema updates
apps/dashboard/lib/collections/deploy/projects.ts, apps/dashboard/lib/collections/index.ts, apps/dashboard/lib/trpc/routers/deploy/project/list.ts
Replaces updatedAt with latestDeploymentId in Project schema and TRPC list mapping; adds CollectionManager.preloadProject and generalizes per-project cleanup.
Keyboard shortcut & UI helper changes
apps/dashboard/components/logs/live-switch-button/index.tsx, internal/ui/src/components/buttons/refresh-button.tsx, internal/ui/src/components/logs/control-cloud/index.tsx, internal/ui/src/components/buttons/keyboard-button.tsx
Updates several keyboard shortcuts and related UI hints (live switch → ⌥+⇧+Q, refresh → ⌥+⇧+W, clear/focus filters → ⌥+⇧+A/⌥+⇧+S); refactors KeyboardButton classname merging and adds hover-revealed shortcut wrappers.
Project creation payload update
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/create-project/create-project-dialog.tsx
Removes updatedAt insertion and initializes latestDeploymentId: null when creating a project.
Go deploy polling simplification
go/cmd/deploy/control_plane.go, go/cmd/deploy/main.go
Removes per-step update handling and processNewSteps; PollDeploymentStatus now only accepts onStatusChange; renames variables to deploymentID and passes environment to completion printing with title-casing.
Misc UI behavior
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx, apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/deployment-select.tsx, apps/dashboard/components/virtual-table/index.tsx, internal/ui/src/components/logs/control-cloud/index.tsx
Several data-selection, tooltip, trigger, indicator, and conditional-rendering tweaks across openapi-diff, deployment-select, and virtual table LoadMoreFooter conditional render.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as PromotionDialog (client)
  participant TRPC as TRPC API
  participant Cache as TRPC utils
  participant Coll as Collections (projects/deployments/domains)

  User->>UI: clicks "Promote"
  UI->>TRPC: mutate(promote, { targetDeploymentId, liveDeploymentId })
  TRPC-->>UI: success
  UI->>Cache: invalidate()
  UI->>Coll: try refetch() (projects, deployments, domains)
  UI-->>User: show success toast, close dialog
  TRPC-->>UI: error
  UI-->>User: show error toast
Loading
sequenceDiagram
  autonumber
  participant CLI as deploy command
  participant CP as ControlPlaneClient

  CLI->>CP: PollDeploymentStatus(deploymentID, onStatusChange)
  loop polling
    CP->>CP: fetch deployment status
    alt status changed
      CP->>CLI: onStatusChange(DeploymentStatusEvent)
    end
  end
  Note over CP: per-step updates removed — no step events emitted
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

UI, 🕹️ oss.gg, :joystick: 150 points

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark
  • MichaelUnkey
  • Flo4604

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description summarizes the UI tweaks and keyboard shortcut updates and includes a screenshot, but it is missing the required ‘Fixes #’ line and the type of change checkboxes are left unchecked. The testing instructions are minimal and do not detail specific steps to verify the changes. The description also does not explicitly list dependencies or context as outlined in the template, and appreciated items do not reflect the included visual asset. Taken together, these gaps mean the description does not fully adhere to the repository’s required structure. Please add a ‘Fixes #’ line linking to the relevant issue (or create one if none exists), mark the appropriate type of change checkbox, and expand the testing section with concrete steps to verify each UI update. Include any necessary context or dependencies encountered during development. Finally, update the appreciated section to acknowledge the included screenshot or screen recording.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title ‘chore: UI improvements v2’ is too generic and does not clearly summarize the main changes made in the pull request. It refers broadly to UI tweaks without specifying which components or behaviors were updated and the ‘v2’ suffix does not add meaningful context. This vagueness hinders a teammate’s ability to quickly understand the primary focus of the changeset. A more descriptive title that highlights the key modifications, such as updating keyboard shortcuts and hover-to-show indicators, would improve clarity. Consider revising the title to highlight the principal UI changes, for example ‘refactor: update keyboard shortcuts and hover-to-show indicators’ or ‘chore: apply UI tweaks for ENG-2098 including shortcut updates’. This will help communicative clarity and align with guidelines for concise and specific titles.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ui-improvements-v2

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/index.tsx (1)

170-186: Duplicate onClick handlers break the chevron toggle.

The outer button element (line 172) and the inner Button component (line 178) both have onClick={() => setExpanded(!isExpanded)}. When clicking the inner chevron button, both handlers fire in sequence, toggling the state twice and canceling out the effect—leaving the expansion state unchanged.

Apply this diff to remove the duplicate handler from the inner Button:

-          <button
-            className="flex items-center gap-1.5"
-            onClick={() => setExpanded(!isExpanded)}
-            type="button"
-          >
+          <button
+            className="flex items-center gap-1.5"
+            onClick={() => setExpanded(!isExpanded)}
+            type="button"
+          >
             <div className="text-grayA-9 text-xs">
               {showBuildSteps ? "Build logs" : "Gateway logs"}
             </div>
-            <Button size="icon" variant="ghost" onClick={() => setExpanded(!isExpanded)}>
+            <Button size="icon" variant="ghost" asChild>
+              <div>
               <ChevronDown
                 className={cn(
                   "text-grayA-9 !size-3 transition-transform duration-200",
                   isExpanded && "rotate-180",
                 )}
               />
+              </div>
             </Button>
           </button>

Alternatively, if you want the chevron to be a distinct clickable area, remove the outer button's onClick and keep only the inner Button's handler.

apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx (1)

65-73: Address placeholder deployment ID in project settings navigation.

Lines 69-71 contain placeholder code with a hardcoded fake deployment ID ("idk"), which will result in broken navigation for the "Project settings" menu item.

The comment indicates this will change soon. To prevent this from being forgotten:

  1. Either implement the correct navigation now (if the proper route is known), or
  2. Temporarily disable this menu item until the correct implementation is ready.

Would you like me to open a new issue to track completing this implementation?

🧹 Nitpick comments (11)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/filter-button.tsx (1)

28-28: Visual distinction added for inactive state icons.

The change reduces the icon size for inactive filter buttons using !size-3, creating a visual hierarchy where active buttons have larger icons. However, the !important flag suggests a specificity conflict.

Consider whether the important flag is necessary or if the underlying size conflict can be resolved at the component/theme level for cleaner CSS.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/index.tsx (1)

211-218: Consider aligning internal filter state with UI labels.

The UI labels were updated to "5XX" and "4XX" (lines 211, 218), but the internal logFilter state still checks for "errors" and "warnings" (lines 207, 214). This mismatch between user-facing terminology and internal state can reduce code clarity.

For consistency, consider updating the filter state values to match the UI labels (e.g., "5xx" and "4xx"), or alternatively keep the generic terms in the UI if the filters apply beyond HTTP status codes. This change would touch the useDeploymentLogs hook and related filter logic.

apps/dashboard/lib/trpc/routers/deploy/project/list.ts (1)

21-21: LGTM! Backend provides latestDeploymentId via subquery.

The new subquery correctly selects the most recent deployment ID for each project, and the mapping to latestDeploymentId aligns with the updated project schema. The workspace filter in the subquery ensures proper multi-tenancy.

For future optimization, consider whether the subquery could be moved to a materialized column or index if this query becomes a performance bottleneck. However, for current usage, the implementation is correct and performant enough.

Also applies to: 44-52, 79-79

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (1)

43-47: Avoid @ts-expect-error by exposing a typed invalidate/refetch method.

Instead of calling internal utils.refetch with a type error, add a typed method on collectionManager (e.g., collections.domains.invalidate() or collectionManager.invalidate("domains")) and use that here.

apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/index.tsx (1)

80-112: Leverage ProximityPrefetch route prefetch (optional).

If you can compute the project route here, pass it via the route prop to also prefetch the page for faster nav. Alternatively, move ProximityPrefetch inside ProjectCard where projectPath is known and provide route there.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/domains-section.tsx (1)

20-26: LGTM; minor style consistency nit.

Implementation is sound. Optional: align border color classes with DomainRow’s defaults to avoid mixed gray tokens.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-card.tsx (1)

20-22: Prefer shortenId for consistency; add branch fallback.

Use shortenId for deployment.id formatting (already used for commit SHA) and guard against missing gitBranch.

-            <span className="text-xs text-accent-12 font-mono">
-              {`${deployment.id.slice(0, 3)}...${deployment.id.slice(-4)}`}
-            </span>
+            <span className="text-xs text-accent-12 font-mono">
+              {shortenId(deployment.id, { startChars: 3, endChars: 4 })}
+            </span>
@@
-          <span className="truncate">{deployment.gitBranch}</span>
+          <span className="truncate">{deployment.gitBranch ?? "-"}</span>

Also applies to: 36-43

apps/dashboard/components/proximity-prefetch.tsx (1)

95-103: Reduce rerenders and duplicate global listeners.

Each instance adds a window mousemove listener and updates state on every event, causing frequent rerenders and N listeners in lists. Prefer a single global pointermove subscription and store position in a ref, or throttle via rAF.

Options:

  • Replace mousemove with pointermove for broader device support.
  • Track mouse position in a ref and run proximity logic inside the listener with a small debounce, avoiding React state updates per event.
  • Share a singleton listener (module scope) that notifies all instances.

Also applies to: 105-116

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/rollback-dialog.tsx (1)

41-51: Remove brittle refetch “hack” and rely on proper invalidation.

collection.projects/deployments/domains.utils.refetch() is suppressed with @ts-expect-error and likely undefined at runtime (caught and logged). This is noisy and fragile. You already call utils.invalidate(); that should be the source of truth. If additional refresh is needed, expose typed refetch APIs via collectionManager or context instead of reaching into non-existent fields.

Apply this diff to drop the hack:

-      // hack to revalidate
-      try {
-        // @ts-expect-error Their docs say it's here
-        collection.projects.utils.refetch();
-        // @ts-expect-error Their docs say it's here
-        collection.deployments.utils.refetch();
-        // @ts-expect-error Their docs say it's here
-        collection.domains.utils.refetch();
-      } catch (error) {
-        console.error("Refetch error:", error);
-      }
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/promotion-dialog.tsx (2)

40-50: Remove brittle refetch “hack” and rely on proper invalidation.

Same issue as in RollbackDialog. Suppressed, likely undefined, and noisy. Prefer utils.invalidate() and/or a typed refetch via collectionManager.

Apply this diff:

-      // hack to revalidate
-      try {
-        // @ts-expect-error Their docs say it's here
-        collection.projects.utils.refetch();
-        // @ts-expect-error Their docs say it's here
-        collection.deployments.utils.refetch();
-        // @ts-expect-error Their docs say it's here
-        collection.domains.utils.refetch();
-      } catch (error) {
-        console.error("Refetch error:", error);
-      }

71-91: Minor: Button label polish (optional).

Consider “Promote to” + shortened SHA/id on the same line might read better with a non-breaking space or colon. Not required.

Example:

  • “Promote to: {shortenId(...)}”
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16d14f6 and 86b7dd7.

📒 Files selected for processing (26)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/promotion-dialog.tsx (0 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/rollback-dialog.tsx (0 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-card.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-section.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/domains-section.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/deployment-list-table-action.popover.constants.tsx (2 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/promotion-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/rollback-dialog.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/deployments-list.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/filter-button.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/index.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/domain-row.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/index.tsx (2 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx (3 hunks)
  • apps/dashboard/components/logs/live-switch-button/index.tsx (2 hunks)
  • apps/dashboard/components/proximity-prefetch.tsx (1 hunks)
  • apps/dashboard/lib/collections/deploy/projects.ts (1 hunks)
  • apps/dashboard/lib/collections/index.ts (1 hunks)
  • apps/dashboard/lib/trpc/routers/deploy/project/list.ts (3 hunks)
  • go/cmd/deploy/control_plane.go (0 hunks)
  • go/cmd/deploy/main.go (5 hunks)
  • internal/ui/src/components/buttons/refresh-button.tsx (2 hunks)
  • internal/ui/src/components/logs/control-cloud/index.tsx (3 hunks)
💤 Files with no reviewable changes (3)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/rollback-dialog.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/promotion-dialog.tsx
  • go/cmd/deploy/control_plane.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-25T19:09:43.284Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/lib/trpc/routers/deployment/list.ts:11-11
Timestamp: 2025-07-25T19:09:43.284Z
Learning: In apps/dashboard/lib/trpc/routers/deployment/list.ts, the listDeployments procedure intentionally queries the versions table rather than a deployments table. The user mcstepp indicated that renaming the table would require a database migration, which was deferred for the current PR focused on UI features.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/deployments-list.tsx
  • apps/dashboard/lib/trpc/routers/deploy/project/list.ts
📚 Learning: 2025-04-24T14:34:30.621Z
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3115
File: apps/dashboard/components/logs/checkbox/filters-popover.tsx:33-55
Timestamp: 2025-04-24T14:34:30.621Z
Learning: In the ShortcutActivator component within filters-popover.tsx, the purpose is to track keys separately for each filter item, providing a registration mechanism for shortcuts passed to it rather than enforcing specific key combinations like option+shift+key.

Applied to files:

  • internal/ui/src/components/logs/control-cloud/index.tsx
📚 Learning: 2025-07-28T20:38:53.244Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx:322-341
Timestamp: 2025-07-28T20:38:53.244Z
Learning: In apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx, mcstepp prefers to keep hardcoded endpoint logic in the getDiffType function during POC phases for demonstrating diff functionality, rather than implementing a generic diff algorithm. This follows the pattern of keeping simplified implementations for demonstration purposes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx
🧬 Code graph analysis (14)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (1)
apps/dashboard/lib/collections/deploy/projects.ts (1)
  • projects (43-109)
apps/dashboard/components/logs/live-switch-button/index.tsx (1)
apps/dashboard/hooks/use-keyboard-shortcut.tsx (1)
  • useKeyboardShortcut (226-304)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/index.tsx (2)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/filter-button.tsx (1)
  • FilterButton (13-34)
internal/icons/src/icons/triangle-warning-2.tsx (1)
  • TriangleWarning2 (16-45)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-card.tsx (4)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (1)
  • StatusIndicator (26-69)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/promotion-dialog.tsx (1)
  • DeploymentCardProps (146-180)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/rollback-dialog.tsx (1)
  • DeploymentCardProps (145-179)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/promotion-dialog.tsx (6)
apps/dashboard/lib/collections/index.ts (2)
  • collectionManager (67-67)
  • collection (70-74)
internal/db/src/schema/domains.ts (1)
  • domains (4-36)
apps/dashboard/lib/trpc/routers/deploy/deployment/promote.ts (1)
  • promote (14-122)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-section.tsx (1)
  • DeploymentSection (12-25)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/domains-section.tsx (1)
  • DomainsSection (8-30)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/domains-section.tsx (2)
internal/db/src/schema/domains.ts (1)
  • domains (4-36)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/domain-row.tsx (1)
  • DomainRow (12-38)
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx (1)
apps/dashboard/components/logs/table-action.popover.tsx (2)
  • TableActionPopover (37-156)
  • MenuItem (20-30)
go/cmd/deploy/main.go (1)
go/gen/proto/ctrl/v1/deployment.pb.go (3)
  • Deployment (412-446)
  • Deployment (459-459)
  • Deployment (474-476)
internal/ui/src/components/logs/control-cloud/index.tsx (1)
internal/ui/src/hooks/use-keyboard-shortcut.tsx (1)
  • useKeyboardShortcut (221-298)
apps/dashboard/lib/trpc/routers/deploy/project/list.ts (3)
internal/db/src/schema/domains.ts (1)
  • domains (4-36)
internal/db/src/schema/deployments.ts (1)
  • deployments (9-54)
internal/db/src/schema/projects.ts (1)
  • projects (8-31)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/rollback-dialog.tsx (6)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout-provider.tsx (1)
  • useProject (16-22)
internal/db/src/schema/domains.ts (1)
  • domains (4-36)
apps/dashboard/lib/trpc/routers/deploy/deployment/rollback.ts (1)
  • rollback (14-127)
apps/dashboard/lib/collections/index.ts (1)
  • collection (70-74)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-section.tsx (1)
  • DeploymentSection (12-25)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/domains-section.tsx (1)
  • DomainsSection (8-30)
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/index.tsx (4)
apps/dashboard/components/proximity-prefetch.tsx (1)
  • ProximityPrefetch (52-123)
apps/dashboard/lib/collections/index.ts (1)
  • collectionManager (67-67)
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/projects-card.tsx (1)
  • ProjectCard (24-135)
apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx (1)
  • ProjectActions (16-23)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (1)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-section.tsx (3)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-card.tsx (1)
  • DeploymentCard (13-47)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/promotion-dialog.tsx (1)
  • DeploymentSectionProps (18-26)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/rollback-dialog.tsx (1)
  • DeploymentSectionProps (19-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build / Build
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test Packages / Test
  • GitHub Check: Test API / API Test Local
🔇 Additional comments (25)
internal/ui/src/components/buttons/refresh-button.tsx (1)

47-72: LGTM! Keyboard shortcut update is consistent.

The keyboard shortcut change from option+shift+r to option+shift+w is correctly applied across all three locations:

  • Hook binding (line 47)
  • Tooltip text (line 65)
  • Visual display (line 72)

This aligns with the PR's objective to improve keyboard shortcuts for better accessibility.

apps/dashboard/components/logs/live-switch-button/index.tsx (3)

12-12: LGTM! Improved keyboard shortcut ergonomics.

The shortcut change from L to Q places the key closer to the modifier keys (Option+Shift), making it more accessible for single-handed use.


19-19: Consistent tooltip text.

The button title correctly reflects the new keyboard shortcut, ensuring users see the updated shortcut when hovering.


34-34: Visual display updated correctly.

The KeyboardButton component now displays the new shortcut, maintaining consistency across all UI elements (hook registration, tooltip, and visual display).

go/cmd/deploy/main.go (5)

12-13: LGTM!

The added imports support the new title-casing functionality for environment names, which is used in the printCompletionInfo function.


285-291: LGTM!

The rename from deploymentId to deploymentID follows Go naming conventions where acronyms should be capitalized (ID, not Id).


309-309: LGTM!

The simplified PollDeploymentStatus call removes per-step update callbacks, streamlining the deployment polling logic to focus on major status transitions.


366-366: LGTM!

The updated signature adds the env parameter to display environment information in the completion summary, called correctly at line 320.


372-378: Title-casing improves output readability.

The implementation correctly uses cases.Title(language.English) to format environment names for display. This works well for simple slugs like "preview" or "production."

Note: If environment slugs can contain hyphens or special formatting (e.g., "staging-v2"), cases.Title will capitalize each word segment, which may or may not be desired. For most common cases, this should be fine.

internal/ui/src/components/logs/control-cloud/index.tsx (1)

30-30: LGTM! Keyboard shortcut remapping from option+shift+d/c to option+shift+a/s improves ergonomics, UI labels are updated accordingly, and no conflicts with existing shortcuts were found.

apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/list/project-actions.tsx (3)

25-29: LGTM!

The function signature correctly accepts workspaceSlug to support workspace-scoped routing, aligning with the broader navigation pattern improvements in this PR.


58-58: LGTM!

The label change from "View logs" to "View gateway logs" improves specificity and user clarity.


61-61: LGTM!

The navigation path correctly constructs a workspace-scoped route using the provided workspaceSlug parameter.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (1)

115-133: LGTM! Enhanced empty state UI.

The new animated empty state provides a more polished user experience with a gradient accent, pulsing icon, and clearer messaging. The use of semantic HTML (h3, p) and appropriate color tokens (grayA-12, grayA-9) maintains accessibility.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (2)

3-3: LGTM! Consistent deployment ID presentation.

The use of shortenId for deployment labels improves readability and aligns with the broader UI overhaul for deployment-related components across the PR.

Also applies to: 88-88


174-174: LGTM! Enhanced loading and error states.

The updated padding and richer error UI (with gradient, icon, and clear messaging) provide a more polished user experience consistent with other UI improvements in this PR.

Also applies to: 182-202

apps/dashboard/lib/collections/index.ts (2)

41-45: LGTM! Useful preloading capability added.

The new preloadProject method enables efficient parallel preloading of all collections for a given project, which aligns with the PR's goal of improving data loading (e.g., proximity prefetch mentioned in the AI summary).


47-54: LGTM! Cleanup refactored for consistency.

The refactored cleanup method now uses the same parallel pattern as preloadProject, improving maintainability and consistency across the collection manager.

apps/dashboard/lib/collections/deploy/projects.ts (1)

12-12: LGTM! Schema updated to include latestDeploymentId.

The addition of latestDeploymentId to the project schema aligns with the backend changes (seen in list.ts) and enables UI components to key on the latest deployment for refetch logic and rendering.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/deployments-list.tsx (1)

119-119: LGTM! DomainList keying updated for latestDeploymentId.

The expanded composite key now includes project?.latestDeploymentId, ensuring the DomainList re-mounts when the latest deployment changes. This prevents stale domain displays and aligns with the new project schema.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/deployment-list-table-action.popover.constants.tsx (2)

10-11: LGTM! Import paths updated for relocated dialogs.

The updated import paths reflect the restructuring of PromotionDialog and RollbackDialog from sibling directories to subdirectories within the actions folder, as noted in the AI summary.


83-83: LGTM! URL path corrected with leading slash.

Adding the leading slash ensures the gateway logs URL is constructed as an absolute path from the workspace root, preventing potential routing issues.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/domain-row.tsx (1)

3-3: LGTM! DomainRow now accepts external styling.

The addition of an optional className prop with proper composition via cn enables flexible styling while preserving default classes. This aligns with the PR's UI improvements and supports usage in components like DomainsSection.

Also applies to: 9-9, 12-19

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/components/deployment-section.tsx (1)

18-24: LGTM.

Simple, cohesive wrapper around DeploymentCard with a clear header.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/deployments/components/table/components/actions/rollback-dialog.tsx (1)

29-33: Validate domain filter logic (inconsistent with PromotionDialog).

Here you filter only on sticky ∈ ["environment","live"]. In PromotionDialog you also add eq(domain.deploymentId, liveDeployment.id). Confirm which is intended and align both dialogs.

@chronark
Copy link
Collaborator

chronark commented Oct 3, 2025

that screenshot makes me wonder whether we should show shortcuts on hover only
cause they take up like half of the screen and my brain
wdyt?

@ogzhanolguncu
Copy link
Contributor Author

that screenshot makes me wonder whether we should show shortcuts on hover only cause they take up like half of the screen and my brain wdyt?

if you ask my opinion I don't think anyone using them but me/us? 😄 So we can hide them yeah

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)/[workspaceSlug]/projects/_components/create-project/create-project-dialog.tsx (1)

65-65: Consider removing or upgrading to structured logging.

Since the collection's onInsert handler already shows error toasts (line 66 comment), this console.error may be redundant. If error logging is needed for debugging, consider using a structured logging solution instead.

internal/ui/src/components/logs/control-cloud/index.tsx (1)

151-153: Consider using max-w-fit for flexible content sizing.

The hover transition uses a fixed max-w-[100px], which could clip content or leave excess space depending on the actual width of KeyboardButton. Using max-w-fit would accommodate varying content widths more gracefully.

-<div className="max-w-0 opacity-0 group-hover:max-w-[100px] group-hover:opacity-100 transition-all duration-300 ease-in-out overflow-hidden">
+<div className="max-w-0 opacity-0 group-hover:max-w-fit group-hover:opacity-100 transition-all duration-300 ease-in-out overflow-hidden">
   <KeyboardButton shortcut="⌥+⇧+A" />
 </div>

Note: This suggestion assumes the critical KeyboardButton API issue in the previous comment is addressed first.

Also applies to: 158-160

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86b7dd7 and 964b2ec.

📒 Files selected for processing (5)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/create-project/create-project-dialog.tsx (1 hunks)
  • apps/dashboard/components/logs/live-switch-button/index.tsx (2 hunks)
  • internal/ui/src/components/buttons/keyboard-button.tsx (1 hunks)
  • internal/ui/src/components/buttons/refresh-button.tsx (2 hunks)
  • internal/ui/src/components/logs/control-cloud/index.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/components/logs/live-switch-button/index.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-24T14:34:30.621Z
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3115
File: apps/dashboard/components/logs/checkbox/filters-popover.tsx:33-55
Timestamp: 2025-04-24T14:34:30.621Z
Learning: In the ShortcutActivator component within filters-popover.tsx, the purpose is to track keys separately for each filter item, providing a registration mechanism for shortcuts passed to it rather than enforcing specific key combinations like option+shift+key.

Applied to files:

  • internal/ui/src/components/logs/control-cloud/index.tsx
🧬 Code graph analysis (2)
internal/ui/src/components/logs/control-cloud/index.tsx (1)
internal/ui/src/hooks/use-keyboard-shortcut.tsx (1)
  • useKeyboardShortcut (221-298)
internal/ui/src/components/buttons/refresh-button.tsx (1)
internal/icons/src/icons/refresh-3.tsx (1)
  • Refresh3 (15-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test
  • GitHub Check: Build / Build
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (9)
internal/ui/src/components/buttons/refresh-button.tsx (3)

47-47: LGTM! Keyboard shortcut updated for better accessibility.

The change from option+shift+r to option+shift+w aligns with the PR objective to improve shortcut ergonomics by using keys that are easier to reach (Q-W pattern).


65-74: LGTM! Clean implementation of hover-reveal pattern.

The changes effectively implement the "show on hover" behavior discussed in the PR comments:

  • Title tooltip correctly reflects the new shortcut (line 65)
  • group and overflow-hidden classes enable the parent hover state (line 68)
  • Smooth transition animation reveals the keyboard shortcut on hover using max-w-0max-w-[100px] and opacity changes (lines 72-74)

This addresses the concern about shortcuts taking up excessive screen space while keeping them discoverable.


83-83: LGTM! Proper public API export.

The export statement correctly exposes both the component and its props type, following standard React/TypeScript conventions.

apps/dashboard/app/(app)/[workspaceSlug]/projects/_components/create-project/create-project-dialog.tsx (2)

45-45: LGTM!

The change from updatedAt to latestDeploymentId correctly aligns with the schema update described in the PR summary. Initializing it as null for a new project is appropriate.


44-52: Verify server-side placeholder replacement.

The insert payload relies on the server to replace several placeholder values (id, author, authorAvatar, branch, commitTitle, domain). Ensure the server-side logic consistently replaces these fields to prevent placeholder strings from appearing in the UI.

internal/ui/src/components/buttons/keyboard-button.tsx (1)

29-29: LGTM! Clean simplification.

Passing className directly to cn() is clearer than wrapping it in an object. The cn utility handles string arguments natively, so this change maintains functionality while improving readability.

internal/ui/src/components/logs/control-cloud/index.tsx (3)

30-46: LGTM! Shortcut update aligns with PR objectives.

The keyboard shortcut change from option+shift+d to option+shift+a places the key in a more accessible position, as noted in the PR description. The string format is correctly parsed by useKeyboardShortcut.


48-50: LGTM! Consistent shortcut repositioning.

The keyboard shortcut change from option+shift+c to option+shift+s maintains consistency with the previous change and improves accessibility.


133-162: Verify keyboard-only accessibility for hover-revealed shortcuts.

The hover-reveal pattern addresses the space concern raised in PR comments, but shortcuts only appear on mouse hover (:hover). Keyboard-only users navigating with Tab won't see these hints.

Consider extending the reveal trigger to include focus states:

-<div className="max-w-0 opacity-0 group-hover:max-w-[100px] group-hover:opacity-100 transition-all duration-300 ease-in-out overflow-hidden">
+<div className="max-w-0 opacity-0 group-hover:max-w-[100px] group-hover:opacity-100 group-focus-within:max-w-[100px] group-focus-within:opacity-100 transition-all duration-300 ease-in-out overflow-hidden">
   <KeyboardButton shortcut="⌥+⇧+A" />
 </div>

This ensures the shortcuts are visible when any element within the control cloud receives keyboard focus, improving accessibility for keyboard-only navigation.

@chronark
Copy link
Collaborator

chronark commented Oct 6, 2025

nitpick, showing the openapi diff without a 2nd deployment makes no sense, it's not valuable to the user and you only encounter it on the first deploy, which is likely from a new users. We should try to minimize the noise for new users especially
@coderabbitai please create an issue for us to only show the openapi diff in the sidebar if there's actually a 2nd deployment to compare to, do not assign anyone.

CleanShot 2025-10-06 at 10 39 47@2x

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

I'll create an issue for this improvement.


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for hiding OpenAPI diff when only one deployment exists

gh issue create \
  --title "Hide OpenAPI diff in sidebar when only one deployment exists" \
  --body "## Context
Showing the OpenAPI diff in the sidebar without a second deployment to compare against provides no value to the user. This scenario typically occurs on the first deploy, which is likely from new users. We should minimize noise for new users especially.

## Requested Change
Only show the OpenAPI diff option in the sidebar if there's actually a second deployment to compare to.

## Additional Context
- Requested by: @chronark
- Related PR: #4060
- Comment: https://github.com/unkeyed/unkey/pull/4060#discussion_r1000000000" \
  --repo unkeyed/unkey

Length of output: 44


@chronark I've created issue #4074 to track hiding the OpenAPI diff in the sidebar when there's only one deployment to compare.

#4074

@chronark
Copy link
Collaborator

chronark commented Oct 6, 2025

CleanShot 2025-10-06 at 10 44 00@2x this is wrong we said we'd have the left one be the live deployment, but here it's not.

edit: actually we didn't say that, we said the right one should be live. But now that I thinka bout it, that makes no sense
I'm, interested how my spec changes, so the "from" should be the live deployment, and the "to" should the latest deployment where env == preview

@ogzhanolguncu
Copy link
Contributor Author

nitpick, showing the openapi diff without a 2nd deployment makes no sense, it's not valuable to the user and you only encounter it on the first deploy, which is likely from a new users. We should try to minimize the noise for new users especially @coderabbitai please create an issue for us to only show the openapi diff in the sidebar if there's actually a 2nd deployment to compare to, do not assign anyone.

CleanShot 2025-10-06 at 10 39 47@2x

I agree, but I don't really like experience of disappearing and appearing stuff. So I think current experience is good, but if it annoys you so much we can do something else 😄

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Tip

For best results, initiate chat on the files or code changes.

@ogzhanolguncu, I understand your concern about the UX implications of elements appearing and disappearing. That's a valid consideration for maintaining a consistent interface experience.

Since the issue has been created per chronark's request (#4074), the team can discuss the best implementation approach when you get to it. Perhaps there's a middle ground—like showing a disabled or grayed-out state instead of completely hiding it, or using a subtle placeholder message that explains why the diff isn't available yet.

Feel free to adjust the approach in the issue description or close it if you decide the current behavior is preferable after all! 😊

@ogzhanolguncu
Copy link
Contributor Author

CleanShot 2025-10-06 at 10 44 00@2x this is wrong we said we'd have the left one be the live deployment, but here it's not.
edit: actually we didn't say that, we said the right one should be live. But now that I thinka bout it, that makes no sense I'm, interested how my spec changes, so the "from" should be the live deployment, and the "to" should the latest deployment where env == preview

so you basically wanna swap the order for both this details section and OpenAPI spec tab. got it.

@chronark
Copy link
Collaborator

chronark commented Oct 7, 2025

CleanShot 2025-10-06 at 10 44 00@2x this is wrong we said we'd have the left one be the live deployment, but here it's not.
edit: actually we didn't say that, we said the right one should be live. But now that I thinka bout it, that makes no sense I'm, interested how my spec changes, so the "from" should be the live deployment, and the "to" should the latest deployment where env == preview

so you basically wanna swap the order for both this details section and OpenAPI spec tab. got it.

not just swapping but showing the correct one

from = live deployment
to = latest preview

@ogzhanolguncu
Copy link
Contributor Author

Okay, left one will always point to latest "production" and right one will always target the latest "preview". I also found 2 minor stuff and fixed them as well

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 (1)
go/cmd/deploy/main.go (1)

360-372: Environment title-casing improves presentation.

The title-casing transformation correctly formats environment names for display (e.g., "preview" → "Preview"). The implementation is straightforward and appropriate for a CLI tool.

Consider extracting the caser to a package-level variable to avoid recreating it on every invocation:

+var envCaser = cases.Title(language.English)
+
 func printCompletionInfo(deployment *ctrlv1.Deployment, env string) {
 	if deployment == nil || deployment.GetId() == "" {
 		fmt.Printf("✓ Deployment completed\n")
 		return
 	}
 
-	caser := cases.Title(language.English)
-
 	fmt.Println()
 	fmt.Println(CompletionTitle)
 	fmt.Printf("  %s: %s\n", CompletionDeploymentID, deployment.GetId())
 	fmt.Printf("  %s: %s\n", CompletionStatus, CompletionReady)
-	fmt.Printf("  %s: %s\n", CompletionEnvironment, caser.String(env))
+	fmt.Printf("  %s: %s\n", CompletionEnvironment, envCaser.String(env))

This is a micro-optimization and not critical for a CLI tool's performance.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 964b2ec and 9ad3fef.

📒 Files selected for processing (6)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (2 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/deployment-select.tsx (4 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (4 hunks)
  • apps/dashboard/components/virtual-table/index.tsx (1 hunks)
  • go/cmd/deploy/control_plane.go (0 hunks)
  • go/cmd/deploy/main.go (5 hunks)
💤 Files with no reviewable changes (1)
  • go/cmd/deploy/control_plane.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-28T20:38:53.244Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx:322-341
Timestamp: 2025-07-28T20:38:53.244Z
Learning: In apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx, mcstepp prefers to keep hardcoded endpoint logic in the getDiffType function during POC phases for demonstrating diff functionality, rather than implementing a generic diff algorithm. This follows the pattern of keeping simplified implementations for demonstration purposes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx
📚 Learning: 2025-07-25T19:11:00.208Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts:110-147
Timestamp: 2025-07-25T19:11:00.208Z
Learning: In apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts, the user mcstepp prefers to keep mock data fallbacks in POC/demonstration code for simplicity, even if it wouldn't be production-ready. This aligns with the PR being work-in-progress for demonstration purposes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx
🧬 Code graph analysis (4)
apps/dashboard/components/virtual-table/index.tsx (1)
apps/dashboard/components/virtual-table/components/loading-indicator.tsx (1)
  • LoadMoreFooter (19-210)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (2)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (1)
  • StatusIndicator (26-69)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/deployment-select.tsx (1)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (1)
  • PulseIndicator (77-105)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (1)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test
🔇 Additional comments (19)
apps/dashboard/components/virtual-table/index.tsx (1)

393-402: LGTM! Conditional rendering prevents unnecessary component mounting.

The conditional check correctly prevents the LoadMoreFooter from rendering when loadMoreFooterProps is not provided, which fixes the blinking/disappearing UI issue mentioned in the comment. This approach is more efficient than always mounting the component and relying on internal visibility logic or the hide prop.

The pattern of spreading loadMoreFooterProps (for optional configuration) while explicitly passing dynamic values (onLoadMore, isFetchingNextPage, totalVisible, totalCount) is appropriate and allows parent components to customize the footer behavior while the VirtualTable controls the calculated state.

go/cmd/deploy/main.go (3)

12-13: LGTM!

The golang.org/x/text packages are the standard library approach for Unicode-aware text transformations. Appropriate for title-casing environment display names.


279-279: LGTM!

The renaming from deploymentId to deploymentID follows Go naming conventions where initialisms should be fully uppercase. The change is applied consistently across the function.

Also applies to: 285-285, 303-303


314-314: LGTM!

Passing opts.Environment parameterizes the completion display, making it correctly reflect the deployed environment rather than using a default value.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (6)

44-44: LGTM! Correct deployment selection.

The logic correctly identifies the latest preview deployment by excluding the live deployment from the query results. This aligns with the PR objective to show "from=live" and "to=latest preview".


48-48: LGTM! Correct old deployment assignment.

Setting oldDeploymentId to liveDeploymentId is correct for the "from" side of the diff comparison.


54-68: LGTM! Proper handling of single deployment case.

The logic correctly handles the edge case where there's a deployment but no live deployment set, displaying a simplified "current" view instead of a diff comparison.


74-74: LGTM! Correct URL parameter order.

The diff URL construction correctly uses from=${liveDeploymentId}&to=${newDeployment.id}, which aligns with the PR objective to compare from live deployment to latest preview.


80-86: LGTM! Appropriate status indicators.

The left side (from/live deployment) correctly shows the diff status with signal indicator, which provides visual feedback about breaking changes or warnings.


92-92: StatusIndicator default props confirmed
StatusIndicator without explicit props defaults to status="safe" and withSignal=false, rendering a safe icon without pulse. Please confirm this matches the intended UX for the “to/new deployment” indicator.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (4)

62-62: Excellent fix! Deployment order now correct.

This change correctly sets the "from" deployment to the live deployment when no URL parameters are present, addressing the issue raised by chronark in the PR comments. The deployment comparison now properly shows: from=live deployment, to=latest preview.


88-88: LGTM! Simplified deployment labeling.

Using shortenId for deployment labels provides consistency across the UI and simplifies the label generation logic.


174-178: LGTM! Improved loading state spacing.

The padding adjustment from mx-3 mb-3 to px-8 provides better visual consistency with other states.


182-201: LGTM! Enhanced error state UI.

The improved error state with gradient background, icon, and better typography significantly improves the user experience when deployment comparison fails.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/deployment-select.tsx (5)

40-42: LGTM! Clear latest deployment identification.

The logic correctly identifies the latest preview deployment by finding the first deployment that's not the live deployment. This assumes deployments are sorted by createdAt desc, which is confirmed in the query at line 29 of openapi-diff/page.tsx.


44-62: LGTM! Well-structured tooltip logic.

The getTooltipContent helper provides clear, contextual tooltips for different deployment states (disabled, live, latest), improving the user experience.


64-72: LGTM! Helpful trigger title.

The getTriggerTitle helper provides accessible title attributes for the select trigger, indicating whether the selected deployment is live or latest preview.


111-117: LGTM! Clear visual indicators.

The dual PulseIndicator approach effectively distinguishes between live deployments (green pulse) and latest preview deployments (gray pulse), making it easy for users to identify deployment status at a glance.


131-131: LGTM! Accessible trigger title.

Using getTriggerTitle() provides a helpful title attribute that improves accessibility by indicating the deployment type on hover.

@chronark
Copy link
Collaborator

chronark commented Oct 8, 2025

@coderabbitai create an issue to change the display of keyboardshortcuts to be in a tooltip instead
assign @ogzhanolguncu

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for changing keyboard shortcuts to tooltips

gh issue create \
  --title "Change keyboard shortcuts display to use tooltips" \
  --body "## Context
Currently, keyboard shortcuts are displayed using hover-revealed containers. While this reduces visual clutter compared to always-visible shortcuts, we can improve the UX further by using proper tooltips instead.

## Current State
- Keyboard shortcuts are shown on hover using a wrapper div with hover state
- Examples include:
  - Live/pause logs: ⌥+⇧+Q
  - Refresh data: ⌥+⇧+W
  - Clear filters: ⌥+⇧+A
  - Focus filters: ⌥+⇧+S

## Requested Change
Replace the current hover-revealed keyboard shortcut displays with proper tooltip components.

## Benefits
- More consistent with standard UI patterns
- Better accessibility
- Cleaner implementation

## Additional Context
- Requested by: @chronark
- Related PR: #4060
- Comment: ${GITHUB_SERVER_URL:-https://github.com}/unkeyed/unkey/pull/4060#issuecomment-$(date +%s)" \
  --assignee ogzhanolguncu \
  --repo unkeyed/unkey

Length of output: 44


@chronark I've created issue #4086 to track changing the keyboard shortcuts display to use tooltips instead of the current hover-revealed containers, and assigned it to @ogzhanolguncu.

#4086

@mcstepp mcstepp self-assigned this Oct 8, 2025
@mcstepp
Copy link
Collaborator

mcstepp commented Oct 8, 2025

nitpick, showing the openapi diff without a 2nd deployment makes no sense, it's not valuable to the user and you only encounter it on the first deploy, which is likely from a new users. We should try to minimize the noise for new users especially @coderabbitai please create an issue for us to only show the openapi diff in the sidebar if there's actually a 2nd deployment to compare to, do not assign anyone.
CleanShot 2025-10-06 at 10 39 47@2x

I agree, but I don't really like experience of disappearing and appearing stuff. So I think current experience is good, but if it annoys you so much we can do something else 😄

Maybe not hide it completely, but a message about "not enough deployments to show spec diffs" so that the user is aware that the feature is there, they just don't meet the criteria to use it yet.

Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

👍

@mcstepp mcstepp added this pull request to the merge queue Oct 8, 2025
@graphite-app
Copy link

graphite-app bot commented Oct 8, 2025

Ad gif. 1990s clip from an Apple Promo of Brent Rambo looking at a desktop computer nodding and smiling, then looking at us and giving a thumbs up. (Added via Giphy)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Tip

For best results, initiate chat on the files or code changes.

@mcstepp That's a great middle-ground solution! Showing a message like "Not enough deployments to show spec diffs" would:

  • Keep users aware the feature exists
  • Avoid the jarring experience of elements appearing/disappearing
  • Provide clear context about why the diff isn't available yet

I'd recommend adding this suggestion as a comment on issue #4074, so the team can discuss the best implementation approach when they tackle it. This feels like a better UX than completely hiding the section!

@graphite-app
Copy link

graphite-app bot commented Oct 8, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (10/08/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

Merged via the queue into main with commit b8496fc Oct 8, 2025
17 checks passed
@mcstepp mcstepp deleted the ui-improvements-v2 branch October 8, 2025 16:21
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