// desktop/src/components/resources/Modals.tsx // // Modal dialogs for the Resources page (Slice 4): // - ConfirmDialog — generic yes/no confirmation // - BindingFormModal — create a new ResourceBinding // - GrantFormModal — create a new ResourceGrant (allowed_actions // constrained to picked binding's permission_scope) import { useEffect, useMemo, useState } from 'react' import { useTranslation } from '../../i18n' import { type CreateBindingInput, type CreateGrantInput, type ResourceBinding, type ResourceStatus, type ResourceType, } from '../../api/heicodeResources' // ─── ConfirmDialog ────────────────────────────────────────────── type ConfirmDialogProps = { open: boolean title: string body: string confirmLabel: string danger?: boolean busy?: boolean errorMessage?: string | null onConfirm: () => void onCancel: () => void } export function ConfirmDialog({ open, title, body, confirmLabel, danger, busy, errorMessage, onConfirm, onCancel, }: ConfirmDialogProps) { const t = useTranslation() if (!open) return null return (

{title}

{body}
{errorMessage ? (
{errorMessage}
) : null}
) } // ─── BindingFormModal ────────────────────────────────────────── type BindingFormProps = { open: boolean busy?: boolean errorMessage?: string | null onSubmit: (input: CreateBindingInput) => void onCancel: () => void } export function BindingFormModal({ open, busy, errorMessage, onSubmit, onCancel, }: BindingFormProps) { const t = useTranslation() const [type, setType] = useState('git') const [name, setName] = useState('') const [externalRef, setExternalRef] = useState('') const [permissionScope, setPermissionScope] = useState('') const [secretRef, setSecretRef] = useState('') const [status, setStatus] = useState('pending') // reset when reopened useEffect(() => { if (open) { setType('git') setName('') setExternalRef('') setPermissionScope('') setSecretRef('') setStatus('pending') } }, [open]) if (!open) return null const canSubmit = name.trim().length > 0 && !busy const handleSubmit = () => { const scope = permissionScope .split(/[\n,]/) .map((s) => s.trim()) .filter(Boolean) const input: CreateBindingInput = { type, name: name.trim(), ...(externalRef.trim() && { external_ref: externalRef.trim() }), ...(scope.length > 0 && { permission_scope: scope }), ...(secretRef.trim() && { secret_ref: secretRef.trim() }), status, } onSubmit(input) } return (

{t('resources.modal.create.title')}

{t('resources.modal.create.subtitle')}

setName(e.target.value)} disabled={busy} placeholder="my-repo" maxLength={255} className={inputClass} /> setExternalRef(e.target.value)} disabled={busy} placeholder="https://example.com/org/repo.git" className={inputClass} />