Skip to content

chore: move control cloud to ui#3398

Merged
MichaelUnkey merged 15 commits intomainfrom
move-control-cloud-to-ui
Jun 30, 2025
Merged

chore: move control cloud to ui#3398
MichaelUnkey merged 15 commits intomainfrom
move-control-cloud-to-ui

Conversation

@MichaelUnkey
Copy link
Collaborator

@MichaelUnkey MichaelUnkey commented Jun 20, 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?

  • Test A
  • Test B

Checklist

Required

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

Appreciated

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

Summary by CodeRabbit

  • New Features

    • Introduced a new filter pill component for displaying and managing active filters with keyboard navigation and accessibility support.
    • Added comprehensive documentation and interactive examples for the new filter pill component.
    • Provided utility functions for handling keyboard shortcuts, time parsing, filter validation, and object merging.
    • Added a utility to transform structured filter output into internal filter formats.
  • Bug Fixes

    • Improved type specificity and consistency in event handling and import statements for UI components.
  • Tests

    • Added extensive unit tests for keyboard shortcut handling and parsing utilities.
  • Chores

    • Updated dependencies to include new required libraries for internal UI functionality.
    • Refactored imports of key UI components to use external package sources for consistency.

@changeset-bot
Copy link

changeset-bot bot commented Jun 20, 2025

⚠️ No Changeset found

Latest commit: 802bb81

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 Jun 20, 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 Jun 30, 2025 6:26pm
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 30, 2025 6:26pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 20, 2025

📝 Walkthrough
## Walkthrough

This change updates multiple files across the application to import the `ControlCloud` component and the `transformStructuredOutputToFilters` utility from the external `@unkey/ui` package instead of local paths. It also introduces new documentation, example, utility, type, and test files to the internal UI package, expanding its filter and keyboard shortcut handling capabilities.

## Changes

| Files/Paths                                                                                           | Change Summary                                                                                                 |
|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| `apps/dashboard/app/(app)/*/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/*/_components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/audit/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/authorization/permissions/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/authorization/roles/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/logs/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/*/logs/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/*/_overview/components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/_components/control-cloud/index.tsx`,<br>`apps/dashboard/app/(app)/settings/root-keys/components/control-cloud/index.tsx` | Changed import source of `ControlCloud` from local to `@unkey/ui`.                                             |
| `apps/dashboard/app/(app)/*/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/*/_components/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/audit/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/authorization/permissions/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/authorization/roles/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/logs/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/*/logs/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/*/_overview/components/controls/components/logs-search/index.tsx`,<br>`apps/dashboard/app/(app)/ratelimits/_components/components/controls/components/logs-search/index.tsx` | Changed import source of `transformStructuredOutputToFilters` from local to `@unkey/ui`.                       |
| `apps/engineering/content/design/components/filter/control-cloud.examples.tsx`                      | Added new example file with multiple exported React components demonstrating `ControlCloud` usage.             |
| `apps/engineering/content/design/components/filter/control-cloud.mdx`                               | Added new documentation file for the `ControlCloud` component, including usage, props, and best practices.     |
| `internal/ui/package.json`                                                                            | Added dependencies: `nuqs@1.17.6` and `zod@3.23.5`; moved `tailwindcss-animate` to devDependencies.            |
| `internal/ui/src/components/logs/control-cloud/control-pill.tsx`,<br>`internal/ui/src/components/logs/control-cloud/index.tsx` | Refactored imports for clarity; improved event typing; added `"use client"` directive.                         |
| `internal/ui/src/index.ts`                                                                            | Added exports for `control-cloud` and `transform-structured-output-filter-format` modules.                     |
| `internal/ui/src/lib/utils.ts`                                                                        | Added utility functions: `isBrowser`, `debounce`, `throttle`, `getTimestampFromRelative`, `processTimeFilters`, `getBaseUrl`, `deepMerge`. |
| `internal/ui/src/hooks/use-keyboard-shortcut.tsx`                                                   | Added new hook for global keyboard shortcut handling and related types/utilities.                              |
| `internal/ui/src/hooks/use-keyboard-shortcut.test.tsx`                                              | Added comprehensive tests for `useKeyboardShortcut` hook and shortcut string parsing.                          |
| `internal/ui/src/validation/filter.types.ts`                                                        | Added new types for filter operators, field configs, filter values, and related Zod schemas.                   |
| `internal/ui/src/validation/utils/nuqs-parsers.ts`                                                  | Added new parsers for relative time, filter value arrays, and sort arrays for URL query handling.              |
| `internal/ui/src/validation/utils/structured-output-schema-generator.ts`                            | Added utilities for generating and validating structured filter output schemas using Zod.                       |
| `internal/ui/src/validation/utils/transform-structured-output-filter-format.ts`                     | Added utility to transform structured output into internal filter format.                                       |
| `internal/ui/src/validation/utils/type-guards.ts`                                                   | Added type guard functions for distinguishing string and number field configs.                                  |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant AppComponent
  participant @unkey/ui
  AppComponent->>@unkey/ui: import { ControlCloud, transformStructuredOutputToFilters }
  AppComponent->>ControlCloud: Render with filters, handlers, formatting props
  AppComponent->>transformStructuredOutputToFilters: Convert structured output to filter format
  Note right of AppComponent: All logic and UI now sourced from @unkey/ui

