import type { components } from 'api-types' import { Copy, Download, Key, Plus, RotateCcw, X } from 'lucide-react' import { useEffect, useRef, useState } from 'react' import { toast } from 'sonner' import { Button, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Input, Popover, PopoverContent, PopoverTrigger, ScrollArea, Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, WarningIcon, } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { FormLayout } from 'ui-patterns/form/Layout/FormLayout' import { usePrivateApps } from '../../PrivateAppsContext' import { PERMISSIONS } from '../Apps.constants' import { CreateAppSheetStep } from './CreateAppSheetStep' import { usePlatformAppCreateMutation } from '@/data/platform-apps/platform-app-create-mutation' import { usePlatformAppDeleteMutation } from '@/data/platform-apps/platform-app-delete-mutation' import { usePlatformAppInstallationCreateMutation } from '@/data/platform-apps/platform-app-installation-create-mutation' import { usePlatformAppSigningKeyCreateMutation } from '@/data/platform-apps/platform-app-signing-key-create-mutation' import { useCopyToClipboard } from '@/hooks/ui/useCopyToClipboard' type CreatePlatformAppResponse = components['schemas']['CreatePlatformAppResponse'] type CreatePlatformAppSigningKeyResponse = components['schemas']['CreatePlatformAppSigningKeyResponse'] interface CreateAppSheetProps { visible: boolean onClose: () => void onCreated: (app: CreatePlatformAppResponse) => void } export function CreateAppSheet({ visible, onClose, onCreated }: CreateAppSheetProps) { const { slug, installations, addInstallation } = usePrivateApps() const { copy } = useCopyToClipboard() const [name, setName] = useState('') const [selectedPermissions, setSelectedPermissions] = useState([]) const [permissionSearchOpen, setPermissionSearchOpen] = useState(false) const [createdApp, setCreatedApp] = useState(null) const [generatedKey, setGeneratedKey] = useState(null) const [keyCopied, setKeyCopied] = useState(false) const [showCloseConfirm, setShowCloseConfirm] = useState(false) const step3Ref = useRef(null) const { mutate: deleteApp, isPending: isDeleting } = usePlatformAppDeleteMutation({ onSuccess: () => handleClose(), }) const { mutate: installApp } = usePlatformAppInstallationCreateMutation({ onSuccess: (data) => { if (data) addInstallation(data, 'all') }, }) const { mutate: createSigningKey, isPending: isCreatingKey } = usePlatformAppSigningKeyCreateMutation({ onSuccess: (keyData, vars) => { if (keyData) setGeneratedKey(keyData) if (installations.length === 0 && slug) { installApp({ slug, app_id: vars.appId }) } }, }) const { mutate: createApp, isPending: isCreatingApp } = usePlatformAppCreateMutation({ onSuccess: (data) => { toast.success(`App "${data.name}" created`) setCreatedApp(data) createSigningKey({ slug: slug!, appId: data.id }) }, }) function reset() { setName('') setSelectedPermissions([]) setPermissionSearchOpen(false) setCreatedApp(null) setGeneratedKey(null) setKeyCopied(false) } function handleClose() { reset() onClose() } function handleRequestClose() { setShowCloseConfirm(true) } function handleCreate() { if (!slug) return createApp({ slug, name: name.trim(), permissions: selectedPermissions as components['schemas']['CreatePlatformAppBody']['permissions'], }) } function toggle(id: string) { setSelectedPermissions((prev) => prev.includes(id) ? prev.filter((p) => p !== id) : [...prev, id] ) } const canCreate = name.trim().length > 0 && selectedPermissions.length > 0 const isLoading = isCreatingApp || isCreatingKey || isDeleting const keyRevealed = generatedKey !== null useEffect(() => { if (generatedKey) { step3Ref.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }) } }, [generatedKey]) return ( <> { if (!open) handleRequestClose() }} > Create private app Create a private app to generate scoped access tokens for your organization.
setName(e.target.value)} disabled={isLoading} />
Configure permissions
{selectedPermissions.length > 0 && ( No permissions found.
{PERMISSIONS.map((perm) => ( toggle(perm.id)} className="text-foreground" >
toggle(perm.id)} onClick={(e) => e.stopPropagation()} /> {perm.label}
))}
{selectedPermissions.length === 0 ? (

No permissions configured yet.

) : (
{selectedPermissions.map((id, index) => { const perm = PERMISSIONS.find((p) => p.id === id) return (

{perm?.label}

{perm?.description && (

{perm.description}

)}
{index < selectedPermissions.length - 1 && (
)}
) })}
)}
Once you've set these permissions, you cannot edit them.
{isCreatingKey && (

Generating signing key...

)} {keyRevealed && (

Private key