diff --git a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.constants.ts b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.constants.ts
index 847b29fd213..4448dfb5f40 100644
--- a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.constants.ts
+++ b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.constants.ts
@@ -6,6 +6,12 @@ export type ScopedAccessTokenPermission =
export const CUSTOM_EXPIRY_VALUE = 'custom'
+/** Warning shown on both entry points that create a classic (account-wide) token. */
+export const CLASSIC_TOKEN_WARNING = {
+ title: 'Access tokens can be used to control your whole account',
+ description: 'Be careful when sharing your tokens',
+} as const
+
export const EXPIRES_AT_OPTIONS = {
hour: { value: 'hour', label: '1 hour' },
day: { value: 'day', label: '1 day' },
diff --git a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.permissions.ts b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.permissions.ts
index 1417df70d0d..5e4586d21b6 100644
--- a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.permissions.ts
+++ b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.permissions.ts
@@ -642,7 +642,7 @@ export const computeOverallRisk = (
): OverallRisk => {
const active = Object.entries(selection).filter(([, mode]) => mode !== 'none')
if (active.length === 0) {
- return { level: 'Minimal', text: 'Minimal — no capabilities', tone: 'default' }
+ return { level: 'Minimal', text: 'Minimal — No capabilities', tone: 'default' }
}
const anyWrite = active.some(([, mode]) => mode === 'readwrite')
@@ -652,10 +652,10 @@ export const computeOverallRisk = (
const scopeWord =
resourceAccess === 'account'
- ? 'account-wide'
+ ? 'Account-wide'
: resourceAccess === 'organization'
- ? 'organization-wide'
- : 'single-project'
+ ? 'Organization-wide'
+ : 'Single-project'
const accessWord = anyWrite ? 'read-write' : 'read-only'
let level: string
diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Classic/ExperimentalTokenDropdown.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Classic/ExperimentalTokenDropdown.tsx
new file mode 100644
index 00000000000..07efe992006
--- /dev/null
+++ b/apps/studio/components/interfaces/Account/AccessTokens/Classic/ExperimentalTokenDropdown.tsx
@@ -0,0 +1,60 @@
+import { ChevronDown } from 'lucide-react'
+import { useState } from 'react'
+import {
+ Button,
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from 'ui'
+
+import { NewTokenDialog } from './NewTokenDialog'
+import { type NewAccessToken } from '@/data/access-tokens/access-tokens-create-mutation'
+
+interface ExperimentalTokenDropdownProps {
+ onCreateToken: (token: NewAccessToken) => void
+}
+
+/**
+ * The chevron half of the "Generate new token" split button: a dropdown whose single
+ * item opens the experimental API (V0 scope) token dialog. Rendered flush against a
+ * `rounded-r-none` primary button.
+ */
+export const ExperimentalTokenDropdown = ({ onCreateToken }: ExperimentalTokenDropdownProps) => {
+ const [visible, setVisible] = useState(false)
+
+ return (
+ <>
+ Generate token for experimental API