Possibly related PRs

  • unkeyed/unkey#3369: Introduces RootKeysListControlCloud component using ControlCloud and related filtering logic, sharing code-level connections with this PR's import changes.
  • unkeyed/unkey#2804: The initial implementation of the ControlCloud component and related filter logic, foundational to this PR's component imports.
  • unkeyed/unkey#3289: Consolidates UI component imports to @unkey/ui including KeyboardButton, related to this PR's import refactoring.

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark
  • ogzhanolguncu

</details>

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between ebaa474d3a2c2213b84dc0aa0a0001f93981cfce and 173fa42ebb673169851303a43353caa69f12943c.

</details>

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

* `internal/ui/src/validation/utils/structured-output-schema-generator.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (2)</summary>

<details>
<summary>📓 Common learnings</summary>

Learnt from: ogzhanolguncu
PR: #2825
File: apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-datetime/index.tsx:0-0
Timestamp: 2025-01-30T20:38:00.058Z
Learning: In the logs dashboard, keyboard shortcuts that toggle UI elements (like popovers) should be implemented in the component that owns the state being toggled, not in the presentational wrapper components. For example, the 'T' shortcut for toggling the datetime filter is implemented in DatetimePopover, not in LogsDateTime.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/ui/button.tsx:39-46
Timestamp: 2024-10-23T16:33:02.143Z
Learning: In apps/www/components/ui/ directory, components are based on shadcn UI patterns, including their typing conventions.


Learnt from: ogzhanolguncu
PR: #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.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/search.tsx:16-20
Timestamp: 2024-10-23T16:21:47.395Z
Learning: For the FilterableCommand component in apps/www/components/glossary/search.tsx, refactoring type definitions into an interface is not necessary at this time.


</details>
<details>
<summary>internal/ui/src/validation/utils/structured-output-schema-generator.ts (16)</summary>

Learnt from: MichaelUnkey
PR: #2810
File: internal/ui/src/components/date-time/components/time-split.tsx:10-14
Timestamp: 2025-01-22T16:51:59.978Z
Learning: The DateTime component in internal/ui/src/components/date-time/components/time-split.tsx already includes sufficient validation through handleChange and handleBlur functions, making additional runtime validation unnecessary.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/search.tsx:16-20
Timestamp: 2024-10-23T16:21:47.395Z
Learning: For the FilterableCommand component in apps/www/components/glossary/search.tsx, refactoring type definitions into an interface is not necessary at this time.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/search.tsx:41-57
Timestamp: 2024-10-23T16:19:42.049Z
Learning: For the FilterableCommand component in apps/www/components/glossary/search.tsx, adding error handling and loading states to the results list is not necessary.


Learnt from: ogzhanolguncu
PR: #3401
File: apps/dashboard/app/(app)/logs/filters.query-params.ts:10-0
Timestamp: 2025-06-24T13:29:10.129Z
Learning: The buildQueryParams function in apps/dashboard/app/(app)/logs/filters.query-params.ts calls useFilters() hook inside it, but this is valid because the function is only called from within other React hooks, maintaining the Rules of Hooks compliance.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/terms-rolodex-desktop.tsx:26-37
Timestamp: 2024-10-23T16:20:19.324Z
Learning: When reviewing React components in this project, avoid suggesting manual memoization with useMemo for performance optimizations, as the team prefers to rely on the React compiler to handle such optimizations.


Learnt from: ogzhanolguncu
PR: #3375
File: apps/dashboard/app/(app)/settings/root-keys/components/table/hooks/use-root-keys-list-query.ts:0-0
Timestamp: 2025-06-25T20:32:10.428Z
Learning: In the Unkey codebase, ogzhanolguncu prefers strict validation with fail-fast error handling. When validation errors occur that shouldn't happen in normal operation (like invalid operators), throwing errors to crash the page is preferred over graceful error handling or console logging.


Learnt from: ogzhanolguncu
PR: #2883
File: apps/dashboard/app/(app)/logs/components/controls/components/logs-search/index.tsx:29-31
Timestamp: 2025-02-10T14:12:17.261Z
Learning: In the logs search component's error handling, error messages are deliberately wrapped in single quotes within template literals for visual distinction (e.g. "Unable to process your search request 'some error message'").


Learnt from: chronark
PR: #2143
File: apps/dashboard/app/(app)/logs/components/log-details/components/log-footer.tsx:58-61
Timestamp: 2024-12-03T14:21:19.543Z
Learning: For the "Outcome" field in the LogFooter component (apps/dashboard/app/(app)/logs/components/log-details/components/log-footer.tsx), default to "N/A" instead of "VALID" when handling null values to avoid confusing customers.


Learnt from: mcstepp
PR: #3242
File: apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/controls/components/logs-search/index.tsx:7-43
Timestamp: 2025-05-15T16:09:49.243Z
Learning: For type safety issues involving any type assertions, the team prefers to address these systematically with linter updates rather than fixing them individually in code reviews.


Learnt from: mcstepp
PR: #3242
File: apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx:230-266
Timestamp: 2025-05-15T15:59:20.955Z
Learning: Avoid using any type in TypeScript code as it defeats the purpose of type safety and will cause linter issues in the future. Instead, create proper interfaces or utilize existing type definitions, especially for complex nested objects.


Learnt from: mcstepp
PR: #3242
File: apps/dashboard/app/(app)/apis/[apiId]/api-id-navbar.tsx:47-50
Timestamp: 2025-05-15T15:57:02.128Z
Learning: When reviewing code for Unkey, prefer using Boolean() over the double negation (!!) operator for boolean coercion, as their linter rules favor this pattern.


Learnt from: ogzhanolguncu
PR: #3292
File: apps/dashboard/lib/trpc/routers/key/create.ts:11-14
Timestamp: 2025-06-02T11:09:58.791Z
Learning: In the unkey codebase, TypeScript and the env() function implementation already provide sufficient validation for environment variables, so additional runtime error handling for missing env vars is not needed.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/terms-stepper-mobile.tsx:16-20
Timestamp: 2024-10-23T16:25:33.113Z
Learning: In the apps/www/components/glossary/terms-stepper-mobile.tsx file, avoid suggesting to extract the term navigation logic into a custom hook, as the user prefers to keep the component straightforward.


Learnt from: p6l-richard
PR: #2085
File: apps/www/components/glossary/terms-rolodex-desktop.tsx:39-50
Timestamp: 2024-10-23T16:19:59.657Z
Learning: Debouncing of the scroll handler is not needed yet in the function TermsRolodexDesktop in apps/www/components/glossary/terms-rolodex-desktop.tsx.


Learnt from: ogzhanolguncu
PR: #3156
File: apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/ratelimit-setup.tsx:36-47
Timestamp: 2025-04-22T11:48:39.670Z
Learning: The Unkey dashboard's form validation for numeric values like rate limits is handled through the Zod schema validation (with .positive() validators and additional checks in superRefine), rather than HTML input attributes like min.


Learnt from: ogzhanolguncu
PR: #2825
File: apps/dashboard/lib/trpc/routers/logs/query-distinct-paths.ts:29-36
Timestamp: 2025-01-30T20:46:29.482Z
Learning: The team prefers to implement pagination and other optimizations only when they become necessary, rather than prematurely optimizing. This was demonstrated in the context of unique paths query where a simple LIMIT clause was deemed sufficient until proven otherwise.


</details>

</details>

</details>

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

* GitHub Check: Test Go API Local / Test (Shard 7/8)
* GitHub Check: Test Go API Local / Test (Shard 8/8)
* GitHub Check: Test Go API Local / Test (Shard 6/8)
* GitHub Check: Test Go API Local / Test (Shard 5/8)
* GitHub Check: Test Go API Local / Test (Shard 3/8)
* GitHub Check: Test Go API Local / Test (Shard 2/8)
* GitHub Check: Test Go API Local / Test (Shard 4/8)
* GitHub Check: Test Go API Local / Test (Shard 1/8)
* GitHub Check: Test API / API Test Local
* GitHub Check: Build / Build
* GitHub Check: Test Packages / Test ./packages/rbac
* GitHub Check: Test Packages / Test ./internal/keys
* GitHub Check: Test Packages / Test ./apps/dashboard
* GitHub Check: Test Packages / Test ./internal/hash
* GitHub Check: Test Packages / Test ./internal/encryption
* GitHub Check: Test Packages / Test ./packages/cache
* GitHub Check: Test Packages / Test ./packages/nextjs
* GitHub Check: Test Packages / Test ./internal/billing
* GitHub Check: Test Packages / Test ./packages/hono
* GitHub Check: Test Packages / Test ./internal/id
* GitHub Check: Test Packages / Test ./internal/clickhouse
* GitHub Check: Test Packages / Test ./packages/api
* GitHub Check: Test Packages / Test ./internal/resend
* GitHub Check: autofix
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>internal/ui/src/validation/utils/structured-output-schema-generator.ts (4)</summary>

`1-8`: **LGTM! Clean imports and type definitions.**

The imports are well-organized and the `DataWithValidationResults` interface properly types the validation result caching mechanism.

---

`10-39`: **LGTM! Well-structured validation helper function.**

The `validateSingleFilter` function provides clear, specific error messages and follows a logical validation flow. The use of `String(field)` for safe string conversion is a good defensive programming practice.

---

`41-98`: **Excellent implementation of performance optimization and error handling.**

The implementation successfully addresses several concerns from previous reviews:
- Validation result caching eliminates redundant calls
- Runtime type checks provide additional safety before type assertions
- Specific error messages improve user experience

The code follows best practices with proper separation of validation logic and error handling.

---

`100-119`: **LGTM! Robust field value validation with proper type checking.**

The function correctly uses type guards to validate values based on field configuration and returns `false` for type mismatches, which enforces strict validation as preferred by the team.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


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

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=unkeyed/unkey&utm_content=3398):

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

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

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

### CodeRabbit Configuration File (`.coderabbit.yaml`)

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

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@github-actions
Copy link
Contributor

github-actions bot commented Jun 25, 2025

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

♻️ Duplicate comments (14)
apps/dashboard/app/(app)/apis/[apiId]/_overview/components/control-cloud/index.tsx (1)

2-2: Same import change as noted earlier – see the first comment for the required verifications.

apps/dashboard/app/(app)/audit/components/control-cloud/index.tsx (1)

2-2: Repeats the @unkey/ui import switch; the considerations from the first file apply here as well.

apps/dashboard/app/(app)/authorization/roles/components/control-cloud/index.tsx (1)

2-2: Same import migration; please refer to the initial verification checklist.

apps/dashboard/app/(app)/logs/components/control-cloud/index.tsx (1)

2-2: Import updated to @unkey/ui; identical concerns as previously raised.

apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/control-cloud/index.tsx (1)

2-2: Same import consolidation as earlier comment

Nothing else changed – rely on previous note regarding dependency declaration.

apps/dashboard/app/(app)/apis/_components/control-cloud/index.tsx (1)

2-2: Consistent switch to @unkey/ui

Matches the pattern; no additional remarks beyond the first comment.

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/control-cloud/index.tsx (1)

2-2: Consistent switch to @unkey/ui

Same feedback as earlier: ensure the package is declared in the relevant package.json.

apps/dashboard/app/(app)/ratelimits/_components/control-cloud/index.tsx (1)

2-2: Consistent switch to @unkey/ui

Import path update looks correct. Refer to the initial comment for dependency-presence verification.

apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/controls/components/logs-search/index.tsx (1)

4-4: Same verification needed for Keys Logs-Search

Please run the export check above for this usage path as well to avoid runtime import errors.

apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-search/index.tsx (1)

4-4: Same verification needed for Overview Logs-Search

Import relies on the same re-export. Verify package version and symbol presence.

apps/dashboard/app/(app)/authorization/permissions/components/controls/components/logs-search/index.tsx (1)

4-4: Same consideration as earlier comment about package-root import

See the advice on the first file regarding sub-path imports and leftover references.

apps/dashboard/app/(app)/logs/components/controls/components/logs-search/index.tsx (1)

5-5: Same consideration as earlier comment about package-root import

See the advice on the first file regarding sub-path imports and leftover references.

apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/controls/components/logs-search/index.tsx (1)

4-4: Same consideration as earlier comment about package-root import

See the advice on the first file regarding sub-path imports and leftover references.

apps/dashboard/app/(app)/audit/components/controls/components/logs-search/index.tsx (1)

4-4: Same consideration as earlier comment about package-root import

See the advice on the first file regarding sub-path imports and leftover references.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4841f7a and 347e9a7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • apps/dashboard/app/(app)/apis/[apiId]/_overview/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/apis/_components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/audit/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/audit/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/permissions/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/permissions/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/roles/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/authorization/roles/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/control-cloud/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/controls/components/logs-search/index.tsx (1 hunks)
  • apps/dashboard/app/(app)/ratelimits/_components/control-cloud/index.tsx (1 hunks)
  • apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1 hunks)
  • apps/engineering/content/design/components/filter/control-cloud.mdx (1 hunks)
  • internal/ui/package.json (1 hunks)
  • internal/ui/src/components/logs/control-cloud/control-pill.tsx (2 hunks)
  • internal/ui/src/components/logs/control-cloud/index.tsx (2 hunks)
  • internal/ui/src/hooks/use-keyboard-shortcut.test.tsx (1 hunks)
  • internal/ui/src/hooks/use-keyboard-shortcut.tsx (1 hunks)
  • internal/ui/src/index.ts (1 hunks)
  • internal/ui/src/lib/utils.ts (1 hunks)
  • internal/ui/src/validation/filter.types.ts (1 hunks)
  • internal/ui/src/validation/utils/nuqs-parsers.ts (1 hunks)
  • internal/ui/src/validation/utils/structured-output-schema-generator.ts (1 hunks)
  • internal/ui/src/validation/utils/transform-structured-output-filter-format.ts (1 hunks)
  • internal/ui/src/validation/utils/type-guards.ts (1 hunks)
🧰 Additional context used
🪛 LanguageTool
apps/engineering/content/design/components/filter/control-cloud.mdx

[uncategorized] ~125-~125: Loose punctuation mark.
Context: ...us ## Keyboard Shortcuts - ⌥+⇧+D: Clear all filters and set a default tim...

(UNLIKELY_OPENING_PUNCTUATION)

🔇 Additional comments (25)
apps/dashboard/app/(app)/authorization/permissions/components/control-cloud/index.tsx (1)

2-2: ```shell
#!/bin/bash
set -e

