diff --git a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.test.ts b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.test.ts deleted file mode 100644 index c8b58c4fad9..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import { PermissionRowSchema, TokenSchema } from './AccessToken.schemas' - -const validTokenData = { - tokenName: 'My Token', - expiresAt: 'day', - resourceAccess: 'all-orgs' as const, - permissionRows: [{ resource: 'organization:billing', actions: ['read'] }], -} - -// --- PermissionRowSchema --- - -describe('PermissionRowSchema', () => { - it('should pass for a valid permission row', () => { - const result = PermissionRowSchema.safeParse({ - resource: 'organization:billing', - actions: ['read'], - }) - expect(result.success).toBe(true) - }) - - it('should fail when resource is empty', () => { - const result = PermissionRowSchema.safeParse({ - resource: '', - actions: ['read'], - }) - expect(result.success).toBe(false) - if (!result.success) { - expect(result.error.issues[0].message).toBe('Please select a resource') - } - }) - - it('should fail when actions is empty', () => { - const result = PermissionRowSchema.safeParse({ - resource: 'organization:billing', - actions: [], - }) - expect(result.success).toBe(false) - if (!result.success) { - expect(result.error.issues[0].message).toBe('Please select at least one action') - } - }) - - it('should fail when resource is missing', () => { - const result = PermissionRowSchema.safeParse({ actions: ['read'] }) - expect(result.success).toBe(false) - }) - - it('should fail when actions is missing', () => { - const result = PermissionRowSchema.safeParse({ resource: 'organization:billing' }) - expect(result.success).toBe(false) - }) -}) - -// --- TokenSchema --- - -describe('TokenSchema', () => { - it('should pass for valid token data', () => { - const result = TokenSchema.safeParse(validTokenData) - expect(result.success).toBe(true) - }) - - it('should fail when tokenName is empty', () => { - const result = TokenSchema.safeParse({ ...validTokenData, tokenName: '' }) - expect(result.success).toBe(false) - if (!result.success) { - const nameError = result.error.issues.find((i) => i.path.includes('tokenName')) - expect(nameError?.message).toBe('Please enter a name for the token') - } - }) - - it('should fail when tokenName is missing', () => { - const { tokenName, ...rest } = validTokenData - const result = TokenSchema.safeParse(rest) - expect(result.success).toBe(false) - }) - - it('should fail when permissionRows is empty', () => { - const result = TokenSchema.safeParse({ ...validTokenData, permissionRows: [] }) - expect(result.success).toBe(false) - if (!result.success) { - const permError = result.error.issues.find((i) => i.path.includes('permissionRows')) - expect(permError?.message).toBe('Please configure at least one permission') - } - }) - - it('should fail when resourceAccess is not a valid enum value', () => { - const result = TokenSchema.safeParse({ ...validTokenData, resourceAccess: 'invalid' }) - expect(result.success).toBe(false) - }) - - it('should accept all valid resourceAccess enum values', () => { - for (const value of ['all-orgs', 'selected-orgs', 'selected-projects'] as const) { - const result = TokenSchema.safeParse({ ...validTokenData, resourceAccess: value }) - expect(result.success).toBe(true) - } - }) - - describe('expiresAt preprocessing', () => { - it('should convert "never" to undefined', () => { - const result = TokenSchema.safeParse({ ...validTokenData, expiresAt: 'never' }) - expect(result.success).toBe(true) - if (result.success) { - expect(result.data.expiresAt).toBeUndefined() - } - }) - - it('should pass through other string values', () => { - const result = TokenSchema.safeParse({ ...validTokenData, expiresAt: 'day' }) - expect(result.success).toBe(true) - if (result.success) { - expect(result.data.expiresAt).toBe('day') - } - }) - - it('should allow expiresAt to be omitted', () => { - const { expiresAt, ...rest } = validTokenData - const result = TokenSchema.safeParse(rest) - expect(result.success).toBe(true) - }) - }) - - describe('custom expiry refinement', () => { - it('should fail when expiresAt is "custom" and customExpiryDate is not provided', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - expiresAt: 'custom', - customExpiryDate: undefined, - }) - expect(result.success).toBe(false) - if (!result.success) { - const customError = result.error.issues.find((i) => i.path.includes('expiresAt')) - expect(customError?.message).toBe('Please select a custom expiry date') - } - }) - - it('should fail when expiresAt is "custom" and customExpiryDate is empty string', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - expiresAt: 'custom', - customExpiryDate: '', - }) - expect(result.success).toBe(false) - }) - - it('should pass when expiresAt is "custom" and customExpiryDate is provided', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - expiresAt: 'custom', - customExpiryDate: '2026-12-31T00:00:00Z', - }) - expect(result.success).toBe(true) - }) - - it('should pass when expiresAt is not "custom" even without customExpiryDate', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - expiresAt: 'day', - }) - expect(result.success).toBe(true) - }) - }) - - describe('nested permissionRows validation', () => { - it('should fail when a permission row has an empty resource', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - permissionRows: [{ resource: '', actions: ['read'] }], - }) - expect(result.success).toBe(false) - }) - - it('should fail when a permission row has empty actions', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - permissionRows: [{ resource: 'organization:billing', actions: [] }], - }) - expect(result.success).toBe(false) - }) - - it('should pass with multiple valid permission rows', () => { - const result = TokenSchema.safeParse({ - ...validTokenData, - permissionRows: [ - { resource: 'organization:billing', actions: ['read'] }, - { resource: 'organization:members', actions: ['read', 'write'] }, - ], - }) - expect(result.success).toBe(true) - }) - }) -}) diff --git a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.ts b/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.ts deleted file mode 100644 index da0604f0633..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/AccessToken.schemas.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { z } from 'zod' - -export const PermissionRowSchema = z.object({ - resource: z.string().min(1, 'Please select a resource'), - actions: z.array(z.string()).min(1, 'Please select at least one action'), -}) - -export const TokenSchema = z - .object({ - tokenName: z.string().min(1, 'Please enter a name for the token'), - expiresAt: z.preprocess((val) => (val === 'never' ? undefined : val), z.string().optional()), - customExpiryDate: z.string().optional(), - resourceAccess: z.enum(['all-orgs', 'selected-orgs', 'selected-projects']), - selectedOrganizations: z.array(z.string()).optional(), - selectedProjects: z.array(z.string()).optional(), - permissionRows: z.array(PermissionRowSchema).min(1, 'Please configure at least one permission'), - }) - .refine((data) => !(data.expiresAt === 'custom' && !data.customExpiryDate), { - message: 'Please select a custom expiry date', - path: ['expiresAt'], - }) - -export type TokenFormValues = z.infer diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx deleted file mode 100644 index 79955c9ebce..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Key, Plus } from 'lucide-react' -import { - Button, - Checkbox, - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - Popover, - PopoverContent, - PopoverTrigger, -} from 'ui' - -import { PermissionResourceSelectorProps, PermissionRow } from './Permissions.types' -import { ACCESS_TOKEN_RESOURCES } from '@/components/interfaces/Account/AccessTokens/AccessToken.constants' - -export const PermissionResourceSelector = ({ - open, - onOpenChange, - onResourceToggled, - permissionRows, - align = 'center', -}: PermissionResourceSelectorProps) => { - return ( - - - - - - - - - No resources found. - - -
- {ACCESS_TOKEN_RESOURCES.map((resource) => { - const isChecked = permissionRows.some( - (row: PermissionRow) => row.resource === resource.resource - ) - return ( - onResourceToggled(resource)} - className="text-foreground" - > -
- onResourceToggled(resource)} - onClick={(e) => e.stopPropagation()} - /> - -
- - {resource.title} - -
-
-
- ) - })} -
-
-
-
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.tsx deleted file mode 100644 index 1860d289d08..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { ChevronDown, RotateCcw, X } from 'lucide-react' -import { useFieldArray, useFormState } from 'react-hook-form' -import { - Button, - Checkbox, - FormControl, - FormField, - FormMessage, - Popover, - PopoverContent, - PopoverTrigger, - WarningIcon, -} from 'ui' - -import { TokenFormValues } from '../../../AccessToken.schemas' -import { PermissionResourceSelector } from './PermissionResourceSelector' -import { PermissionsProps } from './Permissions.types' -import { sortActions } from './Permissions.utils' -import { ACCESS_TOKEN_RESOURCES } from '@/components/interfaces/Account/AccessTokens/AccessToken.constants' -import { formatAccessText } from '@/components/interfaces/Account/AccessTokens/AccessToken.utils' -import { ButtonTooltip } from '@/components/ui/ButtonTooltip' - -export const Permissions = ({ - control, - resourceSearchOpen, - setResourceSearchOpen, -}: PermissionsProps) => { - const { - fields: permissionRows, - append, - remove, - } = useFieldArray({ - name: 'permissionRows', - control, - }) - const { errors } = useFormState({ control, name: 'permissionRows' }) - - return ( -
-
-
- Configure permissions -
- {permissionRows.length > 0 && ( - remove()} - icon={} - tooltip={{ - content: { - side: 'top', - align: 'center', - alignOffset: -10, - text: 'Reset all permissions', - }, - }} - /> - )} - { - const index = permissionRows.findIndex((p) => p.resource === resource.resource) - if (index > -1) { - return remove(index) - } - append(resource) - }} - align="end" - /> -
-
- - {permissionRows.length === 0 ? ( -
-

No permissions configured yet.

-
- ) : ( -
- {permissionRows.map((row, index) => { - const selectedResource = ACCESS_TOKEN_RESOURCES.find( - (r) => r.resource === row.resource - ) - return ( - { - const fieldValue = field.value || [] - - return ( -
-
-
-
-
- - {selectedResource?.title} - -
-
-
-
- {selectedResource && ( - - - - - - - -
- {sortActions(selectedResource.actions).map((action) => ( - - ))} -
-
-
- )} -
-
-
- -
- {index < permissionRows.length - 1 && ( -
- )} -
- ) - }} - /> - ) - })} -
- )} -
- -
- - - Once you've set these permissions, you cannot edit them. - -
- {errors.permissionRows?.message || errors.permissionRows?.root?.message ? ( -

- {errors.permissionRows?.message || errors.permissionRows?.root?.message} -

- ) : null} -
- ) -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.types.ts b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.types.ts deleted file mode 100644 index 8b3c4a5d439..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.types.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Control, FieldValues } from 'react-hook-form' - -import { TokenFormValues } from '../../../AccessToken.schemas' - -export interface PermissionResource { - resource: string - title: string - actions: string[] -} - -export interface PermissionRow { - resource: string - actions: string[] -} - -export interface PermissionsFormValues extends FieldValues { - permissionRows?: PermissionRow[] -} - -export interface PermissionsProps { - control: Control - resourceSearchOpen: boolean - setResourceSearchOpen: (open: boolean) => void -} - -export interface PermissionResourceSelectorProps { - open: boolean - onOpenChange: (open: boolean) => void - permissionRows: PermissionRow[] - onResourceToggled: (resource: PermissionResource) => void - align?: 'center' | 'end' | 'start' -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.test.ts b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.test.ts deleted file mode 100644 index 35c1cd4b384..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import type { PermissionResource, PermissionRow } from './Permissions.types' -import { sortActions, togglePermissionResource } from './Permissions.utils' - -// --- sortActions --- - -describe('sortActions', () => { - it('should sort actions by priority order: read, write, create, delete', () => { - expect(sortActions(['delete', 'create', 'write', 'read'])).toEqual([ - 'read', - 'write', - 'create', - 'delete', - ]) - }) - - it('should return empty array for empty input', () => { - expect(sortActions([])).toEqual([]) - }) - - it('should keep a single action as-is', () => { - expect(sortActions(['write'])).toEqual(['write']) - }) - - it('should place unknown actions after the priority ones', () => { - expect(sortActions(['custom-action', 'read', 'delete'])).toEqual([ - 'read', - 'delete', - 'custom-action', - ]) - }) - - it('should preserve relative order of multiple unknown actions', () => { - expect(sortActions(['zeta', 'alpha', 'read'])).toEqual(['read', 'zeta', 'alpha']) - }) - - it('should handle only unknown actions', () => { - expect(sortActions(['foo', 'bar'])).toEqual(['foo', 'bar']) - }) - - it('should handle a subset of priority actions', () => { - expect(sortActions(['delete', 'read'])).toEqual(['read', 'delete']) - }) - - it('should not mutate the original array', () => { - const original = ['delete', 'read'] - sortActions(original) - expect(original).toEqual(['delete', 'read']) - }) -}) - -// --- togglePermissionResource --- - -describe('togglePermissionResource', () => { - const billingResource: PermissionResource = { - resource: 'organization:billing', - title: 'Billing', - actions: ['read', 'write'], - } - - const membersResource: PermissionResource = { - resource: 'organization:members', - title: 'Members', - actions: ['read', 'write', 'create', 'delete'], - } - - const storageResource: PermissionResource = { - resource: 'project:storage', - title: 'Storage', - actions: ['write', 'create'], - } - - it('should add a resource with "read" as the default action when available', () => { - const result = togglePermissionResource([], billingResource) - expect(result).toEqual([{ resource: 'organization:billing', actions: ['read'] }]) - }) - - it('should add a resource with the first action as default when "read" is not available', () => { - const result = togglePermissionResource([], storageResource) - expect(result).toEqual([{ resource: 'project:storage', actions: ['write'] }]) - }) - - it('should remove a resource if it is already in the list', () => { - const existing: PermissionRow[] = [ - { resource: 'organization:billing', actions: ['read'] }, - { resource: 'organization:members', actions: ['read', 'write'] }, - ] - const result = togglePermissionResource(existing, billingResource) - expect(result).toEqual([{ resource: 'organization:members', actions: ['read', 'write'] }]) - }) - - it('should not modify other rows when removing a resource', () => { - const existing: PermissionRow[] = [ - { resource: 'organization:billing', actions: ['read'] }, - { resource: 'organization:members', actions: ['read', 'write'] }, - ] - const result = togglePermissionResource(existing, billingResource) - expect(result).toHaveLength(1) - expect(result[0]).toEqual({ resource: 'organization:members', actions: ['read', 'write'] }) - }) - - it('should append to existing rows when adding', () => { - const existing: PermissionRow[] = [{ resource: 'organization:billing', actions: ['read'] }] - const result = togglePermissionResource(existing, membersResource) - expect(result).toHaveLength(2) - expect(result[1]).toEqual({ resource: 'organization:members', actions: ['read'] }) - }) - - it('should not mutate the original array', () => { - const existing: PermissionRow[] = [{ resource: 'organization:billing', actions: ['read'] }] - const original = [...existing] - togglePermissionResource(existing, membersResource) - expect(existing).toEqual(original) - }) - - it('should toggle off then on again correctly', () => { - const step1 = togglePermissionResource([], billingResource) - expect(step1).toHaveLength(1) - - const step2 = togglePermissionResource(step1, billingResource) - expect(step2).toHaveLength(0) - - const step3 = togglePermissionResource(step2, billingResource) - expect(step3).toHaveLength(1) - expect(step3[0]).toEqual({ resource: 'organization:billing', actions: ['read'] }) - }) -}) diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.ts b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.ts deleted file mode 100644 index cb7547ee431..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/Permissions.utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { PermissionResource, PermissionRow } from './Permissions.types' - -export const sortActions = (actions: string[]): string[] => { - const sorted: string[] = [] - const remaining = [...actions] - const priority = ['read', 'write', 'create', 'delete'] - - for (const action of priority) { - const index = remaining.indexOf(action) - if (index !== -1) { - sorted.push(action) - remaining.splice(index, 1) - } - } - - sorted.push(...remaining) - return sorted -} - -export const togglePermissionResource = ( - permissionRows: PermissionRow[], - resource: PermissionResource -): PermissionRow[] => { - const isAlreadyAdded = permissionRows.some((row) => row.resource === resource.resource) - - if (isAlreadyAdded) { - return permissionRows.filter((row) => row.resource !== resource.resource) - } - - const defaultActions = resource.actions.includes('read') ? ['read'] : [resource.actions[0]] - return [...permissionRows, { resource: resource.resource, actions: defaultActions }] -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.tsx deleted file mode 100644 index f14184a9b72..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { FormControl, FormField } from 'ui' -import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' - -import { ResourceAccessProps } from './ResourceAccess.types' -import { ResourceMultiSelector } from './ResourceMultiSelector' -import { ResourceOption } from './ResourceOption' -import { useOrgAndProjectData } from '@/components/interfaces/Account/AccessTokens/hooks/useOrgAndProjectData' -import { useProfile } from '@/lib/profile' - -const RESOURCE_OPTIONS = [ - { - value: 'all-orgs' as const, - label: 'Everything', - description: 'Access to all projects across all organizations you have access to.', - }, - { - value: 'selected-orgs' as const, - label: 'Selected orgs', - description: 'Access only to the organizations you have specified.', - }, - { - value: 'selected-projects' as const, - label: 'Selected projects', - description: 'Access only to the projects you have specified.', - }, -] - -export const ResourceAccess = ({ control, resourceAccess, setValue }: ResourceAccessProps) => { - const { profile } = useProfile() - - const { organizations, projects, isLoadingOrgs, isLoadingProjects } = useOrgAndProjectData({ - enabled: !!profile, - }) - - const handleResourceAccessChange = (newValue: string, currentValue: string) => { - if (newValue !== currentValue) { - setValue('selectedOrganizations', []) - setValue('selectedProjects', []) - } - } - - return ( -
- ( - - -
-
- Resource access level - {RESOURCE_OPTIONS.map((option) => ( - { - handleResourceAccessChange(option.value, field.value) - field.onChange(option.value) - }} - /> - ))} -
- -

- {RESOURCE_OPTIONS.find((opt) => opt.value === field.value)?.description} -

-
-
-
- )} - /> - - {resourceAccess === 'selected-orgs' && ( - ( - ({ id: org.slug, name: org.name }))} - isLoading={isLoadingOrgs} - fieldName="selectedOrganizations" - label="Select organizations" - loadingMessage="Loading organizations..." - emptyMessage="No organizations available" - /> - )} - /> - )} - - {resourceAccess === 'selected-projects' && ( - ( - ({ id: project.ref, name: project.name }))} - isLoading={isLoadingProjects} - fieldName="selectedProjects" - label="Select projects" - loadingMessage="Loading projects..." - emptyMessage="No projects available" - /> - )} - /> - )} -
- ) -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.types.ts b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.types.ts deleted file mode 100644 index 24164866752..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.types.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Control, ControllerRenderProps, UseFormSetValue } from 'react-hook-form' - -import { TokenFormValues } from '@/components/interfaces/Account/AccessTokens/AccessToken.schemas' - -export interface ResourceAccessProps { - control: Control - resourceAccess: string - setValue: UseFormSetValue -} - -export interface ResourceItem { - id: string - name: string -} - -export interface ResourceMultiSelectorProps { - field: ControllerRenderProps - items: ResourceItem[] - isLoading: boolean - fieldName: string - label: string - loadingMessage: string - emptyMessage: string -} - -export interface ResourceOptionProps { - value: string - label: string - isSelected: boolean - onChange: () => void -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceMultiSelector.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceMultiSelector.tsx deleted file mode 100644 index dc9fb0b07f4..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceMultiSelector.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useMemo } from 'react' -import { FormControl } from 'ui' -import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' -import { - MultiSelector, - MultiSelectorContent, - MultiSelectorItem, - MultiSelectorList, - MultiSelectorTrigger, -} from 'ui-patterns/multi-select' - -import { ResourceMultiSelectorProps } from './ResourceAccess.types' - -export const ResourceMultiSelector = ({ - field, - items, - isLoading, - fieldName, - label, - loadingMessage, - emptyMessage, -}: ResourceMultiSelectorProps) => { - const idToName = useMemo(() => new Map(items.map((item) => [item.id, item.name])), [items]) - - const displayValues = (field.value || []).map((id: string) => idToName.get(id) || id) - - const handleValuesChange = (names: string[]) => { - const ids = names - .map((name) => { - for (const [id, itemName] of idToName.entries()) { - if (itemName === name) return id - } - return name - }) - .filter(Boolean) - field.onChange(ids) - } - - return ( - - - - - - {isLoading ? ( -
{loadingMessage}
- ) : items.length === 0 ? ( -
{emptyMessage}
- ) : ( - - {items.map((item) => ( - - {item.name} - - ))} - - )} -
-
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceOption.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceOption.tsx deleted file mode 100644 index 60b3a2f8400..00000000000 --- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceOption.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Box, Check } from 'lucide-react' -import { cn } from 'ui' - -export const ResourceOption = ({ - value, - label, - isSelected, - onChange, -}: { - value: string - label: string - isSelected: boolean - onChange: () => void -}) => ( - -)