fix: improve inlinelink target prop api to be more intuitive#3463
Conversation
…-improve-inlinelink-target-prop-api-to-be-more-intuitive
|
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Skipped Deployments
|
📝 Walkthrough""" WalkthroughThis update refactors the Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant InlineLink
participant Browser
Caller->>InlineLink: Render with anchor attributes (e.g., target, rel)
InlineLink->>Browser: Render <a> with provided attributes
Browser-->>Caller: Opens link in new tab if target="_blank"
Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (2)📓 Common learningspackages/api/src/openapi.d.ts (6)undefined <retrieved_learning> <retrieved_learning> <retrieved_learning> <retrieved_learning> <retrieved_learning> <retrieved_learning> ⏰ 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). (16)
🔇 Additional comments (1)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Thank you for following the naming conventions for pull request titles! 🙏 |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (8)
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/ratelimit-setup.tsx(1 hunks)apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx(1 hunks)apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx(1 hunks)apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx(1 hunks)apps/engineering/content/design/components/inline-link.example.tsx(2 hunks)apps/engineering/content/design/components/inline-link.mdx(3 hunks)internal/ui/src/components/inline-link.tsx(2 hunks)packages/api/src/openapi.d.ts(39 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2697
File: apps/engineering/content/design/components/id.mdx:34-40
Timestamp: 2024-12-04T17:20:37.426Z
Learning: In component documentation files (e.g., `.mdx` files in `apps/engineering/content/design/components/`), Michael prefers to include a `Props` section but prefers to exclude `Accessibility` and `Best Practices` sections.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3425
File: apps/engineering/content/design/components/filter/control-cloud.examples.tsx:73-83
Timestamp: 2025-07-02T14:13:01.711Z
Learning: In apps/engineering/content/design/components/, when the `RenderComponentWithSnippet` component does not render code snippets correctly, use the `customCodeSnippet` prop to manually provide the correct JSX code as a string. This manual approach is necessary due to technical limitations in the automatic rendering mechanism.
apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx (8)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.
Learnt from: AkshayBandi027
PR: unkeyed/unkey#2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: p6l-richard
PR: unkeyed/unkey#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: MichaelUnkey
PR: unkeyed/unkey#3425
File: apps/engineering/content/design/components/filter/control-cloud.examples.tsx:73-83
Timestamp: 2025-07-02T14:13:01.711Z
Learning: In apps/engineering/content/design/components/, when the `RenderComponentWithSnippet` component does not render code snippets correctly, use the `customCodeSnippet` prop to manually provide the correct JSX code as a string. This manual approach is necessary due to technical limitations in the automatic rendering mechanism.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3242
File: apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/components/override-indicator.tsx:50-65
Timestamp: 2025-05-15T16:26:08.666Z
Learning: In the Unkey dashboard, Next.js router (router.push) should be used for client-side navigation instead of window.location.href to preserve client state and enable smoother transitions between pages.
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/ratelimit-setup.tsx (10)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.
Learnt from: chronark
PR: unkeyed/unkey#2544
File: apps/api/src/pkg/env.ts:4-6
Timestamp: 2024-10-23T12:05:31.121Z
Learning: The `cloudflareRatelimiter` type definition in `apps/api/src/pkg/env.ts` should not have its interface changed; it should keep the `limit` method returning `Promise<{ success: boolean }>` without additional error properties.
Learnt from: AkshayBandi027
PR: unkeyed/unkey#2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: chronark
PR: unkeyed/unkey#2294
File: apps/api/src/pkg/keys/service.ts:268-271
Timestamp: 2024-10-20T07:05:55.471Z
Learning: In `apps/api/src/pkg/keys/service.ts`, `ratelimitAsync` is a table relation, not a column selection. When querying, ensure that table relations are included appropriately, not as columns.
Learnt from: chronark
PR: unkeyed/unkey#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: 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: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:32-36
Timestamp: 2025-04-22T17:33:28.162Z
Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2866
File: apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/log-details/components/log-footer.tsx:85-98
Timestamp: 2025-02-05T12:56:44.873Z
Learning: The RequestResponseDetails component in the ratelimit logs UI already handles empty content cases by preventing rendering when content is empty, so no additional empty state handling is needed in the parent components.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3173
File: apps/docs/security/delete-protection.mdx:21-24
Timestamp: 2025-04-22T17:34:04.438Z
Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.
apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx (5)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: AkshayBandi027
PR: unkeyed/unkey#2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.
Learnt from: chronark
PR: unkeyed/unkey#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: ogzhanolguncu
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses `roleId` as the property name for the role identifier, not `id`. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
apps/engineering/content/design/components/inline-link.example.tsx (4)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3425
File: apps/engineering/content/design/components/filter/control-cloud.examples.tsx:73-83
Timestamp: 2025-07-02T14:13:01.711Z
Learning: In apps/engineering/content/design/components/, when the `RenderComponentWithSnippet` component does not render code snippets correctly, use the `customCodeSnippet` prop to manually provide the correct JSX code as a string. This manual approach is necessary due to technical limitations in the automatic rendering mechanism.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2697
File: apps/engineering/content/design/components/id.mdx:34-40
Timestamp: 2024-12-04T17:20:37.426Z
Learning: In component documentation files (e.g., `.mdx` files in `apps/engineering/content/design/components/`), Michael prefers to include a `Props` section but prefers to exclude `Accessibility` and `Best Practices` sections.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3242
File: apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/components/override-indicator.tsx:50-65
Timestamp: 2025-05-15T16:26:08.666Z
Learning: In the Unkey dashboard, Next.js router (router.push) should be used for client-side navigation instead of window.location.href to preserve client state and enable smoother transitions between pages.
apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx (4)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3072
File: apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx:58-60
Timestamp: 2025-04-14T13:13:13.421Z
Learning: The IP address validation for the UpdateIpWhitelist component is handled in the TRPC route on the server side, not in the client-side component.
Learnt from: AkshayBandi027
PR: unkeyed/unkey#2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In `authorization/roles/[roleId]/update-role.tsx`, the tag `role-${role.id}` is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/components/ui/group-button.tsx:21-31
Timestamp: 2024-12-03T14:07:45.173Z
Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.
apps/engineering/content/design/components/inline-link.mdx (3)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2697
File: apps/engineering/content/design/components/id.mdx:34-40
Timestamp: 2024-12-04T17:20:37.426Z
Learning: In component documentation files (e.g., `.mdx` files in `apps/engineering/content/design/components/`), Michael prefers to include a `Props` section but prefers to exclude `Accessibility` and `Best Practices` sections.
Learnt from: MichaelUnkey
PR: unkeyed/unkey#3425
File: apps/engineering/content/design/components/filter/control-cloud.examples.tsx:73-83
Timestamp: 2025-07-02T14:13:01.711Z
Learning: In apps/engineering/content/design/components/, when the `RenderComponentWithSnippet` component does not render code snippets correctly, use the `customCodeSnippet` prop to manually provide the correct JSX code as a string. This manual approach is necessary due to technical limitations in the automatic rendering mechanism.
internal/ui/src/components/inline-link.tsx (2)
Learnt from: chronark
PR: unkeyed/unkey#3324
File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27
Timestamp: 2025-07-03T11:57:15.263Z
Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.
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.
packages/api/src/openapi.d.ts (20)
undefined
<retrieved_learning>
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #2693
File: apps/api/src/routes/v1_keys_updateKey.ts:350-368
Timestamp: 2024-11-29T15:15:47.308Z
Learning: In apps/api/src/routes/v1_keys_updateKey.ts, the code intentionally handles externalId and ownerId separately for clarity. The ownerId field will be removed in the future, simplifying the code.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For destructive operations like deletion in the Unkey API, oneOf validation is preferred over anyOf to enforce explicit targeting and prevent ambiguity.
</retrieved_learning>
<retrieved_learning>
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.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #2544
File: apps/api/src/pkg/env.ts:4-6
Timestamp: 2024-10-23T12:05:31.121Z
Learning: The cloudflareRatelimiter type definition in apps/api/src/pkg/env.ts should not have its interface changed; it should keep the limit method returning Promise<{ success: boolean }> without additional error properties.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #2294
File: apps/api/src/pkg/keys/service.ts:268-271
Timestamp: 2024-10-20T07:05:55.471Z
Learning: In apps/api/src/pkg/keys/service.ts, ratelimitAsync is a table relation, not a column selection. When querying, ensure that table relations are included appropriately, not as columns.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #2544
File: apps/api/src/pkg/ratelimit/client.ts:83-83
Timestamp: 2024-10-23T12:04:12.530Z
Learning: In the metrics.emit call, it's acceptable to set mode to "cloudflare" when using Cloudflare's rate limiter.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.
</retrieved_learning>
<retrieved_learning>
Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #3324
File: apps/dashboard/app/(app)/authorization/roles/components/table/components/actions/keys-table-action.popover.constants.tsx:17-18
Timestamp: 2025-06-19T11:48:05.070Z
Learning: In the authorization roles refactor, the RoleBasic type uses roleId as the property name for the role identifier, not id. This is consistent throughout the codebase in apps/dashboard/lib/trpc/routers/authorization/roles/query.ts.
</retrieved_learning>
<retrieved_learning>
Learnt from: AkshayBandi027
PR: #2215
File: apps/dashboard/app/(app)/@breadcrumb/authorization/roles/[roleId]/page.tsx:28-29
Timestamp: 2024-10-08T15:33:04.290Z
Learning: In authorization/roles/[roleId]/update-role.tsx, the tag role-${role.id} is revalidated after updating a role to ensure that the caching mechanism is properly handled for roles.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For identity deletion operations in the Unkey API, identityId takes precedence over externalId when both are provided in the request body.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #3315
File: apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/general-setup.tsx:40-50
Timestamp: 2025-06-19T13:01:55.338Z
Learning: In the create-key form's GeneralSetup component, the Controller is intentionally bound to "identityId" as the primary field while "externalId" is set explicitly via setValue. The ExternalIdField component has been designed to handle this pattern where it receives identityId as its value prop but manages both identityId and externalId through its onChange callback.
</retrieved_learning>
<retrieved_learning>
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.
</retrieved_learning>
<retrieved_learning>
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.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #2866
File: apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/control-cloud/index.tsx:13-30
Timestamp: 2025-02-05T11:49:04.098Z
Learning: In the ratelimits logs context, "requestId" is used for single request IDs, while "requestIds" is used when dealing with multiple request IDs.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #2825
File: apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts:49-58
Timestamp: 2025-01-30T20:43:19.720Z
Learning: Status code validation is handled at the ClickHouse query level rather than in the schema, as invalid status codes will cause query failures that are caught by TRPC error handling.
</retrieved_learning>
🔇 Additional comments (13)
apps/dashboard/app/(app)/apis/[apiId]/settings/components/delete-protection.tsx (1)
144-145: Excellent API improvement for external link handling.The explicit
target="_blank"andrel="noopener noreferrer"attributes make the component's behavior clear and follow web security best practices for external links.apps/dashboard/app/(app)/apis/[apiId]/settings/components/update-ip-whitelist.tsx (1)
78-79: Consistent API improvement applied correctly.The explicit anchor attributes improve clarity and maintain security best practices for external documentation links.
apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx (1)
24-25: Consistent implementation of improved InlineLink API.The explicit target and rel attributes enhance API clarity and follow security best practices for external links.
apps/dashboard/app/(app)/apis/[apiId]/_components/create-key/components/ratelimit-setup.tsx (1)
169-170: Proper implementation of explicit link attributes.The change correctly applies the improved InlineLink API with explicit target and security attributes for the external documentation link.
apps/engineering/content/design/components/inline-link.example.tsx (1)
62-62: Documentation correctly updated to reflect new API.The example properly demonstrates the updated InlineLink API using explicit
target="_blank"instead of the boolean prop, ensuring documentation stays in sync with implementation.Also applies to: 73-73
internal/ui/src/components/inline-link.tsx (2)
5-27: Excellent API improvement - more intuitive and flexible.The change from a custom boolean
targetprop to extendingReact.AnchorHTMLAttributes<HTMLAnchorElement>is a significant improvement that makes the component more intuitive and follows standard HTML patterns. This gives developers full control over all anchor attributes while maintaining type safety.
37-37: Clean implementation of prop spreading.The use of
{...props}correctly forwards all anchor attributes to the underlying element, which is the standard React pattern for this type of component composition.apps/engineering/content/design/components/inline-link.mdx (5)
10-10: Accurate description of the enhanced component.The updated description correctly explains that the component now extends all standard HTML anchor element attributes, which accurately reflects the implementation changes.
52-52: Correct update to make label optional.This change accurately reflects that the
labelprop is now optional in the component interface, which provides more flexibility for developers.
56-56: Excellent addition of anchor attributes documentation.The addition of the
...propsrow in the props table clearly documents that all standard HTML anchor element attributes are supported, which is essential for developers to understand the full API.
66-66: Good addition of security guidance.Adding security attributes to the accessibility section is appropriate and helps developers understand best practices for external links.
42-43: Clarify that these are not automatic defaults.The wording suggests these attributes are automatically applied by default, which is misleading. The component no longer automatically sets these attributes - they must be explicitly provided by the developer.
Consider updating the text to be more accurate:
- Target attribute for new tab opening (defaults to "_blank") - Security attributes (rel="noopener noreferrer" by default) + Target attribute support for new tab opening + Security attributes support (recommend using rel="noopener noreferrer" for external links)⛔ Skipped due to learnings
Learnt from: chronark PR: unkeyed/unkey#3324 File: apps/dashboard/app/(app)/authorization/roles/components/upsert-role/components/warning-callout.tsx:22-27 Timestamp: 2025-07-03T11:57:15.263Z Learning: The `target` prop on `InlineLink` components in the @unkey/ui package is a boolean prop, not a string. When `target` is truthy, it automatically sets `target="_blank"` and `rel="noopener noreferrer"` on the underlying anchor element. Using just `target` (equivalent to `target={true}`) is the correct way to make the link open in a new tab.Learnt from: ogzhanolguncu PR: unkeyed/unkey#2143 File: apps/dashboard/components/ui/group-button.tsx:21-31 Timestamp: 2024-12-03T14:07:45.173Z Learning: In the `ButtonGroup` component (`apps/dashboard/components/ui/group-button.tsx`), avoid suggesting the use of `role="group"` in ARIA attributes.Learnt from: MichaelUnkey PR: unkeyed/unkey#3173 File: apps/docs/security/delete-protection.mdx:32-36 Timestamp: 2025-04-22T17:33:28.162Z Learning: In the Unkey dashboard UI for delete protection, the button/link to initiate the process is labeled "Disable Delete Protection" while the confirmation button is labeled "Disable API Delete Protection". The documentation should maintain these different labels to match the actual UI.Learnt from: MichaelUnkey PR: unkeyed/unkey#3173 File: apps/docs/security/delete-protection.mdx:21-24 Timestamp: 2025-04-22T17:34:04.438Z Learning: In the Unkey dashboard UI for enabling delete protection, the button/link to initiate the process is labeled "Enable Delete Protection" while the confirmation button is labeled "Enable API Delete Protection". The documentation should maintain these different labels to match the actual UI.packages/api/src/openapi.d.ts (1)
6-11: Avoid hand-editing generated filesThis file carries the “auto-generated” banner and will be overwritten the next time
openapi-typescriptruns. Any manual tweaks—such as the refactor ofXOR,OneOf, or formatting clean-ups—will silently disappear and create merge churn.
Move the underlying changes to the OpenAPI source (YAML/JSON) or to the generator’s configuration instead.
perkinsjr
left a comment
There was a problem hiding this comment.
Nice.
Good use of AnchorHTMLAttributes
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
How should this be tested?
Docs are changed to match
Links in dashboard still work
Changes are acceptable
Required
pnpm buildpnpm fmtconsole.logsgit pull origin mainAppreciated
Summary by CodeRabbit
Bug Fixes
target="_blank"andrel="noopener noreferrer"attributes.Documentation
Refactor
targethandling for greater flexibility.Style