1. Locate the @unkey/ui package.json anywhere in the repo

UI_PKG_JSON=$(fd -e json package.json . | xargs -r rg -l '"name"\s*:\s*"@unkey/ui"')
if [ -z "$UI_PKG_JSON" ]; then
echo "❌ Could not find @unkey/ui package.json in the workspace."
exit 1
fi
echo "✅ Found UI package.json at: $UI_PKG_JSON"
UI_PKG_DIR=$(dirname "$UI_PKG_JSON")
echo "UI package directory: $UI_PKG_DIR"

2. Inspect the public barrel for ControlCloud export

for BARREL in "$UI_PKG_DIR"/src/index.ts "$UI_PKG_DIR"/src/index.tsx; do
if [ -f "$BARREL" ]; then
echo "🔍 Inspecting barrel: $BARREL"
rg -n "export\s+.*ControlCloud" "$BARREL" || echo "⚠️ No ControlCloud export found in $BARREL"
fi
done

3. Verify @unkey/ui is declared in each workspace package.json

echo "🔍 Checking workspace package.json files for @unkey/ui dependency"
fd -e json package.json . | xargs -r rg -n '"@unkey/ui"' || echo "⚠️ @unkey/ui is not declared in at least one package.json"

4. Check tsconfig for any local alias to control-cloud

echo "🔍 Searching tsconfig for '@/components/logs/control-cloud' alias"
rg -n '"@/components/logs/control-cloud"' tsconfig*.json && echo "❌ Local alias found" || echo "✅ No leftover alias"


</details>
<details>
<summary>apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/control-cloud/index.tsx (1)</summary>

`2-2`: Let’s try a simpler check across all package.json files:


```shell
#!/usr/bin/env bash
# Search every package.json for a declaration of @unkey/ui
grep -R '"@unkey\/ui"[[:space:]]*:' -n --include="package.json" .
apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/control-cloud/index.tsx (1)

2-2: Ensure the new package export matches the previous contract

The local implementation was replaced with @unkey/ui.
Please verify that the external package still exports ControlCloud with the same prop signature (especially historicalWindow, filters, updateFilters, removeFilter, formatFieldName). A silent mismatch will compile but break at runtime.

#!/bin/bash
# Confirm that ControlCloud is exported from the package and review its props.
fd --extension ts 'index.ts' $(npm root)/@unkey/ui | xargs -I{} sed -n '1,120p' {}
internal/ui/package.json (1)

29-29: Let’s re-run a comprehensive search for any runtime references to nuqs in the UI package:

#!/bin/bash
# 1. ES6 imports
echo "🔍 Searching for ES6 imports of nuqs..."
rg -n "import.*['\"]nuqs['\"]" internal/ui/src || echo "No ES6 imports found"

# 2. CommonJS requires
echo -e "\n🔍 Searching for CommonJS requires of nuqs..."
rg -n "require\(['\"]nuqs['\"]\)" internal/ui/src || echo "No requires found"

# 3. Any direct references
echo -e "\n🔍 Searching for any other references to nuqs..."
rg -n "nuqs" internal/ui/src || echo "No references found"
apps/dashboard/app/(app)/authorization/roles/components/controls/components/logs-search/index.tsx (1)

4-4: ```bash
#!/bin/bash

1. Search entire repo for definition or references of transformStructuredOutputToFilters

grep -R "transformStructuredOutputToFilters" -n .

2. Check package.json files for @unkey/ui dependency and its version

grep -R ""@unkey/ui"" -n .


</details>
<details>
<summary>apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/controls/components/logs-search/index.tsx (1)</summary>

`4-4`: Let’s verify whether the `@unkey/ui` package exports support deep imports for this util:


```shell
#!/bin/bash
# Show package entry and export mapping
grep -n '"main"' -n internal/ui/package.json || echo "No main field found"
grep -n '"exports"' -n internal/ui/package.json || echo "No exports field found"
apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/controls/components/logs-search/index.tsx (1)

4-4: LGTM: Clean import refactor to external package.

The import source change from local path to @unkey/ui package is consistent with the PR objective to centralize UI components. The function usage on line 25 remains unchanged, maintaining functional compatibility.

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

4-5: LGTM: New exports enable component centralization.

The wildcard exports for control-cloud and transform-structured-output-filter-format properly expose the components and utilities that are being imported by external packages. The placement is consistent with the existing export structure.

internal/ui/src/components/logs/control-cloud/control-pill.tsx (2)

1-9: LGTM: Improved import organization and type safety.

The changes enhance the code quality:

  • Namespace React import with explanatory biome ignore comment is appropriate
  • Relative import path updates align with the new module structure
  • Explicit React hooks imports improve clarity

40-40: LGTM: Enhanced type specificity for event handler.

The type annotation change from generic KeyboardEvent to React.KeyboardEvent<HTMLButtonElement> improves type safety by being more specific about the element type and using React's synthetic event system.

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

1-7: LGTM: Proper client-side component setup and import organization.

The changes follow React best practices:

  • "use client" directive correctly marks this as a client-side component
  • Namespace React import with explanatory biome ignore comment is consistent
  • Relative import path updates properly reflect the new module structure

64-64: LGTM: Improved type safety for keyboard event handling.

The event handler type refinement to React.KeyboardEvent<HTMLDivElement> provides better type safety by specifying the exact element type that will receive the keyboard events, aligning with React's synthetic event system.

internal/ui/src/validation/utils/type-guards.ts (1)

1-9: LGTM: Clean and well-structured type guard implementation.

The type guard functions follow TypeScript best practices:

  • Clear, descriptive function names that convey their purpose
  • Proper type guard syntax using config is Type return type annotation
  • Simple discriminant logic based on the type property
  • Good modular separation in a dedicated utilities file
internal/ui/src/validation/utils/transform-structured-output-filter-format.ts (1)

18-61: Well-implemented filter transformation utility!

The function correctly handles merging and deduplication of filters using an efficient Set-based approach. Good use of TypeScript generics for type safety.

internal/ui/src/hooks/use-keyboard-shortcut.test.tsx (1)

1-493: Excellent test coverage!

Comprehensive test suite covering all major scenarios including edge cases, error conditions, and lifecycle management. Well-structured with clear test descriptions.

apps/engineering/content/design/components/filter/control-cloud.mdx (1)

1-198: Comprehensive documentation!

Well-structured documentation with clear examples, keyboard navigation guide, and accessibility considerations. The formatting is correct throughout.

internal/ui/src/lib/utils.ts (5)

8-25: LGTM!

The isBrowser constant and debounce function are well-implemented with proper type safety and cleanup handling.


27-132: LGTM!

Comprehensive throttle implementation with proper support for leading/trailing edges, cancel, and flush methods. The TypeScript generics are well-structured.


134-159: LGTM!

The relative time parser correctly validates input format and converts time units to milliseconds. Good error messaging with examples.


173-186: LGTM!

Standard implementation for environment-aware base URL detection, commonly used in Next.js applications.


188-215: Consider handling circular references.

The deepMerge function could encounter stack overflow with circular references in the input objects.

Consider adding circular reference detection or documenting this limitation. Would you like me to provide an implementation that handles circular references?

apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1)

1-29: LGTM!

Good setup with local type definitions and helper function for creating mock data. This makes the examples self-contained and easy to understand.

internal/ui/src/validation/utils/nuqs-parsers.ts (2)

5-25: LGTM!

The relative time parser properly leverages the existing validation function and handles errors gracefully.


27-57: LGTM!

Well-implemented generic parser with proper handling of values containing colons using regex split pattern.

internal/ui/src/validation/filter.types.ts (1)

1-62: LGTM!

Well-structured type definitions with good use of generics and composition. The separation between base configs and specialized variants (number/string/sortable) provides excellent flexibility.

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

♻️ Duplicate comments (1)
internal/ui/src/validation/utils/nuqs-parsers.ts (1)

67-96: Consistency issue from previous review has been resolved.

Good improvement! The parseAsSortArray parser now returns an empty array on parse failure (lines 70, 87), which aligns with the behavior of parseAsFilterValueArray. This provides consistent error handling across all parsers.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 347e9a7 and 84dc448.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1 hunks)
  • internal/ui/package.json (2 hunks)
  • internal/ui/src/hooks/use-keyboard-shortcut.tsx (1 hunks)
  • internal/ui/src/lib/utils.ts (1 hunks)
  • internal/ui/src/validation/utils/nuqs-parsers.ts (1 hunks)
  • internal/ui/src/validation/utils/structured-output-schema-generator.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
internal/ui/src/validation/utils/structured-output-schema-generator.ts (2)
internal/ui/src/validation/filter.types.ts (1)
  • FieldConfig (40-42)
internal/ui/src/validation/utils/type-guards.ts (2)
  • isStringConfig (7-9)
  • isNumberConfig (4-6)
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: Test Go API Local / Test (Shard 4/8)
  • GitHub Check: Test Go API Local / Test (Shard 5/8)
  • GitHub Check: Test Go API Local / Test (Shard 7/8)
  • GitHub Check: Test Go API Local / Test (Shard 8/8)
  • GitHub Check: Test Go API Local / Test (Shard 1/8)
  • GitHub Check: Test Go API Local / Test (Shard 3/8)
  • GitHub Check: Test Go API Local / Test (Shard 6/8)
  • GitHub Check: Test Go API Local / Test (Shard 2/8)
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: autofix
🔇 Additional comments (6)
internal/ui/package.json (1)

30-30: LGTM! Dependencies are correctly placed.

The new runtime dependencies nuqs and zod are appropriately added to support the new validation and parsing utilities. Also, tailwindcss-animate has been correctly moved to devDependencies as suggested in the previous review.

Also applies to: 34-34

apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1)

1-272: Well-structured examples with comprehensive coverage!

The examples effectively demonstrate various use cases of the ControlCloud component:

  • Proper TypeScript typing with imported FilterOperator type
  • Cross-platform keyboard shortcut detection
  • Clear demonstration of different filter types and states
  • Interactive example for dynamic filter management
internal/ui/src/validation/utils/nuqs-parsers.ts (4)

1-4: Import statements look appropriate.

The imports are well-organized, bringing in the necessary Parser type, utility function, and type definitions.


5-25: parseAsRelativeTime implementation is solid.

The parser correctly validates relative time strings using the utility function and handles null inputs gracefully. The error handling with try-catch ensures robustness.


29-57: parseAsFilterValueArray parser handles complex cases well.

The use of split(/:(.+)/) with a capturing group is clever - it correctly splits on the first colon only, allowing filter values to contain colons. The operator validation and error handling are appropriate.


59-65: Type definitions are well-structured.

The SortDirection and SortUrlValue types provide good type safety with appropriate constraints using const assertions and generics.

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 84dc448 and a8023b1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (14)
  • GitHub Check: Test Go API Local / Test (Shard 7/8)
  • GitHub Check: Test Go API Local / Test (Shard 8/8)
  • GitHub Check: Test Go API Local / Test (Shard 6/8)
  • GitHub Check: Test Go API Local / Test (Shard 5/8)
  • GitHub Check: Test Go API Local / Test (Shard 3/8)
  • GitHub Check: Test Go API Local / Test (Shard 2/8)
  • GitHub Check: Test Go API Local / Test (Shard 4/8)
  • GitHub Check: Test Go API Local / Test (Shard 1/8)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
  • GitHub Check: Test Packages / Test ./packages/hono
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: autofix
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/engineering/content/design/components/filter/control-cloud.examples.tsx (1)

271-273: Keyboard shortcut implementation looks good.

Great improvement! The platform detection properly addresses the previous review concern about Mac-specific keyboard shortcuts by showing appropriate shortcuts for different platforms.

@mcstepp mcstepp self-assigned this Jun 26, 2025
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: 4

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6471f18 and d040a9c.

📒 Files selected for processing (1)
  • internal/ui/src/validation/utils/structured-output-schema-generator.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-datetime/index.tsx:0-0
Timestamp: 2025-01-30T20:38:00.058Z
Learning: In the logs dashboard, keyboard shortcuts that toggle UI elements (like popovers) should be implemented in the component that owns the state being toggled, not in the presentational wrapper components. For example, the 'T' shortcut for toggling the datetime filter is implemented in DatetimePopover, not in LogsDateTime.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/ui/button.tsx:39-46
Timestamp: 2024-10-23T16:33:02.143Z
Learning: In `apps/www/components/ui/` directory, components are based on shadcn UI patterns, including their typing conventions.
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.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/glossary/search.tsx:16-20
Timestamp: 2024-10-23T16:21:47.395Z
Learning: For the `FilterableCommand` component in `apps/www/components/glossary/search.tsx`, refactoring type definitions into an interface is not necessary at this time.
internal/ui/src/validation/utils/structured-output-schema-generator.ts (4)
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2810
File: internal/ui/src/components/date-time/components/time-split.tsx:10-14
Timestamp: 2025-01-22T16:51:59.978Z
Learning: The DateTime component in internal/ui/src/components/date-time/components/time-split.tsx already includes sufficient validation through handleChange and handleBlur functions, making additional runtime validation unnecessary.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/glossary/search.tsx:16-20
Timestamp: 2024-10-23T16:21:47.395Z
Learning: For the `FilterableCommand` component in `apps/www/components/glossary/search.tsx`, refactoring type definitions into an interface is not necessary at this time.
Learnt from: p6l-richard
PR: unkeyed/unkey#2085
File: apps/www/components/glossary/search.tsx:41-57
Timestamp: 2024-10-23T16:19:42.049Z
Learning: For the `FilterableCommand` component in `apps/www/components/glossary/search.tsx`, adding error handling and loading states to the results list is not necessary.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3401
File: apps/dashboard/app/(app)/logs/filters.query-params.ts:10-0
Timestamp: 2025-06-24T13:29:10.129Z
Learning: The `buildQueryParams` function in `apps/dashboard/app/(app)/logs/filters.query-params.ts` calls `useFilters()` hook inside it, but this is valid because the function is only called from within other React hooks, maintaining the Rules of Hooks compliance.
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: Test Go API Local / Test (Shard 4/8)
  • GitHub Check: Test Go API Local / Test (Shard 7/8)
  • GitHub Check: Test Go API Local / Test (Shard 3/8)
  • GitHub Check: Test Go API Local / Test (Shard 8/8)
  • GitHub Check: Test Go API Local / Test (Shard 6/8)
  • GitHub Check: Test Go API Local / Test (Shard 1/8)
  • GitHub Check: Test Go API Local / Test (Shard 5/8)
  • GitHub Check: Test Go API Local / Test (Shard 2/8)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
  • GitHub Check: Test Packages / Test ./internal/clickhouse
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
internal/ui/src/validation/utils/structured-output-schema-generator.ts (2)

1-3: Imports look appropriate for the functionality.

The imports correctly include Zod for schema validation, type definitions, and type guards needed for the validation logic.


92-111: Good improvement: strict validation with proper type checking.

The validateFieldValue function correctly returns false for type mismatches (line 110), addressing the previous concern about being too permissive. The logic properly handles both string and number configurations with appropriate validation.

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.

👍 good stuff

@MichaelUnkey MichaelUnkey added this pull request to the merge queue Jun 30, 2025
Merged via the queue into main with commit b8772db Jun 30, 2025
29 of 37 checks passed
@MichaelUnkey MichaelUnkey deleted the move-control-cloud-to-ui branch June 30, 2025 18:36
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